Files
orion/docs/architecture/diagrams/store-domain-diagrams.md
Samir Boulahtit e9253fbd84 refactor: rename Wizamart to Orion across entire codebase
Replace all ~1,086 occurrences of Wizamart/wizamart/WIZAMART/WizaMart
with Orion/orion/ORION across 184 files. This includes database
identifiers, email addresses, domain references, R2 bucket names,
DNS prefixes, encryption salt, Celery app name, config defaults,
Docker configs, CI configs, documentation, seed data, and templates.

Renames homepage-wizamart.html template to homepage-orion.html.
Fixes duplicate file_pattern key in api.yaml architecture rule.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 16:46:56 +01:00

27 KiB

Store Domains - Architecture Diagram

System Architecture Overview

┌─────────────────────────────────────────────────────────────────┐
│                         CLIENT REQUEST                          │
│                    POST /stores/1/domains                      │
│                   {"domain": "myshop.com"}                      │
└────────────────────────────┬────────────────────────────────────┘
                             │
                             ▼
┌─────────────────────────────────────────────────────────────────┐
│                      ENDPOINT LAYER                             │
│              app/api/v1/admin/store_domains.py                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  @router.post("/{store_id}/domains")                          │
│  def add_store_domain(                                         │
│      store_id: int,                                            │
│      domain_data: StoreDomainCreate,  ◄───┐                   │
│      db: Session,                           │                   │
│      current_admin: User                    │                   │
│  ):                                         │                   │
│      domain = store_domain_service         │                   │
│                .add_domain(...)             │                   │
│      return StoreDomainResponse(...)       │                   │
│                                             │                   │
└─────────────────────┬───────────────────────┼───────────────────┘
                      │                       │
                      │                       │
         ┌────────────▼──────────┐   ┌────────▼─────────┐
         │  Pydantic Validation  │   │  Authentication  │
         │  (Auto by FastAPI)    │   │  Dependency      │
         └────────────┬──────────┘   └──────────────────┘
                      │
                      ▼
┌─────────────────────────────────────────────────────────────────┐
│                      SERVICE LAYER                              │
│           app/services/store_domain_service.py                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  class StoreDomainService:                                     │
│                                                                 │
│      def add_domain(db, store_id, domain_data):                │
│          ┌─────────────────────────────────────┐               │
│          │ 1. Verify store exists             │               │
│          │ 2. Check domain limit               │               │
│          │ 3. Validate domain format           │               │
│          │ 4. Check uniqueness                 │               │
│          │ 5. Handle primary domain logic      │               │
│          │ 6. Create database record           │               │
│          │ 7. Generate verification token      │               │
│          └─────────────────────────────────────┘               │
│                          │                                      │
│                          ▼                                      │
│          ┌─────────────────────────────────────┐               │
│          │   Raises Custom Exceptions          │               │
│          │   - StoreNotFoundException         │               │
│          │   - DomainAlreadyExistsException    │               │
│          │   - MaxDomainsReachedException      │               │
│          └─────────────────────────────────────┘               │
│                                                                 │
└─────────────────────┬───────────────────────────────────────────┘
                      │
                      ▼
┌─────────────────────────────────────────────────────────────────┐
│                     DATABASE LAYER                              │
│            models/database/store_domain.py                     │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  class StoreDomain(Base):                                      │
│      id: int                                                    │
│      store_id: int (FK)                                        │
│      domain: str (unique)                                       │
│      is_primary: bool                                           │
│      is_active: bool                                            │
│      is_verified: bool                                          │
│      verification_token: str                                    │
│      ssl_status: str                                            │
│      ...                                                        │
│                                                                 │
└─────────────────────┬───────────────────────────────────────────┘
                      │
                      ▼
┌─────────────────────────────────────────────────────────────────┐
│                         DATABASE                                │
│                   PostgreSQL / MySQL                            │
└─────────────────────────────────────────────────────────────────┘

Request Flow Diagram

┌──────────┐
│  Client  │
└────┬─────┘
     │ POST /stores/1/domains
     │ {"domain": "myshop.com", "is_primary": true}
     │
     ▼
┌────────────────────────────────────────────┐
│  FastAPI Router                            │
│  ┌──────────────────────────────────────┐ │
│  │ 1. URL Routing                       │ │
│  │ 2. Pydantic Validation               │ │
│  │ 3. Dependency Injection              │ │
│  │    - get_db()                        │ │
│  │    - get_current_admin_api()         │ │
│  └──────────────────────────────────────┘ │
└────────────────┬───────────────────────────┘
                 │
                 ▼
┌────────────────────────────────────────────┐
│  Endpoint Function                         │
│  add_store_domain()                       │
│                                            │
│  ✓ Receives validated data                │
│  ✓ Has DB session                         │
│  ✓ Has authenticated admin user           │
│  ✓ Calls service layer                    │
│  ✓ Returns response model                 │
└────────────────┬───────────────────────────┘
                 │
                 ▼
