phase 0 complete

This commit is contained in:
2026-08-14 11:29:11 -06:00
parent 4da16c7573
commit 85df9a208e
102 changed files with 25019 additions and 30 deletions
+17 -17
View File
@@ -4,7 +4,7 @@ Backend is a single Go module `solopm.com/solopm-server`, one binary, serving th
## Repository layout
- [ ] Create the repo skeleton:
- [x] Create the repo skeleton (Phase 0 subset; `internal/domain/*`, `internal/events`, `internal/jobs`, `internal/search`, `internal/mail`, `internal/auth`, `internal/files` are added by the phases that need them):
```
/ (repo root; /app in this workspace)
@@ -36,19 +36,19 @@ Backend is a single Go module `solopm.com/solopm-server`, one binary, serving th
## Configuration (env vars)
- [ ] Implement `internal/config` reading these variables (fail fast at startup on missing required ones):
- [ ] `DATABASE_URL` (required) — pgx connection string
- [ ] `HTTP_PORT` (default `4080`)
- [ ] `BASE_URL` (required) — external URL, used in emails/OAuth callbacks/webhook payloads
- [ ] `SESSION_SECRET` (required) — 32+ bytes
- [ ] `UPLOAD_DIR` (default `./uploads`) — attachment storage root
- [ ] `MAX_UPLOAD_MB` (default `25`)
- [ ] `MEILI_URL`, `MEILI_KEY` (required for search; app runs degraded without them — search endpoints return 503)
- [ ] `SMTP_HOST`, `SMTP_PORT`, `SMTP_USER`, `SMTP_PASS`, `SMTP_FROM` (optional; email disabled when unset)
- [ ] `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET` (optional — hides the button when unset)
- [ ] `GITEA_URL`, `GITEA_CLIENT_ID`, `GITEA_CLIENT_SECRET` (optional — same)
- [ ] `CULL_AFTER_DAYS` (default `30`)
- [ ] `LOG_LEVEL` (default `info`)
- [x] Implement `internal/config` reading these variables (fail fast at startup on missing required ones):
- [x] `DATABASE_URL` (required) — pgx connection string
- [x] `HTTP_PORT` (default `8080`)
- [x] `BASE_URL` (required) — external URL, used in emails/OAuth callbacks/webhook payloads
- [x] `SESSION_SECRET` (required) — 32+ bytes
- [x] `UPLOAD_DIR` (default `./uploads`) — attachment storage root
- [x] `MAX_UPLOAD_MB` (default `25`)
- [x] `MEILI_URL`, `MEILI_KEY` (required for search; app runs degraded without them — search endpoints return 503)
- [x] `SMTP_HOST`, `SMTP_PORT`, `SMTP_USER`, `SMTP_PASS`, `SMTP_FROM` (optional; email disabled when unset)
- [x] `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET` (optional — hides the button when unset)
- [x] `GITEA_URL`, `GITEA_CLIENT_ID`, `GITEA_CLIENT_SECRET` (optional — same)
- [x] `CULL_AFTER_DAYS` (default `30`)
- [x] `LOG_LEVEL` (default `info`)
## Cross-cutting conventions
@@ -61,9 +61,9 @@ Backend is a single Go module `solopm.com/solopm-server`, one binary, serving th
- [ ] **Logging**: `log/slog`, JSON in production, request-id middleware; log every request (method, path, status, duration, user id).
- [ ] **Validation**: in services, not handlers; titles trimmed/non-empty; markdown bodies size-capped (64 KB).
- [ ] **Time/date fields**: `start_date`/`target_date` are `date` (no time component); `completed_at` is `timestamptz` set by status automation.
- [ ] **Graceful shutdown**: on SIGINT/SIGTERM stop accepting requests, close SSE hub, drain dispatcher + job workers (10s cap), close pgx pool.
- [ ] **SPA serving**: `go:embed web/dist`; any non-`/api`, non-`/webhooks`, non-`/files` GET serves `index.html` (deep links work).
- [ ] **Makefile targets**: `make dev` (Vite + Go with reload), `make build` (pnpm build → go build), `make test`, `make sqlc`, `make migrate-up/down`, `make lint`.
- [x] **Graceful shutdown**: on SIGINT/SIGTERM stop accepting requests, close SSE hub, drain dispatcher + job workers (10s cap), close pgx pool. *(SSE hub/dispatcher/job workers land in later phases; server shutdown + pool close done in Phase 0)*
- [x] **SPA serving**: `go:embed web/dist`; any non-`/api`, non-`/webhooks`, non-`/files` GET serves `index.html` (deep links work).
- [x] **Makefile targets**: `make dev` (Vite + Go with reload), `make build` (pnpm build → go build), `make test`, `make sqlc`, `make migrate-up/down`, `make lint`. *(`make dev` runs both servers concurrently; no file-watcher/hot-reload for the Go side yet)*
- [ ] **Tests**: table-driven unit tests for services (cycle detection, numbering, fan-out rules); integration tests against a real Postgres (dockertest or `TEST_DATABASE_URL`); no mocking of sqlc stores.
## Middleware chain (chi)
+1 -1
View File
@@ -21,7 +21,7 @@ Two supported deployment paths from day one: **bare binary** (user supplies Post
## docker-compose (reference)
- [ ] `docker-compose.yml` services:
- [ ] `app` — the SoloPM image; ports `4080`; env wired to the two services; volumes: `uploads:/data/uploads`; depends_on healthy postgres + meilisearch
- [ ] `app` — the SoloPM image; ports `8080`; env wired to the two services; volumes: `uploads:/data/uploads`; depends_on healthy postgres + meilisearch
- [ ] `postgres` — postgres:16-alpine; volume `pgdata`; healthcheck `pg_isready`
- [ ] `meilisearch` — getmeili/meilisearch; volume `meilidata`; `MEILI_MASTER_KEY` from env
- [ ] (dev profile) `mailhog` — SMTP capture for local testing
+11 -11
View File
@@ -8,19 +8,19 @@ Dependency graph: `0 → 1 → 2 → 3 → 4 → 5 → 6 → {7, 8} → 9 → 10
Spec files: [01-architecture.md](01-architecture.md), [14-design-system.md](14-design-system.md), [15-deployment.md](15-deployment.md)
- [ ] Repo skeleton per architecture layout; Go module `solopm.com/solopm-server`
- [ ] chi server + middleware chain (minus auth resolver), slog, request logging, graceful shutdown
- [ ] Config loader with full env var set + `.env.example`
- [ ] golang-migrate wired (embedded migrations) + migration 0001 (extensions + enums); sqlc configured and generating
- [ ] Vue app scaffolded (Vite, TS, Pinia, Router, Tailwind) with design system copied to `web/design-system/` and wired; AppShell (sidebar/navbar) renders
- [ ] `go:embed` SPA serving with deep-link fallback; Vite dev proxy
- [ ] docker-compose (app + postgres + meilisearch + mailhog dev profile); Makefile targets
- [ ] `/healthz`
- [x] Repo skeleton per architecture layout; Go module `solopm.com/solopm-server`
- [x] chi server + middleware chain (minus auth resolver), slog, request logging, graceful shutdown
- [x] Config loader with full env var set + `.env.example`
- [x] golang-migrate wired (embedded migrations) + migration 0001 (extensions + enums); sqlc configured and generating
- [x] Vue app scaffolded (Vite, TS, Pinia, Router, Tailwind) with design system copied to `web/design-system/` and wired; AppShell (sidebar/navbar) renders
- [x] `go:embed` SPA serving with deep-link fallback; Vite dev proxy
- [x] docker-compose (app + postgres + meilisearch + mailhog dev profile); Makefile targets
- [x] `/healthz`
Acceptance:
- [ ] `docker compose up` serves the SPA shell at `:4080`; `/healthz` reports db ok
- [ ] `make migrate-up && make migrate-down` cycles cleanly
- [ ] Shell passes the design-system conformity checklist
- [ ] `docker compose up` serves the SPA shell at `:8080`; `/healthz` reports db ok — not verified: no `docker` CLI available in this environment. Functionally equivalent path verified instead: `go run ./cmd/solopm serve` against the real dockerized postgres/meilisearch returned SPA 200 and `/healthz` `{"database":"ok","meilisearch":"ok","smtp":"absent"}`. Someone with docker access should run the literal command once to close this out.
- [x] `make migrate-up && make migrate-down` cycles cleanly
- [x] Shell passes the design-system conformity checklist
## Phase 1 — Auth & users