Skip to content

17 — Production Readiness & Launch Checklist

Status: 🟡 Live checklist. The frontend-phase items are done and ticked here with the evidence; everything else is gated on the backend phase (16) or on decisions only the business can make. Re-read this before any deploy that a real restaurant will touch.

🟢 বাংলা ভূমিকা: প্রোডাকশনে যাওয়ার আগে কী কী লাগবে — কোনটা এখন শেষ, কোনটা ব্যাকএন্ড আসার পরে, আর কোনটা ব্যবসার সিদ্ধান্ত। প্রতিটা ✅-এর পাশে প্রমাণ দেওয়া আছে, যাতে "হয়ে গেছে" কথাটা যাচাই করা যায়।


1. Two different launches

Confusing these is the main way a date slips.

LaunchWhat it needsStatus
A — The marketing site (restaurant-os.com, the landing page, pricing, about, contact, legal, docs)Real legal text, a contact address that is monitored, DNS, analyticsBuildable today; only §5 items block it
B — A real restaurant taking real ordersEverything in A, plus the whole backend phase: database, auth, live orders, payments, backupsBlocked on 16

Nothing in the product should be sold as B until B's checklist passes. A demo tenant on the live domain is fine; a restaurant whose evening depends on it is not — today's "persistence" is one browser's localStorage (CLAUDE.md rule 1).

🟢 বাংলা সারাংশ: দুটো আলাদা লঞ্চ — (ক) মার্কেটিং সাইট, যেটা আজই দেওয়া যায় (শুধু আইনি টেক্সট, ডোমেইন, অ্যানালিটিক্স বাকি), আর (খ) আসল রেস্টুরেন্ট আসল অর্ডার নেবে — সেটার জন্য পুরো ব্যাকএন্ড দরকার। আজকের "ডেটা" শুধু একটা ব্রাউজারের localStorage-এ থাকে, তাই (খ)-এর প্রতিশ্রুতি এখন দেওয়া যাবে না।


2. Done — with evidence

