Ribbit.DealsSystem Architecture — Team Document v1.3 · OCT 2026

Ribbit.Deals — System Architecture

One screen, whole system · Companions: Functional Spec · Admin & Operations Manual · Data Layer · App UI · ✅ Accounts checklist

Architecture philosophy: proven, widely-deployed technology, professionally operated, sized for the real market (Utah local commerce) with a pre-planned path to 100× scale. No speculative complexity: every component below exists because a requirement demands it — and every one has millions of production deployments, deep documentation, and a large hiring pool behind it.

How to read this page: the diagram shows the launch architecture, with each component marked by where it stands today. Components already running carry a solid border; components still to come carry a dashed border. The section after the diagram describes the three environments that exist right now and how code moves into them.

LIVE running today NEXT in the current build queue PRE-LAUNCH in place before public launch

Client Layer

Member App (PWA) LIVEInstallable on iPhone and Android · animated splash · self-updates after every deploy · Web Push to follow
Business Tools LIVEResponsive web · deal creation, pause, 48-hour void · deal photo manager
Admin Dashboard LIVEIn the production build · KPIs · businesses and deal coaching · members and merges · fees · categories · agreements · statements
↓ HTTPS only (TLS, HSTS)

Edge Layer — Cloudflare

CDN Cache PRE-LAUNCHStatic assets served from 300+ global points
WAF + DDoS Shield PRE-LAUNCHAttack traffic stopped before it reaches the server
Rate Limiting PRE-LAUNCHBrute-force and abuse throttled at the edge (sign-in is already rate-limited in the app)
↓

Application Layer — Laravel 13 (PHP 8.3) on a dedicated IONOS VPS (Ubuntu 24.04, Plesk)

Auth & Access LIVEbcrypt · rate-limited · member / business owner · admin access as a dated, audited grant
Media Library LIVEPrivate per-business deal photos · stored outside the web root · served only through a gatekeeper route
Audit Logging LIVEEvery admin action and fee change · who, what, when · append-only
Fee Settings LIVEAdmin-editable rates · snapshotted at agreement and at verification
Redemption Engine NEXTGPS check + placard QR scan + caps in one DB transaction · running in the prototype, moving to Laravel
Billing Engine LIVEEnrollment · category fees with overrides · monthly statements and optional nightly charges · nothing billed twice
REST API PRE-LAUNCHToken auth (Sanctum) for the member app once its screens move to Laravel
Scheduler LIVEMonthly statements on the 3rd · nightly charges when daily billing is on · queues to follow
↓ local connection only — no public database access

Data Layer

MariaDB 10.11 LIVEMySQL-compatible · schema v1.1 (16 tables) plus 8 added since · money as integer cents · append-only ledgers
Private Media Storage LIVEServer disk outside the web root · uniform 3:1 deal photos (1800 × 600)
Redis + Object Storage PRE-LAUNCHCache, sessions and queue backbone (database-backed today) · S3-compatible offsite backups
↓ outbound integrations — compliance lives with the specialists

Integration Layer

Transactional Email LIVEPlesk smarthost relay through IONOS SMTP · no-reply@genxapp.org · password resets
Stripe LIVE · TEST MODESecure checkout and saved cards · all card data stays with Stripe · SAQ-A scope for us
Web Push (VAPID) PRE-LAUNCHDeal notifications · no vendor lock
Twilio PRE-LAUNCHSMS opt-in alerts · TCPA consent records kept (opt-in timestamp already stored)
↓ watching everything

Operations Layer

Git Deploys LIVEEvery Laravel change committed, pushed, and deployed automatically · versioned migrations
Staged Environments LIVEDesign reference → prototype → production build · nothing reaches members untested
Encrypted Backups PRE-LAUNCHDated backups before every deploy today · nightly + hourly offsite, restore-tested, before launch
Monitoring PRE-LAUNCH60-second uptime checks · Sentry error tracking · instant alerts

Where it runs today

Three environments, each with one job. All application traffic runs on a dedicated IONOS virtual server (6 vCore, 8 GB RAM, 240 GB NVMe, Ubuntu 24.04, managed through Plesk). Both apps on that server read and write the same database, so a deal created in one appears immediately in the other.

Production build

beta.genxapp.org
  • Laravel 13 on PHP 8.3, the path to launch.
  • The admin dashboard, business enrollment with Stripe checkout and versioned agreements, the business tools, and billing (statements and charges).
  • Private deal-photo library and photo manager.
  • Deployed from Git.

Prototype

ribbit.genxapp.org
  • Plain PHP, the founders' clickable playground for UX decisions.
  • The member app only (browsing, redemption, rewards), until it moves to the production build in M4. The original admin and business tools now redirect to the production build.
  • Retires screen by screen as each one is rebuilt in Laravel.
  • Deployed by file upload.

Design reference

