# Szabadpálya Community funding for Hungarian public projects, with no platform fee. **Backend** Go + Gin + pgx, Postgres 17 · **Frontend** React 19 + React Router + TypeScript + Vite + Tailwind 4 · **Deployment** Docker Compose, self-hosted. The product is Hungarian: every user-facing string, campaign and reward tier is in Hungarian. Everything else — code, comments, commit messages, documentation — is in English. ## Layout ``` api/ Go server: JSON API, the HTML document, share images, migrations api/test/ development fixture and the seeder — never built into the shipping image web/ Vite + React Router single-page app scripts/ up.sh, db.sh, dev.sh, go.sh, ci.sh ``` One binary serves everything in production: the API under `/api`, the hashed Vite assets under `/assets`, the generated share images, and the HTML document for every other path. ## Getting started Docker and pnpm are all you need installed. The Go toolchain is not required on the host — `scripts/go.sh` runs it in a container against a cached module volume. ```bash cp .env.example .env # defaults are the development ones; set ADMIN_EMAILS ./scripts/up.sh ``` That is the whole thing. `up.sh` starts Postgres, applies any migration that has not run yet, then runs the API on :3000 and Vite on :5173 until Ctrl-C stops both. Open **http://localhost:5173**. A fresh database is empty. To load the fixture — 4 campaigns, 550 pledges: ```bash ./scripts/dev.sh seed # wipes campaigns first, so it is safe to repeat ``` In development Vite serves the page and proxies `/api` to the Go process. **The share tags are therefore not exercised in development** — Vite owns `index.html` there, and the document template only runs in the container. That is what the CI smoke test is for. ### The scripts | | | |---|---| | `./scripts/up.sh` | everything at once, the normal way to start | | `./scripts/db.sh {up\|down\|psql\|logs\|reset}` | Postgres on localhost:5433 | | `./scripts/dev.sh {server\|migrate\|seed}` | one Go process, reading `.env` | | `./scripts/go.sh ` | the Go toolchain itself: `go test ./...`, `go mod tidy` | | `./scripts/ci.sh [--fast]` | the pipeline (see CI below) | `dev.sh` needs `.env` and a running database; `go.sh` needs neither, which is why the static half of CI goes through it and works on a fresh clone. ## Why the Go server renders HTML Every campaign needs its own `og:` tags. The crawlers that build a Facebook share card do not execute JavaScript, so a plain SPA shell makes every shared campaign look identical — which is exactly the weakness SPEC.md section 8 identifies in the commercial Hungarian platforms. The seam is deliberately sharp: - **Go owns ``** — title, description, `og:` tags, the theme script, and the hashed asset tags read out of Vite's `manifest.json`. - **React owns everything inside `#root`.** No markup is produced in two places, so no markup can drift. The document also inlines the data the first route would otherwise fetch, in a `