go-htmx-gsd #1

Merged
arthur merged 558 commits from go-htmx-gsd into main 2026-05-23 15:16:44 +00:00
3 changed files with 86 additions and 180 deletions
Showing only changes of commit cd8034f33b - Show all commits

View file

@ -95,17 +95,17 @@ Populated during roadmap creation.
| Requirement | Phase | Status |
|-------------|-------|--------|
| AUTH-08..13 | TBD | Pending |
| ETAPE-01..06 | TBD | Pending |
| EVENT-01..05 | TBD | Pending |
| PLAN-01..04 | TBD | Pending |
| CHAT-01..06 | TBD | Pending |
| AUTH-08..13 | Phase 8 | Pending |
| ETAPE-01..06 | Phase 9 | Pending |
| EVENT-01..05 | Phase 10 | Pending |
| PLAN-01..04 | Phase 11 | Pending |
| CHAT-01..06 | Phase 12 | Pending |
**Coverage:**
- v2.0 requirements: 27 total
- Mapped to phases: 0
- Unmapped: 27
- Mapped to phases: 27
- Unmapped: 0
---
*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
**Project mode:** Vertical MVP (each phase delivers an end-to-end user-visible slice where possible)
**Milestone:** v1 — Tablos workflow on Go+HTMX
**Created:** 2026-05-15
**Project mode:** Brownfield milestone on existing Go+HTMX backend
**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 |
|---|-------|------|--------------|
| 1 | Foundation | Fresh `backend/` Go package boots, renders HTMX, talks to Postgres | FOUND-01..05 |
| 2 | Authentication | Complete (7/7) | AUTH-01..07 |
| 3 | Tablos CRUD | Complete (3/3) | TABLO-01..06 |
| 4 | 3/4 | In Progress| |
| 5 | 4/4 | Complete | 2026-05-15 |
| 6 | 1/3 | In Progress| |
| 7 | Deploy v1 | The product runs in production on a single host | DEPLOY-01..05 |
| 8 | Social Sign-in | Google and Apple sign-in create/link local users and issue existing Xtablo sessions | AUTH-08..13 |
| 9 | Etapes | Tasks can be grouped under one-level etapes without breaking the kanban model | ETAPE-01..06 |
| 10 | Events | Tablos have scheduled events with CRUD, validation, and authorization | EVENT-01..05 |
| 11 | Individual Planning | Users can view their own event agenda across tablos | PLAN-01..04 |
| 12 | Native Tablo Chat | Each tablo has persisted discussion with real-time delivery and no managed chat provider | CHAT-01..06 |
---
## Phase Details
### Phase 1: Foundation
**Goal:** A fresh `backend/` Go package boots a web server, renders an HTMX-driven base layout, and connects to a local Postgres with migrations.
### Phase 8: Social Sign-in
**Goal:** Users can sign in with Google or Apple while Xtablo keeps owning user accounts and sessions.
**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:**
1. `just dev` starts the web server on a local port and live-reloads on `.go` and template changes
2. `GET /healthz` returns 200 with a JSON `{status:"ok", db:"ok"}` only when the DB is reachable
3. The root route renders a Tailwind-styled HTMX page that loads without console errors and includes a working `hx-get` example
4. `just migrate up` applies migrations from `backend/migrations/` against the local Postgres
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`
1. Login/signup page shows Google and Apple sign-in entry points alongside email/password
2. Google callback validates state, exchanges authorization code, verifies ID token, creates or links `user_identities`, and issues a local session
3. Apple callback validates state/nonce, exchanges authorization code, verifies ID token, creates or links `user_identities`, and issues a local session
4. Existing email/password signup/login/logout tests still pass unchanged
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
Plans:
- [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.
### Phase 9: Etapes
**Goal:** A user can organize tasks under one-level etapes inside a tablo while preserving existing task status and ordering behavior.
**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:**
1. Signing up creates a user row with hashed password (argon2id or bcrypt) and starts a session
2. Logging in with valid credentials issues a signed HTTP-only cookie; invalid credentials show a clear error
3. Hitting any protected route while unauthenticated redirects to `/login`; logged-in users on `/login` go to `/`
4. Logout invalidates the session server-side (cookie cleared + DB session row deleted)
5. All POST routes require a valid CSRF token; missing/invalid tokens return 403
6. >5 failed logins per email/IP per minute triggers rate-limiting
1. User can create, edit, delete, and reorder etapes inside a tablo
2. User can assign or unassign a task from an etape
3. Tasks continue to move/reorder across kanban statuses after etape support is added
4. Deleting an etape unassigns its tasks and does not delete those tasks
5. Database schema prevents nested etapes by modeling etapes as a separate table and tasks as optional children
**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
Plans:
- [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.
### Phase 10: Events
**Goal:** A user can schedule events that belong to tablos, with the same authorization expectations as tasks and files.
**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:**
1. Dashboard lists the current user's tablos newest-first; empty state shows a "Create your first tablo" CTA
2. Creating a tablo via the create form inserts a row, dismisses the modal/inline form, and prepends the new tablo via HTMX swap
3. Tablo detail page renders title and description; non-owners (or unauthenticated) get a 404
4. Editing title/description updates the row and re-renders the affected fragments without a full page reload
5. Deleting a tablo removes it from the list (with a confirmation step) and is irreversible via the UI
6. All actions work without JS errors and degrade gracefully if HTMX is unavailable (forms still submit)
1. User can create an event for a tablo with title, start time, optional end time, optional description, and optional location
2. User can edit and delete a tablo event
3. Tablo detail page exposes an events view listing events for that tablo
4. Server validation rejects events whose end time is before or equal to start time
5. Tests prove inaccessible tablo events cannot be read, created, updated, or deleted
**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
Plans:
- [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.
### Phase 11: Individual Planning
**Goal:** Each authenticated user can open a personal planning view that aggregates their scheduled events across tablos.
**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:**
1. A tablo detail page shows a kanban board with at least three columns
2. Creating a task inserts it into the target column and renders without full reload
3. Editing a task updates title/description in place
4. Moving a task between columns persists the new column and refreshes the source + target columns
5. Reordering within a column persists and survives reload
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)
1. `/planning` is protected and renders only for authenticated users
2. Planning page lists the user's accessible events across tablos in chronological order
3. Each listed event links back to its tablo context
4. Empty state and date filtering/navigation work without a JS framework
5. Planning query does not leak events from inaccessible tablos
**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
Plans:
- [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.
### Phase 12: Native Tablo Chat
**Goal:** Each tablo has a native persisted discussion stream with real-time updates and no managed chat/realtime provider.
**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:**
1. Uploading a file from a tablo detail page creates a `tablo_files` row and stores bytes in the configured S3 bucket
2. The files list shows original filename, size, and uploaded-at; sorted newest first
3. Downloads use signed URLs with a short TTL (e.g. 5 minutes) generated server-side
4. Deleting a file removes both the DB row and the S3 object; failures are surfaced and logged
5. Only the tablo owner can upload/list/download/delete files for a given tablo (verified by tests)
6. Configurable max upload size enforced server-side, with a friendly error message above the form
1. Tablo detail page includes a discussion view that loads persisted message history
2. User can post a text message with CSRF protection and server-side validation
3. Messages persist in Postgres with tablo, author, body, created timestamp, and edit/delete metadata
4. A second open browser receives new messages without manual refresh
5. Implementation uses Xtablo-owned infrastructure only; no managed chat/realtime provider or external realtime runtime is added
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).
**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)
**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.
---
## Coverage
- v1 requirements: 40
- Mapped to phases: 40
- Unmapped: 0
- v2.0 requirements: 27
- Mapped to phases: 27
- Unmapped: 0
## Notes
- Sequential execution: each phase depends on the previous. Auth must work before Tablos; Tablos must exist before Tasks/Files can attach to them.
- 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.
- 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 legacy `apps/*` JS app is the behavioral reference — `.planning/codebase/` is the source of truth for "what does the JS version do today?".
- Phase ordering isolates auth changes first, task schema/UI extension second, event domain third, planning aggregation fourth, and real-time chat last.
- Existing v1.0 roadmap history remains available in git history and `.planning/phases/`.
- The user will provide a more polished UI later; each phase should build functional, clean, testable UI with minimal visual ambition.
- 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*
*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*
*Roadmap created: 2026-05-15*

View file

@ -6,7 +6,7 @@ status: planning
last_updated: "2026-05-15T18:07:28.641Z"
last_activity: 2026-05-15
progress:
total_phases: 0
total_phases: 5
completed_phases: 0
total_plans: 0
completed_plans: 0
@ -24,18 +24,24 @@ progress:
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.
**Current focus:** Defining v2.0 requirements and roadmap
**Current focus:** Phase 8 — Social Sign-in
## Current Position
Phase: Not started (defining requirements)
Phase: 8 — Social Sign-in
Plan: —
Status: Defining requirements
Last activity: 2026-05-15 — Milestone v2.0 started
Status: Ready for discussion/planning
Last activity: 2026-05-15 — Milestone v2.0 roadmap created
## 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