docs: create milestone v2.0 roadmap (5 phases)

This commit is contained in:
Arthur Belleville 2026-05-15 20:16:20 +02:00
parent 39a1e4d21d
commit cd8034f33b
No known key found for this signature in database
3 changed files with 86 additions and 180 deletions

View file

@ -95,17 +95,17 @@ Populated during roadmap creation.
| Requirement | Phase | Status | | Requirement | Phase | Status |
|-------------|-------|--------| |-------------|-------|--------|
| AUTH-08..13 | TBD | Pending | | AUTH-08..13 | Phase 8 | Pending |
| ETAPE-01..06 | TBD | Pending | | ETAPE-01..06 | Phase 9 | Pending |
| EVENT-01..05 | TBD | Pending | | EVENT-01..05 | Phase 10 | Pending |
| PLAN-01..04 | TBD | Pending | | PLAN-01..04 | Phase 11 | Pending |
| CHAT-01..06 | TBD | Pending | | CHAT-01..06 | Phase 12 | Pending |
**Coverage:** **Coverage:**
- v2.0 requirements: 27 total - v2.0 requirements: 27 total
- Mapped to phases: 0 - Mapped to phases: 27
- Unmapped: 27 - Unmapped: 0
--- ---
*Requirements defined: 2026-05-15* *Requirements defined: 2026-05-15*
*Last updated: 2026-05-15 after v2.0 requirements draft* *Last updated: 2026-05-15 after v2.0 roadmap creation*

View file

