# TRACEABILITY.yml - MGN-004: Multi-tenant
# Matriz de trazabilidad: Documentacion -> Codigo
# Ubicacion: docs/01-fase-foundation/MGN-004-tenants/implementacion/

epic_code: MGN-004
epic_name: Multi-tenant
phase: 1
phase_name: Foundation
story_points: 35
status: documented

# =============================================================================
# DOCUMENTACION
# =============================================================================

documentation:

  requirements:
    - id: RF-TENANT-001
      file: ../requerimientos/RF-TENANT-001.md
      title: CRUD de Tenants
      priority: P0
      status: migrated
      description: |
        Crear, leer, actualizar y eliminar tenants (organizaciones).
        Cada tenant tiene nombre, slug, dominio y configuracion.

    - id: RF-TENANT-002
      file: ../requerimientos/RF-TENANT-002.md
      title: Configuracion por Tenant
      priority: P0
      status: migrated
      description: |
        Configuracion personalizada: moneda, zona horaria,
        formato de fecha, configuracion fiscal, modulos habilitados.

    - id: RF-TENANT-003
      file: ../requerimientos/RF-TENANT-003.md
      title: Planes y Suscripciones
      priority: P1
      status: migrated
      description: |
        Definicion de planes con features y limites.
        Suscripciones de tenants a planes.

    - id: RF-TENANT-004
      file: ../requerimientos/RF-TENANT-004.md
      title: Aislamiento RLS
      priority: P0
      status: migrated
      description: |
        Row Level Security en PostgreSQL para aislar datos.
        Contexto de tenant en cada request.

  requirements_index:
    file: ../requerimientos/INDICE-RF-TENANT.md
    status: migrated

  specifications:
    - id: ET-TENANTS-001
      file: ../especificaciones/ET-tenants-backend.md
      title: Backend Tenants
      rf: [RF-TENANT-001, RF-TENANT-002, RF-TENANT-003, RF-TENANT-004]
      status: migrated

    - id: ET-TENANTS-002
      file: ../especificaciones/ET-TENANT-database.md
      title: Database Tenants
      rf: [RF-TENANT-001, RF-TENANT-002, RF-TENANT-003, RF-TENANT-004]
      status: migrated

  user_stories:
    - id: US-MGN004-001
      file: ../historias-usuario/US-MGN004-001.md
      title: Crear Tenant
      rf: [RF-TENANT-001]
      story_points: 8
      status: migrated

    - id: US-MGN004-002
      file: ../historias-usuario/US-MGN004-002.md
      title: Configurar Tenant
      rf: [RF-TENANT-002]
      story_points: 5
      status: migrated

    - id: US-MGN004-003
      file: ../historias-usuario/US-MGN004-003.md
      title: Gestionar Suscripcion
      rf: [RF-TENANT-003]
      story_points: 8
      status: migrated

    - id: US-MGN004-004
      file: ../historias-usuario/US-MGN004-004.md
      title: Cambiar Plan
      rf: [RF-TENANT-003]
      story_points: 5
      status: migrated

  backlog:
    file: ../historias-usuario/BACKLOG-MGN004.md
    status: migrated

# =============================================================================
# IMPLEMENTACION
# =============================================================================

