docs(12-03): complete discussion realtime plan
This commit is contained in:
parent
409245eac0
commit
81538bb780
4 changed files with 159 additions and 15 deletions
|
|
@ -21,8 +21,8 @@ Requirements for milestone v2.0. Each requirement must map to exactly one roadma
|
||||||
- [x] **CHAT-01**: Each tablo has a discussion view where authenticated authorized users can see persisted message history
|
- [x] **CHAT-01**: Each tablo has a discussion view where authenticated authorized users can see persisted message history
|
||||||
- [x] **CHAT-02**: User can post a text message to a tablo discussion with validation and CSRF protection
|
- [x] **CHAT-02**: User can post a text message to a tablo discussion with validation and CSRF protection
|
||||||
- [x] **CHAT-03**: Messages are stored in Postgres with tablo, author, body, created timestamp, and deletion/edit metadata
|
- [x] **CHAT-03**: Messages are stored in Postgres with tablo, author, body, created timestamp, and deletion/edit metadata
|
||||||
- [ ] **CHAT-04**: Open tablo discussion views receive new messages in real time without a manual refresh
|
- [x] **CHAT-04**: Open tablo discussion views receive new messages in real time without a manual refresh
|
||||||
- [ ] **CHAT-05**: Real-time delivery uses Xtablo-owned infrastructure only; no managed chat or realtime provider is introduced
|
- [x] **CHAT-05**: Real-time delivery uses Xtablo-owned infrastructure only; no managed chat or realtime provider is introduced
|
||||||
- [x] **CHAT-06**: Message rendering escapes user content and enforces a server-side maximum body length
|
- [x] **CHAT-06**: Message rendering escapes user content and enforces a server-side maximum body length
|
||||||
|
|
||||||
### Etapes
|
### Etapes
|
||||||
|
|
@ -99,7 +99,7 @@ Populated during roadmap creation.
|
||||||
| ETAPE-01..06 | Phase 9 | Pending |
|
| ETAPE-01..06 | Phase 9 | Pending |
|
||||||
| EVENT-01..05 | Phase 10 | Complete |
|
| EVENT-01..05 | Phase 10 | Complete |
|
||||||
| PLAN-01..04 | Phase 11 | Pending |
|
| PLAN-01..04 | Phase 11 | Pending |
|
||||||
| CHAT-01..06 | Phase 12 | Pending |
|
| CHAT-01..06 | Phase 12 | Complete |
|
||||||
|
|
||||||
**Coverage:**
|
**Coverage:**
|
||||||
- v2.0 requirements: 27 total
|
- v2.0 requirements: 27 total
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
| 9 | Etapes | Tasks can be grouped under one-level etapes without breaking the kanban model | ETAPE-01..06 |
|
| 9 | Etapes | Tasks can be grouped under one-level etapes without breaking the kanban model | ETAPE-01..06 |
|
||||||
| 10 | 4/4 | Complete | 2026-05-16 |
|
| 10 | 4/4 | Complete | 2026-05-16 |
|
||||||
| 11 | 2/2 | Complete | 2026-05-16 |
|
| 11 | 2/2 | Complete | 2026-05-16 |
|
||||||
| 12 | 2/3 | In Progress| |
|
| 12 | 3/3 | Complete | 2026-05-16 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,14 @@ gsd_state_version: 1.0
|
||||||
milestone: v2.0
|
milestone: v2.0
|
||||||
milestone_name: Collaboration, planning, and social sign-in
|
milestone_name: Collaboration, planning, and social sign-in
|
||||||
status: executing
|
status: executing
|
||||||
last_updated: "2026-05-16T08:16:14.486Z"
|
last_updated: "2026-05-16T08:33:45.416Z"
|
||||||
last_activity: 2026-05-16 -- Phase 12 planning complete
|
last_activity: 2026-05-16 -- Phase 12 execution complete
|
||||||
progress:
|
progress:
|
||||||
total_phases: 5
|
total_phases: 5
|
||||||
completed_phases: 4
|
completed_phases: 5
|
||||||
total_plans: 18
|
total_plans: 18
|
||||||
completed_plans: 17
|
completed_plans: 18
|
||||||
percent: 94
|
percent: 100
|
||||||
---
|
---
|
||||||
|
|
||||||
# STATE
|
# STATE
|
||||||
|
|
@ -24,15 +24,15 @@ 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:** Phase 12 — Native Tablo Chat
|
**Current focus:** v2.0 milestone verification
|
||||||
|
|
||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Phase: 12
|
Phase: 12
|
||||||
Plan: Not started
|
Plan: 03 complete
|
||||||
Status: Ready to execute
|
Status: Complete
|
||||||
Last activity: 2026-05-16 -- Phase 12 planning complete
|
Last activity: 2026-05-16 -- Phase 12 execution complete
|
||||||
Resume file: .planning/phases/12-native-tablo-chat/12-01-PLAN.md
|
Resume file: .planning/phases/12-native-tablo-chat/12-03-SUMMARY.md
|
||||||
|
|
||||||
## Phase Status
|
## Phase Status
|
||||||
|
|
||||||
|
|
@ -42,13 +42,14 @@ Resume file: .planning/phases/12-native-tablo-chat/12-01-PLAN.md
|
||||||
| 9 | Etapes | ◆ UAT passed; security pending |
|
| 9 | Etapes | ◆ UAT passed; security pending |
|
||||||
| 10 | Events | ✓ Complete |
|
| 10 | Events | ✓ Complete |
|
||||||
| 11 | Individual Planning | ✓ Complete |
|
| 11 | Individual Planning | ✓ Complete |
|
||||||
| 12 | Native Tablo Chat | ◆ Ready to execute |
|
| 12 | Native Tablo Chat | ✓ Complete |
|
||||||
|
|
||||||
## Verification Record
|
## Verification Record
|
||||||
|
|
||||||
- 2026-05-15: Phase 8 execution complete. Local verification passed with `go test ./... -count=1`; database-backed integration coverage skips unless `TEST_DATABASE_URL` is configured.
|
- 2026-05-15: Phase 8 execution complete. Local verification passed with `go test ./... -count=1`; database-backed integration coverage skips unless `TEST_DATABASE_URL` is configured.
|
||||||
- 2026-05-15: Phase 9 UAT complete. Five browser checkpoints passed after fixing the selected-etape create gap; backend verification passed with `TEST_DATABASE_URL='postgres://xtablo:xtablo@localhost:5432/xtablo?sslmode=disable' go test ./... -count=1`.
|
- 2026-05-15: Phase 9 UAT complete. Five browser checkpoints passed after fixing the selected-etape create gap; backend verification passed with `TEST_DATABASE_URL='postgres://xtablo:xtablo@localhost:5432/xtablo?sslmode=disable' go test ./... -count=1`.
|
||||||
- 2026-05-16: Phase 10 execution complete. Events UAT approved; backend verification passed with `TEST_DATABASE_URL='postgres://xtablo:xtablo@localhost:5432/xtablo?sslmode=disable' go test ./... -count=1`.
|
- 2026-05-16: Phase 10 execution complete. Events UAT approved; backend verification passed with `TEST_DATABASE_URL='postgres://xtablo:xtablo@localhost:5432/xtablo?sslmode=disable' go test ./... -count=1`.
|
||||||
|
- 2026-05-16: Phase 12 execution complete. Discussion realtime UAT approved after duplicate-row and composer-reset fixes; backend verification passed with `just generate` and `TEST_DATABASE_URL='postgres://xtablo:xtablo@localhost:5432/xtablo?sslmode=disable' go test ./... -count=1`.
|
||||||
|
|
||||||
## Decisions
|
## Decisions
|
||||||
|
|
||||||
|
|
@ -123,6 +124,7 @@ Resume file: .planning/phases/12-native-tablo-chat/12-01-PLAN.md
|
||||||
| Phase 11 P02 | ~20min | 2 tasks | 4 files |
|
| Phase 11 P02 | ~20min | 2 tasks | 4 files |
|
||||||
| Phase 12 P01 | ~25min | 3 tasks | 22 files |
|
| Phase 12 P01 | ~25min | 3 tasks | 22 files |
|
||||||
| Phase 12 P02 | ~25min | 2 tasks | 5 files |
|
| Phase 12 P02 | ~25min | 2 tasks | 5 files |
|
||||||
|
| Phase 12 P03 | ~45min | 4 tasks | 9 files |
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
|
|
||||||
142
.planning/phases/12-native-tablo-chat/12-03-SUMMARY.md
Normal file
142
.planning/phases/12-native-tablo-chat/12-03-SUMMARY.md
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
---
|
||||||
|
phase: 12-native-tablo-chat
|
||||||
|
plan: 03
|
||||||
|
subsystem: discussion
|
||||||
|
tags: [chat, discussion, sse, realtime, htmx, templ]
|
||||||
|
|
||||||
|
requires:
|
||||||
|
- phase: 12-native-tablo-chat
|
||||||
|
plan: 01
|
||||||
|
provides: discussion message persistence and POST send
|
||||||
|
- phase: 12-native-tablo-chat
|
||||||
|
plan: 02
|
||||||
|
provides: persistent read state and unread badge behavior
|
||||||
|
provides:
|
||||||
|
- Authenticated owner-only SSE stream endpoint
|
||||||
|
- In-process discussion event broker
|
||||||
|
- Local EventSource browser integration
|
||||||
|
- Duplicate suppression between sender POST response and SSE event
|
||||||
|
- Composer reset after successful sends
|
||||||
|
affects: [discussion, router, static-assets, templates, tests]
|
||||||
|
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns:
|
||||||
|
- "Realtime receive uses SSE from the Go process; sends remain CSRF-protected HTMX POSTs."
|
||||||
|
- "Discussion SSE events carry rendered message HTML with message IDs for duplicate suppression."
|
||||||
|
- "Composer reset is attached directly to the HTMX form after successful requests."
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created:
|
||||||
|
- backend/internal/web/discussion_broker.go
|
||||||
|
- backend/static/discussion-sse.js
|
||||||
|
modified:
|
||||||
|
- backend/internal/web/handlers_discussion.go
|
||||||
|
- backend/internal/web/handlers_discussion_test.go
|
||||||
|
- backend/internal/web/router.go
|
||||||
|
- backend/cmd/web/main.go
|
||||||
|
- backend/templates/discussion.templ
|
||||||
|
- backend/templates/discussion_forms.go
|
||||||
|
- backend/templates/layout.templ
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "Use in-process pub/sub for the first native realtime slice; Postgres remains the reconnect/missed-event source of truth."
|
||||||
|
- "Do not add WebSockets, managed realtime providers, workers, or runtime CDN scripts."
|
||||||
|
- "Keep sender POST rendering, but suppress duplicate rows when SSE wins the race."
|
||||||
|
- "Use `hx-on::after-request` on the composer form for clearing input, avoiding fragile delegated HTMX event source lookup."
|
||||||
|
|
||||||
|
patterns-established:
|
||||||
|
- "Discussion routes accept `DiscussionDeps{Queries, Realtime}`; router provides a default broker when none is injected."
|
||||||
|
- "SSE handlers set `text/event-stream`, `Cache-Control: no-cache`, `Connection: keep-alive`, and `X-Accel-Buffering: no`."
|
||||||
|
- "Local JS silently reconnects through EventSource and exposes no connection-status, typing, or presence UI."
|
||||||
|
|
||||||
|
requirements-completed: [CHAT-04, CHAT-05]
|
||||||
|
|
||||||
|
duration: ~45min
|
||||||
|
completed: 2026-05-16
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 12 Plan 03: Discussion Realtime Summary
|
||||||
|
|
||||||
|
**Native realtime discussion delivery is implemented with Go-owned SSE receive and HTMX POST send.**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
- **Duration:** ~45 min
|
||||||
|
- **Started:** 2026-05-16T08:16:00Z
|
||||||
|
- **Completed:** 2026-05-16T08:33:05Z
|
||||||
|
- **Tasks:** 4
|
||||||
|
- **Files modified:** 9
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- Added RED tests for stream authentication, owner-only access, SSE headers, broker publishing, broker cancellation cleanup, and browser script behavior.
|
||||||
|
- Added `DiscussionBroker` with per-tablo subscriptions, non-blocking publish, and unregister-on-cancel behavior.
|
||||||
|
- Added protected `GET /tablos/{id}/discussion/stream` with SSE headers, initial flush, keepalives, and request-context cancellation.
|
||||||
|
- Wired discussion POST to broadcast newly inserted messages after DB persistence and read-state update.
|
||||||
|
- Added local `/static/discussion-sse.js` EventSource integration with duplicate suppression.
|
||||||
|
- Added form-level HTMX reset behavior so successful sends clear the composer reliably.
|
||||||
|
- Completed browser UAT: one visible row per sent message, composer clears, second tab receives messages without manual refresh, and no external realtime provider is used.
|
||||||
|
|
||||||
|
## Task Commits
|
||||||
|
|
||||||
|
1. **Task 1: Add RED SSE handler and broker tests** - `c6dcb68`
|
||||||
|
2. **Task 2: Implement SSE broker, stream route, and local browser glue** - `d15c374`
|
||||||
|
3. **Realtime UAT fixes: duplicate suppression and composer reset** - `6f17c30`, `426d89c`, `1034efc`, `409245e`
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
- `backend/internal/web/discussion_broker.go` - Adds in-process discussion pub/sub.
|
||||||
|
- `backend/internal/web/handlers_discussion.go` - Adds stream handler and publish-after-insert behavior.
|
||||||
|
- `backend/internal/web/handlers_discussion_test.go` - Adds SSE, broker, and browser-script regression coverage.
|
||||||
|
- `backend/internal/web/router.go` - Adds discussion stream route and default broker wiring.
|
||||||
|
- `backend/cmd/web/main.go` - Wires production discussion broker.
|
||||||
|
- `backend/templates/discussion.templ` - Adds stream URL hook and form-level reset behavior.
|
||||||
|
- `backend/templates/discussion_forms.go` - Adds stream URL helper.
|
||||||
|
- `backend/templates/layout.templ` - Loads local discussion SSE script.
|
||||||
|
- `backend/static/discussion-sse.js` - Adds EventSource append and duplicate suppression.
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
- The broker broadcasts persisted messages only after the database insert succeeds.
|
||||||
|
- The browser script does not surface connection state; EventSource handles silent reconnect.
|
||||||
|
- Sender duplicate prevention stays client-side because the same user may legitimately have a second tab that should receive the SSE event.
|
||||||
|
- Composer reset is attached to the HTMX form instead of a delegated script handler after HTMX v2 event detail differences made delegated source lookup brittle.
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
- UAT found two UI regressions in the initial SSE implementation: sender-visible duplicate rows and composer text not clearing. Both were fixed before close-out.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
- HTMX v2 event details did not expose the source form where the initial delegated reset handler expected it.
|
||||||
|
- Canceling duplicate swaps meant `detail.successful` was not reliable for reset behavior, so reset moved onto the form with `hx-on::after-request`.
|
||||||
|
|
||||||
|
## User Setup Required
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- RED command failed before implementation because SSE types/routes did not exist:
|
||||||
|
`TEST_DATABASE_URL='postgres://xtablo:xtablo@localhost:5432/xtablo?sslmode=disable' go test ./internal/web -run 'TestDiscussionStream|TestDiscussionBroker|TestDiscussionPostBroadcasts' -count=1`
|
||||||
|
- `cd backend && just generate` passed.
|
||||||
|
- `cd backend && TEST_DATABASE_URL='postgres://xtablo:xtablo@localhost:5432/xtablo?sslmode=disable' go test ./internal/web -run 'TestDiscussionStream|TestDiscussionBroker|TestDiscussionPostBroadcasts|TestDiscussion' -count=1` passed.
|
||||||
|
- `cd backend && TEST_DATABASE_URL='postgres://xtablo:xtablo@localhost:5432/xtablo?sslmode=disable' go test ./... -count=1` passed.
|
||||||
|
- `git diff --check` passed.
|
||||||
|
- Browser UAT approved by user on 2026-05-16 after duplicate-row and composer-reset fixes.
|
||||||
|
|
||||||
|
## Self-Check: PASSED
|
||||||
|
|
||||||
|
- CHAT-04 is covered by SSE implementation and browser UAT.
|
||||||
|
- CHAT-05 is satisfied with only Xtablo-owned Go/Postgres/static infrastructure.
|
||||||
|
- No WebSocket, managed chat, external realtime runtime, or runtime CDN script was added.
|
||||||
|
- Stream auth, ownership, headers, broker publish, and cancellation cleanup have automated coverage.
|
||||||
|
|
||||||
|
## Phase 12 Readiness
|
||||||
|
|
||||||
|
Phase 12 is ready for final phase verification and close-out.
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 12-native-tablo-chat*
|
||||||
|
*Completed: 2026-05-16*
|
||||||
Loading…
Reference in a new issue