diff --git a/.planning/STATE.md b/.planning/STATE.md
index 9afa524..5504b63 100644
--- a/.planning/STATE.md
+++ b/.planning/STATE.md
@@ -2,15 +2,15 @@
gsd_state_version: 1.0
milestone: v2.0
milestone_name: Collaboration, planning, and social sign-in
-status: planning
-last_updated: "2026-05-16T07:55:44.531Z"
-last_activity: 2026-05-16
+status: executing
+last_updated: "2026-05-16T08:03:11.927Z"
+last_activity: 2026-05-16 -- Phase 12 planning complete
progress:
total_phases: 5
completed_phases: 4
- total_plans: 15
+ total_plans: 18
completed_plans: 15
- percent: 100
+ percent: 83
---
# STATE
@@ -24,15 +24,15 @@ 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:** Phase 11 — Individual Planning
+**Current focus:** Phase 12 — Native Tablo Chat
## Current Position
Phase: 12
Plan: Not started
-Status: Ready to plan
-Last activity: 2026-05-16
-Resume file: .planning/phases/12-native-tablo-chat/12-UI-SPEC.md
+Status: Ready to execute
+Last activity: 2026-05-16 -- Phase 12 planning complete
+Resume file: .planning/phases/12-native-tablo-chat/12-01-PLAN.md
## Phase Status
@@ -41,8 +41,8 @@ Resume file: .planning/phases/12-native-tablo-chat/12-UI-SPEC.md
| 8 | Social Sign-in | ✓ Complete |
| 9 | Etapes | ◆ UAT passed; security pending |
| 10 | Events | ✓ Complete |
-| 11 | Individual Planning | ◆ Ready to execute |
-| 12 | Native Tablo Chat | ○ Pending |
+| 11 | Individual Planning | ✓ Complete |
+| 12 | Native Tablo Chat | ◆ Ready to execute |
## Verification Record
diff --git a/.planning/phases/12-native-tablo-chat/12-01-PLAN.md b/.planning/phases/12-native-tablo-chat/12-01-PLAN.md
new file mode 100644
index 0000000..c4087f1
--- /dev/null
+++ b/.planning/phases/12-native-tablo-chat/12-01-PLAN.md
@@ -0,0 +1,170 @@
+---
+phase: 12-native-tablo-chat
+plan: 01
+type: execute
+wave: 1
+depends_on: []
+files_modified:
+ - backend/migrations/0009_discussion.sql
+ - backend/internal/db/queries/discussion.sql
+ - backend/internal/web/handlers_discussion_test.go
+ - backend/internal/web/handlers_discussion.go
+ - backend/internal/web/router.go
+ - backend/cmd/web/main.go
+ - backend/templates/tablos.templ
+ - backend/templates/discussion.templ
+ - backend/templates/discussion_forms.go
+autonomous: true
+requirements: [CHAT-01, CHAT-02, CHAT-03, CHAT-06]
+
+must_haves:
+ truths:
+ - "D-01/D-02/D-03/D-04: Discussion is a fifth tablo detail tab after Events, with direct full-page fallback."
+ - "D-06/D-07/D-08/D-09/D-10: rows show author, absolute timestamp, text, oldest first, day separators, bottom composer, and specified empty state."
+ - "D-11/D-12/D-13/D-14: schema carries nullable edit/delete metadata; no edit/delete UI appears."
+ - "D-15/D-16: composer is textarea plus Send message; no Enter-to-send behavior."
+ - "D-22/D-23/D-24/D-25: owner-only; author label uses email fallback; header may show 1 participant."
+ - "CHAT-06: message body is length-limited server-side and rendered escaped through templ."
+ artifacts:
+ - path: "backend/migrations/0009_discussion.sql"
+ provides: "message and read-state schema foundation"
+ - path: "backend/internal/db/queries/discussion.sql"
+ provides: "typed sqlc discussion history/send/read queries"
+ - path: "backend/internal/web/handlers_discussion.go"
+ provides: "protected discussion tab and send handlers"
+ - path: "backend/templates/discussion.templ"
+ provides: "server-rendered discussion UI"
+---
+
+
+Vertical slice 1: add persisted discussion history and CSRF-protected message posting inside the tablo detail Discussion tab, without realtime or dashboard unread badges yet.
+
+
+
+@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/12-native-tablo-chat/12-CONTEXT.md
+@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/12-native-tablo-chat/12-UI-SPEC.md
+@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/12-native-tablo-chat/12-RESEARCH.md
+@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/12-native-tablo-chat/12-PATTERNS.md
+
+
+
+T-12-01 Schema bypass: message rows must reference real tablos/users with cascading foreign keys.
+T-12-02 Future lifecycle ambiguity: include nullable edit/delete metadata but do not expose edit/delete UI or decide tombstone copy.
+T-12-03 Unauthenticated access: discussion routes must live inside `auth.RequireAuth`.
+T-12-04 Cross-user leak/mutation: all handlers must call `loadOwnedTablo`; non-owner access returns 404.
+T-12-05 XSS/body abuse: body is trimmed, non-empty, max-length checked, and rendered through templ escaped expressions.
+T-12-06 CSRF bypass: message send remains normal POST with gorilla/csrf hidden token.
+
+
+
+
+
+ Task 1: Add discussion schema and sqlc queries
+
+ - backend/migrations/0009_discussion.sql
+ - backend/internal/db/queries/discussion.sql
+
+
+ - backend/migrations/0003_tablos.sql
+ - backend/migrations/0008_events.sql
+ - backend/internal/db/queries/tablos.sql
+ - backend/internal/db/queries/events.sql
+ - .planning/phases/12-native-tablo-chat/12-RESEARCH.md
+
+
+ Create `discussion_messages` with `id uuid default gen_random_uuid()`, `tablo_id uuid not null references tablos(id) on delete cascade`, `author_user_id uuid not null references users(id) on delete restrict`, `body text not null`, `created_at timestamptz not null default now()`, `updated_at timestamptz not null default now()`, nullable `edited_at`, `edited_by_user_id`, `deleted_at`, and `deleted_by_user_id`. Add checks for non-blank trimmed body and maximum body length; use 10000 characters unless implementation finds a stronger local convention.
+ Create `discussion_read_states` keyed by `(tablo_id, user_id)` with nullable `last_read_message_id`, `last_read_at timestamptz not null default now()`, `created_at`, and `updated_at`.
+ Add indexes for `(tablo_id, created_at, id)` and read-state lookup. Add sqlc queries for list history oldest-first with author email, insert message, get message row with author email, and upsert read state.
+
+
+ cd backend && just generate
+
+
+ - Migration includes message lifecycle metadata fields required by CHAT-03.
+ - Migration includes persistent read-state table for later D-05/D-26 work.
+ - `discussion.sql` exposes typed queries needed by history and send handlers.
+ - `cd backend && just generate` exits 0.
+
+
+
+
+ Task 2: Add RED discussion handler tests
+
+ - backend/internal/web/handlers_discussion_test.go
+
+
+ - backend/internal/web/handlers_events_test.go
+ - backend/internal/web/handlers_tablos_test.go
+ - backend/internal/web/router.go
+ - .planning/phases/12-native-tablo-chat/12-UI-SPEC.md
+
+
+ Add DB-backed full-router tests that initially fail before implementation:
+ 1. `TestDiscussionTabRendersHistoryAndComposer` creates two messages with HTML-looking body text, requests `GET /tablos/{id}/discussion`, and expects Discussion, `1 participant`, oldest-first ordering, author email, absolute timestamp content, escaped text, day separator, textarea `Message`, placeholder `Write a message...`, and `Send message`.
+ 2. `TestDiscussionTabFullPageFallback` sends a non-HTMX direct GET and expects the full tablo detail shell with Discussion active.
+ 3. `TestDiscussionPostCreatesMessage` obtains CSRF, posts a valid body with `HX-Request:true`, expects 200, the new message fragment, and a DB row for the authenticated author/tablo.
+ 4. `TestDiscussionPostRejectsEmptyAndTooLong` expects 422 plus `Message is required.` and `Message is too long.`.
+ 5. `TestDiscussionOwnershipReturns404` verifies another user cannot GET or POST to the owner's discussion.
+ 6. `TestDiscussionRequiresCSRF` posts without CSRF and expects gorilla/csrf rejection.
+
+
+ cd backend && go test ./internal/web -run 'TestDiscussion' -count=1
+
+
+ - Tests use the existing session/CSRF/full-router helper patterns.
+ - Tests prove body escaping by asserting raw `