> ## Documentation Index
> Fetch the complete documentation index at: https://docs.esakrissa.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Architecture

> System architecture and component interactions

## System Overview

The User Service follows a serverless, event-driven architecture on AWS. All components are managed services, eliminating operational overhead while providing automatic scaling.

```mermaid theme={null}
graph TB
    subgraph "Client Layer"
        APP[Web/Mobile App]
    end
    
    subgraph "Authentication"
        COG[AWS Cognito]
    end
    
    subgraph "API Layer"
        APIGW[API Gateway]
        AUTH[Cognito Authorizer]
    end
    
    subgraph "User Service - Lambda Functions"
        UH[User Handlers]
        EH[Email Handlers]
        TRG[Cognito Triggers]
    end
    
    subgraph "Data Layer"
        DDB[(DynamoDB<br/>Single Table)]
    end
    
    subgraph "Event Bus"
        EB[EventBridge]
        DLQ[SQS Dead Letter Queue]
    end
    
    subgraph "Downstream Services"
        SVC1[Booking Service]
        SVC2[Notification Service]
        SVC3[Billing Service]
        SVC4[Analytics Service]
    end
    
    APP -->|Authenticate| COG
    COG -->|JWT Token| APP
    APP -->|API Request| APIGW
    APIGW --> AUTH
    AUTH -->|Validate Token| COG
    AUTH -->|Authorized| APIGW
    APIGW -->|Invoke| UH
    APIGW -->|Invoke| EH
    COG -->|Post-Confirmation| TRG
    TRG --> DDB
    UH --> DDB
    EH --> DDB
    UH -->|Publish Events| EB
    EH -->|Publish Events| EB
    EB --> SVC1
    EB --> SVC2
    EB --> SVC3
    EB --> SVC4
    EB -.->|Failed Events| DLQ
```

<sub>[View full diagram](/diagrams/architecture.png)</sub>

## Component Breakdown

### Client Layer

The client (web or mobile application) initiates all interactions. Authentication happens directly with Cognito, and all subsequent API calls include the JWT token.

### Authentication Layer

<CardGroup cols={2}>
  <Card title="AWS Cognito" icon="shield">
    Handles user registration, login, password reset, and MFA. Issues JWT tokens for authenticated sessions.
  </Card>

  <Card title="Cognito Authorizer" icon="check">
    Attached to API Gateway. Validates JWT signature and expiry before any Lambda invocation.
  </Card>
</CardGroup>

### API Layer

**API Gateway** serves as the single entry point:

* Routes requests to appropriate Lambda handlers
* Enforces authentication via Cognito Authorizer
* Provides throttling and rate limiting
* Handles CORS and request validation

### Compute Layer

Lambda functions organized by domain:

| Handler Group    | Responsibility                                   |
| ---------------- | ------------------------------------------------ |
| User Handlers    | Profile CRUD, user status management             |
| Email Handlers   | Email CRUD, verification, primary designation    |
| Cognito Triggers | Post-confirmation hook to create DynamoDB record |

### Data Layer

**DynamoDB** with single-table design:

* One table for all User Service entities
* Global Secondary Index for email lookups
* On-demand capacity for unpredictable workloads

### Event Layer

**EventBridge** for inter-service communication:

* Publishes domain events (user.created, email.verified, etc.)
* Rules route events to interested consumers
* Dead Letter Queue captures failed deliveries

## Request Flow

<Steps>
  <Step title="Authentication">
    Client authenticates with Cognito, receives JWT access token
  </Step>

  <Step title="API Request">
    Client sends request to API Gateway with JWT in Authorization header
  </Step>

  <Step title="Token Validation">
    Cognito Authorizer validates JWT signature, expiry, and audience
  </Step>

  <Step title="Lambda Invocation">
    API Gateway invokes appropriate Lambda with user claims in context
  </Step>

  <Step title="Data Operation">
    Lambda performs DynamoDB operation, extracting userId from JWT claims
  </Step>

  <Step title="Event Publication">
    On state change, Lambda publishes event to EventBridge
  </Step>

  <Step title="Event Distribution">
    EventBridge routes event to subscribed downstream services
  </Step>
