Преглед изворни кода

docs: resolve open Q1 (admin-invite Telegram linking) and Q2 (source-localized pass-through)

- SPEC §8: bot /start takes an invite_code; admin must pre-create
  the individual; unknown users rejected
- SPEC §4: add telegram_invite_code + telegram_invite_expires_at
  to individuals
- ARCHITECTURE §7: sequence updated to show invite-code flow
- PROMPT: log the decisions in the build log
Luis Rosales пре 2 месеци
родитељ
комит
430c683aca
3 измењених фајлова са 28 додато и 19 уклоњено
  1. 6 4
      ARCHITECTURE.md
  2. 15 13
      PROMPT.md
  3. 7 2
      SPEC.md

+ 6 - 4
ARCHITECTURE.md

@@ -211,10 +211,12 @@ sequenceDiagram
     participant RT as routerd
     participant PG as Postgres
 
-    U->>TG: /start
-    TG->>BOT: update (chat_id, from.id)
-    BOT->>PG: link telegram_chat_id to individual
-    Note over BOT,PG: Individual must pre-exist; user supplies email/phone to match
+    U->>TG: /start <invite_code>
+    TG->>BOT: update (chat_id, from.id, text=invite_code)
+    BOT->>PG: SELECT individual WHERE invite_code=?
+    Note over BOT,PG: Individual must pre-exist;<br/>admin creates row + invite code,<br/>bot matches and burns code
+    BOT->>PG: UPDATE individual SET telegram_chat_id=...
+    BOT->>TG: sendMessage(chat_id, "Linked to <name>")
 
     U->>TG: /mute 2h
     TG->>BOT: update

+ 15 - 13
PROMPT.md

@@ -23,19 +23,21 @@
   50k/sec is the design ceiling; the K8s + multi-broker work
   is what unlocks it.
 
-**Open**
-- Bot ↔ individual linking: need a clean flow. The current plan is
-  user runs `/start <email_or_phone>` and we match against
-  `individuals.email` / `phone_e164`. Open question: do we let
-  unknown users self-register via the bot, or do we require an
-  admin to create the `individuals` row first? **Toward stricter
-  is better** (admin invites, bot confirms).
-- Localized titles: we need a `title_key` / `body_key` model, or
-  accept pre-localized strings per-recipient from the source.
-  Starting simple: source sends a single `title`/`body`; we
-  do **not** localize in v1. If a customer needs localization, they
-  send the alert multiple times (one per locale) keyed on
-  `subscriptions.locale`. Re-evaluate at v2.
+**Open (was) → Resolved 2026-06-13**
+- ~~Bot ↔ individual linking~~ → **admin-invites only**. Flow: admin
+  creates `individuals` row + generates one-time invite code;
+  user runs `/start <invite_code>` in the Telegram bot; bot
+  matches the code, links `telegram_chat_id` to the
+  pre-existing individual, and burns the code. Stricter path:
+  prevents drive-by bot self-registration, keeps
+  `individuals` auditable.
+- ~~Localized titles~~ → **source-localized, pass through**. v1
+  does NOT translate. Sources send pre-localized
+  `title`/`body` strings (or use the locale on the
+  subscription to key into their own lookup table before
+  calling our API). `Alert` schema carries `locale` and
+  `title`/`body` already-resolved. We can add a translation
+  layer in v2 if customers ask.
 - mTLS: schema supports it, but the docker-compose profile won't
   terminate client certs in v1. Documented as opt-in for
   enterprise sources.

+ 7 - 2
SPEC.md

@@ -100,7 +100,9 @@ companies(id, name, slug, status, fcm_shared, telegram_bot_token_enc,
 
 -- People & devices
 individuals(id, company_id, full_name, email, phone_e164, locale, tz,
-            telegram_chat_id, telegram_user_id, status, created_at)
+            telegram_chat_id, telegram_user_id,
+            telegram_invite_code, telegram_invite_expires_at,
+            status, created_at)
 fcm_tokens(id, individual_id, token, device_id, platform, locale,
            app_version, last_seen, status, created_at)
 groups(id, company_id, name, description, fcm_topic, telegram_chat_id,
@@ -210,7 +212,10 @@ A single FCM project can hold this. Storage is on our side (the
 - For group alerts we use the bot in a company group chat
   (`telegram_chat_id` on the `groups` table).
 - **Bot commands** (Telegram = management UI):
-  - `/start` — link telegram account to `individuals.id`
+  - `/start <invite_code>` — link telegram account to the
+    pre-existing `individuals.id` (admin must create the
+    individual and issue the code first; unknown users are
+    rejected)
   - `/mute <duration>` — e.g. `/mute 2h`, `/mute until 18:00`
   - `/unmute`
   - `/subscribe <source> <min_severity>`