Skip to content

🏗️ Technical Architecture Overview

The CPL Group Real Rewards Loyalty system is built upon Odoo 17.0 Community Edition running containerized microservices on Ubuntu Linux (GCP VM odoo-production-vm).


1. Modular Architecture

All custom loyalty logic, ingestion pipelines, and security mechanisms are isolated in modular addons located in odoo/addons/:

odoo/addons/
├── cpl_real_rewards_ui/       # UI Overrides, Staff Dashboards, Card Wizards, /docs Auth Controller
├── real_rewards_loyalty/      # Demographics Validations, Points Moderation, Ledger Engine
├── real_rewards_importer/     # POS CSV Batch Ingestion & Order Deduplication
├── real_rewards_security/     # Microsoft Entra ID (Azure AD) SSO, Passwordless OTP Login, Session Security
└── real_rewards_api_mailer/   # Transactional Email Server Dispatcher

2. Data Model Hierarchy & Anchoring

To avoid split accounts and broken loyalty histories across physical card replacements, the data model anchors member profiles to an immutable UUID:

erDiagram
    RES_PARTNER ||--o{ REAL_REWARDS_LOYALTY_LEDGER : "has points entries"
    RES_PARTNER ||--o{ REAL_REWARDS_CARD_REPLACEMENT_LOG : "has card changes"
    RES_PARTNER ||--o{ POS_ORDER : "participates in"

    RES_PARTNER {
        uuid rrp_member_uuid PK "Permanent Immutable Anchor"
        string rrp_card_number "Active Card Number (Index)"
        string name "Full Name"
        date birth_date "Validated DOB (1900 to Today)"
        string phone "Normalized Mobile"
        integer loyalty_points "Calculated Whole Points"
    }

    REAL_REWARDS_LOYALTY_LEDGER {
        id id PK
        many2one partner_id FK
        integer points_delta "Truncated Whole Points"
        string source_type "pos_sale | manual_adjustment | redemption"
        datetime timestamp
    }

    REAL_REWARDS_CARD_REPLACEMENT_LOG {
        id id PK
        many2one partner_id FK
        string old_card_number
        string new_card_number
        string replacement_reason
        datetime timestamp
    }

3. Strict Point Truncation Rule

In compliance with the project constitution.md: * Point accruals are integer truncated (no floating point or rounding up). * A POS spend of K45.95 generates strictly 45 points. * Decimal precision errors are eliminated at the database level by storing whole integer values in real.rewards.loyalty.ledger.