Svelte Commerce
SvelteKit으로 만든 독립형 오픈소스 스토어프론트, 26개 상거래 백엔드와 헤드리스 연동, MIT 라이선스
온라인 주문을 받아 집주방·도시락·노점 주문 페이지, WhatsApp·UPI 결제, 직접·Zomato 배달, 무료 시작
Get online orders for your home kitchen, tiffin service or stall. Your own ordering page, WhatsApp orders, UPI payments, and delivery by you or by Zomato riders. Free to start.
커머스TypeScript · CSSGitHub @Code2Conquer온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Restaurant Vertical AI
README 전체를 불러오는 중입니다.
README 전문 보기 ↗An AI operations team for restaurants that sell on Zomato, Swiggy and dine-in. A web app plus a conversational copilot that can act on the owner's behalf, with every change held for the owner's approval. Product plan: PLAN.md.
npm install
cp .env.example .env.local # optional: add ANTHROPIC_API_KEY for the full copilot
npm run dev # http://localhost:3000
The first request creates .data/zest.db and seeds a sample restaurant (Rasoi 27). "Look around with sample data" opens it; "Get started" creates your own restaurant in the same database.
For a production build: npm run build && npm start. Production needs ZEST_SECRET_KEY, and keeps the sample restaurant read-only unless ZEST_DEMO_WRITABLE=1.
To try a real MCP connection locally:
node scripts/mock-partner-mcp.mjs # a stand-in partner MCP server on :8787
Then in Connections pick a platform → "MCP server" → http://localhost:8787/mcp. Approving a menu change calls its tools; http://localhost:8787/log shows what it received.
The pages and the API are one Next.js app, so one Vercel project serves both. The database lives on Turso (hosted SQLite).
Database. In Turso, create a database (pick the Mumbai region). Copy its URL (libsql://…) and create a token.
Project. In Vercel, import this GitHub repository. Framework is detected as Next.js; leave the build settings as they are.
Environment variables (Project → Settings → Environment Variables, then redeploy):
| Name | Value |
|---|---|
DATABASE_URL | the Turso URL |
DATABASE_AUTH_TOKEN | the Turso token |
ZEST_SECRET_KEY | output of node -e "console.log(require('crypto').randomBytes(32).toString('base64'))". Keep it safe: changing it makes stored platform credentials unreadable. |
ANTHROPIC_API_KEY | optional, for the full copilot and document reading |
ZEST_DEMO_WRITABLE | optional, 1 to let visitors change the sample restaurant |
Open the deployment URL. The first request creates the tables and the sample restaurant.
Without DATABASE_URL the app still starts on Vercel, but on a temporary database that resets whenever the server restarts.
Other hosts. Dockerfile builds a self-contained server (data on /data), and render.yaml is a Render blueprint with a persistent disk.
Browser (Next.js pages) ──► /api/* route handlers ──► lib/server/*
├─ db.ts, schema.ts libSQL/SQLite via Drizzle
├─ copilot.ts Claude tool runner + keyword fallback
├─ approvals.ts draft → approve → execute → audit
├─ connectors.ts sandbox | MCP | partner API | partner-app sign-in
├─ ingest.ts payout emails (rules, Claude fallback)
├─ vision.ts documents and menu photos (Claude vision)
├─ whatsapp.ts Meta Cloud API, outbox
└─ crypto.ts, session.ts encrypted credentials, signed cookie
Nothing reaches a platform without the owner. Agents and the menu editor create approvals. Approving one runs it through each live platform's connector and records every step (and any failure, per platform) in the audit log. Menu changes can be undone; posted replies and disputes can't.
Connectors. Every platform implements one interface (setAvailability, setPrice, updateItem, replyToReview, raiseDispute, createPromo, listOrders):
| Method | Status |
|---|---|
| MCP server | Works. Verified on connect by listing tools; actions call the server's tools. |
| Partner API | Adapter in place; paths are placeholders until partner API access and specs are available. Saved keys show as "pending" until *_PARTNER_API_URL is set. |
| Partner-app sign-in | Credentials are stored encrypted. The browser worker that signs in and acts on the partner portal is the next build step; until then actions report that clearly. |
| Sandbox | Used by the sample restaurant. Mirrors actions locally. |
Copilot. With ANTHROPIC_API_KEY, the copilot runs Claude (claude-opus-5-5, server-side refusal fallback on) with nine tools: five that read the database (sales, orders, payouts, reviews, menu) and four that draft approvals (menu change, review reply, dispute, promo). Without a key it answers from the same data with keyword rules. Conversations are stored per restaurant.
Zomato and Swiggy listings. When an owner pastes their Zomato link (full or zoma.to share link) or Swiggy link, Zest reads it (Zomato: the public page and order page; Swiggy: the menu API its mobile site uses), fills in their profile, saves the rating and details, and brings in the menu with photos. The first read of a platform imports the menu if there is none, or sets that platform's prices and stock on dishes with the same name, adds the rest for that platform only, and marks dishes the listing doesn't have as off on that platform. Reading again (Connections) refreshes rating and details but never the menu. Results are cached for 10 minutes per link. Zomato blocks data-centre IPs, Vercel's included, so production needs LISTING_FETCH_VIA, a scraping relay URL template (see .env.example); without it the owner fills the form in by hand.
Dining. Tables grouped by area, each free, seated, bill printed or reserved, with party, time at the table and the running bill. Staff seat walk-ins, bookings or waitlisted guests, add dishes from the master menu at the dine-in price (the lowest platform price), print, and settle by cash, UPI or card; settling records a dine-in order so it counts in Today's sales. Bookings and the waitlist live alongside, with a WhatsApp "table ready" message to the guest. Each restaurant gets a public QR menu page. New restaurants get a starter floor plan to edit; the demo floor is rebuilt each day.
Growth. Promos and ads per platform with a hard spend cap (MAX_PROMO_SPEND). The builder estimates extra orders, spend, sales and return from the outlet's last 14 days of orders (or stated typical numbers when there is no history) and sends the plan for approval; approving it starts it through the platform connector and tracks it as a campaign. Suggestions come from the slowest open hours, a well-rated dish that sells little, new customers and upcoming festivals. The daily cron (and "Check now") ends campaigns at their cap or end date and pauses any returning less than its floor (3×) after ₹500, with a WhatsApp note. Campaign results need the platform's attribution data, so real outlets show spend and results once connectors report them; pausing on the platform side also waits on connector support.
Gmail. Owners connect Gmail with read-only access. Zest searches only Zomato and Swiggy senders (GMAIL_SENDERS), reads the last 30 days on first connect, then new mail on each sync. Each mail is sorted into payout, report, complaint, onboarding or other; payouts are extracted from the body (rules) or, with Claude, from PDF and CSV attachments. Tokens are stored encrypted. Disconnecting revokes access and deletes everything read, including payouts. While the Google app is in Testing mode, owners must be listed as test users and reconnect every 7 days.
Data in. Payout emails also go through POST /api/ingest/email (paste on the Money page, or a mail-forwarding rule). Orders arrive by POST /api/sync (pull from MCP/API connectors; run it on a schedule) or signed webhooks at /api/webhooks/{platform}.
| Endpoint | Does |
|---|---|
GET/POST/PATCH /api/outlet | Current restaurant; POST creates your restaurant and owner profile (name, area, city, optional FSSAI/GSTIN and listing links), PATCH updates details |
POST/DELETE /api/outlet/demo | Switch to the sample restaurant / reset it |
GET/POST/DELETE /api/connections | Platform connections |
GET /api/today | Dashboard summary |
GET /api/menu, POST /api/menu/changes, POST /api/menu/import | Menu, edits as an approval, add dishes |
GET /api/orders, POST /api/sync, POST /api/webhooks/[platform] | Orders in |
GET /api/payouts, POST /api/ingest/email | Payouts and email ingestion |
GET/DELETE /api/mail, POST /api/mail/sync | Connected inbox status, disconnect, sync now |
POST /api/listing/preview, POST /api/listing/{zomato|swiggy} | Read a listing link (preview only / save to the restaurant: rating, address, hours, FSSAI, cost for two, and the menu with photos and per-platform prices) |
GET /api/dining; POST /api/dining/tables, DELETE /api/dining/tables/{id} | Floor, open bills, today's bookings and waitlist, today's dine-in numbers; edit the floor plan |
POST /api/dining/tabs, PATCH /api/dining/tabs/{id} | Seat a party; change dishes, print, reopen, settle (cash/UPI/card, records a dine-in order) or clear |
POST /api/dining/reservations, PATCH /api/dining/reservations/{id} | Add a booking or waitlist entry; tell a guest their table is ready on WhatsApp, cancel, no-show |
GET /api/dining/qr, page /m/{outletId} | Table QR code and the public dine-in menu it opens |
GET /api/growth; POST /api/growth/estimate, /propose, /check; PATCH /api/growth/campaigns/{id} |
lib/server/jobs.ts): queued rows, claimed with an expiring lock, retried after 1, 5, 25 and 60 minutes, and marked failed after 5 attempts. /api/jobs/run queues an order sync per connected outlet every 5 minutes and runs due jobs; call it every minute from a free scheduler such as cron-job.org with Authorization: Bearer $CRON_SECRET. .github/workflows/sync.yml calls it every 15 minutes as a backup, and Vercel Cron calls /api/cron daily to queue inbox syncs and campaign checks. Failed jobs: SELECT kind, attempts, last_error FROM jobs WHERE status = 'failed'.components/dishes.tsx) until the owner uploads photos in the menu editor.motion and respects reduced-motion settings.| Campaigns and suggestions; estimate a plan from the outlet's orders; send it for approval; run the automatic pause; pause, resume or end |
GET /api/mail/insights | Payouts per platform, commission/ads/deduction shares, complaints and listing mails from the last 30 days |
GET /api/mail/google/start, /callback | Google sign-in for Gmail |
GET /api/cron | Scheduled sync of every inbox and platform (needs CRON_SECRET) |
GET /api/reviews, POST /api/reviews/[id]/reply | Reviews and reply drafts |
GET/POST /api/approvals, POST /api/approvals/[id] | Drafts; {action: approve | skip | undo} |
POST /api/onboarding/document, /menu, /submit | Read documents and menu photos, listing application |
GET/POST/DELETE /api/copilot | Conversation |
GET /api/notifications, POST /api/notifications/daily-summary | WhatsApp outbox, morning summary |
GET /api/audit | Activity log |