How RestaPro works under the hood
For technical restaurant owners, partners, or anyone who wants to understand the architecture without reading code.
Stack in one image
Internet (HTTPS)
v
Traefik (TLS, rate limit 100 req/s + burst)
v
nginx (gzip, immutable cache, security headers)
v
React 19 + TypeScript (static build)
v
Supabase (PostgreSQL + Edge Functions + Auth + Storage)
Static frontend served by nginx, no traditional application server. Anything that isn't UI runs in Edge Functions Deno or in PostgreSQL via RLS.
Frontend
- React 19 + TypeScript + Vite.
- Static build compiled to HTML+JS+CSS with hashed names (cached forever).
- Tailwind CSS 4 with
oklch()tokens. - shadcn/ui + base-nova as the component system.
- Served by nginx on
:8090. - TanStack React Query for server state.
- React Hook Form + Zod for forms.
Backend: Supabase
- Managed PostgreSQL in Frankfurt (EU). GDPR-compliant by design.
- Edge Functions Deno: ~60 serverless functions running on demand.
- Auth: JWT with refresh tokens, email+password + Google OAuth.
- Storage: for logos, covers, menu images.
- Realtime: instant notifications via WebSocket.
- pg_cron: scheduled tasks (email cron, proposal expiration, etc.).
Multi-tenant security: Row Level Security (RLS)
Every table with customer data has RLS policies that filter rows by logged-in user at the PostgreSQL layer:
USING (workspace_id IN (
SELECT workspace_id FROM workspace_users
WHERE user_id = auth.uid()
))
Even if someone hijacked a session, the database rejects cross-workspace queries. It's security at the DBMS level, not the application level.
Encryption
- In transit: HTTPS/TLS 1.3 with Let's Encrypt certificates automated by Traefik.
- At rest: PostgreSQL encrypts the volume.
- Passwords: bcrypt (not reversible).
- Secrets (Stripe API key, Gemini key, Resend, etc.): in Supabase Vault, not in
.envor in the repository.
AI: Gemini + Pinche
- Google's Gemini 2.5 Flash with function calling.
- Pinche: 25 tools (10 write + 15 read).
- Each call is logged in
pinche_chat_logsfor audit. - Google's Vertex AI policy: data is not used to train models.
Notifications
Realtime (instant)
When an online reservation comes in, every team device receives a real-time toast via Supabase Realtime (WebSocket over PostgreSQL CDC).
Transactional email (Resend)
- Sending of confirmations, reminders, alerts, campaigns.
- Idempotency in webhooks (
resend_processed_events): if Resend re-sends due to timeout, it's processed only once. - Email logs auditable: each send with timestamp, status, tokens.
List-Unsubscribeheaders RFC 5322 so Gmail offers one-click unsubscribe.
Payments: Stripe
- Subscriptions managed by Stripe Billing.
- Checkout Session + Customer Portal for payments and self-service.
- Webhooks with idempotency check (
stripe_processed_events). - RestaPro does not store cards - only Stripe Customer ID and Subscription ID.
Hosting
- Supabase: AWS Frankfurt (EU). Replication + daily backups with 30-day retention.
- CDN: Cloudflare for static assets.
- Edge Functions: server latency close to the user.
GDPR
- Data in Frankfurt, no transfers outside the EU without safeguards.
- Right to be forgotten via the
gdpr_delete_customerRPC: anonymizes name, email, phone incustomers,customer_identities,email_logs,email_queue,marketing_*. Keeps reservations for audit/accounting. - Full audit in
activity_logs. - More in Privacy and GDPR.
Backup and recovery
- Daily Supabase backups automatic (30-day retention).
- Geographic replication.
- In case of accidental deletion: contact Supabase support to restore from a specific backup (RTO ~4 h).
Monitoring
- Sentry: frontend error capture with
userId+restaurant_idas tags. Anti-bot filters. - Structured logs in edge functions via
createLoggerwith metadata. - Activity log in DB for sensitive actions (role changes, GDPR delete, etc.).
CI/CD
- GitHub Actions runs lint + typecheck + tests + build on every push.
- HTTP smoke tests post-deploy: if they fail, we abort.
- Snapshots of the last 10 builds in
/opt/backups/restapro-dist/for fast rollback.
Continuous deployment
- Every commit on
maincan reach production after manual review. - Build ID = git SHA, visible in
<meta name="restapro:build-id">. - No semantic versioning - changes flow continuously.
More in Versioning and releases.