@ -1,10 +1,10 @@
# Roadmap: Xtablo Go+HTMX Rewrite # Roadmap: Xtablo v2.0 Collaboration, Planning, and Social Sign-in
**Created:** 2026-05-14 **Created:** 2026-05-15
**Project mode:** Vertical MVP (each phase delivers an end-to-end user-visible slice where possible) **Project mode:** Brownfield milestone on existing Go+HTMX backend
**Milestone:** v1 — Tablos workflow on Go+HTMX **Milestone:** v2.0 — Collaboration, planning, and social sign-in
7 phases, sequential. Earlier phases are foundational; later phases build atop them. Phase boundaries are deliberate review points — especially for DB schema decisions (Phases 2, 3, 4, 5). 5 phases, sequential. Phase numbering continues from v1.0, so v2.0 starts at Phase 8.
--- ---
@ -12,198 +12,98 @@
| # | Phase | Goal | Requirements | | # | Phase | Goal | Requirements |
|---|-------|------|--------------| |---|-------|------|--------------|
| 1 | Foundation | Fresh `backend/` Go package boots, renders HTMX, talks to Postgres | FOUND-01..05 | | 8 | Social Sign-in | Google and Apple sign-in create/link local users and issue existing Xtablo sessions | AUTH-08..13 |
| 2 | Authentication | Complete (7/7) | AUTH-01..07 | | 9 | Etapes | Tasks can be grouped under one-level etapes without breaking the kanban model | ETAPE-01..06 |
| 3 | Tablos CRUD | Complete (3/3) | TABLO-01..06 | | 10 | Events | Tablos have scheduled events with CRUD, validation, and authorization | EVENT-01..05 |
| 4 | 3/4 | In Progress| | | 11 | Individual Planning | Users can view their own event agenda across tablos | PLAN-01..04 |
| 5 | 4/4 | Complete | 2026-05-15 | | 12 | Native Tablo Chat | Each tablo has persisted discussion with real-time delivery and no managed chat provider | CHAT-01..06 |
| 6 | 1/3 | In Progress| |
| 7 | Deploy v1 | The product runs in production on a single host | DEPLOY-01..05 |
--- ---
## Phase Details ## Phase Details
### Phase 1: Foundation ### Phase 8: Social Sign-in
**Goal:** A fresh `backend/` Go package boots a web server, renders an HTMX-driven base layout, and connects to a local Postgres with migrations. **Goal:** Users can sign in with Google or Apple while Xtablo keeps owning user accounts and sessions.
**Mode:** mvp **Mode:** mvp
**Requirements:** FOUND-01, FOUND-02, FOUND-03, FOUND-04, FOUND-05 **Requirements:** AUTH-08, AUTH-09, AUTH-10, AUTH-11, AUTH-12, AUTH-13
**Success Criteria:** **Success Criteria:**
1. `just dev` starts the web server on a local port and live-reloads on `.go` and template changes 1. Login/signup page shows Google and Apple sign-in entry points alongside email/password
2. `GET /healthz` returns 200 with a JSON `{status:"ok", db:"ok"}` only when the DB is reachable 2. Google callback validates state, exchanges authorization code, verifies ID token, creates or links `user_identities`, and issues a local session
3. The root route renders a Tailwind-styled HTMX page that loads without console errors and includes a working `hx-get` example 3. Apple callback validates state/nonce, exchanges authorization code, verifies ID token, creates or links `user_identities`, and issues a local session
4. `just migrate up` applies migrations from `backend/migrations/` against the local Postgres 4. Existing email/password signup/login/logout tests still pass unchanged
5. A new dev can clone the repo, run `compose up -d` + `just dev`, and see the page within ~5 minutes following `backend/README.md` 5. `.env.example` and README document required Google and Apple config without committing secrets
**User-in-loop:** Approve directory layout (`backend/cmd/web`, `backend/cmd/worker`, `backend/internal/...`) and pick the migration tool (`goose` vs `golang-migrate`). **User-in-loop:** Approve `user_identities` schema and account-linking behavior for matching verified emails before migration/sqlc generation.
**Plans:** 4 plans ### Phase 9: Etapes
Plans: **Goal:** A user can organize tasks under one-level etapes inside a tablo while preserving existing task status and ordering behavior.
- [x] 01-01-PLAN.md — Project scaffold: Go module, compose, justfile, env, sqlc/air/tailwind config, bootstrap migration
- [x] 01-02-PLAN.md — RED gate: failing handler tests + `internal/web/ui` design-system package (Button/Card/Badge)
- [x] 01-03-PLAN.md — GREEN slice: pgxpool, chi router, middleware, templates, cmd/web + cmd/worker, end-to-end HTMX demo
- [x] 01-04-PLAN.md — README quickstart + clean-clone onboarding walkthrough (closes FOUND-05)
### Phase 2: Authentication
**Goal:** A new user can sign up, log in with email + password, and stay logged in across requests using server-managed sessions.
**Mode:** mvp **Mode:** mvp
**Requirements:** AUTH-01, AUTH-02, AUTH-03, AUTH-04, AUTH-05, AUTH-06, AUTH-07 **Requirements:** ETAPE-01, ETAPE-02, ETAPE-03, ETAPE-04, ETAPE-05, ETAPE-06
**Success Criteria:** **Success Criteria:**
1. Signing up creates a user row with hashed password (argon2id or bcrypt) and starts a session 1. User can create, edit, delete, and reorder etapes inside a tablo
2. Logging in with valid credentials issues a signed HTTP-only cookie; invalid credentials show a clear error 2. User can assign or unassign a task from an etape
3. Hitting any protected route while unauthenticated redirects to `/login`; logged-in users on `/login` go to `/` 3. Tasks continue to move/reorder across kanban statuses after etape support is added
4. Logout invalidates the session server-side (cookie cleared + DB session row deleted) 4. Deleting an etape unassigns its tasks and does not delete those tasks
5. All POST routes require a valid CSRF token; missing/invalid tokens return 403 5. Database schema prevents nested etapes by modeling etapes as a separate table and tasks as optional children
6. >5 failed logins per email/IP per minute triggers rate-limiting
**User-in-loop:** Approve the `users` and `sessions` table schemas (columns, indexes, deletion semantics) before sqlc generation. Approve hash algorithm choice. **User-in-loop:** Approve etape table fields, delete behavior, and the first functional UI shape for grouping/filtering tasks.
**Plans:** 7/7 plans executed ### Phase 10: Events
Plans: **Goal:** A user can schedule events that belong to tablos, with the same authorization expectations as tasks and files.
- [x] 02-01-PLAN.md — Schema + sqlc + auth-package skeleton (citext + users + sessions, test DB harness)
- [x] 02-02-PLAN.md — argon2id password hashing (TDD: Hash/Verify with PHC encoding)
- [x] 02-03-PLAN.md — Session store + cookie + ResolveSession/RequireAuth/RedirectIfAuthed middleware
- [x] 02-04-PLAN.md — Signup vertical slice (form → validate → hash → InsertUser → session → cookie → redirect)
- [x] 02-05-PLAN.md — Login vertical slice + in-memory rate limiter (AUTH-07)
- [x] 02-06-PLAN.md — Logout + protect GET / + layout header logout button (AUTH-04, AUTH-05)
- [x] 02-07-PLAN.md — Mount gorilla/csrf + @ui.CSRFField templ helper across every form (AUTH-06)
### Phase 3: Tablos CRUD
**Goal:** A logged-in user can list, create, view, edit, and delete their tablos end-to-end through HTMX-driven flows.
**Mode:** mvp **Mode:** mvp
**Requirements:** TABLO-01, TABLO-02, TABLO-03, TABLO-04, TABLO-05, TABLO-06 **Requirements:** EVENT-01, EVENT-02, EVENT-03, EVENT-04, EVENT-05
**Success Criteria:** **Success Criteria:**
1. Dashboard lists the current user's tablos newest-first; empty state shows a "Create your first tablo" CTA 1. User can create an event for a tablo with title, start time, optional end time, optional description, and optional location
2. Creating a tablo via the create form inserts a row, dismisses the modal/inline form, and prepends the new tablo via HTMX swap 2. User can edit and delete a tablo event
3. Tablo detail page renders title and description; non-owners (or unauthenticated) get a 404 3. Tablo detail page exposes an events view listing events for that tablo
4. Editing title/description updates the row and re-renders the affected fragments without a full page reload 4. Server validation rejects events whose end time is before or equal to start time
5. Deleting a tablo removes it from the list (with a confirmation step) and is irreversible via the UI 5. Tests prove inaccessible tablo events cannot be read, created, updated, or deleted
6. All actions work without JS errors and degrade gracefully if HTMX is unavailable (forms still submit)
**User-in-loop:** Approve the `tablos` table schema (ownership model, soft-delete vs hard-delete, slug strategy). **User-in-loop:** Approve event schema, timezone/display assumptions, and whether the first UI is list/agenda-first rather than calendar-grid.
**Plans:** 3/3 plans executed ### Phase 11: Individual Planning
Plans: **Goal:** Each authenticated user can open a personal planning view that aggregates their scheduled events across tablos.
- [x] 03-01-PLAN.md — Wave 0: migration 0003_tablos + sqlc queries + handlers_tablos_test.go RED scaffold + button.css danger/neutral variants
- [x] 03-02-PLAN.md — Vertical slice 1: dashboard list + inline-form create (HTMX OOB swap; TABLO-01, TABLO-02, TABLO-06)
- [x] 03-03-PLAN.md — Vertical slice 2: detail + inline edit (title/description) + inline-confirmation delete (TABLO-03, TABLO-04, TABLO-05, TABLO-06)
### Phase 4: Tasks (Kanban)
**Goal:** Inside a tablo, a user can run a kanban board — create, edit, move, reorder, and delete tasks across columns.
**Mode:** mvp **Mode:** mvp
**Requirements:** TASK-01, TASK-02, TASK-03, TASK-04, TASK-05, TASK-06, TASK-07 **Requirements:** PLAN-01, PLAN-02, PLAN-03, PLAN-04
**Success Criteria:** **Success Criteria:**
1. A tablo detail page shows a kanban board with at least three columns 1. `/planning` is protected and renders only for authenticated users
2. Creating a task inserts it into the target column and renders without full reload 2. Planning page lists the user's accessible events across tablos in chronological order
3. Editing a task updates title/description in place 3. Each listed event links back to its tablo context
4. Moving a task between columns persists the new column and refreshes the source + target columns 4. Empty state and date filtering/navigation work without a JS framework
5. Reordering within a column persists and survives reload 5. Planning query does not leak events from inaccessible tablos
6. Deleting a task removes it from the board with a confirmation
7. Two concurrent edits don't corrupt order (last-write-wins is acceptable for v1, documented)
**User-in-loop:** Approve the `task_columns` (or fixed-column) schema and the ordering strategy (fractional indices, gaps-of-100, linked list — to be decided with research). Approve whether reorder is drag-and-drop or button-driven. **User-in-loop:** Approve first working planning view behavior: today/upcoming filter versus week navigation.
**Plans:** 3/4 plans executed ### Phase 12: Native Tablo Chat
Plans: **Goal:** Each tablo has a native persisted discussion stream with real-time updates and no managed chat/realtime provider.
- [x] 04-01-PLAN.md — Wave 0: migration 0004_tasks + sqlc queries + handlers_tasks_test.go RED scaffold + soft-danger button CSS + Sortable.js bootstrap
- [x] 04-02-PLAN.md — Vertical slice 1: kanban board render + task create + task delete (TASK-01, TASK-02, TASK-06)
- [x] 04-03-PLAN.md — Vertical slice 2: task inline edit + Sortable.js drag reorder/move (TASK-03, TASK-04, TASK-05, TASK-07)
- [x] 04-04-PLAN.md — Human-verify checkpoint: full kanban board browser verification
### Phase 5: Files
**Goal:** A user can attach files to a tablo, list them, download them via signed URLs, and delete them — backed by S3-compatible storage.
**Mode:** mvp **Mode:** mvp
**Requirements:** FILE-01, FILE-02, FILE-03, FILE-04, FILE-05, FILE-06 **Requirements:** CHAT-01, CHAT-02, CHAT-03, CHAT-04, CHAT-05, CHAT-06
**Success Criteria:** **Success Criteria:**
1. Uploading a file from a tablo detail page creates a `tablo_files` row and stores bytes in the configured S3 bucket 1. Tablo detail page includes a discussion view that loads persisted message history
2. The files list shows original filename, size, and uploaded-at; sorted newest first 2. User can post a text message with CSRF protection and server-side validation
3. Downloads use signed URLs with a short TTL (e.g. 5 minutes) generated server-side 3. Messages persist in Postgres with tablo, author, body, created timestamp, and edit/delete metadata
4. Deleting a file removes both the DB row and the S3 object; failures are surfaced and logged 4. A second open browser receives new messages without manual refresh
5. Only the tablo owner can upload/list/download/delete files for a given tablo (verified by tests) 5. Implementation uses Xtablo-owned infrastructure only; no managed chat/realtime provider or external realtime runtime is added
6. Configurable max upload size enforced server-side, with a friendly error message above the form 6. Message rendering escapes user content and enforces a maximum body length
7. Streaming behavior is verified behind the local/prod reverse proxy path, including keep-alives or buffering behavior
**User-in-loop:** Approve the `tablo_files` schema (key strategy, content-type handling, dedup). Approve upload method (direct PUT vs server-proxied). **User-in-loop:** Approve final real-time transport choice during planning. Research recommends SSE receive + HTMX POST send for v2; WebSockets remain available if the plan-phase proves bidirectional transport is required.
**Plans:** 4/4 plans complete
Plans:
**Wave 1**
- [x] 05-01-PLAN.md — Wave 1: go get aws-sdk-go-v2 + migration 0005_files + sqlc queries + files.Store + FileStorer interface + RED test scaffold + MinIO in compose.yaml
**Wave 2** *(blocked on Wave 1 completion)*
- [x] 05-02-PLAN.md — Wave 2: handlers_files.go (FilesDeps + FileUploadHandler + TabloFilesTabHandler + TabloTasksTabHandler) + tablos.templ 3-tab layout + files.templ (upload form + list) + router + main.go wiring (FILE-01, FILE-02, FILE-03, FILE-06)
**Wave 3** *(blocked on Wave 2 completion)*
- [x] 05-03-PLAN.md — Wave 3: FileDownloadHandler (302 → presigned URL) + FileDeleteConfirmHandler + FileDeleteHandler (S3-first delete) + FileDeleteConfirmFragment + full TestFile* green (FILE-04, FILE-05, FILE-06)
**Wave 4** *(blocked on Wave 3 completion)*
- [x] 05-04-PLAN.md — Wave 4: Human-verify checkpoint: tab navigation + upload/list/download/delete end-to-end browser walkthrough
### Phase 6: Background Worker
**Goal:** A second binary (`cmd/worker`) runs against the same Postgres, processes jobs from a queue, and proves end-to-end with at least one real job.
**Mode:** mvp
**Requirements:** WORK-01, WORK-02, WORK-03, WORK-04
**Success Criteria:**
1. `cmd/worker` starts, connects to Postgres, and registers handlers; logs are structured and graceful shutdown works
2. At least one real job (chosen during plan-phase — e.g. periodic orphan-file cleanup) runs on a schedule and is observable in logs
3. ~~A failing job is retried with backoff and visible via a simple CLI surface (`backend list-failed-jobs` or admin route)~~ — deferred; log observability satisfies v1 (D-06)
4. ~~Web binary can enqueue a job; worker picks it up within a few seconds~~ — deferred; web-side enqueueing deferred to a phase with a real event trigger (D-03)
5. README documents how to run the worker locally alongside the web binary
**User-in-loop:** Approve the queue library/approach (`river` vs `asynq` vs hand-rolled `pg_notify`) and pick the proof-of-life job.
**Plans:** 2/3 plans executed
Plans:
**Wave 1**
- [x] 06-01-PLAN.md — Wave 1: go get river + ListOrphanFiles sqlc query + internal/jobs/ package (HeartbeatWorker, OrphanCleanupWorker, SlogErrorHandler) + unit tests (WORK-01 partial, WORK-02, WORK-03, WORK-04)
**Wave 2** *(blocked on Wave 1 completion)*
- [x] 06-02-PLAN.md — Wave 2: replace cmd/worker/main.go with full river wiring (rivermigrate + Client + periodic jobs + graceful shutdown) + just worker target + README section (WORK-01, WORK-02, WORK-03)
**Wave 3** *(blocked on Wave 2 completion)*
- [x] 06-03-PLAN.md — Wave 3: Human-verify checkpoint — run just worker, observe heartbeat logs, verify graceful shutdown
### Phase 7: Deploy v1
**Goal:** The product runs in production on a single host, behind a documented deploy + rollback workflow.
**Mode:** mvp
**Requirements:** DEPLOY-01, DEPLOY-02, DEPLOY-03, DEPLOY-04, DEPLOY-05
**Success Criteria:**
1. A multi-stage Dockerfile builds both `web` and `worker` and the image starts either via a subcommand
2. The container runs on the chosen single-host target (e.g. Hetzner VM / Fly.io / Cloud Run) with env-injected config
3. Deploy step runs migrations against the production database before traffic is shifted
4. `/healthz` and `/readyz` return appropriate status codes during startup, steady state, and shutdown
5. `backend/README.md` documents: first-time deploy, routine deploy, rollback, and incident triage basics
**User-in-loop:** Approve the deploy target choice (Hetzner / Fly / Cloud Run) and the secret-management strategy (env vars vs `.env` file vs SOPS).
**Plans:** 3 plans
Plans:
**Wave 1**
- [x] 07-01-PLAN.md — Wave 1: go:embed assets + goose RunMigrations + /healthz liveness split + /readyz readiness (DEPLOY-03, DEPLOY-04)
**Wave 2** *(blocked on Wave 1 completion)*
- [x] 07-02-PLAN.md — Wave 2: multi-stage Dockerfile (assets + builder + distroless) + .env.example update (DEPLOY-01, DEPLOY-02)
**Wave 3** *(blocked on Wave 2 completion)*
- [x] 07-03-PLAN.md — Wave 3: docker-compose.prod.yaml + deploy/Caddyfile + README runbook (DEPLOY-02..DEPLOY-05)
--- ---
## Coverage ## Coverage
- v1 requirements: 40 - v2.0 requirements: 27
- Mapped to phases: 40 - Mapped to phases: 27
- Unmapped: 0 - Unmapped: 0
## Notes ## Notes
- Sequential execution: each phase depends on the previous. Auth must work before Tablos; Tablos must exist before Tasks/Files can attach to them. - Phase ordering isolates auth changes first, task schema/UI extension second, event domain third, planning aggregation fourth, and real-time chat last.
- The user is in the loop on **DB schema decisions** at the start of Phases 2, 3, 4, and 5. Treat schema approval as a hard gate inside `plan-phase` — sqlc generation does not run until the schema is approved. - Existing v1.0 roadmap history remains available in git history and `.planning/phases/`.
- Visual design is intentionally undefined per phase; UI plans choose Tailwind patterns inline. A `gsd-ui-phase` step can be invoked for any phase if a more deliberate UI contract is desired (Phases 3, 4, 5 are the strongest candidates). - The user will provide a more polished UI later; each phase should build functional, clean, testable UI with minimal visual ambition.
- The legacy `apps/*` JS app is the behavioral reference — `.planning/codebase/` is the source of truth for "what does the JS version do today?". - Schema decisions remain hard gates before migrations/sqlc generation.
- Research recommends SSE for real-time chat because message sends can stay as CSRF-protected HTTP POSTs while receive streams provide real-time updates.
--- ---
*Roadmap created: 2026-05-14* *Roadmap created: 2026-05-15*
*Phase 3 plans added: 2026-05-15*
*Phase 4 plans added: 2026-05-15*
*Phase 5 plans added: 2026-05-15*
*Phase 7 plans added: 2026-05-15*