implementation:

  database:
    schema: core_tenants
    path: apps/database/ddl/schemas/core_tenants/

    tables:
      - name: tenants
        file: apps/database/ddl/schemas/core_tenants/tables/tenants.sql
        rf: RF-TENANTS-001
        status: pending
        columns:
          - {name: id, type: UUID, pk: true}
          - {name: name, type: VARCHAR(200)}
          - {name: slug, type: VARCHAR(100), unique: true}
          - {name: domain, type: VARCHAR(255)}
          - {name: logo_url, type: TEXT}
          - {name: settings, type: JSONB}
          - {name: is_active, type: BOOLEAN}
          - {name: trial_ends_at, type: TIMESTAMPTZ}
          - {name: created_at, type: TIMESTAMPTZ}
          - {name: updated_at, type: TIMESTAMPTZ}
          - {name: deleted_at, type: TIMESTAMPTZ}
        indexes:
          - idx_tenants_slug
          - idx_tenants_domain

      - name: tenant_settings
        file: apps/database/ddl/schemas/core_tenants/tables/tenant_settings.sql
        rf: RF-TENANTS-002
        status: pending
        columns:
          - {name: id, type: UUID, pk: true}
          - {name: tenant_id, type: UUID, fk: tenants, unique: true}
          - {name: currency, type: VARCHAR(3)}
          - {name: timezone, type: VARCHAR(50)}
          - {name: date_format, type: VARCHAR(20)}
          - {name: fiscal_config, type: JSONB}
          - {name: modules_enabled, type: JSONB}
          - {name: created_at, type: TIMESTAMPTZ}
          - {name: updated_at, type: TIMESTAMPTZ}

      - name: plans
        file: apps/database/ddl/schemas/core_tenants/tables/plans.sql
        rf: RF-TENANTS-003
        status: pending
        columns:
          - {name: id, type: UUID, pk: true}
          - {name: name, type: VARCHAR(100)}
          - {name: slug, type: VARCHAR(50), unique: true}
          - {name: description, type: TEXT}
          - {name: price_monthly, type: DECIMAL(10,2)}
          - {name: price_yearly, type: DECIMAL(10,2)}
          - {name: features, type: JSONB}
          - {name: limits, type: JSONB}
          - {name: is_active, type: BOOLEAN}
          - {name: created_at, type: TIMESTAMPTZ}

      - name: subscriptions
        file: apps/database/ddl/schemas/core_tenants/tables/subscriptions.sql
        rf: RF-TENANTS-003
        status: pending
        columns:
          - {name: id, type: UUID, pk: true}
          - {name: tenant_id, type: UUID, fk: tenants}
          - {name: plan_id, type: UUID, fk: plans}
          - {name: status, type: VARCHAR(20)}
          - {name: starts_at, type: TIMESTAMPTZ}
          - {name: ends_at, type: TIMESTAMPTZ}
          - {name: canceled_at, type: TIMESTAMPTZ}
          - {name: created_at, type: TIMESTAMPTZ}
        indexes:
          - idx_subscriptions_tenant
          - idx_subscriptions_status

    rls_policies:
      - name: tenant_isolation
        description: Politica base para aislamiento de datos
        rf: RF-TENANTS-004
        status: pending
        tables: ALL
        definition: |
          CREATE POLICY tenant_isolation ON {table}
            USING (tenant_id = current_setting('app.current_tenant_id')::uuid);

    functions:
      - name: set_tenant_context
        file: apps/database/ddl/schemas/core_tenants/functions/set_tenant_context.sql
        rf: RF-TENANTS-004
        status: pending
        params: [p_tenant_id UUID]
        returns: VOID
        description: Establece contexto de tenant para RLS

      - name: create_tenant_with_defaults
        file: apps/database/ddl/schemas/core_tenants/functions/create_tenant_with_defaults.sql
        rf: RF-TENANTS-005
        status: pending
        params: [p_name VARCHAR, p_slug VARCHAR, p_admin_user_id UUID]
        returns: UUID
        description: Crea tenant con datos iniciales y roles

  backend:
    module: tenants
    path: apps/backend/src/modules/tenants/
    framework: NestJS

    entities:
      - name: Tenant
        file: apps/backend/src/modules/tenants/entities/tenant.entity.ts
        rf: RF-TENANTS-001
        status: pending

      - name: TenantSettings
        file: apps/backend/src/modules/tenants/entities/tenant-settings.entity.ts
        rf: RF-TENANTS-002
        status: pending

      - name: Plan
        file: apps/backend/src/modules/tenants/entities/plan.entity.ts
        rf: RF-TENANTS-003
        status: pending

      - name: Subscription
        file: apps/backend/src/modules/tenants/entities/subscription.entity.ts
        rf: RF-TENANTS-003
        status: pending

    services:
      - name: TenantsService
        file: apps/backend/src/modules/tenants/tenants.service.ts
        rf: [RF-TENANTS-001, RF-TENANTS-005]
        status: pending
        methods:
          - {name: create, rf: RF-TENANTS-001}
          - {name: findAll, rf: RF-TENANTS-001}
          - {name: findOne, rf: RF-TENANTS-001}
          - {name: findBySlug, rf: RF-TENANTS-001}
          - {name: update, rf: RF-TENANTS-001}
          - {name: remove, rf: RF-TENANTS-001}
          - {name: onboard, rf: RF-TENANTS-005}

      - name: TenantSettingsService
        file: apps/backend/src/modules/tenants/tenant-settings.service.ts
        rf: [RF-TENANTS-002]
        status: pending
        methods:
          - {name: getSettings, rf: RF-TENANTS-002}
          - {name: updateSettings, rf: RF-TENANTS-002}

      - name: PlansService
        file: apps/backend/src/modules/tenants/plans.service.ts
        rf: [RF-TENANTS-003]
        status: pending
        methods:
          - {name: findAll, rf: RF-TENANTS-003}
          - {name: findOne, rf: RF-TENANTS-003}

      - name: SubscriptionsService
        file: apps/backend/src/modules/tenants/subscriptions.service.ts
        rf: [RF-TENANTS-003]
        status: pending
        methods:
          - {name: create, rf: RF-TENANTS-003}
          - {name: getCurrentSubscription, rf: RF-TENANTS-003}
          - {name: changePlan, rf: RF-TENANTS-003}
          - {name: cancel, rf: RF-TENANTS-003}

    middleware:
      - name: TenantMiddleware
        file: apps/backend/src/modules/tenants/middleware/tenant.middleware.ts
        rf: RF-TENANTS-004
        status: pending
        description: |
          Extrae tenant_id del JWT y establece contexto.
          SET LOCAL app.current_tenant_id = '{uuid}'

    guards:
      - name: TenantGuard
        file: apps/backend/src/modules/tenants/guards/tenant.guard.ts
        rf: RF-TENANTS-004
        status: pending
        description: Verifica que tenant este activo

      - name: SubscriptionGuard
        file: apps/backend/src/modules/tenants/guards/subscription.guard.ts
        rf: RF-TENANTS-003
        status: pending
        description: Verifica que suscripcion este activa

    controllers:
      - name: TenantsController
        file: apps/backend/src/modules/tenants/tenants.controller.ts
        status: pending
        endpoints:
          - method: GET
            path: /api/v1/tenants
            rf: RF-TENANTS-001
            description: Listar tenants (super admin)

          - method: POST
            path: /api/v1/tenants
            rf: RF-TENANTS-001
            description: Crear tenant

          - method: GET
            path: /api/v1/tenants/:id
            rf: RF-TENANTS-001
            description: Obtener tenant

          - method: PATCH
            path: /api/v1/tenants/:id
            rf: RF-TENANTS-001
            description: Actualizar tenant

          - method: GET
            path: /api/v1/tenants/current
            rf: RF-TENANTS-001
            description: Tenant actual del usuario

          - method: GET
            path: /api/v1/tenants/current/settings
            rf: RF-TENANTS-002
            description: Configuracion del tenant

          - method: PATCH
            path: /api/v1/tenants/current/settings
            rf: RF-TENANTS-002
            description: Actualizar configuracion

      - name: PlansController
        file: apps/backend/src/modules/tenants/plans.controller.ts
        status: pending
        endpoints:
          - method: GET
            path: /api/v1/plans
            rf: RF-TENANTS-003
            description: Listar planes disponibles

          - method: GET
            path: /api/v1/plans/:id
            rf: RF-TENANTS-003
            description: Detalle de plan

      - name: SubscriptionsController
        file: apps/backend/src/modules/tenants/subscriptions.controller.ts
        status: pending
        endpoints:
          - method: GET
            path: /api/v1/subscriptions/current
            rf: RF-TENANTS-003
            description: Suscripcion actual

          - method: POST
            path: /api/v1/subscriptions
            rf: RF-TENANTS-003
            description: Crear suscripcion

          - method: PATCH
            path: /api/v1/subscriptions/current/plan
            rf: RF-TENANTS-003
            description: Cambiar plan

          - method: POST
            path: /api/v1/subscriptions/current/cancel
            rf: RF-TENANTS-003
            description: Cancelar suscripcion

    decorators:
      - name: CurrentTenant
        file: apps/backend/src/modules/tenants/decorators/current-tenant.decorator.ts
        rf: RF-TENANTS-004
        status: pending
        description: Inyecta tenant actual del request

  frontend:
    feature: tenants
    path: apps/frontend/src/features/tenants/
    framework: React

    pages:
      - name: TenantsPage
        file: apps/frontend/src/features/tenants/pages/TenantsPage.tsx
        rf: RF-TENANTS-001
        status: pending
        route: /admin/tenants
        description: Lista de tenants (super admin)

      - name: TenantSettingsPage
        file: apps/frontend/src/features/tenants/pages/TenantSettingsPage.tsx
        rf: RF-TENANTS-002
        status: pending
        route: /settings/organization

      - name: OnboardingPage
        file: apps/frontend/src/features/tenants/pages/OnboardingPage.tsx
        rf: RF-TENANTS-005
        status: pending
        route: /onboarding

      - name: PlansPage
        file: apps/frontend/src/features/tenants/pages/PlansPage.tsx
        rf: RF-TENANTS-003
        status: pending
        route: /settings/subscription

    components:
      - name: TenantSettingsForm
        file: apps/frontend/src/features/tenants/components/TenantSettingsForm.tsx
        rf: RF-TENANTS-002
        status: pending

      - name: OnboardingWizard
        file: apps/frontend/src/features/tenants/components/OnboardingWizard.tsx
        rf: RF-TENANTS-005
        status: pending

      - name: PlanCard
        file: apps/frontend/src/features/tenants/components/PlanCard.tsx
        rf: RF-TENANTS-003
        status: pending

      - name: SubscriptionStatus
        file: apps/frontend/src/features/tenants/components/SubscriptionStatus.tsx
        rf: RF-TENANTS-003
        status: pending

    stores:
      - name: tenantStore
        file: apps/frontend/src/features/tenants/stores/tenantStore.ts
        rf: [RF-TENANTS-001, RF-TENANTS-002]
        status: pending
        state:
          - {name: currentTenant, type: "Tenant | null"}
          - {name: settings, type: "TenantSettings | null"}
          - {name: subscription, type: "Subscription | null"}
        actions:
          - fetchCurrentTenant
          - updateSettings
          - changePlan

    hooks:
      - name: useTenant
        file: apps/frontend/src/features/tenants/hooks/useTenant.ts
        rf: RF-TENANTS-001
        status: pending
        description: Hook para acceder a tenant actual

      - name: useSubscription
        file: apps/frontend/src/features/tenants/hooks/useSubscription.ts
        rf: RF-TENANTS-003
        status: pending
        description: Hook para verificar features del plan

