Phase 3a — Governed LINE-group assistant (engineering spec)
- Date: 2026-06-23
- Status: Design (implements ADR-0143 §D1–D5; gated on the DPIA —
docs/compliance/dpia-line-group-memory.md) - Scope (3a): opt-in full-thread storage + on-join consent + KB-grounded Q&A (@mention/command) + on-demand summarization + retention cron. Tasks (3b), slip verification (3c, buy), infographics (deferred) are later.
Hard gate: the message-store tables + the ingest write path must not deploy to prod until the DPIA is signed (ADR-0143 §D1). Everything else (schema scaffolding behind a feature flag, the consent flow, the mention-gated mode) can land earlier.
1. Data model (new — first migration of this work)
Section titled “1. Data model (new — first migration of this work)”line_groups id TEXT pk grp_{nanoid} tenantId TEXT (scoped; P0 invariant) workspaceId TEXT NULL lineGroupId TEXT LINE group/room id (unique per tenant) consentStatus TEXT 'pending' | 'opted_in' | 'opted_out' (storage OFF unless opted_in) consentBy TEXT NULL LINE userId of the admin who opted in consentAt INTEGER NULL mode TEXT 'full_thread' | 'mention_only' (per-group privacy mode, ADR-0143 D1) retentionDays INTEGER conservative default (DPIA-set) features TEXT JSON: { qa, summarize, tasks } enabled INTEGER createdAt/updatedAt INTEGER
group_messages -- DPIA-GATED; only written when consentStatus='opted_in' AND mode='full_thread' id TEXT pk tenantId, groupId TEXT lineMessageId TEXT senderId TEXT LINE userId senderName TEXT NULL cached display name text TEXT REDACTED on ingest (national id/phone/card) attachmentsJson TEXT NULL reuse ADR-0043 shape (slip/doc images) createdAt INTEGER (retention cron deletes by this)
group_summaries id, tenantId, groupId TEXT summary TEXT fromMessageId/toMessageId TEXT requestedBy TEXT createdAt INTEGER- Indexes:
(tenantId, lineGroupId)unique online_groups;(groupId, createdAt)ongroup_messages(window reads + retention scan). - Enum widening already done (
conversations.source/TicketChannelinclude channel keys); group entities are separate tables, not conversations (ADR-0143 §D4 — multi-participant, not 1:1).
2. Consent flow (ADR-0143 §D2)
Section titled “2. Consent flow (ADR-0143 §D2)”- LINE
joinevent (bot added) → upsertline_groups(consentStatus=‘pending’) → bot posts the on-join transparency notice (TH/EN: what it stores, retention, opt-out, privacy link). - Admin command
จดจำ เปิด(opt in) → consentStatus=‘opted_in’, record consentBy/At. Any memberจดจำ ปิด/ออก→ ‘opted_out’ (storage stops; existing data subject to retention/erasure). leave/memberLefthandled; admin can setmode+retentionDaysvia command or the admin UI.
3. Webhook branch (reuse the existing LINE handler)
Section titled “3. Webhook branch (reuse the existing LINE handler)”api/channels/line/+server.tsPOST: after signature verify, branch onevent.source.type:'user'→ existing 1:1runChannelTurn(unchanged).'group' | 'room'→ newrunGroupEvent(event)(newlib/channels/group-turn.ts).
runGroupEventdispatches:join/leave/memberJoined→ consent/lifecycle;message→ (a) ifmention_onlyor not addressed → store only if addressed; (b) iffull_thread+ opted_in → redact + store; then if the message addresses the bot (@mention/command) → handle Q&A / summarize.
4. Ingest + redaction (DPIA-gated write path)
Section titled “4. Ingest + redaction (DPIA-gated write path)”- On a stored message: run the PII redactor (Workers AI / regex for Thai national id
\d{13}, phone, card) → store redactedtext. Raw bytes never persisted for slips beyond the ADR-0043 pipeline (vendor verifies in 3c). - Write gated:
consentStatus==='opted_in' && mode==='full_thread'. Ack-fast +waitUntil(same hot-path discipline as ADR-0133 §D2).
5. Q&A + summarization (reuse shared libs)
Section titled “5. Q&A + summarization (reuse shared libs)”- Q&A: addressed message →
hybridSearch(tenant KB, persona-scoped) + LLM, reply to the group. ReuseselectChatModel,buildSystemPrompt, the answer-marker parsing. - Summarize:
จดจำ สรุป [N]→ read last Ngroup_messages(or transient fetch in mention-only mode) → LLM summary → store ingroup_summaries→ reply. Bounded N.
6. Retention cron
Section titled “6. Retention cron”- Extend the existing cron (or new
/api/cron/group-retention): deletegroup_messageswherecreatedAt < now - retentionDays*86400, per group. Redact stale summaries. Idempotent, batched (mind D1 throughput — the overload discipline from the backup/retention crons).
7. Erasure (ADR-0055/0056 reuse)
Section titled “7. Erasure (ADR-0055/0056 reuse)”- Per-group: admin command / admin UI → delete group_messages + summaries + line_groups (or tombstone). Per-member (§33): delete that senderId’s messages + redact their spans in summaries; audit-logged.
8. Build sequence (each validated + deployed like the channels)
Section titled “8. Build sequence (each validated + deployed like the channels)”- Schema + consent flow + mention-gated Q&A (NO full-thread storage) — low DPIA exposure; a narrow pilot is possible if counsel agrees (DPIA §5).
- Full-thread storage + redaction + retention cron — DPIA sign-off required before this deploys.
- Summarization over the stored thread.
- Tasks (3b), then slip verification (3c, buy).
9. Open (from ADR-0143 / DPIA)
Section titled “9. Open (from ADR-0143 / DPIA)”- Audience (internal vs customer-facing) → fixes the default
mode+ lawful basis. - Retention default, redaction coverage, member-notification wording — DPIA.
- Pricing/quota for a group product (storage + AI credits + group count) — distinct from per-seat support plans.