the pipeline

the cafeteria sends a weekly email every friday containing a link to a pdf menu. this bot picks that up and automates everything else.

[University Email]
      |
      v
[n8n: Gmail Search] --> [Playwright API: Fetch SharePoint PDF]
      |
      v
[Claude API: Extract menu as JSON]
      |
      v
[PostgreSQL: Store menu items]
      |
      v
[n8n: Daily Discord Poster @ 9am JST]

tech stack

ComponentTechnology
Workflow automationn8n
PDF fetchingPlaywright + Express (Node.js)
AI extractionClaude (Anthropic API)
DatabasePostgreSQL
Bot frameworkdiscord.js
InfrastructureProxmox (self-hosted)

step by step

1. email detection (saturday)

every saturday, an n8n workflow checks a gmail account for the weekly menu email. when found, it extracts the sharepoint link from the email body.

2. pdf fetching

because the pdf is hosted on microsoft sharepoint behind authentication, a playwright-powered express api handles the browser session and returns the raw pdf bytes.

3. menu extraction with claude

the pdf is sent to the claude api with a prompt asking it to extract structured dish data: dish name, category, subcategory, calories, protein, fat, and allergens. the result is a clean json array ready for storage.

4. database storage

each dish is stored in a postgresql menu_items table keyed by date. the schema is simple and efficient, queries by date take milliseconds.

5. daily posting (monday-friday, 9 am jst)

a second n8n workflow (and the discord bot’s built-in scheduler) runs every weekday morning. it queries the database for that day’s menu, formats it with emojis and nutrition info, and sends it to every subscribed discord server.

6. per-server subscriptions

each discord server independently subscribes to a specific channel. the bot manages per-guild notification roles so members can self-opt into pings.