Architecture: Domain Model — mcd-tracker

arch-domain-mcd-tracker Architecture

architecture active

Architecture: Domain Model — mcd-tracker

Purpose

What are the things? Entities, their attributes, and how they relate. This diagram drives the SQLAlchemy models and Alembic migrations.

Diagram

Key Design Decisions

  • No local User table. Identity comes from Keycloak JWT (sub claim). keycloak_sub is stored as a string FK-like reference on all entities.
  • Two codes, not one. The survey code is on the receipt (input to mcdvoice.com). The BOGO code is the output of the survey (the valuable one you redeem). Receipt holds the survey code, CouponUsage holds the BOGO code.
  • Receipt is a first-class entity. It's proof of purchase — the photo, the survey code, and whether the survey was completed. A Receipt produces a CouponUsage (one-to-one, nullable — you might scan a receipt but not finish the survey).
  • Location has required lat/lng. GPS auto-detection is a core feature. When the user scans a receipt, the app uses GPS to find the nearest McDonald's and auto-fills the location. source tracks whether the location was auto-detected or manually entered.
  • Photo storage. Receipt photos stored on a PVC (same pattern as basketball-api uploads). Path stored in DB. Future: migrate to MinIO for S3-compatible storage.
  • expires_at is computed. earned_at + 30 days. Stored for query efficiency, derived from earned_at.
  • Redeemed is separate from earned. You earn a BOGO code when you complete the survey. You redeem it when you use it at the counter. The 30-day timer starts at redemption (redeemed_at), and the slot reopens 30 days later.

Rolling Window Logic

The core business rule: 5 codes per location per user per rolling 30-day window.
  • project-mcd-tracker — project page
  • arch-dataflow-mcd-tracker — runtime flows
  • arch-deployment-mcd-tracker — infrastructure