# =============================================================================
# DEPENDENCIAS
# =============================================================================

dependencies:
  depends_on:
    - module: MGN-001
      type: hard
      reason: Tenant ID se incluye en JWT
    - module: MGN-002
      type: hard
      reason: Usuarios pertenecen a tenants
    - module: MGN-003
      type: hard
      reason: Roles son por tenant

  required_by:
    - module: MGN-005
      type: hard
      reason: Catalogos son por tenant
    - module: MGN-006
      type: hard
      reason: Inventario por tenant
    - module: MGN-007
      type: hard
      reason: Ventas por tenant
    - module: ALL_BUSINESS
      type: hard
      reason: Todos los datos son por tenant

# =============================================================================
# TESTS
# =============================================================================

tests:
  unit:
    - name: TenantsService.spec.ts
      file: apps/backend/src/modules/tenants/__tests__/tenants.service.spec.ts
      status: pending
      cases: 12

    - name: SubscriptionsService.spec.ts
      file: apps/backend/src/modules/tenants/__tests__/subscriptions.service.spec.ts
      status: pending
      cases: 8

    - name: TenantMiddleware.spec.ts
      file: apps/backend/src/modules/tenants/__tests__/tenant.middleware.spec.ts
      status: pending
      cases: 6

  integration:
    - name: tenants.controller.e2e.spec.ts
      file: apps/backend/test/tenants/tenants.controller.e2e.spec.ts
      status: pending
      cases: 15

    - name: rls-isolation.e2e.spec.ts
      file: apps/backend/test/tenants/rls-isolation.e2e.spec.ts
      status: pending
      cases: 10
      description: Tests de aislamiento RLS entre tenants

  coverage:
    target: 80%
    current: 0%

# =============================================================================
# METRICAS
# =============================================================================

metrics:
  story_points:
    estimated: 35
    actual: null

  files:
    database: 8
    backend: 20
    frontend: 12
    tests: 8
    total: 48

# =============================================================================
# HISTORIAL
# =============================================================================

history:
  - date: "2025-12-05"
    action: "Creacion de TRACEABILITY.yml"
    author: Requirements-Analyst
