---
phase: 12-native-tablo-chat
plan: 02
subsystem: discussion
tags: [chat, discussion, unread, postgres, sqlc, htmx, templ]

requires:
  - phase: 12-native-tablo-chat
    plan: 01
    provides: discussion message persistence and read-state schema
provides:
  - Persistent per-user discussion unread counts
  - Dashboard unread badge rendering
  - Read-state clearing when Discussion is opened
  - Sender read-state update after message creation
affects: [discussion, tablos, dashboard, templates, tests]

tech-stack:
  added: []
  patterns:
    - "Dashboard cards use a view model that carries sqlc.Tablo plus discussion unread count."
    - "Unread counts are computed in one owner-scoped dashboard query, avoiding per-card queries."

key-files:
  created: []
  modified:
    - backend/internal/db/queries/tablos.sql
    - backend/internal/web/handlers_tablos.go
    - backend/internal/web/handlers_discussion_test.go
    - backend/templates/tablos.templ
    - backend/templates/discussion_forms.go

key-decisions:
  - "Unread badges are omitted at zero, numeric above zero, and display-capped at 99+."
  - "Unread counts compare message creation time against the last read message, not wall-clock last_read_at."
  - "The dashboard list query remains owner-scoped through tablos.user_id."

patterns-established:
  - "TablosDashboard now receives []TabloCardView instead of raw []sqlc.Tablo."
  - "Dashboard unread behavior is covered by DB-backed handler tests."

requirements-completed: [CHAT-01]

duration: ~25min
completed: 2026-05-16
---

# Phase 12 Plan 02: Discussion Unread Badge Summary

**Persistent unread state is wired into the dashboard and discussion read paths.**

## Performance

- **Duration:** ~25 min
- **Started:** 2026-05-16T07:50:00Z
- **Completed:** 2026-05-16T08:15:52Z
- **Tasks:** 2
- **Files modified:** 5

## Accomplishments

- Added RED tests for dashboard unread badges, ownership scoping, discussion GET read clearing, and sender read-state updates.
- Added `ListTablosByUserWithDiscussionUnread` to compute dashboard unread counts in a single owner-scoped query.
- Added dashboard card view helpers and unread badge display/accessibility helpers.
- Updated the dashboard handler and non-HTMX create-error fallback to render unread-aware card data.
- Preserved zero-unread dashboard behavior by omitting badges when count is zero.

## Task Commits

1. **Task 1: Add RED unread badge and read-state tests** - `e3c8d51`
2. **Task 2: Implement unread query integration and dashboard badge** - `3111b6e`

## Files Created/Modified

- `backend/internal/web/handlers_discussion_test.go` - Adds unread/read-state coverage.
- `backend/internal/db/queries/tablos.sql` - Adds unread-aware dashboard query.
- `backend/internal/web/handlers_tablos.go` - Uses unread-aware query and dashboard view models.
- `backend/templates/discussion_forms.go` - Adds card view model and unread display helpers.
- `backend/templates/tablos.templ` - Renders compact numeric unread badge.

## Decisions Made

- Unread count uses the last read message's `created_at` boundary, which keeps test fixtures deterministic and avoids depending on database wall-clock time.
- The unread badge uses restrained dashboard styling and accessible labels such as `3 unread discussion messages`.
- Existing `TabloCardWithOOBFormClear` wraps newly created tablos with zero unread count so create behavior remains unchanged.

## Deviations from Plan

None - plan executed as written.

## Issues Encountered

None.

## User Setup Required

None.

## Verification

- RED command with local DB failed before implementation because dashboard unread badges were absent:
  `TEST_DATABASE_URL='postgres://xtablo:xtablo@localhost:5432/xtablo?sslmode=disable' go test ./internal/web -run 'TestTablosListDiscussionUnread|TestDiscussion.*Read' -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 'TestTablosListDiscussionUnread|TestDiscussion.*Read' -count=1` passed.
- `git diff --check` passed.

## Self-Check: PASSED

- Task commits exist for `12-02`.
- Dashboard unread badges are owner-scoped and omitted at zero.
- Opening Discussion and posting as sender update persistent read state.
- No open deviations.

## Next Phase Readiness

Ready for Plan 12-03: SSE receive stream and realtime discussion updates.

---
*Phase: 12-native-tablo-chat*
*Completed: 2026-05-16*
