Case management platform for NGOs working with forcibly displaced people and animals. Replaces spreadsheets with a structured, auditable system for registering individuals, tracking support history, managing documents, and reporting.
Stack: Go 1.25 · PostgreSQL · Redis · React 19 · TanStack Router · Tailwind
Prerequisites: Go 1.25+, PostgreSQL, Redis, Bun, Just
# 1. Start dependencies
just docker-up
# 2. Generate RSA keys for JWT
just keygen
# 3. Apply migrations
just migrate-up
# 4. Install frontend dependencies
bun install
# 5. Run backend + frontend dev servers concurrently (port 9000 + Vite on 5173)
just devThe backend exposes Swagger at http://localhost:9000/swagger/index.html in dev mode.
To create the first admin account:
just create-admin admin@example.com yourpasswordAll config is read from environment variables with sensible defaults. Key ones:
| Variable | Default | Description |
|---|---|---|
DATABASE_DSN |
— | Postgres connection string |
REDIS_URL |
redis://localhost:6379/0 |
Redis URL |
JWT_PRIVATE_KEY_PATH |
keys/jwt_rsa |
RSA private key |
JWT_PUBLIC_KEY_PATH |
keys/jwt_rsa.pub |
RSA public key |
STORAGE_BACKEND |
local |
local or s3 |
STORAGE_PATH |
data/uploads |
Local upload directory |
S3_BUCKET |
— | S3 bucket (when backend=s3) |
S3_REGION |
us-east-1 |
S3 region |
CORS_ORIGINS |
http://localhost:5173 |
Comma-separated allowed origins |
COOKIE_SECURE |
true |
Set false for local HTTP dev |
SWAGGER_ENABLED |
false |
Enable Swagger UI |
SENTRY_DSN |
— | Sentry error tracking |
cmd/observer/ CLI entrypoints (serve, migrate, keygen, create-admin, seed)
internal/
domain/ Entities, repository interfaces, domain errors
user/ auth/ project/ person/ support/ migration/
household/ document/ pet/ note/ tag/ reference/
usecase/ Business logic — all non-trivial logic lives here
auth/ admin/ project/
handler/ Thin HTTP adapters (bind → usecase → respond)
middleware/ Auth, RBAC, project role checks
postgres/ Repository implementations (sqlx)
storage/ FileStorage interface + local + S3 backends
crypto/ RSA keys, Argon2 hasher, token generator
config/ Env-based config
app/ Manual DI container
server/ HTTP server (Gin)
spa/ Embedded SPA for production builds
migrations/ Forward-only .up.sql files
packages/observer-web/ React SPA
src/
routes/ TanStack Router file-based routes
components/ Shared UI components
hooks/ React Query data hooks
stores/ Zustand stores (auth, toast)
types/ TypeScript types matching API responses
lib/ Utilities (api client, export, params, i18n)
constants/ Enum → i18n key maps
adr/ Architecture decision records
- DDD + Clean Architecture — domain layer has no dependencies; usecases depend on domain interfaces; handlers depend on usecases
- Manual DI — wired in
internal/app/container.go, no DI framework - ULID IDs —
ulid.ULIDin entities,stringin DTOs - Forward-only migrations — no rollbacks; schema only moves forward
- Dual-level RBAC — platform role (
admin/staff/consultant/guest) × project role × 3 sensitivity flags
just test # Unit tests (fast, no Docker)
just test-all # All tests including integration (requires Docker)
just generate-mocks # Regenerate gomock mocks
just migrate-create name=add_foo # New migration
just seed # Seed demo data
just build-prod # Build frontend + Go binary with embedded SPAContributions and donations are welcome.