View file

@ -6,7 +6,7 @@ status: planning
last_updated: "2026-05-15T18:07:28.641Z" last_updated: "2026-05-15T18:07:28.641Z"
last_activity: 2026-05-15 last_activity: 2026-05-15
progress: progress:
total_phases: 0 total_phases: 5
completed_phases: 0 completed_phases: 0
total_plans: 0 total_plans: 0
completed_plans: 0 completed_plans: 0
@ -24,18 +24,24 @@ progress:
See: `.planning/PROJECT.md` (updated 2026-05-15) See: `.planning/PROJECT.md` (updated 2026-05-15)
**Core value:** A user can sign in and run the Tablos workflow — organize work, attach files, discuss, and plan scheduled events — without a JS framework or managed chat provider. **Core value:** A user can sign in and run the Tablos workflow — organize work, attach files, discuss, and plan scheduled events — without a JS framework or managed chat provider.
**Current focus:** Defining v2.0 requirements and roadmap **Current focus:** Phase 8 — Social Sign-in
## Current Position ## Current Position
Phase: Not started (defining requirements) Phase: 8 — Social Sign-in
Plan: — Plan: —
Status: Defining requirements Status: Ready for discussion/planning
Last activity: 2026-05-15 — Milestone v2.0 started Last activity: 2026-05-15 — Milestone v2.0 roadmap created
## Phase Status ## Phase Status
No v2.0 phases defined yet. Previous v1.0 phase history is preserved in `.planning/PROJECT.md`, `.planning/ROADMAP.md`, and `.planning/phases/`. | # | Phase | Status |
|---|-------|--------|
| 8 | Social Sign-in | ○ Pending |
| 9 | Etapes | ○ Pending |
| 10 | Events | ○ Pending |
| 11 | Individual Planning | ○ Pending |
| 12 | Native Tablo Chat | ○ Pending |
## Verification Record ## Verification Record