ribbit.pixrite.com
  • Approved hi-fi mockups, the living functional spec, and this page.
  • Its original prototype now redirects to ribbit.genxapp.org; that database is kept as a frozen backup.

The permanent home is app.ribbit.deals. Moving to it is a DNS and certificate change, not a code change. The genxapp.org domains are interim.

How a change reaches the production build

BuildChanges are prepared and checked as complete files.
CommitEach change is recorded in the Git history with a message, so every version can be traced and restored.
PushThe commit is pushed to the server's repository.
Auto-deployThe server installs dependencies, applies database migrations, and refreshes its caches, with no manual steps.

Database changes for the production build are written as Laravel migrations, so the schema's history lives with the code and can be rolled back. Changes that the prototype needs ahead of Laravel are applied as reviewed SQL scripts. A dated backup is taken before every deploy.

The database

Staging runs MariaDB 10.11, a drop-in, MySQL-compatible database shipped with the server's operating system. The schema, queries, and transaction behavior the architecture depends on (row locks for redemption caps, integer-cents money, append-only ledgers) are identical. Managed hosting on the scale path offers MariaDB and MySQL alike, so this choice does not affect any later step.

The original 16-table schema (v1.1) has grown by eight tables as features shipped:

AddedPurpose
categoriesAdmin-editable deal categories with optional sub-categories
platform_settings · platform_settings_auditFee rates, the Home feature slot, and drawing settings, with a full change history
platform_admins · admin_auditAdmin access as a dated grant, and a log of every admin action
password_reset_tokensSelf-service password reset
offer_viewsDeal view counts for the business funnel, recorded without location
mediaThe private deal-photo library (linked from each offer)

Columns were also added for member suspension (with a recorded reason). Laravel adds its own framework tables for sessions, cache, queued jobs, and migration history.

Deal photos

Deal photos are stored on the server outside the public web folder, in a library separated by business. No photo has a public address: the app requests it by an unguessable ID through a gatekeeper route, which checks access before sending it. Every photo is framed to one standard shape (3:1, 1800 × 600) so the deal card always fits on screen; the shape is defined in a single setting in each app.

Email

The hosting provider blocks direct outgoing mail from the server (a common anti-spam measure). App email is therefore relayed through the provider's authenticated mail service as no-reply@genxapp.org, which also gives it better deliverability. A dedicated transactional-email service remains an option when statements and receipts raise the volume.

Why this stack (the one-liner per choice)

ChoiceWhy it survives scrutiny
Laravel 13 / PHP 8.3The most widely deployed web framework family on earth; batteries included (auth, queues, scheduler, migrations, Stripe library); enormous hiring pool — no key-person risk. Modern PHP 8 benchmarks within range of Node/Python for this workload.
MariaDB (MySQL-compatible)Boring in the best way: the MySQL family has 25+ years in production everywhere. Our schema is already deployed and running on it — transactions, row-locks for redemption caps, and a straight upgrade path to a managed database.
Git + automatic deploysEvery change is recorded, reviewable, and reversible; deploys are identical every time because no step is done by hand.
RedisIndustry-standard cache/queue; keeps the RIBBIT moment fast and notification work off the request path. Until volume calls for it, the database carries this role with no code change needed to switch.
Cloudflare edgeDDoS, WAF, rate limiting, and global caching before traffic touches our server — enterprise-grade shielding at startup cost.
Stripe / TwilioCard data and carrier compliance are the two scariest liabilities — we place them with the two companies best at exactly those, keeping us in the lightest PCI scope (SAQ-A: card data never touches our servers).
Dedicated VPS now, managed path laterRight-sized for launch; the path up (below) is planned, tested, and boring — no re-architecture required at any step.

Capacity & the scaling path

Honest capacity math: Utah's whole population is ~3.5M. A successful first year — tens of thousands of members, hundreds of businesses — generates request volumes a single well-tuned 4-vCPU server handles with a large margin; the current server has 6 (redemptions are short transactions; discovery is cache-friendly; static assets will not touch the server at all once the CDN is in front). We are deliberately not building Facebook's infrastructure to serve Saratoga Springs — but the road up is mapped:

StageTriggerMoveDowntime
1. Launch—Hardened VPS: app + MariaDB + Redis, Cloudflare in front, on the permanent domain—
2. VerticalSustained CPU/RAM pressureResize the VPS (minutes, reversible)~ minutes, off-peak
3. Split dataDB contentionMove the database to a managed service (AWS RDS / DO Managed, MariaDB or MySQL) — automated backups, failoverNear-zero (replica promote)
4. HorizontalApp saturation2+ app servers behind a load balancer; sessions in Redis so this is config, not codeZero
5. Beyond UtahMulti-state expansionRead replicas per region · queue workers scaled independently · same codebaseZero

