Café Fausse knowledge map

Not the restaurant. MVP = official SRS freeze.

Café Fausse — developer system map

Plain-English map of the restaurant app a software developer needs to orient fast. Inventory tip: App 73d202d (New Bot stack / API / schema / FE/BE cut). Same React → Flask → Postgres design locally and on staging.

Related: Stack · Local vs AWS · Part 4 coding overview · Quantic · Honesty · SRS freeze

Honesty locks: Local (dev) + Docker cafe-pg (postgres:16) · on-box Postgres on MSAIE staging (not a shared RDS; no florist Path B) · routes are app-factory @app.get / @app.post — not Flask Blueprints · no /api/gallery · newsletter store-only unless SES env is set · fail-closed if DB is down · on camera say MSAIE staging · HTTP only (no event bus).


1. Stack, versions, rationale

New Bot inventory at tip 73d202d (pinned range + observed install). Do not treat a hostname as a version probe.

LayerWhatVersion (pinned / observed)Why
FrontendReact + JSXReact/ReactDOM ^18.3.1SPA pages for SRS surface
Routingreact-router-dom^6.28.0Client routes
BuildVite + @vitejs/plugin-reactVite ^5.4.11, plugin ^4.3.4Fast local FE; production build served by Flask/Caddy
BackendFlask + gunicornFlask 3.1.3 (range ≥3<4), gunicorn 23.0.0 (≥22<24)Thin HTTP API + static SPA
DB driverpsycopg2-binary2.9.12 (≥2.9<3)Postgres access
CORSflask-cors5.0.1 (≥4<6)Vite 5173 → Flask when not same-origin; staging same-origin via Caddy
Optional mailboto31.43.89 (≥1.34<2)Present; unused when SES env unset
RuntimePython3.12.14 on staging boxApp runtime
Staging edgeCaddyCaddy:2TLS + reverse proxy
DatabasePostgreSQLpostgres:16On-box data store (Docker locally; on-box on staging)

Rationale (short): one freeze file for official copy; React for the public UX; Flask in the middle; Postgres for bookings/customers with fail-closed writes; staging proves the same design over HTTPS without claiming forever hosting.


2. Frontend / backend segmentation

