diff --git a/docs/superpowers/specs/2026-05-10-go-backend-tablo-edit-color-design.md b/docs/superpowers/specs/2026-05-10-go-backend-tablo-edit-color-design.md new file mode 100644 index 0000000..c49714d --- /dev/null +++ b/docs/superpowers/specs/2026-05-10-go-backend-tablo-edit-color-design.md @@ -0,0 +1,295 @@ +# Go Backend Tablo Edit And Color Design + +**Date:** 2026-05-10 + +**Goal** + +Add edit support to the Go backend `/tablos` page so each project card and list row exposes an edit action immediately to the left of delete, opening a modal that allows the owner to update the tablo `name` and `color`. + +**Chosen Approach** + +This change follows the minimal additive path: + +- keep the existing `/tablos` page structure, HTMX flow, and delete behavior +- keep the current persisted `status` field and status-based filtering unchanged +- add a persisted `color` field +- extend the existing create modal to accept `color` +- add a dedicated edit modal and update route for `name` and `color` + +This intentionally does not start the broader `status` deprecation effort. `status` remains in place as-is for this slice. + +**Scope** + +- Add a `color` field to Go backend tablo persistence. +- Render an edit action on project cards and list rows. +- Open a server-rendered edit modal for a specific tablo. +- Allow create and edit flows to submit `name` and `color`. +- Validate `color` as a full 6-digit hexadecimal value in `#RRGGBB` format. +- Re-render the `/tablos` content after successful create, update, or delete while preserving current page state. + +**Out Of Scope** + +- Removing or deprecating the existing `status` field +- Task-derived status inference +- Reworking the current search or filter model +- Introducing custom JavaScript beyond the existing HTMX-driven pattern +- Adding color pickers, preset palettes, or browser-native advanced color UI +- Building a `/tablos/:id` detail edit page + +**User Experience** + +On the Go backend `Mes Projets` page: + +- every grid card shows an edit icon button immediately left of the trash icon +- every list row shows the same edit icon button immediately left of the trash icon +- clicking edit opens a modal prefilled with the tablo's current `name` and `color` +- the modal lets the user update: + - `name` + - `color` +- `status` is not editable in the create or edit modal for this slice + +The color is entered as a text value using a strict full hex format such as `#3B82F6`. + +**Data Model** + +Extend `public.tablos` with: + +- `color text not null` + +The Go domain model should add: + +- `Color string` on `tablos.Record` + +Create and update inputs should both include: + +- `Name string` +- `Color string` + +The current `status` field remains present and unchanged. + +**Validation** + +Validation rules: + +- `name` is required after trimming whitespace +- `color` is required +- `color` must match `^#[0-9A-Fa-f]{6}$` + +Validation happens in the handler layer for this slice. The handler should return inline modal errors with HTTP `422` when validation fails. + +Examples: + +- valid: `#3B82F6` +- valid: `#ff6600` +- invalid: `3B82F6` +- invalid: `#0af` +- invalid: `blue` + +**Routes** + +Add or extend the following routes: + +- `GET /tablos` + - unchanged page render entrypoint + - supports existing query params: + - `view=grid|list` + - `q=` + - `status=all|todo|in_progress|done` + - `modal=create` +- `POST /tablos` + - create a new tablo using `name` and `color` + - continue assigning the existing default `status` +- `GET /tablos/{id}/edit` + - render the edit modal for the owner + - preserve current page state through query params +- `POST /tablos/{id}` + - update `name` and `color` for the owner +- `DELETE /tablos/{id}` + - unchanged behavior, aside from adjacent edit action in the UI + +`POST /tablos/{id}` is preferred here over introducing `PATCH` because it keeps the modal form flow simple and consistent with the current server-rendered HTMX form handling. + +**Repository Design** + +Minimum repository behavior: + +- create tablo with `name`, `color`, and current default `status` +- list tablos including `color` +- update `name`, `color`, and `updated_at` for an owned non-deleted tablo +- soft delete owned tablos as before + +Minimum repository methods: + +- `CreateTablo` +- `ListTablos` +- `UpdateTablo` +- `SoftDeleteTablo` + +Update semantics: + +- scope by `id` +- require `owner_id = current user` +- reject deleted rows +- update `name`, `color`, and `updated_at` +- treat missing, foreign-owned, or deleted rows as not found for this slice + +**Rendering Contract** + +The `/tablos` page should keep its current HTMX-rendered dashboard composition and add edit support without restructuring the page. + +Grid cards: + +- keep the existing status badge +- render an edit icon button immediately before the delete icon button +- continue using the current card structure and layout + +List rows: + +- keep the current trailing action cell +- render edit and delete as adjacent icon buttons with edit on the left + +Modal behavior: + +- create modal collects `name` and `color` +- edit modal collects `name` and `color` +- both modals render inline validation errors +- cancel closes the modal and preserves current page state + +**Color Rendering** + +The page should use the stored hex value directly rather than only relying on predefined accent classes. + +Expected usage: + +- avatar or visual accent background +- progress or supporting color accent where appropriate +- any existing accent mapping should be replaced or bypassed only where needed for real color rendering + +Implementation should keep style usage narrow and predictable, for example through inline `style` attributes generated from validated values. Since the input is strictly validated server-side, using the stored value in inline styles is acceptable for this slice. + +**HTMX Flow** + +Open create modal: + +- `hx-get` to `/tablos?...&modal=create` +- swap the main content region as today + +Open edit modal: + +- `hx-get` to `/tablos/{id}/edit?...current state...` +- swap the main content region with the page content that includes the modal + +Submit create: + +- `hx-post` to `/tablos` +- on success: + - return refreshed `/tablos` content + - modal closes because returned state omits modal-open flag +- on failure: + - return `422` + - re-render create modal with entered values and inline errors + +Submit edit: + +- `hx-post` to `/tablos/{id}` +- on success: + - return refreshed `/tablos` content + - modal closes +- on failure: + - return `422` + - re-render edit modal with entered values and inline errors + +Delete: + +- keep existing HTMX delete flow +- preserve `view`, `q`, and `status` + +**View Model Changes** + +`TabloCardView` should add fields needed for edit and color support, for example: + +- `Color string` +- `EditRequestURL string` + +`TablosPageViewModel` should continue carrying current page state and modal form values. To support both create and edit cleanly, the modal state will likely need to expand beyond the current boolean-only create modal approach. + +A pragmatic shape is: + +- modal kind: none, create, edit +- form values: + - name + - color +- optional editing tablo id +- error message or field-level errors + +The exact struct layout can be chosen during implementation, but it should support both modal variants without duplicating page-state plumbing. + +**Error Handling** + +Create or update validation failure: + +- return HTTP `422` +- keep modal open +- show clear inline error message near the relevant field or top of form + +Unknown or unauthorized tablo on edit open or update: + +- return not found behavior +- do not leak whether the tablo exists for another owner + +Repository or rendering failures: + +- return the existing server error behavior + +**Testing Strategy** + +Repository coverage: + +- create persists `color` +- list returns `color` +- update changes `name`, `color`, and `updated_at` +- update rejects different owner +- update rejects deleted tablo + +Handler coverage: + +- `GET /tablos` create modal includes `color` field +- `GET /tablos/{id}/edit` renders prefilled `name` and `color` +- `POST /tablos` rejects missing or invalid `color` +- `POST /tablos/{id}` rejects missing or invalid `color` +- `POST /tablos/{id}` updates visible name and color in returned HTML +- grid card markup contains edit action before delete +- list row markup contains edit action before delete + +HTML assertions should verify: + +- the edit trigger exists with the expected icon/button semantics +- the edit trigger appears before delete in the rendered action area +- the modal contains both `Nom du projet` and `Couleur` +- invalid hex values return a `422` response with inline feedback mentioning `#RRGGBB` + +**Implementation Notes** + +- preserve the current page query state on create, edit open, edit submit, and delete +- avoid introducing unrelated refactors to status handling +- prefer reuse of the existing modal and shared UI primitives +- keep changes scoped to the Go backend vertical slice: + - schema + - queries + - repository + - handlers + - `templ` views + - tests + +**Acceptance Criteria** + +The feature is complete when: + +- the Go backend `/tablos` page shows an edit action to the left of delete +- clicking edit opens a modal for the selected tablo +- the modal allows changing the tablo `name` +- the modal allows changing the tablo `color` +- create also accepts `color` +- `color` only accepts full 6-digit hex values like `#3B82F6` +- successful edits update the rendered project card or list row +- current search, filter, and view state are preserved throughout the HTMX flow