AreaItemEvidence
SecurityHSTS, nosniff, Referrer-Policy, X-Frame-Options, Permissions-Policy, no X-Powered-Bynext.config.ts; curl -I on a built server shows all six
SecurityStaff surfaces noindex + disallowed in robots.txtsrc/app/robots.ts, docs/02 §page metadata
SEOSitemap covering the marketing site and every active restaurant's menu, table picker and live campaigns, under the restaurant's own domainsrc/app/sitemap.ts
SEORestaurant + full Menu structured data on every menu; Offer on every campaign; Organization + WebSite on the landing pagesrc/lib/structured-data.ts, 8 unit tests
SEOCanonical URL per public page (a restaurant's own domain wins), hreflang between en and bn on the landing pagecurl shows <link rel="canonical"> / alternate
SharingGenerated share cards for the menu, each campaign and the landing page — restaurant's name, tagline and accent, Bengali glyphs includedopengraph-image.tsx ×3, src/lib/og.ts; cards render at 1200×630
A11ySkip-to-content link on every surface, <main> landmark on eachsrc/components/shared/skip-to-content.tsx; MAIN_CONTENT_ID on 11 surfaces
A11yReduced-motion respected; focus-visible rings; aria-labels and placeholders translatedglobals.css, docs/11
UXLoading skeletons on all eight guest/staff/owner routes that fetchloading.tsx ×8
UXKitchen can 86 a dish and the next scan does not show it; guests rate a meal and the owner reads it; A5 bilingual table tent carddocs/06 §2.1, docs/05 §7, docs/04 §5
UXDish names in Bengali as well as English; tips at checkout, itemised and carried onto the receiptdocs/04 §3.2, docs/05 §5
UXOffline notice + service worker; printable receipts; empty states on every boardsw.js, print-receipt.ts, EmptyState
i18n1815 keys at parity, no hardcoded guest- or dashboard-facing textparity check + string scan (5 known exceptions: CNAME, a T-13 placeholder, the deliberately bilingual global-error, two platform-admin lines)
Quality361 unit tests, 226 E2E journeys, full CI gate on every push.github/workflows/ci.yml

🟢 বাংলা সারাংশ: এই টেবিলটাই "কী কী শেষ" তার প্রমাণসহ তালিকা — সিকিউরিটি হেডার, staff পেজ noindex, sitemap, schema.org স্ট্রাকচার্ড ডেটা, প্রতিটা পাবলিক পেজের canonical ও hreflang, শেয়ার কার্ড (বাংলা অক্ষরসহ), skip-to-content ও <main> ল্যান্ডমার্ক, আটটা রুটে লোডিং স্কেলিটন, অফলাইন নোটিস, ১৫৩৪ কী-তে দুই ভাষার সমতা, ৩৩৭ ইউনিট ও ২০৭ E2E টেস্ট।


3. Blocked on the backend phase

Not gaps in the design — they cannot exist without a server. Each links to where it is planned.

  • Real auth. SessionGuard is a client-side prop and is deleted in phase 2 (16 §2).
  • Data that survives a device. Every owner edit is localStorage today (16 §3.1).
  • Content-Security-Policy with a nonce — needs the proxy to generate one per request (12 §6).
  • Rate limiting on order submit and PIN sign-in (12 §3).
  • Payments, SMS, invoices (08).
  • Backups and point-in-time recovery (14 §1).
  • Custom domains issuing real certificates (13 §8).

🟢 বাংলা সারাংশ: এগুলো ডিজাইনের ঘাটতি না — সার্ভার ছাড়া সম্ভবই না: আসল লগইন, ডিভাইস বদলালেও টিকে থাকা ডেটা, nonce-সহ CSP, রেট লিমিট, পেমেন্ট ও SMS, ব্যাকআপ, আর কাস্টম ডোমেইনে আসল সার্টিফিকেট।


4. Before the first deploy — operational

#ItemWhy it is not optional
1Error tracking (Sentry or equivalent), server + browserToday a guest hitting an error sees a friendly screen and nobody is told. A restaurant cannot report what it did not see
2Uptime check on the marketing page and one tenant menu, alerting a phoneA menu that is down during dinner service is the whole product being down
3Analytics (Vercel Analytics or Plausible — cookie-free keeps §6 simple)Otherwise there is no way to tell whether scans convert to orders
4Log drain + CRON_SECRET-protected jobsCron routes are public URLs; unprotected they are a free way to run your jobs
5A staging environment that mirrors productionMigrations must fail somewhere that is not dinner service
6Deploy protection on production (required checks, no direct pushes to main)CI already runs the full gate; nothing should bypass it
7A rollback you have actually practisedVercel instant rollback covers code; a database migration needs its own down path

🟢 বাংলা সারাংশ: প্রথম ডিপ্লয়ের আগে অপারেশনাল কাজ: এরর ট্র্যাকিং (নইলে ভুল হলে কেউ জানবেই না), আপটাইম মনিটর (ডিনারের সময় মেনু বন্ধ মানে পুরো প্রোডাক্ট বন্ধ), অ্যানালিটিক্স, cron সুরক্ষা, স্টেজিং এনভায়রনমেন্ট, main-এ সরাসরি push বন্ধ, আর অন্তত একবার অনুশীলন করা rollback।


5. Before the first deploy — content and legal

#ItemWhere
1Replace the template legal text. The pages say on their face that they are templates/legal/{privacy,terms,cookies}
2A privacy policy that matches reality: guest phone numbers, how long they are kept, who processes paymentsdecided in 16 §4
3Monitored addresses behind sales@ / support@ / privacy@src/config/site.ts
4Real social handles, or remove them from the footersrc/config/site.ts → social
5A cookie banner only if you add tracking cookies. Cookie-free analytics avoids it; the cookies page must then say so honestly§4 item 3
6Pricing that matches what you will charge, including VAT treatment in BangladeshsubscriptionPlans

🟢 বাংলা সারাংশ: কনটেন্ট ও আইনি কাজ: টেমপ্লেট আইনি টেক্সট বদলানো (পেজেই লেখা আছে যে এগুলো টেমপ্লেট), বাস্তবের সাথে মিলিয়ে প্রাইভেসি পলিসি, ইমেইল ঠিকানাগুলো সত্যিই মনিটর করা, ফুটারের সোশ্যাল লিংক আসল করা বা বাদ দেওয়া, ট্র্যাকিং কুকি থাকলে তবেই কুকি ব্যানার, আর VAT-সহ আসল দাম।


6. Design QA — run before each release

Ten minutes, and it catches most of what users report. Run at 375 px and at desktop, in both themes and both languages.

  1. Every screen at 375 px — no horizontal scroll. (document.documentElement.scrollWidth <= innerWidth in the console.)
  2. Bengali at every breakpoint — Bengali runs longer than English; buttons and tabs are where it breaks first.
  3. Dark and light on the guest menu, dashboard and promo page — including images and badges over photos.
  4. Keyboard only through the order flow: Tab from the top, skip link, menu, cart, place order.
  5. Tab titles and share cards on the pages you changed.
  6. Slow 3G + offline on the guest menu: skeletons appear, the offline notice appears, nothing white-screens.
  7. A long restaurant name and a long dish name — the two strings that break layouts.
  8. Print the receipt from the orders board.

🟢 বাংলা সারাংশ: প্রতিটা রিলিজের আগে দশ মিনিটের ডিজাইন যাচাই: ৩৭৫ পিক্সেলে কোনো পেজ আড়াআড়ি স্ক্রল করে কিনা, বাংলায় লেখা লম্বা হয়ে বাটন ভাঙে কিনা, ডার্ক ও লাইট দুটোতেই ঠিক দেখায় কিনা, শুধু কি-বোর্ড দিয়ে অর্ডার করা যায় কিনা, ট্যাব টাইটেল ও শেয়ার কার্ড ঠিক আছে কিনা, ধীর নেটে ও অফলাইনে কী হয়, লম্বা নামে লেআউট ভাঙে কিনা, আর রসিদ প্রিন্ট হয় কিনা।


7. Performance targets

Measured on a mid-range Android on 4G, because that is what a guest at a table is holding — not a laptop on office wifi.

MetricTargetWhy this number
LCP on /table< 2.5 sThe menu is the product; a guest has already waited for the scan
INP< 200 msTapping a dish must feel instant on a phone
CLS< 0.1A shifting menu makes people tap the wrong dish
JS on /table< 200 KB gzipped — not met: 340 KB (see below)Every extra KB is a second on a crowded restaurant's wifi

Where /table's 340 KB goes (gzipped, the scripts a modern browser downloads for the first paint — noModule polyfills excluded, measured against next start): about 150 KB is React 19 and the Next.js runtime, which no page of this app can go below; 44 KB is framer-motion; the rest is the menu itself. Getting under 200 KB would mean taking framer-motion off the guest surface, which is a design decision rather than a tidy-up. The target stays as a direction, not a gate.

What was fixed on the way (360 → 340 KB): the table page imported MenuExperience through the folder's index.ts, and a server page importing a barrel of client components makes every export a client reference — so sheets that load on demand were shipped up front anyway. Pages now import components directly. The guest's cart and menu also stopped reading mock-data in the browser (every seeded restaurant's staff, orders and promos); the page resolves this restaurant's slice on the server (lib/guest-context.ts). Item detail, allergy filter, reservations, package detail, split bill, spin wheel and the photo lightbox load when first opened and are prefetched when the page is idle.

To measure again: build, next start, then sum the gzipped size of every /_next/static/chunks/*.js the page's HTML references, skipping nomodule tags.

mermaid (~1 MB) is loaded only by /docs, never by a guest or dashboard page — keep it that way when adding libraries: check which route the bundle lands in.

🟢 বাংলা সারাংশ: পারফরম্যান্স মাপতে হবে মাঝারি অ্যান্ড্রয়েড ফোনে 4G-তে — কারণ টেবিলে বসা অতিথির হাতে সেটাই থাকে, ল্যাপটপ না। লক্ষ্য: /table-এ LCP ২.৫ সেকেন্ডের কম, INP ২০০ মিলিসেকেন্ডের কম, CLS ০.১-এর কম, আর JS ২০০ KB-এর কম। mermaid শুধু /docs-এ লোড হয় — নতুন লাইব্রেরি যোগ করার সময় দেখে নিতে হবে সেটা কোন রুটের বান্ডলে যাচ্ছে।