Browser (React SPA)
  ├── Home / Menu / About / Gallery — import shared/freeze.json (not GET /api/menu)
  ├── Reservations / Newsletter forms → fetch /api/*
  └── /operator → read-only demo snapshot
         │
         ▼
Flask app factory (`create_app` — @app.get / @app.post, not Blueprints)
  ├── /api/* JSON
  ├── /images/<file> allowlisted gallery assets
  └── /unsubscribe HTML
         │
         ▼
PostgreSQL (on-box)
  ├── customers
  └── reservations  UNIQUE(time_slot, table_number)
SideOwnsDoes not own
FrontendRoutes, forms, freeze display, gallery lightbox UIBusiness rules for capacity / DB honesty
BackendSlots, reservations, newsletter store, fail-closed, freeze JSON APIsInventing menu/gallery copy outside freeze; Flask Blueprints
DBCustomers + reservations integrityFrontend state

SPA routes: / · /menu · /reservations · /about · /gallery · /operator Gallery = FE page + static /images/… — not an API resource. /api/gallery does not exist.


3. API endpoints

Registered on the Flask app factory in backend/cafe_fausse/__init__.py (@app.get / @app.post). Not Flask Blueprints (Hiren’s cut uses Blueprints; this repo does not).

MethodPathPurpose
GET/api/healthLiveness; DB ping → {ok:true}
GET/api/menuOfficial menu from freeze (exposed; public pages import freeze)
GET/api/siteSite/awards/reviews/… from freeze (exposed; public pages import freeze)
GET/api/slots?date=YYYY-MM-DDSlots for date (400 without date)
GET/api/availability?time_slot=Remaining tables / fully_booked
POST/api/reservationsCreate booking (GET → 404)
POST/api/newsletterStore signup FR-15 / FR-16 (GET → 404)
GET/POST/api/newsletter/unsubscribeFuture #135 unsubscribe — not a new FR
GET/unsubscribeHTML unsubscribe page
GET/api/operatorDemo snapshot only — not a product FR / not FR-19
GET/images/<file>Basename-allowlisted images
—/api/galleryDoes not exist (404)

4. DB schema (backend/schema.sql)

customers

reservations

No florist Path B tables. Staging DB is on-box Postgres (MSAIE staging) — not a shared RDS.


5. Methods / modules overview (developer map)

Not every helper — the map:

AreaWhere to lookRole
Freeze sourceshared/freeze.jsonMenu, hours, awards, reviews, site copy
FE pagesfrontend/src/pages/Render freeze + forms
HTTP client callsReservations + NewsletterFormfetch to /api/slots then /api/reservations; POST /api/newsletter
Flask app / routesbackend/cafe_fausse/__init__.py app factory (@app.get/@app.post)Wire HTTP → services (not Flask Blueprints)
Slot / booking logicslots.py · reservations.pyRandom table 1–30, uniqueness, full-slot errors
Newsletter storenewsletter.pyValidate/normalize email; store; skip SES if unset
Fail-closeddb.py + test_fail_closed.pyMissing/unreachable DB → honest error, no fake success
Operator snapshot/api/operatorRead-only recording helper
CI freeze locktest_freeze.py (and related)Fail if freeze copy drifts

6. Event / listener map (runtime)

There is no app event bus, WebSocket, or server-sent event stream. Runtime is classic HTTP request/response only.

Actor“Event”What happens
UserClick nav / open pageReact Router renders; static pages import freeze.json
UserPick date on reservationsGET /api/slots?date=
UserCheck / submit bookingGET /api/availability · POST /api/reservations
UserNewsletter submitPOST /api/newsletter → store; email_delivery.status=skipped if SES unset
UserGalleryClient UI + GET /images/… only — no /api/gallery
BrowserPage loadStaging: same-origin behind Caddy. Local (dev): Vite proxies /api and /images to Flask (:5000); CORS also allows 5173

7. Local (dev) + Docker vs MSAIE staging (same design)

Do not name a developer workstation as the product. Local (dev) is Vite + Flask + Postgres on a clone.

Local (dev)Docker (local Postgres)MSAIE staging
URLVite http://127.0.0.1:5173 + Flask :5000cafe-pg on 127.0.0.1:5432https://cafe.artof.link/
FEVite hot reload (proxies /api + /images)—Built SPA
Edge——Caddy:2 TLS
DBApp points at DATABASE_URLdocker run … postgres:16 (cafe-pg) or a local Postgres installOn-box Postgres (MSAIE staging) — not a shared RDS
PurposeIterate without touching the shared demoGive local Flask a real PostgresShared HTTPS proof for graders/team

Same design on both deploy targets: React + JSX → Flask → PostgreSQL. Fail-closed without a database. Newsletter is store-only until SES env is set. On camera: cafe.artof.link = MSAIE staging (temporary — not production forever). Deploy table: Local vs AWS.


8. Gotchas checklist

  1. No /api/gallery — gallery is SPA + /images/….
  2. Newsletter grade floor = store-only until SES env is set (email_delivery.status=skipped when unset). Not a Coverage send claim.
  3. On-box Postgres only on staging — not a shared RDS; no florist Path B.
  4. Fail-closed if DB missing/unreachable (no pretend writes). Full slot (30 tables) → honest error (FR-9).
  5. No event bus — HTTP only.
  6. Routes are @app.get / @app.post on the app factory — not Flask Blueprints.
  7. /api/operator is a demo/recording helper, not FR-19.
  8. On camera: MSAIE staging, not Lightsail jargon.
  9. Local (dev) + Docker — Docker here is postgres:16 as cafe-pg (or a local install). Not the product name.

Sources: New Bot App inventory tip 73d202d; backend/schema.sql; frontend/src/pages/; Flask app factory in backend/cafe_fausse/__init__.py (@app.get/@app.post, not Blueprints); README Docker cafe-pg. Unknown until probed stays labeled if anything drifts after tip. Parts 3–5 materials · Handoff mapping (not spoken on camera).