kereru-forms/README.md

151 lines
6.8 KiB
Markdown
Raw Normal View History

# 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 <http://localhost:8080>. The SQLite database (`kereru.db`) and its schema are created automatically.
### 2. Frontend
```bash
cd frontend
npm install
npm run dev
```
Open <http://localhost:5173>. Vite proxies `/api/*` to `http://localhost:8080/api/*`. The API is also available without the `/api` prefix for probes and direct clients.
2026-10-23 19:36:02 +00:00
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` |
2026-10-23 19:36:02 +00:00
| – | `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).
2026-10-23 19:36:02 +00:00
## 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 <http://localhost:5173/docs>. 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 |
2026-10-23 19:36:02 +00:00
| `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
2026-10-23 19:36:02 +00:00
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.