Initial kitchen scaffold — Phase 1 kitchen port (build-verified 2026-07-11)

FastAPI backend (Python 3.11, MSSQL ODBC for SambaPOS, Azure DI OCR),
kitchen_db on central PG. React/TS/Vite frontend with navy sidebar layout.

Backend: auth.py (APP_SLUG=kitchen, SimpleNamespace — archive routes use
.kitchen_id/.is_admin without modification), main.py (51 migrations, scheduler,
internal router for KDS bookings feed), api/internal.py, full archive API
(31 routers: invoices, recipes, menus, sambapos, resos, newbook, disputes,
purchase_orders, etc.), models, migrations, OCR pipeline.
kitchen_id pinned to 1 (B1 — single hotel).

Frontend: AuthGate (app=kitchen, token shim for archive compat — B5b pending),
Layout (navy sidebar, 6 sections, Lucide icons, teal --app-primary),
App.tsx (Outlet pattern, UploadApp outside Layout), index.css (full :root block).
strict: false — archive components have type issues; build clean.

Note: 45 archive components call fetch('/api/...') without /kitchen/ prefix
(B5b). Runtime 404s; deferred until after initial testing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-12 12:15:39 +00:00
commit 8d688b459d
10003 changed files with 1928395 additions and 0 deletions

File diff suppressed because one or more lines are too long

445
frontend/dist/assets/index-DiXG3yPo.js vendored Normal file

File diff suppressed because one or more lines are too long

BIN
frontend/dist/icons/icon-192.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
frontend/dist/icons/icon-512.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

13
frontend/dist/index.html vendored Normal file
View file

@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Kitchen</title>
<script type="module" crossorigin src="/kitchen/assets/index-DiXG3yPo.js"></script>
<link rel="stylesheet" crossorigin href="/kitchen/assets/index-Cs9AL0NS.css">
</head>
<body>
<div id="root"></div>
</body>
</html>

24
frontend/dist/kds-manifest.json vendored Normal file
View file

@ -0,0 +1,24 @@
{
"name": "Kitchen Display System",
"short_name": "KDS",
"description": "Kitchen Display System for Kitchen Invoice Flash",
"start_url": "/kds-app",
"display": "standalone",
"background_color": "#1a1a2e",
"theme_color": "#1a1a2e",
"orientation": "landscape",
"icons": [
{
"src": "/icons/icon-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/icons/icon-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
]
}

24
frontend/dist/manifest.json vendored Normal file
View file

@ -0,0 +1,24 @@
{
"name": "Kitchen Invoice Upload",
"short_name": "Invoice Upload",
"description": "Quick invoice photo upload for Kitchen Invoice Flash",
"start_url": "/upload-app",
"display": "standalone",
"background_color": "#1a1a2e",
"theme_color": "#1a1a2e",
"orientation": "portrait",
"icons": [
{
"src": "/icons/icon-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/icons/icon-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
]
}

28
frontend/dist/pdf.worker.min.mjs vendored Normal file

File diff suppressed because one or more lines are too long

61
frontend/dist/sw.js vendored Normal file
View file

@ -0,0 +1,61 @@
const CACHE_NAME = 'kitchen-app-v3'
const SHELL_URLS = [
'/manifest.json',
'/kds-manifest.json',
]
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => cache.addAll(SHELL_URLS))
)
self.skipWaiting()
})
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((keys) =>
Promise.all(keys.filter((k) => k !== CACHE_NAME).map((k) => caches.delete(k)))
)
)
self.clients.claim()
})
self.addEventListener('fetch', (event) => {
const url = new URL(event.request.url)
// Never cache API/auth calls
if (url.pathname.startsWith('/api/') || url.pathname.startsWith('/auth/')) {
return
}
// Navigation requests (HTML pages): always network-first
if (event.request.mode === 'navigate') {
event.respondWith(
fetch(event.request)
.then((response) => {
const clone = response.clone()
caches.open(CACHE_NAME).then((cache) => cache.put(event.request, clone))
return response
})
.catch(() => caches.match(event.request).then((c) => c || caches.match('/')))
)
return
}
// Static assets (JS/CSS with content hashes): cache-first
event.respondWith(
caches.match(event.request).then((cached) => {
return cached || fetch(event.request).then((response) => {
if (event.request.method === 'GET' && response.status === 200) {
const clone = response.clone()
caches.open(CACHE_NAME).then((cache) => cache.put(event.request, clone))
}
return response
})
}).catch(() => {
if (event.request.mode === 'navigate') {
return caches.match('/')
}
})
)
})