# Architecture Rules - Authentication & Authorization Rules
# Rules for auth patterns and multi-tenancy

auth_rules:

  - id: "AUTH-001"
    name: "Use JWT tokens in Authorization header"
    severity: "error"
    description: |
      Authentication must use JWT tokens in Authorization: Bearer header
    pattern:
      file_pattern: "app/api/**/*.py"
      enforcement: "middleware"

  - id: "AUTH-002"
    name: "Role-based access control with Depends"
    severity: "error"
    description: |
      Use Depends(get_current_admin/vendor/customer) for role checks
    pattern:
      file_pattern: "app/api/v1/**/*.py"
      required: "Depends\\(get_current_"

  - id: "AUTH-003"
    name: "Never store plain passwords"
    severity: "error"
    description: |
      Always hash passwords with bcrypt before storing
    pattern:
      file_pattern: "app/services/auth_service.py"
      required: "bcrypt"

  - id: "AUTH-004"
    name: "Vendor context pattern - use appropriate dependency for endpoint type"
    severity: "error"
    description: |
      Two vendor context patterns exist - use the appropriate one:

      1. SHOP ENDPOINTS (public, no authentication required):
         - Use: vendor: Vendor = Depends(require_vendor_context())
         - Vendor is detected from URL/subdomain/domain
         - File pattern: app/api/v1/storefront/**/*.py
         - Mark as public with: # public

      2. VENDOR API ENDPOINTS (authenticated):
         - Use: current_user.token_vendor_id from JWT token
         - Or use permission dependencies: require_vendor_permission(), require_vendor_owner
         - These dependencies get vendor from token and set request.state.vendor
         - File pattern: app/api/v1/vendor/**/*.py

      DEPRECATED for vendor APIs:
         - require_vendor_context() - only for shop endpoints
         - getattr(request.state, "vendor", None) without permission dependency

      See: docs/backend/vendor-in-token-architecture.md
    pattern:
      file_pattern: "app/api/v1/vendor/**/*.py"
      anti_patterns:
        - "require_vendor_context\\(\\)"
      file_pattern: "app/api/v1/storefront/**/*.py"
      required_patterns:
        - "require_vendor_context\\(\\)|# public"

  - id: "AUTH-005"
    name: "Routes must use UserContext, not User model attributes"
    severity: "error"
    description: |
      When using current_user from dependency injection, it is a UserContext
      (Pydantic schema), NOT a User (SQLAlchemy model). Do not access:

      FORBIDDEN (SQLAlchemy relationships/columns not in UserContext):
        - current_user.admin_platforms    → Use accessible_platform_ids
        - current_user.vendors            → Use token_vendor_id
        - current_user.owned_companies    → Query via service
        - current_user.hashed_password    → Never needed in routes
        - current_user.created_at         → Query User if needed
        - current_user.updated_at         → Query User if needed

      CORRECT ALTERNATIVES:
        - current_user.accessible_platform_ids  # list[int] | None
        - current_user.token_platform_id        # Selected platform from JWT
        - current_user.token_vendor_id          # Vendor from JWT
        - current_user.is_super_admin           # Boolean
        - current_user.can_access_platform(id)  # Helper method

      See: docs/architecture/user-context-pattern.md
    pattern:
      file_pattern: "app/modules/*/routes/**/*.py"
      anti_patterns:
        - "current_user\\.admin_platforms"
        - "current_user\\.vendors"
        - "current_user\\.owned_companies"
        - "current_user\\.hashed_password"

  - id: "AUTH-006"
    name: "JWT token context fields must be defined in UserContext"
    severity: "error"
    description: |
      When adding new context to JWT tokens, ensure the field is:

      1. Added to UserContext schema (models/schema/auth.py)
      2. Extracted in verify_token() (middleware/auth.py)
      3. Attached to User in get_current_user() (middleware/auth.py)
      4. Copied in UserContext.from_user() method

      Pattern: token_* prefix for JWT-derived fields
        - token_platform_id, token_platform_code (admin platform context)
        - token_vendor_id, token_vendor_code, token_vendor_role (vendor context)

      If getattr(current_user, "token_X", None) is needed, the field is missing
      from UserContext and should be added.

      See: docs/architecture/user-context-pattern.md
    pattern:
      file_pattern: "app/modules/*/routes/**/*.py"
      anti_patterns:
        - "getattr\\(current_user,\\s*['\"]token_"

  - id: "AUTH-007"
    name: "Response models must match available UserContext data"
    severity: "error"
    description: |
      When returning user data from endpoints that use UserContext:

      1. Do NOT return LoginResponse(user=current_user) if LoginResponse.user
         expects UserResponse with created_at/updated_at

      2. Create dedicated response models for different contexts:
         - LoginResponse: Full user data (from login, has timestamps)
         - PlatformSelectResponse: Token + platform info (no user data)
         - TokenRefreshResponse: Just new token data

      3. If user timestamps are needed, query the User model explicitly

      See: docs/architecture/user-context-pattern.md
    pattern:
      file_pattern: "app/modules/*/routes/**/*.py"
      enforcement: "review"

# ============================================================================
# MULTI-TENANCY RULES
# ============================================================================

multi_tenancy_rules:

  - id: "MT-001"
    name: "All queries must be scoped to vendor_id"
    severity: "error"
    description: |
      In vendor/shop contexts, all database queries must filter by vendor_id
    pattern:
      file_pattern: "app/services/**/*.py"
      context: "vendor_shop"
      required_pattern: ".filter\\(.*vendor_id.*\\)"

  - id: "MT-002"
    name: "No cross-vendor data access"
    severity: "error"
    description: |
      Queries must never access data from other vendors
    pattern:
      file_pattern: "app/services/**/*.py"
      enforcement: "database_query_level"