┌────────────────────────────────────────────┐
│  Service Layer                             │
│  store_domain_service.add_domain()        │
│                                            │
│  Business Logic:                           │
│  ┌──────────────────────────────────────┐ │
│  │ Store Validation                    │ │
│  │   ├─ Check store exists             │ │
│  │   └─ Get store object               │ │
│  │                                      │ │
│  │ Limit Checking                       │ │
│  │   ├─ Count existing domains          │ │
│  │   └─ Enforce max limit               │ │
│  │                                      │ │
│  │ Domain Validation                    │ │
│  │   ├─ Normalize format                │ │
│  │   ├─ Check reserved subdomains       │ │
│  │   └─ Validate regex pattern          │ │
│  │                                      │ │
│  │ Uniqueness Check                     │ │
│  │   └─ Query existing domains          │ │
│  │                                      │ │
│  │ Primary Domain Logic                 │ │
│  │   └─ Unset other primary domains     │ │
│  │                                      │ │
│  │ Create Record                        │ │
│  │   ├─ Generate verification token     │ │
│  │   ├─ Set initial status              │ │
│  │   └─ Create StoreDomain object      │ │
│  │                                      │ │
│  │ Database Transaction                 │ │
│  │   ├─ db.add()                        │ │
│  │   ├─ db.commit()                     │ │
│  │   └─ db.refresh()                    │ │
│  └──────────────────────────────────────┘ │
└────────────────┬───────────────────────────┘
                 │
                 ▼
┌────────────────────────────────────────────┐
│  Database                                  │
│  INSERT INTO store_domains ...            │
└────────────────┬───────────────────────────┘
                 │
                 ▼
┌────────────────────────────────────────────┐
│  Return to Endpoint                        │
│  ← StoreDomain object                     │
└────────────────┬───────────────────────────┘
                 │
                 ▼
┌────────────────────────────────────────────┐
│  Endpoint Response                         │
│  StoreDomainResponse(                     │
│      id=1,                                 │
│      domain="myshop.com",                  │
│      is_verified=False,                    │
│      verification_token="abc123...",       │
│      ...                                   │
│  )                                         │
└────────────────┬───────────────────────────┘
                 │
                 ▼
┌────────────────────────────────────────────┐
│  FastAPI Serialization                     │
│  Convert to JSON                           │
└────────────────┬───────────────────────────┘
                 │
                 ▼
┌────────────────────────────────────────────┐
│  HTTP Response (201 Created)               │
│  {                                         │
│    "id": 1,                                │
│    "domain": "myshop.com",                 │
│    "is_verified": false,                   │
│    "verification_token": "abc123...",      │
│    ...                                     │
│  }                                         │
└────────────────┬───────────────────────────┘
                 │
                 ▼
            ┌──────────┐
            │  Client  │
            └──────────┘

Error Handling Flow

┌──────────┐
│  Client  │
└────┬─────┘
     │ POST /stores/1/domains
     │ {"domain": "existing.com"}
     │
     ▼
┌────────────────────────────────────────────┐
│  Service Layer                             │
│                                            │
│  def add_domain(...):                      │
│      if self._domain_exists(db, domain):   │
│          raise StoreDomainAlready         │
│                ExistsException(            │
│              domain="existing.com",        │
│              existing_store_id=2          │
│          )                                 │
└────────────────┬───────────────────────────┘
                 │
                 │ Exception raised
                 │
                 ▼
┌────────────────────────────────────────────┐
│  Exception Handler                         │
│  app/exceptions/handler.py                 │
│                                            │
│  @app.exception_handler(OrionException) │
│  async def custom_exception_handler(...):  │
│      return JSONResponse(                  │
│          status_code=exc.status_code,      │
│          content=exc.to_dict()             │
│      )                                     │
└────────────────┬───────────────────────────┘
                 │
                 ▼
┌────────────────────────────────────────────┐
│  HTTP Response (409 Conflict)              │
│  {                                         │
│    "error_code": "STORE_DOMAIN_           │
│                   ALREADY_EXISTS",         │
│    "message": "Domain 'existing.com'       │
│                is already registered",     │
│    "status_code": 409,                     │
│    "details": {                            │
│      "domain": "existing.com",             │
│      "existing_store_id": 2               │
│    }                                       │
│  }                                         │
└────────────────┬───────────────────────────┘
                 │
                 ▼
            ┌──────────┐
            │  Client  │
            └──────────┘

Component Interaction Diagram

┌─────────────────┐
│   Endpoints     │ ◄─── HTTP Requests from client
│   (HTTP Layer)  │ ───► HTTP Responses to client
└────────┬────────┘
         │ Calls
         │
         ▼
┌─────────────────┐
│   Service       │ ◄─── Business logic
│   Layer         │ ───► Returns domain objects
└────────┬────────┘      or raises exceptions
         │ Uses
         │
         ├──────────────────┐
         │                  │
         ▼                  ▼
┌─────────────────┐  ┌─────────────────┐
│   Database      │  │   Exceptions    │
│   Models        │  │   (Custom)      │
└─────────────────┘  └─────────────────┘
         │                  │
         │                  │
         ▼                  ▼
┌─────────────────┐  ┌─────────────────┐
│   SQLAlchemy    │  │   Exception     │
│   ORM           │  │   Handler       │
└─────────────────┘  └─────────────────┘
         │                  │
         │                  │
         ▼                  ▼
