9.2 KiB
16 — Phased Roadmap
Eleven phases, each independently buildable and verifiable. A build agent starting a phase should read: 00, 01, 02, the files listed for the phase, and nothing else. Check off tasks and acceptance criteria here (and the phase box in 00-overview.md) as they are completed and verified.
Dependency graph: 0 → 1 → 2 → 3 → 4 → 5 → 6 → {7, 8} → 9 → 10 (7 and 8 are parallel-safe after 6).
Phase 0 — Foundation
Spec files: 01-architecture.md, 14-design-system.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:embedSPA serving with deep-link fallback; Vite dev proxy- docker-compose (app + postgres + meilisearch + mailhog dev profile); Makefile targets
/healthz
Acceptance:
docker compose upserves the SPA shell at:4080;/healthzreports db okmake migrate-up && make migrate-downcycles cleanly- Shell passes the design-system conformity checklist
Phase 1 — Auth & users
Spec files: 05-auth.md · Depends: 0
- Migrations: users (+seeds), oauth_accounts, sessions, api_tokens
- Register/login/logout with scs sessions; first-user-becomes-admin; rate limiting
- GitHub + Gitea OAuth (linking rules incl. verified-email guard)
- PAT create/list/revoke + bearer middleware
/meendpoints,/userspicker, admin user endpoints- Frontend: login/register/oauth-callback pages, auth store + guard, settings→profile/security/tokens tabs, admin users page
Acceptance (scriptable with curl):
- Register → is_admin true; second register → false
- Cookie-authed and PAT-authed
GET /meboth succeed; revoked PAT → 401 - system/zombie users absent from
/users; login as ids 1–2 impossible - OAuth flow against a real or mocked provider produces a linked account (verified-email path unit-tested)
Phase 2 — Event backbone & audit
Spec files: 03-domain-events.md · Depends: 1
- Migrations: audit_log, events, jobs
events.Emit(audit + outbox in-tx), pg_notify, dispatcher goroutine, job worker pool with backoff/dead statesauth.*anduser.*events emitting through the pipeline- Admin jobs inspection endpoint
Acceptance:
- Login writes an audit row and a processed event row
kill -9during a pending job → job retried after restart (integration test)- A job failing 8 times lands in
deadand is visible via admin endpoint
Phase 3 — Projects core
Spec files: 06-projects.md · Depends: 2
- Migrations: projects, project_members, project_dependencies, project_favorites, labels
- Project CRUD + status/completed_at automation + owner transfer + membership + favorites + label CRUD/seeding + dependencies with cycle detection
RequireProjectMember/RequireProjectOwnermiddleware; non-member 404s- Activity feed endpoints (project + dashboard)
- All mutations emit events per taxonomy
Acceptance:
- Non-member GET on another's project → 404
- Dependency cycle attempt → 409
cycle_detected - Every mutation appears in
/projects/{id}/activitywith correct actor - Sole-owner cannot be removed/deleted without transfer (409)
Phase 4 — Issues & epics
Spec files: 07-issues-epics.md · Depends: 3
- Migrations: epics, issues, issue_blockers, issue_labels, issue_watchers
- Issue CRUD, numbering, sub-issues, blockers + cycles, labels, points, completed_at automation
- board_rank helpers (
Between/Before/After) with unit tests;?view=board; list filters/sort - Epic CRUD, attach/detach/reorder issues, computed progress (counts + points)
Acceptance:
- Two projects both mint
#1; 20 parallel creates in one project yield 20 unique consecutive numbers - Status→done sets completed_at; back to in_progress clears it
- Blocker cycle → 409; epic progress matches a hand-computed fixture
- Board view returns rank-ordered groups; a move lands between its neighbors
Phase 5 — Views (frontend core)
Spec files: 13-frontend.md (+ 14-design-system.md) · Depends: 4
- Dashboard, project list/overview, project settings (general/members/labels tabs)
- Issue table with FilterBar + URL-synced state
- Kanban board with optimistic drag-and-drop
- Issue detail page (all sidebar fields editable, sub-issues, blockers)
- Epic list/detail pages
- Stores: projects, issues, board, epics; badges/pickers/dialog components
Acceptance:
- Drag card between columns → persists after reload (status + position)
- Filters/sort survive refresh via URL; shareable link reproduces the view
- Failed PATCH rolls back the optimistic move with a toast
- New pages pass the conformity checklist
Phase 6 — Collaboration
Spec files: 08-collaboration.md · Depends: 5
- Migrations: comments, links, attachments, wiki_pages
- Comments CRUD + resolve; polymorphic links/attachments +
/files/auth-checked serving; wiki CRUD with slug rules + conflict warning - Server-side mention/#ref extraction into event payloads; watcher auto-watch/mute semantics
- Frontend: MarkdownEditor/MarkdownView (mention + #ref autocomplete/rendering, paste-to-attach), comments UI with resolve, attachments/links UI, wiki pages, WatchButton + watcher list
Acceptance:
@userin a comment produces a mention entry in the event payload;#3renders as a link to issue 3- Resolving collapses the thread; unresolve restores it
- Upload lands at the specified disk path; non-member GET on
/files/…→ 404; oversized upload → 413 - Unwatch (mute) then comment again → no re-auto-watch
Phase 7 — Notifications & real-time
Spec files: 09-notifications-realtime.md · Depends: 6
- Migration: notifications
- Fan-out consumer (rules + precedence + dedupe), inbox/bell endpoints
- SSE hub +
/stream+ heartbeats; frontend sse.ts + realtime store + in-place updates - SMTP sender, instant emails, daily digest job, email_mode setting UI
Acceptance:
- Two-browser test: assign in A → B's bell increments and B's board card moves within 2s, no reload
- Actor never notified of own action;
mentionedwins precedence overcommented - MailHog shows instant email; digest job groups a day of notifications into one email
- Muted watcher gets neither bell nor email
Phase 8 — Search (parallel-safe with 7)
Spec files: 10-search.md · Depends: 6
- Meilisearch client, index bootstrap, event→sync mapping,
search_syncjob handler /searchendpoint with membership filtering; reindex CLI + admin endpoint- CommandPalette (Cmd+K) +
/searchpage
Acceptance:
- Created issue findable in < 5s; soft-deleted issue disappears from results
- Non-member's content never appears (integration test with two users)
solopm reindexrebuilds equal counts from Postgres truth- Palette opens with Cmd+K, arrows navigate, Enter routes
Phase 9 — Integrations
Spec files: 11-integrations.md · Depends: 7
- Migrations: incoming_webhook_receipts, outgoing_webhooks, outgoing_webhook_deliveries
- Incoming endpoint: HMAC verify, receipts, repo routing, closes-#N automation (system user, via_webhook), replay
- Outgoing: CRUD, signed delivery jobs, delivery log, test endpoint, SSRF guard
- Export JSON + CSV streaming
- Frontend: settings→webhooks tab (secret, receipts, outgoing CRUD + deliveries), export tab
Acceptance:
- Replayed GitHub PR-merged fixture with valid signature closes
#N; audit shows system user with via_webhook=true; bad signature → 401 with receipt logged invalid - Duplicate delivery id → 200 without reprocessing
- Outgoing delivery retries against a flaky test receiver, then records success with correct
X-SoloPM-Signature - JSON export contains every entity family; CSV opens with correct columns
Phase 10 — Retention & hardening
Spec files: 12-retention.md · Depends: 9
- Cull job + CLI + admin endpoint with dry-run; cascade scopes incl. disk files; zombie reassignment; auxiliary retention (notifications/events/jobs/receipts/deliveries)
- Backup/restore docs + drill; systemd unit example; reverse-proxy doc
- Final pass: rate limits verified, error envelope consistency,
/healthzcomplete, README quickstart
Acceptance:
- Dry-run reports the exact would-delete set with zero deletions
- Culling a project removes all its rows and files (orphan-check test passes)
- Culled user's comments render as "Deleted User"; audit keeps original id
- Fresh-clone
docker compose upwalkthrough from the README works end-to-end