Imported from artyom-kalman/daily-menu (
AGENTS.md). Install upstream withnpx skills add artyom-kalman/daily-menu. Copyright stays with the author.
Agent Guidelines for daily-menu (Convex)
Project tracking (Notion)
Issues and project notes live in Notion. Read open issues and the project page, and update issue status (In progress / Done) as you go.
Build & Test Commands
- Install:
npm install - Dev (codegen + watch):
npx convex dev - Deploy to Convex dev (
enchanted-goshawk-667):npx convex deploy --yeswith the devCONVEX_DEPLOY_KEY(prefixdev:enchanted-goshawk-667). Never pass--prodfrom a feature branch. - Production deploy is CI only (push to
master). Do notnpx convex deploy --prodfrom an agent. - Test:
npm test(Vitest; includes mock-Telegram button E2E) - Typecheck:
npx tsc --noEmit(afternpx convex codegen)
Real-env testing (required)
Vitest is not enough for Telegram UX. After the code is ready, deploy to Convex dev and exercise the real dev bot before calling the work done.
- Cloud agents have
CONVEX_DEPLOY_KEYfor dev (enchanted-goshawk-667). Use that. It is not the production key. - Prefer
npx convex deploy --yes.npx convex dev --onceoften fails on this key (deployment:logs:viewis missing). npx convex deploy/npx convex devdo not change Telegram webhooks. Do not runtelegram:setWebhookunless asked.- Confirm on the dev bot (not prod): new buttons, copy, opt-in/out, admin commands if they changed.
- If the deploy key is missing or is a prod key, stop and say so. Do not guess.
Code Style
- TypeScript, Convex query/mutation/action patterns
- All Convex functions are internal; the only public surface is
POST /telegram/webhook TELEGRAM_WEBHOOK_SECRETis required; the webhook 401s if it is missing or wrong- Separate Telegram bots for Convex dev and prod (one bot = one webhook). Register with
npx convex run telegram:setWebhook(usesCONVEX_SITE_URL; do not paste URLs).npx convex devdoes not change Telegram webhooks. - Secrets in Convex env; cafeteria URLs in
appConfigsingleton (key: "default") - Telegram UX: two inline buttons —
today_menuand morningПрисылать утром/Отписаться. No student commands. - Admin commands (
/status,/refetch,/stats) only forADMIN_CHAT_ID; everyone else gets today's menu with the two buttons./statssendsAPTABASE_DASHBOARD_URL - Keep bot logic in
telegramHandlers.tsso E2E can run without a live deploy - Prune
menusandfetchAttemptsolder than 30 days at 00:00 KST; never delete today's rows.subscribersare dropped on unsubscribe or blocked-chat delivery. - Morning push: after a weekday cron fetch when both cafeterias are settled (each has its own complete live tray of 5+ dishes, or a closed/holiday notice). Do not push while either hall is still a stub, except on the last 12:30 KST attempt, which sends whatever is posted even if one hall is empty. Skip weekends and both-empty days. One message per opted-in chat. Store
chatIdin Convex only; never send it to Aptabase. - Product events go to Aptabase (
start,today_menu,scrape_ok/scrape_empty/scrape_error). OptionalAPTABASE_APP_KEY; no-op if unset. Do not sendchatIdor menu text. Convex dev (enchanted-goshawk-667) uses Aptabase Debug; prod uses Release.