06 2 vista funcional - lfnavarroj1/sport-app-platform GitHub Wiki

Vista funcional

Objetivo

La vista funcional muestra los componentes que ejecutan las capacidades de SportApp, sus límites de responsabilidad y sus interacciones síncronas y asíncronas.

Componentes funcionales

flowchart TB
    subgraph CLIENTES[Canales]
      WEB[Web Angular] --> BFW[BFF web]
      MOB[Móvil Android] --> BFM[BFF móvil]
    end

    EDGE[API Gateway e Ingress]

    subgraph DOMINIOS[Servicios de negocio]
      U["Usuarios<br/>comandos y consultas"]
      A[Afiliación]
      S[Servicios complementarios]
      T["Entrenamientos<br/>comandos y consultas"]
      E["Eventos<br/>comandos y consultas"]
      X["Terceros<br/>adaptador Strava"]
    end

    subgraph ASYNC[Integración asíncrona]
      OUT[Publicadores outbox]
      PS["Pub/Sub<br/>tópicos por dominio"]
      PRJ[Proyectores de lectura]
    end

    subgraph DATA[Persistencia PostgreSQL]
      W[(Modelos de escritura)]
      R[(Modelos de lectura)]
      D[("Bases únicas<br/>afiliación y servicios")]
    end

    STR[API Strava]
    SENSOR[Dispositivos y sensores]

    BFW --> EDGE
    BFM --> EDGE
    EDGE --> U
    EDGE --> A
    EDGE --> S
    EDGE --> T
    EDGE --> E
    EDGE --> X
    U --> W
    T --> W
    E --> W
    A --> D
    S --> D
    W --> OUT --> PS --> PRJ --> R
    PS <--> A
    PS <--> S
    X <--> PS
    X <--> STR
    SENSOR --> MOB
Loading

Responsabilidades por dominio

Dominio Responsabilidad HU principales Persistencia
Usuarios Identidad, autenticación, perfiles y hábitos. HU001–HU006, HU008–HU009 Escritura y lectura separadas.
Afiliación Catálogo maestro precargado, capacidades, alta FREE, cambios de suscripción y estado de cuenta. HU001, HU007, HU016 Base única; sin CRUD administrativo de planes.
Servicios Catálogo, proveedores, disponibilidad y contratación. HU015, HU017, HU019, HU020, HU029, HU040 Base única.
Entrenamientos Planes, alimentación, sesiones, sensores, indicadores e historial. HU010–HU014, HU026, HU028, HU030, HU032–HU034, HU036–HU038 Escritura y lectura separadas.
Eventos Creación, publicación, tarifas, inscritos, calendario y alertas. HU018, HU021–HU025, HU027, HU035, HU039 Escritura y lectura separadas.
Terceros OAuth, adaptación y sincronización con Strava. HU031 Modelo pendiente de completar.

Flujo de registro con CQRS

sequenceDiagram
    actor U as Usuario
    participant W as Web
    participant B as BFF web
    participant C as Usuarios comandos
    participant DB as PostgreSQL escritura
    participant O as Publicador outbox
    participant P as Pub/Sub
    participant R as Proyector usuarios
    participant Q as PostgreSQL lectura
    participant A as Afiliación
    participant D as PostgreSQL afiliación

    U->>W: Completar registro
    W->>B: Enviar datos
    B->>C: Registrar usuario
    C->>DB: Guardar usuario y evento en una transacción
    C-->>B: Registro aceptado
    B-->>W: Confirmación
    O->>DB: Reclamar evento pendiente
    O->>P: Publicar usuario.registrado.v1
    P->>R: Entregar evento
    R->>Q: Actualizar proyección idempotente
    P->>A: usuario.registrado.v1
    alt actor_type = athlete
      A->>D: Crear suscripción FREE idempotente
      A-->>P: ACK después del COMMIT
    else otro tipo de actor
      A->>D: Registrar evento procesado
      A-->>P: ACK
    end
Loading

Nota — significado de ACK: ACK (Acknowledgement) es la confirmación que el consumidor envía a Pub/Sub para indicar que el mensaje fue procesado correctamente. Afiliación debe enviarlo únicamente después del COMMIT de su transacción: el COMMIT confirma el cambio en PostgreSQL y el ACK confirma el procesamiento ante la mensajería. Si no se envía dentro del plazo, Pub/Sub puede entregar nuevamente el evento; por eso el consumidor debe ser idempotente y una reentrega de usuario.registrado.v1 no puede crear otra suscripción FREE.

El registro del deportista garantiza la asignación automática del plan gratuito, pero la coordinación entre dominios es eventual. Mientras afiliación termina el procesamiento, web y móvil muestran PROVISIONING y no conceden capacidades antes de tiempo.

Habilitación de funciones por plan

flowchart LR
    A[Afiliación<br/>plan y capacidades vigentes] --> B[BFF web o móvil]
    B --> C[Instantánea versionada<br/>de capacidades]
    C --> UI[Guardas y componentes de interfaz]
    C --> API[Autorización en BFF y microservicio]
    UI -->|capacidad incluida| ON[Control habilitado]
    UI -->|requiere plan superior| OFF[Visible en Comparar planes<br/>no como opción operativa]
    UI -->|rol o seguridad| H[Control oculto]
    API -->|capacidad ausente| F[403 capability_required]
Loading

Los clientes evalúan códigos como training.realtime.monitor; nunca comparan nombres de plan. Cada capacidad vigente del deportista genera una opción en el menú lateral izquierdo. Las capacidades de niveles superiores se explican en Comparar planes, pero no aparecen como opciones operativas. Esta navegación mejora la experiencia, pero la autorización efectiva siempre se repite en backend.

La aplicación no administra la definición de los planes. El despliegue carga FREE, INTERMEDIATE y PREMIUM, sus versiones, textos, precios aprobados, capacidades y límites mediante una migración idempotente antes de habilitar Afiliación. Si el catálogo está incompleto o no corresponde a la versión esperada, el servicio no se declara listo. HU016 consume este catálogo para comparar o cambiar una suscripción; no crea, edita ni elimina planes.

Inicio y menú por tipo de usuario

flowchart LR
    S[Sesión autenticada] --> R{actor_type}
    R -->|athlete| A[Inicio deportista<br/>menú según plan]
    R -->|organizer| O[Inicio organizador<br/>gestión de eventos]
    R -->|service_provider| P[Inicio profesional<br/>servicios y atención]
Loading

El tipo de actor determina primero el área de entrada y las operaciones posibles. Los planes solo amplían el menú de athlete; nunca conceden funciones de organizador o profesional. El detalle se encuentra en Inicio y navegación por tipo de usuario.

Límites obligatorios

  • ningún cliente accede directamente a bases de datos o pods internos;
  • ningún dominio escribe en la base de otro;
  • la lógica específica del canal permanece en su BFF;
  • los contratos externos se aíslan mediante adaptadores;
  • un evento se confirma después de persistir el agregado y la outbox atómicamente;
  • la proyección de lectura debe ser idempotente y observable.
  • las capacidades se consultan en afiliación y se validan nuevamente en el backend; la interfaz no es una frontera de seguridad.

Volver a Arquitectura de la solución

⚠️ **GitHub.com Fallback** ⚠️