┌─────────────────┐  ┌─────────────────┐
│   Database      │  │   JSON Error    │
│   (PostgreSQL)  │  │   Response      │
└─────────────────┘  └─────────────────┘

Data Flow for Domain Verification

Step 1: Add Domain
┌──────────┐
│  Admin   │ POST /stores/1/domains
└────┬─────┘ {"domain": "myshop.com"}
     │
     ▼
┌────────────────────────────────────┐
│  System creates domain record      │
│  - domain: "myshop.com"            │
│  - is_verified: false              │
│  - verification_token: "abc123..." │
└────────────────────────────────────┘

Step 2: Get Instructions
┌──────────┐
│  Admin   │ GET /domains/1/verification-instructions
└────┬─────┘
     │
     ▼
┌────────────────────────────────────┐
│  System returns instructions:      │
│  "Add TXT record:                  │
│   _orion-verify.myshop.com      │
│   Value: abc123..."                │
└────────────────────────────────────┘

Step 3: Store Adds DNS Record
┌──────────┐
│  Store  │ Adds TXT record at DNS provider
└────┬─────┘
     │
     ▼
┌────────────────────────────────────┐
│  DNS Provider (GoDaddy/etc)        │
│  _orion-verify.myshop.com TXT   │
│  "abc123..."                       │
└────────────────────────────────────┘

Step 4: Verify Domain
┌──────────┐
│  Admin   │ POST /domains/1/verify
└────┬─────┘
     │
     ▼
┌────────────────────────────────────┐
│  System:                           │
│  1. Queries DNS for TXT record     │
│  2. Checks token matches           │
│  3. Updates domain:                │
│     - is_verified: true            │
│     - verified_at: now()           │
└────────────────────────────────────┘

Step 5: Activate Domain
┌──────────┐
│  Admin   │ PUT /domains/1 {"is_active": true}
└────┬─────┘
     │
     ▼
┌────────────────────────────────────┐
│  System activates domain:          │
│  - is_active: true                 │
│  - Domain now routes to store     │
└────────────────────────────────────┘

Result: Domain Active!
┌──────────────┐
│  Customer    │ Visits https://myshop.com
└──────┬───────┘
       │
       ▼
┌────────────────────────────────────┐
│  Middleware detects custom domain  │
│  Routes to Store 1                │
└────────────────────────────────────┘

File Structure Visual

project/
│
├── app/
│   ├── api/
│   │   └── v1/
│   │       └── admin/
│   │           ├── stores.py              ✓ Existing (reference)
│   │           └── store_domains.py       ★ NEW (endpoints)
│   │
│   ├── services/
│   │   ├── store_service.py              ✓ Existing (reference)
│   │   └── store_domain_service.py       ★ NEW (business logic)
│   │
│   └── exceptions/
│       ├── __init__.py                    ✓ UPDATE (add exports)
│       ├── base.py                        ✓ Existing
│       ├── auth.py                        ✓ Existing
│       ├── admin.py                       ✓ Existing
│       └── store_domain.py               ★ NEW (custom exceptions)
│
└── models/
    ├── schema/
    │   ├── store.py                      ✓ Existing
    │   └── store_domain.py               ★ NEW (pydantic schemas)
    │
    └── database/
        ├── store.py                      ✓ UPDATE (add domains relationship)
        └── store_domain.py               ✓ Existing (database model)

Legend:
★ NEW      - Files to create
✓ Existing - Files already exist
✓ UPDATE   - Files to modify

Separation of Concerns Visual

┌─────────────────────────────────────────────────────────────┐
│                    ENDPOINT LAYER                           │
│  - HTTP request/response                                    │
│  - FastAPI decorators                                       │
│  - Dependency injection                                     │
│  - Response models                                          │
│  - Documentation                                            │
│                                                             │
│  ✓ No business logic                                        │
│  ✓ No database operations                                   │
│  ✓ No validation (handled by Pydantic)                     │
└──────────────────────┬──────────────────────────────────────┘
                       │
                       │ Calls
                       │
┌──────────────────────▼──────────────────────────────────────┐
│                    SERVICE LAYER                            │
│  - Business logic                                           │
│  - Database operations                                      │
│  - Transaction management                                   │
│  - Error handling                                           │
│  - Validation logic                                         │
│  - Logging                                                  │
│                                                             │
│  ✓ Reusable methods                                         │
│  ✓ Unit testable                                            │
│  ✓ No HTTP concerns                                         │
└──────────────────────┬──────────────────────────────────────┘
                       │
                       │ Uses
                       │
┌──────────────────────▼──────────────────────────────────────┐
│                   DATABASE LAYER                            │
│  - SQLAlchemy models                                        │
│  - Table definitions                                        │
│  - Relationships                                            │
│  - Database constraints                                     │
│                                                             │
│  ✓ Pure data models                                         │
│  ✓ No business logic                                        │
└─────────────────────────────────────────────────────────────┘

This architecture ensures:

  • Clean separation of concerns
  • Easy to test each layer
  • Reusable business logic
  • Maintainable codebase
  • Follows SOLID principles