|
|
||
|---|---|---|
| backend | ||
| config | ||
| deploy | ||
| docker | ||
| docs | ||
| frontend | ||
| .dockerignore | ||
| .gitignore | ||
| README.md | ||
README.md
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 viamodernc.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
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
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.
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):
- CLI flags
- Environment variables
.envfile next to the executable, then the working directory- YAML/JSON file passed with
--conf - Built-in defaults
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/.
Authentication
Management is always protected. Two modes are supported:
- Local password fallback when
auth.oidc.issuerUrlis empty. The configured password grants bothadminandviewroles, 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/callbackin development orhttps://forms.example.com/auth/callbackin production.
The backend validates the ID token signature, issuer, audience, expiry and configured role claim. Role mappings are configurable:
adminRole(adminby default) is required for form create/update/delete, activation, versioning and access-code management.viewRole(viewby default) is required to list or read submissions. An admin-only token is deliberately denied submission viewing.requireSubmissionAuth: truerequires 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 and the server stubs are generated with:
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 |
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
cd backend && go test ./...
cd frontend && npm test
Docker / Podman / Kubernetes
See docs/DEPLOYMENT.md and deploy/k8s.yaml.
Documentation
docs/ARCHITECTURE.md— components, data model, request flow, extension points.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.