Customer pasted their essay into the order note field — KDS tablet stalled (PR #657 IX F3)
Lukas (35) runs Kava Klampar specialty coffee + light-meals cafe in Bratislava Old Town. Friday 19:30 dinner rush KDS tablet froze. Order #2918 took 12 seconds to load, scroll lag. Chef Marko: "this order has a HUGE note section." Order details normal: 1 Klampar sandwich + 1 espresso 8 EUR. But "note" field was around 50 KB of academic-article text + e-mails + code snippets. thMenu support 2 wrong theories busted (tablet defect: spare same perf; wrong-field paste theory confirmed via customer chat). Customer Tomas (27 doctoral student Comenius University): "Apologies! I was editing my PhD chapter in Apple Notes, did Command-A Command-C, came to the QR menu, meant to type no extra ice but reflexive Command-V since clipboard not reset pasted the whole 50KB chapter." Order POST body 50KB. Forensic: apps/web-menu/src/app/api/orders/route.ts trims body.note but NO LENGTH CAP, no charset filter, no content validation. D1 orders.note TEXT column happily stored 50KB. Downstream impact: KDS query returned 50KB row, React rendered single huge paragraph, DOM reflow strained low-end Android tablet GPU (12s load + scroll lag). Admin order detail page scrolled for 30 seconds. Surprise finding: sibling endpoints (admin order POST 500-char cap, kiosk order POST PR #585 XX F1 200-char cap) ALREADY had caps. Customer-side web-menu order POST was the one cap-less endpoint — classic sibling-endpoint hardening parity gap. **PR #657 batch IX F3** fix: 5-line validation — typeof check + trim + 500-char truncation (vs reject — truncate keeps well-intended notes intact; accidental paste loses the overflow). Plus item.note 200-char cap. Server-side validation + client-side UI char counter X/500. Three weeks later three other thMenu operators (different cities) had similar accidental paste incidents — but 500-char cap made KDS render smoothly, operators didn t even notice. Pattern: every client-supplied string field (order.note, item.note, table.label, customer.preferences, search queries, profile bios, suggestion messages) must carry explicit server-side length cap + typeof check. "Trim and store" is not validation. Client-side bounds aren t substitutes. Audit checklist: typeof === string, trim, length cap (100-1000 typical), charset allowlist, truncate-vs-reject per-context.