From 7f7ee2c013fc788f8cdc83ef79e569c6021f8838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sun, 21 Jun 2026 11:13:17 +0200 Subject: [PATCH] feat(telegram): add prompt-context table for mood-note correlation Add TelegramPromptContext (migration 0187) mapping a bot force-reply prompt to the entry a free-text reply attaches to, keyed on (chatId, promptMsgId) and scoped to the owning user. MoodEntry.source already accepts the free-text TELEGRAM value, so no enum change is needed. --- .../migration.sql | 20 ++++++++++++++ prisma/schema.prisma | 27 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 prisma/migrations/0187_v1190_telegram_prompt_context/migration.sql diff --git a/prisma/migrations/0187_v1190_telegram_prompt_context/migration.sql b/prisma/migrations/0187_v1190_telegram_prompt_context/migration.sql new file mode 100644 index 000000000..aab9f45f5 --- /dev/null +++ b/prisma/migrations/0187_v1190_telegram_prompt_context/migration.sql @@ -0,0 +1,20 @@ +-- v1.19.0 — force-reply correlation for the interactive mood reminder. +-- Maps a bot prompt message to the entry a free-text reply attaches to. +CREATE TABLE "telegram_prompt_contexts" ( + "id" TEXT NOT NULL, + "user_id" TEXT NOT NULL, + "chat_id" TEXT NOT NULL, + "prompt_msg_id" INTEGER NOT NULL, + "kind" TEXT NOT NULL, + "ref_id" TEXT NOT NULL, + "expires_at" TIMESTAMP(3) NOT NULL, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "telegram_prompt_contexts_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "telegram_prompt_contexts_chat_id_prompt_msg_id_key" ON "telegram_prompt_contexts"("chat_id", "prompt_msg_id"); + +-- CreateIndex +CREATE INDEX "telegram_prompt_contexts_expires_at_idx" ON "telegram_prompt_contexts"("expires_at"); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index f07426b66..e70160cad 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -2262,6 +2262,33 @@ model TelegramScheduledDeletion { @@map("telegram_scheduled_deletions") } +// v1.19.0 — force-reply correlation for the interactive mood reminder. +// +// When a user taps "Notiz…" on a mood prompt the bot sends a force_reply +// message; the user's free-text reply then arrives as a normal `message` +// whose `reply_to_message.message_id` points back at that prompt. This +// row maps `(chatId, promptMessageId)` to the mood entry the note should +// attach to, so the inbound note handler can resolve "what was this a +// reply to" without trusting any client-supplied id. Rows are short-lived +// (`expiresAt`) and best-effort deleted once consumed; the deletion sweep +// is keyed on `expiresAt` so an unanswered note prompt self-cleans. +model TelegramPromptContext { + id String @id @default(cuid()) + userId String @map("user_id") + chatId String @map("chat_id") + // The bot's prompt message the user is expected to reply to. + promptMsgId Int @map("prompt_msg_id") + // What the reply attaches to. "mood_note" carries `refId = moodEntryId`. + kind String + refId String @map("ref_id") + expiresAt DateTime @map("expires_at") + createdAt DateTime @default(now()) @map("created_at") + + @@unique([chatId, promptMsgId]) + @@index([expiresAt]) + @@map("telegram_prompt_contexts") +} + // ─── API Tokens (for external ingest) ────────────────────── model ApiToken {