# Kererū Forms Simple, versioned surveys with a Go + OpenAPI backend and a React frontend. - **Backend**: Go 1.26, Gin, OpenAPI-generated server (`oapi-codegen`), SQLite via `modernc.org/sqlite` (pure Go), zerolog, OpenTelemetry. - **Frontend**: React 18, Vite, TypeScript, Tailwind CSS, React Router, Vitest. - **Deployment**: single container serving both the API and the built SPA, plus Docker Compose, Podman and Kubernetes manifests. ## Quick start ### 1. Backend ```bash cd backend go mod download go run ./cmd/kereru-forms --listen-addr 0.0.0.0 --port 8080 ``` The API listens on . The SQLite database (`kereru.db`) and its schema are created automatically. ### 2. Frontend ```bash cd frontend npm install npm run dev ``` Open . Vite proxies `/api/*` to `http://localhost:8080/api/*`. The API is also available without the `/api` prefix for probes and direct clients. With no OIDC provider configured, management sign-in uses the local development password `admin` and grants both admin and view roles. Change `auth.localPassword` (or `KERERU_AUTH_LOCAL_PASSWORD`) before exposing the service. ## Configuration Settings are resolved in this order (highest wins): 1. CLI flags 2. Environment variables 3. `.env` file next to the executable, then the working directory 4. YAML/JSON file passed with `--conf` 5. Built-in defaults ```bash kereru-forms --conf ./config/config.example.yaml ``` | Flag | Environment variable | Default | | --- | --- | --- | | `--conf` | – | – | | `--log-level` | `KERERU_LOG_LEVEL` | `info` | | `--log-format` | `KERERU_LOG_FORMAT` | `console` | | `--listen-addr` | `KERERU_LISTEN_ADDR` | `0.0.0.0` | | `--listen-addr6` | `KERERU_LISTEN_ADDR6` | – | | `--port` | `KERERU_PORT` | `8080` | | `--db-driver` | `KERERU_DB_DRIVER` | `sqlite` | | `--db-dsn` | `KERERU_DB_DSN` | `file:kereru.db?...` | | `--static-dir` | `KERERU_STATIC_DIR` | – | | – | `KERERU_TELEMETRY_ENABLED` | `false` | | – | `OTEL_EXPORTER_OTLP_ENDPOINT` | `localhost:4318` | | – | `KERERU_CORS_ORIGINS` | `http://localhost:5173` | | – | `KERERU_ENVIRONMENT` | `development` | | – | `KERERU_AUTH_LOCAL_PASSWORD` | `admin` | | – | `KERERU_AUTH_LOCAL_TOKEN_SECRET` | random per process | | – | `KERERU_AUTH_LOCAL_TOKEN_TTL_HOURS` | `8` | | – | `KERERU_AUTH_REQUIRE_SUBMISSION_AUTH` | `false` | | – | `KERERU_OIDC_ISSUER_URL` | – | | – | `KERERU_OIDC_CLIENT_ID` | – | | – | `KERERU_OIDC_SCOPES` | `openid,profile,email` | | – | `KERERU_OIDC_ROLE_CLAIM` | `roles` | | – | `KERERU_OIDC_ADMIN_ROLE` | `admin` | | – | `KERERU_OIDC_VIEW_ROLE` | `view` | Both an IPv4 and an IPv6 listener may be configured at the same time. Set `--listen-addr ""` to disable the IPv4 listener. Frontend build-time setting: `VITE_API_BASE_URL` (defaults to `/api`; set to `http://localhost:8080` when the frontend is hosted separately). Sample files live in [`config/`](config). ## Authentication Management is always protected. Two modes are supported: - **Local password fallback** when `auth.oidc.issuerUrl` is empty. The configured password grants both `admin` and `view` roles, which is intended for local development and testing. - **OAuth/OIDC** when an issuer is configured. The React SPA uses the authorization-code flow with PKCE and presents the provider's ID token as a bearer token. Configure a **public SPA client** in Okta/Keycloak and register the frontend callback URL, for example `http://localhost:5173/auth/callback` in development or `https://forms.example.com/auth/callback` in production. The backend validates the ID token signature, issuer, audience, expiry and configured role claim. Role mappings are configurable: - `adminRole` (`admin` by default) is required for form create/update/delete, activation, versioning and access-code management. - `viewRole` (`view` by default) is required to list or read submissions. An admin-only token is deliberately denied submission viewing. - `requireSubmissionAuth: true` requires any authenticated user (no role) to list/open forms and submit responses. Common role claim examples: `roles`, `groups`, or `realm_access.roles` for Keycloak. Set `localTokenSecret` to a stable value if local-password tokens must survive restarts or multiple replicas. Local tokens and OIDC ID tokens are kept in browser `sessionStorage` and sent as `Authorization: Bearer …`. ## API The contract is defined in [`backend/openapi/openapi.yaml`](backend/openapi/openapi.yaml) and the server stubs are generated with: ```bash cd backend oapi-codegen -config oapi-codegen.yaml openapi/openapi.yaml ``` Interactive API documentation is available at . Swagger UI and the OpenAPI specification are bundled with the frontend, so the docs work without an internet connection. Forms support optional linked PDFs, digital signatures, external reference identifiers and offline PDF uploads. Key routes: | Method | Path | Purpose | | --- | --- | --- | | `GET` | `/health` | Health and version | | `GET` | `/auth/config` | Browser authentication mode / OIDC details | | `POST` | `/auth/login` | Local password login fallback | | `GET` | `/auth/me` | Current user and role flags | | `POST` | `/auth/logout` | Stateless logout acknowledgement | | `GET`/`POST` | `/forms` | List / create forms (create requires admin) | | `GET`/`PUT`/`DELETE` | `/forms/{formId}` | Read / update / delete a form version | | `POST` | `/forms/{formId}/activate` | Activate a form version | | `POST` | `/forms/{formId}/inactivate` | Inactivate a form version | | `POST` | `/forms/{formId}/versions` | Clone into a new version | | `GET` | `/forms/{formId}/pdf` | Printable PDF of the definition | | `GET`/`POST` | `/forms/{formId}/submissions` | List / submit responses | | `GET` | `/submissions/{submissionId}` | Submission details | | `GET` | `/submissions/{submissionId}/offline-pdf` | Download an uploaded offline PDF | | `GET`/`POST` | `/forms/{formId}/access-codes` | List / generate single-use codes | The specification is served at `/openapi.yaml` in development and production builds. ## Tests ```bash cd backend && go test ./... cd frontend && npm test ``` ## Docker / Podman / Kubernetes See [`docs/DEPLOYMENT.md`](docs/DEPLOYMENT.md) and [`deploy/k8s.yaml`](deploy/k8s.yaml). ## Documentation - [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) — components, data model, request flow, extension points. - [`docs/DEPLOYMENT.md`](docs/DEPLOYMENT.md) — development, Docker, Podman and Kubernetes instructions. ## Security note Management endpoints require a bearer JWT. In local-password mode change the default `admin` password and set a stable `localTokenSecret`; in OIDC mode enforce MFA and role assignment in the identity provider. Use HTTPS in production, keep `corsOrigins` narrow, and enable `requireSubmissionAuth` if forms must not be publicly accessible. Access codes protect individual form submissions, not administration.