# Multitenancy Model

## Purpose
Explain how tenant, site, and sector isolation is enforced across models, middleware, and viewsets, based on the current implementation.

## Code Locations (exact paths)
- Tenant base models: `backend/igny8_core/auth/models.py` (`AccountBaseModel`, `SiteSectorBaseModel`)
- Core entities: `backend/igny8_core/auth/models.py` (`Account`, `Plan`, `Site`, `Sector`, `Industry`, `IndustrySector`, `SeedKeyword`, `SiteUserAccess`, `User`)
- Middleware for context: `backend/igny8_core/auth/middleware.py`
- DRF base viewsets: `backend/igny8_core/api/base.py`
- Auth utilities and JWT: `backend/igny8_core/api/authentication.py`, `backend/igny8_core/auth/utils.py`
- URL routing (module mounting): `backend/igny8_core/urls.py`

## High-Level Responsibilities
- Enforce per-account isolation for all models carrying an `account` FK.
- Enforce per-site and per-sector scoping for content models via `SiteSectorBaseModel`.
- Inject tenant context on every request (session or JWT/API key), then apply scoping in base viewsets.
- Allow controlled overrides for admins, developers, and system accounts.

## Detailed Behavior
- `AccountBaseModel` adds an `account` FK plus timestamps and indexes; all tenant-scoped models inherit this to guarantee account linkage.
- `SiteSectorBaseModel` extends `AccountBaseModel` with `site` and `sector` FKs, indexes on `(account, site, sector)`, and a save hook that sets `account` from `site` and validates that `sector` belongs to the same `site`; raises validation errors on mismatch.
- `AccountContextMiddleware` sets `request.account` by refreshing the authenticated session user (with account and plan) or by decoding JWT tokens; it rejects requests when account is missing or plan is inactive, returning structured JSON and logging out session users. It skips admin and auth endpoints to avoid interference.
- JWT authentication (`api/authentication.py`) decodes tokens and sets `request.account` from the token payload; API key authentication sets both `request.account` and `request.site` for WordPress bridge calls.
- `AccountModelViewSet` auto-filters querysets by `account` when models expose that field. It bypasses filtering for admins/developers/system-account users; otherwise, it uses `request.account` or falls back to the authenticated user’s account. Creates set `account` on save when present.
- `SiteSectorModelViewSet` extends the above to filter by site/sector if those fields exist, using request query parameters and tenancy context.
- `User` role helpers (`is_admin_or_developer`, `is_system_account_user`) and account checks gate override behavior.
- `SiteUserAccess` provides explicit per-site access for non-admin roles; `User.get_accessible_sites` respects system account, developer, owner/admin, and granted access rules.

## Data Structures / Models Involved (no code)
- `Account`: tenant container with plan, credits, billing fields, status, and retention settings.
- `Plan`: defines limits (max users/sites/industries/author profiles), credit inclusion, Stripe IDs.
- `Site`: belongs to an account, optionally an industry; includes status, hosting type, legacy WP fields, and SEO metadata.
- `Sector`: belongs to a site and industry sector template; enforces account alignment and plan-based max-sector validation.
- `Industry`, `IndustrySector`, `SeedKeyword`: global reference data not bound to a single account.
- `SiteUserAccess`: explicit many-to-many grants between users and sites.
- `User`: links to account with role-based access flags.

## Execution Flow
- Request enters middleware; `AccountContextMiddleware` determines `request.account` (session or JWT/API key), validating plan status.
- Viewsets inheriting from `AccountModelViewSet`/`SiteSectorModelViewSet` filter querysets by `account` (and site/sector when present) before pagination/serialization.
- Object creation sets `account` automatically when the serializer’s model has that field; site/sector-based models validate alignment on save.
- Admin/developer/system-account users skip account filtering; other users remain constrained.

## Cross-Module Interactions
- All module viewsets depend on the base viewsets for scoping.
- Automation, planner, writer, billing, linker, optimizer, publisher, and integration models inherit from the tenancy bases to enforce account/site/sector ownership.
- API key flows for WordPress set `request.site`, enabling integration-specific logic to run in a site-aware context.

## State Transitions (if applicable)
- Account status changes (active, suspended, trial, cancelled) and plan activation directly affect access through middleware plan validation.
- Sector creation enforces plan-based limits for active sectors per site.

## Error Handling
- Middleware returns JSON errors for missing account or inactive plan, with HTTP 403 or 402 semantics and logs out session users.
- Base viewsets wrap CRUD operations in unified responses; validation failures or missing objects are returned in structured error payloads.
- Save-time validation on `SiteSectorBaseModel` and `Sector` raises validation errors when site/sector alignment or plan limits are violated.

## Tenancy Rules
- Every tenant-scoped model carries `account`; site/sector-aware models carry `site` and `sector` and must align to the same account.
- Middleware populates `request.account`; base viewsets enforce filtering unless the user is an admin/developer/system-account member.
- System accounts (`aws-admin`, `default-account`, `default`) and privileged roles can bypass scoping; protected from deletion via guard clauses.

## Billing Rules (if applicable)
- Middleware requires an active plan before allowing requests (except auth/admin paths). Credits, charges, and plan enforcement are handled in billing modules (documented elsewhere).

## Background Tasks / Schedulers (if applicable)
- Celery tasks inherit tenant context via payloads supplied by calling viewsets/services; the tenancy bases ensure stored records retain `account`/`site`/`sector`.

## Key Design Considerations
- Tenancy is enforced as early as middleware to avoid leakage in view logic.
- Base viewsets centralize scoping and unified responses to reduce duplication across modules.
- Role-based overrides exist for ops and system accounts; safeguards prevent system account deletion.

## How Developers Should Work With This Module
- Inherit from `AccountBaseModel` or `SiteSectorBaseModel` for any new tenant/site/sector data models.
- Inherit viewsets from `AccountModelViewSet` or `SiteSectorModelViewSet` to get automatic scoping and unified responses.
- Do not bypass `AccountContextMiddleware`; ensure new endpoints live under `/api/v1/*` and rely on the auth stack (API key → JWT → session).
- Validate that new background tasks carry account/site/sector identifiers so downstream saves remain scoped.
