Meridian Ops Board
An operations dashboard and daily AI briefing for a small print and display shop. It pulls orders, CRM leads and tasks, EOS to-dos, a content tracker, meeting action items and the shared inboxes into one page per person, and has a language model write each person a morning briefing from the same data.
Everything about the company is fictional. Meridian Display Co., its staff, its clients, its orders and every piece of data in this repository are invented. The system itself is real: it was designed and built with AI-assisted development and ran in daily use, and this is a rebuild of it with sample data.
What it shows
- The people board. Who is loaded and who is not, per person, across every source. A person no source covers reads "not tracked", never zero.
- My Day. Each person's own orders, tasks, to-dos and meeting commitments, with a private task list only they can read.
- The shared inbox. Every role mailbox in one view, with role-gated reply and send, a confirmation step and an audit record.
- The morning briefing. A distilled payload goes to a language model, which writes a company briefing and a personal day plan for each person, tiered by role.
- Onboarding. A training plan and an end-of-day note for a new hire, visible only to the people who should see it.
- Data health. Which sources answered, which failed, and what nothing covers.
How it is built
A pnpm monorepo in TypeScript, with one Python script for the briefing.
| Part | Where |
|---|---|
| API clients for Plinth, Bitrix24, Ninety, Google Sheets, Fathom and Gmail | packages/ |
| Collect, view model and page rendering | apps/dashboard/ |
| Cloudflare Worker: cron sync, Access-verified pages, the inbox, D1 | apps/worker/ |
| Rosters, stage taxonomies, grants and other human-edited config | config/ |
| The briefing, the only place a model is called | analysis/brief.py |
The design rules the code follows, starting with "zero, null and broken must never look the same", are in docs/ARCHITECTURE.md.
Running it
Node 22.5 or later and pnpm 9. The D1 store tests run on node:sqlite, which
older Node does not have; below 22.5 they skip with a warning rather than fail.
pnpm install
pnpm test # 1,168 TypeScript and 49 Python cases, offline
pnpm typecheck
pnpm dashboard --fixtures # writes dashboard.html from sample dataCI (.github/workflows/ci.yml) runs install, typecheck and test on Node 22.
Live runs need credentials in the process environment; see
credentials.example.sh. There is deliberately no .env reader. The
briefing (analysis/brief.py) calls a local OpenAI-compatible server at
http://127.0.0.1:1234/v1 by default. Pointing ANTHROPIC_BASE_URL at the
Anthropic API switches it to that API, which needs ANTHROPIC_API_KEY.
Deploying the Worker
cd apps/worker # once per account
wrangler kv namespace create DASHBOARD # and again with --preview
wrangler d1 create meridian-checkins
wrangler d1 migrations apply meridian-checkins --remote
wrangler secret put NINETY_TOKEN # also BITRIX_WEBHOOK_URL, PLINTH_API_KEY
wrangler deployPaste the printed KV and D1 ids into wrangler.jsonc. Gmail credentials are
Worker secrets too (pnpm inbox:auth mints and stores a mailbox's token).
Put a Cloudflare Access application in front of the workers.dev URL and its
preview URLs, then set ACCESS_TEAM_DOMAIN and ACCESS_AUD in
wrangler.jsonc: until both are set the Worker refuses every request.
pnpm morning syncs, writes the briefings and pushes the pages to the Worker.