</Steps>

## Why Serverless?

| Aspect         | Benefit                                                |
| -------------- | ------------------------------------------------------ |
| **Scaling**    | Automatic scaling to zero and to peak demand           |
| **Cost**       | Pay-per-invocation, no idle costs                      |
| **Operations** | No servers to patch, update, or maintain               |
| **Focus**      | Engineering time on business logic, not infrastructure |

## Technology Stack

| Component | Technology             | Rationale                                               |
| --------- | ---------------------- | ------------------------------------------------------- |
| Runtime   | Node.js 20.x (LTS)     | TypeScript support, fast cold starts, AWS SDK v3 native |
| Framework | Serverless Framework   | Mature, well-documented, Cognito integration            |
| Database  | DynamoDB               | Serverless, single-digit ms latency, scales infinitely  |
| Auth      | Cognito                | Managed auth, JWT tokens, OAuth 2.0 flows               |
| Events    | EventBridge            | Serverless event bus, schema registry, filtering        |
| IaC       | Terraform + Serverless | Split responsibilities (see below)                      |

## Design Decisions

Key architectural choices and the reasoning behind them.

<AccordionGroup>
  <Accordion title="Why Serverless Framework over SAM or CDK?">
    **Options considered:** AWS SAM, AWS CDK, Serverless Framework, Terraform-only

    **Chosen:** Serverless Framework

    **Rationale:**

    * More mature plugin ecosystem (offline, webpack, etc.)
    * Simpler YAML syntax compared to CDK's programmatic approach
    * Better local development experience than SAM
    * Team familiarity reduces onboarding time

    **Trade-off:** Less flexibility than CDK for complex infrastructure patterns
  </Accordion>

  <Accordion title="Why EventBridge over SNS+SQS?">
    **Options considered:** SNS+SQS fan-out, EventBridge, direct Lambda invocation

    **Chosen:** EventBridge

    **Rationale:**

    * Native content-based filtering (no need to filter in Lambda)
    * Schema Registry for event documentation
    * Archive and replay for debugging/recovery
    * Single event bus vs. managing multiple SNS topics

    **Trade-off:** Slightly higher latency than direct SNS (\~50-100ms), higher cost per event (\$1/million vs SNS at \$0.50/million)
  </Accordion>

  <Accordion title="Why split Terraform and Serverless Framework?">
    **Options considered:** All Terraform, all Serverless, split approach

    **Chosen:** Split - Terraform for shared resources, Serverless for Lambda lifecycle

    **Rationale:**

    * Cognito and DynamoDB are long-lived; Lambda functions change frequently
    * Terraform state management better suited for infrastructure
    * Serverless Framework optimized for Lambda deployment patterns
    * Clear separation: Terraform outputs → SSM Parameters → Serverless reads

    **Integration pattern:**

    ```
    Terraform → SSM Parameter Store → Serverless Framework
    (Cognito ARN)   (/user-service/prod/cognito-pool-id)   (${ssm:...})
    ```
  </Accordion>

  <Accordion title="Why DynamoDB single-table over multi-table?">
    **Options considered:** Separate User and Email tables, single table with entities

    **Chosen:** Single-table design

    **Rationale:**

    * Atomic transactions for primary email changes (TransactWriteItems requires same table)
    * Single query to fetch user + all emails
    * One table to monitor, backup, and scale
    * Cost efficiency (one set of on-demand capacity)

    **Trade-off:** More complex access patterns, requires upfront design, harder to evolve
  </Accordion>

  <Accordion title="Why Cognito sub as userId?">
    **Options considered:** Cognito `sub` directly, custom UUID with mapping table

    **Chosen:** Use Cognito `sub` directly

    **Rationale:**

    * No mapping table to maintain
    * Guaranteed unique across pool
    * Available in every JWT token
    * Simpler implementation

    **Trade-off:** Harder to migrate away from Cognito (would need to remap all user IDs)
  </Accordion>
</AccordionGroup>
