docs(03): capture phase 3 context

This commit is contained in:
Arthur Belleville 2026-05-14 23:35:55 +02:00
parent df78ed2832
commit 5fe692aa93
No known key found for this signature in database
2 changed files with 243 additions and 0 deletions

View file

@ -0,0 +1,112 @@
# Phase 3: Tablos CRUD - Context
**Gathered:** 2026-05-14
**Status:** Ready for planning
<domain>
## Phase Boundary
A logged-in user can list, create, view, edit, and delete their own tablos end-to-end through HTMX-driven flows. The dashboard shows the user's tablos newest-first with a "Create your first tablo" empty state. All mutations (create, edit, delete) work without full page reloads; forms degrade gracefully when HTMX is unavailable.
Delivers TABLO-01..06. **Not** in scope: kanban tasks (Phase 4), file attachments (Phase 5), tablo sharing/permissions beyond owner-only, tablo reordering by user, rich text in description, slug-based URLs, color palette picker UI (color stored but picker UI is Claude's discretion).
</domain>
<decisions>
## Implementation Decisions
### Database Schema — tablos
- **D-01:** Hard-delete only — no `deleted_at` column. Matches the D-02 pattern from Phase 2 (users). Simpler queries — no `WHERE deleted_at IS NULL` filters needed throughout. Deletion is irreversible via the UI (confirmation required per D-04).
- **D-02:** `tablos` table columns: `id uuid PK DEFAULT gen_random_uuid()`, `user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE`, `title text NOT NULL`, `description text` (nullable), `color text` (nullable — hex string or Tailwind color name, e.g. `"#6366f1"` or `"indigo"`; validation at planner's discretion), `created_at timestamptz NOT NULL DEFAULT now()`, `updated_at timestamptz NOT NULL DEFAULT now()`. Index on `user_id` (for per-user list queries).
- **D-03:** Sort order is always `ORDER BY created_at DESC` (newest-first). No `position` column — user reordering is out of scope for Phase 3.
### URL Structure
- **D-04:** Tablo detail page URL: `/tablos/{uuid}` — use the `id` UUID primary key directly. No slug column, no slug generation logic. Opaque but simple. Non-owner (or unauthenticated) requests to `/tablos/{uuid}` return 404 (not 403 — no information leakage per TABLO-03).
### Create UX
- **D-05:** "New tablo" button on the dashboard expands an **inline form** above the tablo list via HTMX swap (`hx-swap="afterbegin"` into the list container, or a dedicated `#create-form` slot). On successful POST, the form collapses and the new tablo card is prepended to the list without a full page reload. On validation error, the inline form re-renders with field errors (same HTMX fragment pattern as Phase 2 signup).
### Edit UX
- **D-06:** Editing happens **inline on the tablo detail page**. Clicking the title or description swaps that element to an editable `<input>`/`<textarea>` via HTMX (`hx-get` to fetch an edit fragment). On save (`POST /tablos/{id}/edit` or `PATCH`), the input swaps back to the display element with the updated value. On cancel, restores original without a server round-trip (HTMX `hx-on:htmx:abort` or a cancel button that swaps back the original display fragment).
### Delete Confirmation
- **D-07:** Delete uses an **inline "Are you sure?" confirmation fragment** — no modal, no browser `confirm()`. The delete button (`DELETE /tablos/{id}`) swaps itself to a small confirmation row ("Delete tablo? **Yes** / Cancel") via HTMX. Confirming fires the actual DELETE; cancelling swaps back the original delete button. This keeps the pattern in Go/templ/HTMX with no JS and no new components.
### Claude's Discretion
- Exact Tailwind styling for tablo cards on the dashboard list — consistent with the Phase 1/2 design system (Card component, muted slate palette) but exact layout is Claude's call.
- Whether `color` is rendered as a dot/badge on the card or a left border accent — visual treatment is open.
- HTTP verb for edit: `POST /tablos/{id}/edit` (HTML form compatible) vs a RESTful `PATCH` routed through a `_method` override. Planner should pick whichever is cleaner with chi + HTML forms.
- The `updated_at` trigger: either a Postgres trigger or an explicit `SET updated_at = now()` in the UPDATE query — planner's choice.
</decisions>
<canonical_refs>
## Canonical References
**Downstream agents MUST read these before planning or implementing.**
### Prior Phase Context (locked decisions that constrain this phase)
- `.planning/phases/02-authentication/02-CONTEXT.md` — D-23/D-24 (chi route groups, middleware order), D-22 (logout POST form pattern), RequireAuth + RedirectIfAuthed middleware usage
- `.planning/phases/01-foundation/01-CONTEXT.md` — chi router + templ + sqlc + goose migration conventions established in Phase 1
### Requirements
- `.planning/REQUIREMENTS.md` §TABLO-01..06 — The 6 tablo requirements this phase delivers
- `.planning/PROJECT.md` — Core value statement and constraints (hard-delete default, HTMX-first, single binary)
- `.planning/ROADMAP.md` §Phase 3 — Success criteria and user-in-loop note
### Codebase Patterns (Go backend)
- `backend/internal/web/router.go` — Router structure, protected group pattern, AuthDeps injection
- `backend/internal/web/handlers_auth.go` — HTMX-aware handler pattern (HX-Request header detection, fragment vs full-page response)
- `backend/internal/web/ui/` — Existing Card, Button, Badge, CSRFField components
- `backend/templates/layout.templ` — Base layout, slot injection pattern
- `backend/internal/db/queries/users.sql` — sqlc query style reference
- `backend/migrations/0002_auth.sql` — Migration style reference (citext, uuid, indexes)
</canonical_refs>
<code_context>
## Existing Code Insights
### Reusable Assets
- `ui.Card`, `ui.Button`, `ui.Badge`, `ui.CSRFField` — all available in `backend/internal/web/ui/`. Tablo cards on the dashboard should use `ui.Card`.
- `auth.RequireAuth` middleware — wraps the entire tablos route group; no new auth code needed.
- `auth.Authed(ctx)` — extracts `*auth.User` from context for ownership checks.
- `templates.Layout` — base layout with logout header; tablo pages extend it.
- HTMX fragment pattern from signup (`HX-Request` header detection, 200+fragment vs 303+redirect) — reuse verbatim for create/edit error responses.
### Established Patterns
- sqlc queries in `backend/internal/db/queries/<domain>.sql`, generated output in `backend/internal/db/sqlc/`. Phase 3 adds `tablos.sql`.
- Handler functions return `http.HandlerFunc` from a constructor taking deps (e.g. `TablosDeps` struct) — mirrors `AuthDeps` pattern.
- Middleware order is locked (D-24 from Phase 2): `RequestID → RealIP → SlogLogger → Recoverer → ResolveSession → csrf.Protect → [route groups]`. Tablo routes go inside the `RequireAuth` group.
- goose migrations numbered sequentially: `0003_tablos.sql` is next.
- `templ generate` must be run after any `.templ` file change to regenerate `*_templ.go`.
### Integration Points
- `backend/internal/web/router.go` — add `/tablos*` routes inside the protected chi group.
- `backend/cmd/web/main.go` — pass `TablosDeps` (db pool) to `NewRouter` alongside existing `AuthDeps`.
- `backend/templates/index.templ` — current placeholder "Go + HTMX foundation" page becomes the tablo dashboard.
</code_context>
<specifics>
## Specific Ideas
- The `index.templ` root page (`GET /`) transforms into the tablo dashboard — replace the current HTMX demo card with the tablo list + create form.
- TABLO-06 explicitly requires HTMX-driven mutations ("no full page reloads for CRUD actions") — every mutating handler must handle both HX-Request and non-HX flows.
</specifics>
<deferred>
## Deferred Ideas
- **Tablo reordering by user** — drag-and-drop or button reorder. Not in TABLO requirements; would need a `position` column. Deferred to a future phase or v2.
- **Color palette picker UI** — The `color` column is stored in Phase 3, but a full color picker component is deferred; plain text input or a hardcoded set of swatches is fine in Phase 3.
- **Slug-based URLs** (`/tablos/my-project`) — discussed and deferred; UUID URLs are sufficient for v1.
- **Sharing / permissions beyond owner-only** — scoped out of v1 per PROJECT.md.
</deferred>
---
*Phase: 3-Tablos CRUD*
*Context gathered: 2026-05-14*

View file

@ -0,0 +1,131 @@
# Phase 3: Tablos CRUD - Discussion Log
> **Audit trail only.** Do not use as input to planning, research, or execution agents.
> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.
**Date:** 2026-05-14
**Phase:** 3-Tablos CRUD
**Areas discussed:** Tablos schema, Create/Edit UX, Delete confirmation, URL structure
---
## Tablos Schema
### Delete behavior
| Option | Description | Selected |
|--------|-------------|----------|
| Hard-delete (recommended) | Matches D-02 user pattern. Simpler queries — no WHERE deleted_at IS NULL everywhere. No recovery path needed in v1. | ✓ |
| Soft-delete (deleted_at) | Reversible. Adds deleted_at column and filters to every query. | |
| Soft-delete with a recycle bin page | Soft-delete + a /tablos/deleted route to restore or permanently delete. | |
**User's choice:** Hard-delete
**Notes:** Consistent with the hard-delete pattern established for users in Phase 2 (D-02).
---
### Extra columns beyond required
| Option | Description | Selected |
|--------|-------------|----------|
| title + description only (recommended) | Lean — matches TABLO-02 minimum. | |
| Add a color/icon field | One extra enum or text column for a visual label. | ✓ |
| Add a slug column | Pre-generate a slug for human-readable URLs. | |
**User's choice:** Add a color/icon field
**Notes:** Adds a `color` text column (nullable). Visual treatment (dot, badge, border accent) is Claude's discretion.
---
### Color field type
| Option | Description | Selected |
|--------|-------------|----------|
| A single color string (recommended) | color text (nullable, e.g. hex or Tailwind name). | ✓ |
| An emoji/icon string | icon text (nullable). | |
| Both color and icon | Two nullable columns. Matches JS app most closely. | |
**User's choice:** Single color string
**Notes:** Stored as text (e.g. `"#6366f1"` or `"indigo"`). Validation rules at planner's discretion.
---
### Sort order
| Option | Description | Selected |
|--------|-------------|----------|
| Newest-first only (recommended) | ORDER BY created_at DESC. No position column. | ✓ |
| Add a position column now | Integer position for user-defined order. | |
**User's choice:** Newest-first only
**Notes:** Reordering is out of scope for Phase 3.
---
## Create/Edit UX
### Create flow
| Option | Description | Selected |
|--------|-------------|----------|
| Inline form in the list (recommended) | "New tablo" button expands inline form via HTMX swap. New card prepended on submit. | ✓ |
| Modal dialog | Button opens a modal overlay. Needs new Modal component. | |
| Separate /tablos/new page | Navigate to dedicated create page. Full reload. | |
**User's choice:** Inline form in the list
**Notes:** Consistent with TABLO-06 (no full reloads). Reuses the HTMX fragment swap pattern from Phase 2.
---
### Edit flow
| Option | Description | Selected |
|--------|-------------|----------|
| Inline edit on the detail page (recommended) | Click title/description to swap to editable input via HTMX. | ✓ |
| Edit button opens a form below the header | Persistent Edit button shows/hides a form section. | |
| Separate /tablos/{id}/edit page | Navigate to a dedicated edit form. Full page navigation. | |
**User's choice:** Inline edit on the detail page
**Notes:** Click-to-edit swap pattern; cancel restores original without server round-trip.
---
## Delete Confirmation
| Option | Description | Selected |
|--------|-------------|----------|
| Inline "Are you sure?" fragment (recommended) | Delete button swaps itself to confirm row. No JS, no modal. | ✓ |
| Browser confirm() dialog | hx-confirm attribute. One line, but native dialog — can't style. | |
| Modal confirmation dialog | Modal overlay. Needs Modal component (doesn't exist yet). | |
**User's choice:** Inline "Are you sure?" fragment
**Notes:** Keeps everything in Go/templ/HTMX. Delete button → confirm fragment → DELETE request → card removed.
---
## URL Structure
| Option | Description | Selected |
|--------|-------------|----------|
| /tablos/{uuid} (recommended) | Use existing uuid PK. Simple, no slug logic. | ✓ |
| /tablos/{slug} | Human-readable. Requires slug column + generation + collision handling. | |
| /tablos/{short-id} | Shorter random ID (e.g. nanoid). Needs extra column. | |
**User's choice:** /tablos/{uuid}
**Notes:** No slug column needed. Non-owners get 404 (not 403) to avoid leaking tablo existence.
---
## Claude's Discretion
- Tailwind styling for tablo cards
- Color rendering (dot/badge vs left border accent)
- HTTP verb for edit (POST with path vs PATCH)
- `updated_at` maintenance (Postgres trigger vs explicit SET in query)
## Deferred Ideas
- Tablo reordering by user (drag-and-drop or button) — needs `position` column, out of scope v1
- Full color palette picker UI — color stored in Phase 3, picker UI deferred
- Slug-based URLs — discussed and deferred; UUID sufficient for v1
- Sharing / multi-user permissions — explicitly out of scope per PROJECT.md