A shift scheduling system for departments.
- Docker and Docker Compose
- Go 1.26.1
- Node 22 with
pnpm goosefor local migration commands
- Copy
.env.exampleto.env. - Set local values for Postgres, bootstrap admin, and any SMTP settings you want to test.
- Start Postgres:
docker compose up -d
- Apply migrations:
make migrate-up
- Start the backend:
make run-backend
- Start the frontend in another shell:
make run-frontend
The Vite dev server uses /api/* and proxies those requests to http://localhost:8080, which matches the production Caddy routing shape.
make seed wipes the configured local Postgres data tables with TRUNCATE ... RESTART IDENTITY CASCADE, then inserts a known-good development dataset. It prints the target database before wiping, refuses to run when APP_ENV=production, and uses pa55word for all seeded user passwords unless the bootstrap admin password is set in .env.
make seed
make seed SCENARIO=full
make seed SCENARIO=stressScenarios:
basic: bootstrap admin, 5 employees, 3 positions, and one empty template.full: 8 employees, 4 roles, a populated template, one effectiveASSIGNINGpublication with an 8-week planned active window, and slot-level availability submissions ready for auto-assign.stress: 50 employees, 8 positions, dense template data, oneACTIVEpublication with assignments and pending occurrence-level shift-change requests, plus ended historical fixture data with varied planned active windows. The database permits only one non-ENDEDpublication at a time.
Employees create leave requests from /leaves/new by selecting a date range, choosing an upcoming assigned occurrence, and submitting either a direct give-away or a pool give-away with a leave category and optional reason. Successful submissions return /leaves/:id, which is the share URL for the leave detail page. Employees can review their own requests at /leaves, and admins can list leave requests for a publication through GET /api/publications/{id}/leaves.
- Backend unit tests:
make test-backend - Backend integration tests:
make test-integration - Frontend tests:
cd frontend && pnpm test - Frontend build:
cd frontend && pnpm build
Integration tests expect Postgres to be reachable with the configured POSTGRES_* environment variables and with the migrations already applied.
- Copy
.env.exampleto.env. - Fill in the production values, especially
POSTGRES_PASSWORD,BOOTSTRAP_ADMIN_PASSWORD,SMTP_*,APP_BASE_URL, andCADDY_SITE_ADDRESS. - Bring up the full stack:
make prod-up
- Open the URL served by Caddy.
- Log in with the bootstrap admin user from
.env.
The production stack includes Postgres, a one-shot migration runner, the Go backend, and Caddy serving the SPA plus reverse proxying /api/* to the backend.
- Set
CADDY_SITE_ADDRESSto a real domain such asrota.example.comto let Caddy obtain and renew certificates automatically. - For local Docker testing, keep
CADDY_SITE_ADDRESS=http://localhostso Caddy serves plain HTTP on port 80. APP_BASE_URLmust match the public URL you expect users to open from invitation and password-reset emails.
make prod-up
make prod-down
make prod-logs
make prod-pull| Variable | Default | Purpose |
|---|---|---|
APP_ENV |
development |
Runtime environment name. make seed refuses to run when this is production. |
SERVER_PORT |
8080 |
Backend listen port inside the container. |
POSTGRES_HOST |
localhost |
Database host for local development. Production Compose overrides this to postgres. |
POSTGRES_PORT |
5432 |
Database port. |
POSTGRES_USER |
rota |
Database user. |
POSTGRES_PASSWORD |
empty | Database password. Set a real value before deploy. |
POSTGRES_DB |
rota |
Database name. |
SESSION_EXPIRES_HOURS |
336 |
Session TTL in hours. |
EMAIL_MODE |
log |
Selects the logger or SMTP emailer. |
SMTP_HOST |
empty | SMTP server host. Must be set for production email delivery. |
SMTP_PORT |
587 |
SMTP server port. |
SMTP_USER |
empty | SMTP username. Do not commit real credentials. |
SMTP_PASSWORD |
empty | SMTP password. Do not commit real credentials. |
SMTP_FROM |
Rota <noreply@example.com> |
Default sender address. |
SMTP_TLS_MODE |
starttls |
SMTP TLS mode: starttls, implicit, or none. |
CADDY_SITE_ADDRESS |
http://localhost |
Public site address for Caddy. Use a real domain in production. |
APP_BASE_URL |
http://localhost:5173 |
Base URL embedded in invitation and reset emails. |
INVITATION_TOKEN_TTL |
72h |
Invitation link lifetime. |
PASSWORD_RESET_TOKEN_TTL |
1h |
Password reset link lifetime. |
BOOTSTRAP_ADMIN_EMAIL |
admin@example.com |
Initial admin email when the database is empty. |
BOOTSTRAP_ADMIN_PASSWORD |
empty | Initial admin password. Set before deploy and do not commit the real value. |
BOOTSTRAP_ADMIN_NAME |
Administrator |
Initial admin display name. |
Create a PostgreSQL backup from the production stack with:
docker compose -f docker-compose.prod.yml exec postgres pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB" > rota.sql