Build Log · July 29, 2026

Event location polls and AI-drafted inquiry replies

MedinaCHF's first live Anthropic call — grounded, human-reviewed AI in two places: coordinator-facing location poll suggestions, and coordinator-facing inquiry reply drafts.

  • MedinaCHF
  • AI
  • Coordinator
new coordinator-facing AI features (poll suggestions, inquiry draft replies)
2

new coordinator-facing AI features (poll suggestions, inquiry draft replies)

shared thin AI wrapper (lib/ai.ts) both features call
1

shared thin AI wrapper (lib/ai.ts) both features call

AI-sent messages — every draft requires a human click to send
0

AI-sent messages — every draft requires a human click to send

Timeline

  1. Start

    lib/ai.ts wrapper added

    Lazy-client-init, same discipline as lib/email.ts and lib/db/index.ts

  2. Mid

    Event location polls built

    Coordinator turns on a poll; Claude suggests 3-4 places grounded in past event locations; members vote; coordinator closes and sets the event location

  3. End

    AI-drafted inquiry replies built

    Coordinator clicks 'Draft with AI'; Claude drafts a reply grounded only in the approved Answer Library; coordinator reviews/edits/sends

What shipped

  • lib/ai.ts — a narrow, single-purpose draftWithClaude(system, userPrompt) wrapper; lazy client init (throws only when actually called, not at module load); every caller owns its own parsing and must handle a thrown error with a safe fallback

  • Event location polls: pollOptions/pollVotes tables (already migrated in an earlier commit), enablePollWithAiSuggestions/addPollOption/castPollVote/closePoll server actions, EventPollPanel (coordinator) + PollVoteForm (member) client components

  • AI-suggested poll options grounded in listPastEventLocations — every past event's real location for the org, so Claude can point out repeats vs. genuinely new suggestions instead of inventing anything

  • One vote per family per event — a repeat vote replaces the prior choice rather than accumulating a second row

  • Closing a poll sets the event's real location field directly — the poll's only job is picking a value for events.location, not becoming a parallel field

  • AI-drafted inquiry replies: draftInquiryResponse server action, grounded exclusively in active answerLibraryEntries (the same single source of truth every other response level in this app already uses) — never invents a fact not present in the approved answers

  • InquiryReplyPanel gets a second 'Draft with AI' button alongside the existing 'Send Response' — drafting only ever fills the textarea, sending is always the coordinator's separate, deliberate action