The problem
Restaurant food procurement in Denmark runs on phone, fax, Excel, and a patchwork of supplier-specific ecommerce portals — every supplier has their own ordering site or app, every site needs its own login, every order gets re-typed into half a dozen separate vendor checkouts. Price lists arrive as PDFs; orders go back as emails. On top of that sits a layer of CRMs and ERPs (e-conomic, Dinero, Microsoft NAV, the supplier's own back-office) that don't talk to any of the ordering channels — so reconciliation is manual, often weeks late, and full of errors. Nobody can compare offers across suppliers in any structured way. The buyer side has no visibility into what each supplier is willing to do; the supplier side has no efficient way to respond to dozens of small RFQs per day; the back-office systems on both ends have no programmatic way to plug in.
On the consumer side: small Danish farms have produce to sell but no infrastructure for coordinated pre-orders or scheduled neighbourhood pickup. Individual farm shops exist, physical farmers' markets exist — what was missing was the digital coordination layer between them: multiple farms shipping to one drop point on a schedule consumers commit to in advance. Existing home-delivery boxes (capital-heavy, thin margins) had plateaued.
What we built in response
PickNDeal collapses that fragmentation into one structured marketplace, then exposes the marketplace itself to agents and existing back-office systems via an MCP server, an API-key-authenticated REST surface, and HMAC-signed webhooks. Restaurants and suppliers can use the web/mobile app, or their own AI agent (Claude Desktop, Cursor, custom orchestration), ortheir existing ERP/CRM via webhook subscription — same API surface, same data model. The platform is agent-native by design: the MCP server is not a bolt-on, it's how everything is built. That's what makes the Phase 9 integration story interesting — buyers and suppliers can plug their existing systems into PickNDeal without any human-in-the-middle, and they can do it in a weekend instead of a quarter.
The architecture
A monorepo (Turborepo + pnpm workspaces) with three apps and four shared packages:
- apps/web — Next.js 16 (App Router). Restaurant + supplier + consumer + public marketing, all under one origin.
- apps/admin — Next.js 16 admin app, role-gated, separate origin.
- apps/mobile — Expo 55 React Native, iOS + Android, both live in stores.
- packages/api — tRPC v11 routers, the single API surface for everything.
- packages/db — Drizzle ORM schema, migrations, and seeders.
- packages/ai — Anthropic SDK client, role-scoped tools, agentic chat loop.
- packages/mcp-server — MCP server exposing the platform to external agents.
What the agentic method delivered
1. AI offer agent (Phase 8)
Suppliers configure auto-offer rules (per category: unit price, lead time, min/max quantity). When a restaurant posts an RFQ, the platform fires the agent within seconds. The agent reads the RFQ, matches against the supplier's rules, and posts a structured offer. The restaurant sees offers from multiple suppliers within minutes of posting, not days. Human-review gate on the supplier side: the supplier can override or auto-accept rules per category.
2. Multi-supplier acceptance (Phase 5)
A restaurant can accept different items from different suppliers in a single order. Theorder_item_assignmentstable is the source of truth: each line item is assigned to exactly one supplier. Payment splits and fulfilment notifications flow per-supplier from there.
3. D2C consumer flow (Phase 7)
Consumers discover farmer group orders by neighbourhood, subscribe with one tap, pay via Stripe (saved cards + business invoicing with Danish VAT/CVR support), pick up from the farmer's designated location. Auto-offer rules fire when a consumer subscription completes the minimum-order threshold, notifying the farmer to confirm.
4. MCP server (Phase 9)
External agents (Claude Desktop, Cursor, custom orchestration) can authenticate via API key and operate the platform: list categories, create RFQs, submit offers, query order state. HMAC-signed webhook delivery for ERP integrations. This is what makes the platform agent-native — buyers and suppliers can integrate their own automation without any human-in-the-middle.
5. Production hardening (Phases 10–14)
AI chat assistant for all roles (SSE streaming + rate limiting). Reorder agent cron with safety boundaries. Push notifications fan-out to consumers within delivery radius. Stripe webhook idempotency. Schema-touch detection in the deploy pipeline (force-rerun of Drizzle db:pushwhen schema files change, not on every deploy). Build-then-swap deploy pattern with health-check rollback.
Production reality (the audit-trail snapshot)
- Live at pickndeal.app on a GCP e2-small VM, PM2 fork mode, nginx + Let's Encrypt, automated CI/CD via GitHub Actions.
- Mobile apps live: iOS App Store (build 2 reviewed) and Android Play Store (since 2026-04-18).
- 14 phases shipped from initial scaffold to current production. Each phase has its own committed plan + invariants extracted into the project-scoped library.
- Three production outages caught and recovered through the deploy-then-swap pattern after we hardened the script. Each post-mortem became an invariant in the library so the same class of failure could not recur.
Selected invariants we extracted
- Schema changes need migration files alongside the consuming code. Splitting a column add and the code that reads it across two commits guarantees a 500 in production. Three outages taught us this.
- Build before restart. The deploy script builds to
.next-new/then atomically swaps. The running PM2 process keeps serving the old build the entire time. Health-check before commit; rollback automatically. - Fixed-position overlays must portal to
document.body. Any ancestor withtransformsilently convertsposition: fixedinto “positioned against that ancestor.” Caught three different modal bugs in one week before we made it the rule. - Reproduce UI bugs in the browser before fixing. A confirmed-by-curl hypothesis is not the same as a confirmed root cause. Three speculative fixes burned three deploys before this became invariant.
The full invariant set lives inside the engagement deliverables. A pattern template (name + failure mode + code enforcement) is planned for our public open-source surface alongside the first published artefact.
Why this matters for your build
PickNDeal is one shape of agentic system; your shape will be different. What carries over is the method: the tool-surface design, the invariant library, the audit-trail-first instrumentation, the human-review gates on the fault line. Whether you're building a marketplace, a procurement system, an internal ops tool, or a customer-facing AI feature — the method holds because the failure modes are the same.
Want this applied to your system?
Discovery, build, or transformation engagements. We take on a small number per quarter.