The architecture above requires zero rewrites at any stage — each step is an operational move, not an engineering project. That is the point of choosing boring, horizontally-friendly components on day one.

Security posture (the checklist reviewers ask for)

Advisor Q&A — answers in plain English

“Why are there two apps right now?”

The prototype lets the founders click through and decide on UX quickly, against real data, while the production build is engineered properly underneath. Both share one database, so nothing is entered twice. Each screen is rebuilt in Laravel once its design is settled, and the prototype retires piece by piece; members will only ever use the production build.

“Why not build on AWS with microservices?”

We use cloud infrastructure where it earns its keep (edge shielding, managed services on the scale path, S3 backups) and skip complexity that only pays at 100× our realistic load. Microservices solve organizational scaling problems for 200-engineer teams; for a focused product they add failure modes and cost. Our monolith is modular internally and splits cleanly later if ever needed.

“What is it actually written in?”

Two languages, the standard split: JavaScript in the client — the PWA's service worker, geolocation, camera scanning, push notifications, and all interactivity — and PHP (Laravel framework) on the server — the API, auth, redemption engine, and billing. Structured data lives in MariaDB (SQL). Nothing exotic: this is the same division of labor running most of the transactional web.

“Is PHP… serious?”

PHP 8 with Laravel runs a massive share of the transactional web. It is fast, typed, actively developed, and has one of the deepest talent pools in software — which is a continuity guarantee for a small company. The framework ships production-grade auth, queues, and billing integration we would otherwise build by hand.

“Why MariaDB instead of MySQL?”

It is the MySQL-compatible database that ships with the server's operating system, maintained by MySQL's original creators. Our schema and code run on either without changes, and every managed-database provider on the scale path supports both.

“What happens if you get popular fast?”

Cloudflare absorbs the traffic spike at the edge; the five-stage scaling path (above) is pre-planned and rewrite-free. Stage 2 is a resize measured in minutes. We would be delighted to have this problem and we know exactly which knob to turn first.

“What about a data breach?”

We minimize what there is to steal: no card numbers (Stripe holds those), location only at redemption moments, four fields of personal data, and deal photos that are never publicly addressable. Defense in depth — edge WAF, hardened server, least-privilege access, encrypted backups — plus an incident plan. The cheapest breach is the data you never collected.

“Who maintains this if your developer is unavailable?”

Everything is mainstream: any Laravel shop in Utah can pick up this codebase. The full change history is in Git, documentation lives with the code (this page, the functional spec, the data layer doc), the schema uses framework conventions, and there is no exotic infrastructure requiring specialist knowledge.

“Single server — isn't that a single point of failure?”

At launch scale, yes, mitigated by monitoring (60-second checks), hourly offsite backups, and a documented restore that has actually been rehearsed — worst case is measured in minutes-to-hours of recovery, appropriate for this stage. Stage 3–4 of the scaling path adds managed-database failover and multi-server redundancy when the business justifies it.

“How do you prevent fake redemptions?”

Two independent factors — the member's verified location (redemption is refused without it) and a scan of the business's own counter placard — validated server-side, plus a live anti-screenshot verification screen and the business's 48-hour void window. Fraud requires being physically present at the counter with staff watching, and the business still holds the undo button.

“Why no POS integration?”

See the decision record in the functional spec (§6): integration multiplies development, certification, maintenance, and support cost across every POS platform forever, delays launch past the season, excludes cash-only merchants — and buys little, because the placard handshake plus the void window already verifies real visits. It remains a data-driven Phase 2 option if merchants ask.

Bottom line for reviewers: boring technology, professionally operated — HTTPS everywhere, PCI scope minimized, every change versioned and deployed automatically, sized honestly for its market with a rewrite-free path to 100×. The items marked pre-launch are standard, scheduled hardening steps, and every component has a decade+ of production history and a deep bench of people who can run it.

Revision history

VersionDateChanges
v1.3Oct 7, 2026The original business tools are retired (they redirect to the production build’s business tools, which now include “Forgot password?”). The prototype now holds only the member app.
v1.2Oct 7, 2026The admin dashboard, enrollment, business tools and billing now run in the production build; the original admin redirects there. Billing engine, Stripe (test mode) and the scheduler marked live. The redemption engine remains in the prototype until the member app moves (M4).
v1.1Oct 2026Matched the document to the running system. Added status markers (live, next, pre-launch) to every component. Added “Where it runs today”: the three environments, the Git deploy pipeline, the database and its eight added tables, the private deal-photo library, and the email relay. Updated Laravel 11 → 13 and MySQL 8 → MariaDB 10.11 (MySQL-compatible). Added admin access grants, audit logging, fee settings, and member suspension to the application and security sections. Added Q&A on the two-app approach and the database choice.
v1.0Aug 2026Initial architecture: layers, stack rationale, scaling path, security posture, advisor Q&A.