🍦 Tuutti docs

Arkkitehtuuri

Tuutti on single-binary monoliitti — yksi Deno-prosessi tarjoilee sekä API:n että staattisen SPA-frontin. Tähän lisäksi yksi worker- prosessi taustatöille (SMS, kuitit, tilitykset, kuvien mirroroinnit).

Komponentit

MitäTekniikkaSijainti repossa
API + SSR-fallbackDeno + Honoserver/
Asiakas + admin PWAReact 18 + Vite 6 + Tailwind v3web/
TietokantaPlanetScale Postgresdatabase/migrations/
Reaktiivinen syncPostgres LISTEN/NOTIFY → in-proc pub/sub → SSEserver/lib/events.ts
TaustatyötGraphile Workerserver/jobs.ts, server/worker.ts
TiedostotTigris (S3-yhteensopiva)server/lib/tigris.ts
Kuva-optimointiimgproxy → Tigris (variantit)server/lib/imgproxy.ts
MaksutStripe Connect (direct charges)server/lib/stripe.ts
SMSGatewayAPIserver/lib/sms.ts
SähköpostiSES via SMTPserver/lib/mailer.ts
TekoälykuvatAnthropic Claude (vision)server/lib/vision.ts
i18nLingui v6web/src/locales/

Datavirta tilauksessa

Asiakas selaa <slug>.tuutti.io
   ↓ GET /api/menu (palvelin)
   ↓ asiakas valitsee tuotteet, lisää koriin
   ↓ POST /api/orders (palvelin)
   ↓ palvelin avaa Stripe PaymentIntent
   ↓ asiakas maksaa kortilla / Apple Pay / Google Pay
   ↓ Stripe lähettää webhookin → POST /api/stripe/webhook
   ↓ tilauksen tila päivittyy queued / pre_queue → SSE
   ↓ henkilökunta näkee tilauksen jonosivulla (reaaliajassa)
   ↓ henkilökunta klikkaa "Aloita" → "Valmis"
   ↓ Tuutti lähettää asiakkaalle ilmoituksen
   ↓ asiakas hakee tilauksen tiskiltä
   ↓ henkilökunta klikkaa "Noudettu"

Multi-tenant rakenne

Yksi Postgres-tietokanta hallitsee kaikkia kioskeja:

  • stores — yksi rivi per kioski (slug, nimi, brändi, asetukset)
  • companies — yksi rivi per Y-tunnus (sama yritys voi pyörittää useaa kioskia)
  • products, categories, modifier_groups, modifier_options — kaikki per-store
  • orders, order_items, order_item_modifiers, order_item_companions — per-store
  • staff_memberships — kytkee käyttäjän kioskiin (admin / staff)

Multi-tenancy ratkaistu slug-pohjaisella reititykellä: asiakassovellus toimii osoitteessa <slug>.tuutti.io, hallinta osoitteessa app.tuutti.io/admin/<polku>?store=<slug>.

Hosting

MitäMissä
API + WorkerFly.io (kaksi appia: tuutti + tuutti-worker)
TietokantaPlanetScale (Postgres) — Eurooppa-alueella
Tiedostot + KuvatTigris (Fly:n hallinnoima S3)
imgproxysama Fly.io-koneella sivutyö
SMSGatewayAPI (Tanska)
SähköpostiAWS SES (Frankfurt)
LLMAnthropic API (Yhdysvallat)
MaksutStripe (Euroopan toiminta-alue)

Konfiguraatio (env-vars) hallitaan Dopplerilla ja synkronoidaan Fly:hyn deployissa. Lokaalin kehityksen .env.local on dev-konfiguraation kopio.

Deploy

GitHub Actions pyörittää release-prosessin:

  1. Push merkityllä tagilla (v0.1.X) tai erillinen GH Release
  2. Workflow rakentaa kaksi Docker-imagea (tuutti + tuutti-worker)
  3. Migraatiot ajetaan yhden kertaa containerissa
  4. tuutti deployataan bluegreen-strategialla (no-downtime)
  5. tuutti-worker rolling-deployataan
  6. Healthcheck /health vahvistaa onnistumisen

Kokonaisaika gh release create v0.1.X -komennosta tuotantoon on noin 3–4 minuuttia.

Reaktiivinen sync (kuinka tilaus näkyy tiskillä reaaliajassa)

Tuutti käyttää PostgreSQL:n natiivin LISTEN/NOTIFY-mekanismia kahden prosessin välisenä viestintävälineenä. Asiakassovellus avaa EventSource-yhteyden palvelimelle:

GET /api/events?store=kulmakioski

Palvelin pitää yhden LISTENing-yhteyden Postgresiin per prosessi. Kun joku osa järjestelmästä haluaa lähettää tapahtuman (“queue_changed”, “menu_changed”), se kutsuu NOTIFY tuutti_events, {...} — Postgres broadcastaa tämän kaikille listenenders. Palvelin välittää tapahtuman SSE-streamiin oikealle storen tilaajille.

Tämä on redisettön ja cross-instance turvallinen — useita Fly:n koneita voi pyöriä samanaikaisesti ja Postgresin LISTEN levittää viestit oikein kaikille.