Parent: Aligner Tracker Api
System Diagram
flowchart TB subgraph client [Mobile App] MobileApp[React Native App] end subgraph aws [AWS Cloud] APIGateway[API Gateway] Cognito[Cognito User Pool] S3[S3 Bucket] RDS[(RDS PostgreSQL)] end subgraph backend [Backend Service] FastAPI[FastAPI Application] end MobileApp -->|JWT Token| APIGateway APIGateway --> Cognito APIGateway --> FastAPI FastAPI --> RDS FastAPI --> S3
Authentication Flow
sequenceDiagram participant App as Mobile App participant GW as API Gateway participant Cognito as Cognito participant API as FastAPI App->>GW: Request + JWT Bearer Token GW->>Cognito: Validate JWT Cognito-->>GW: Token Valid GW->>API: Forward Request API->>API: Extract sub from JWT API->>API: Verify sub matches path param API-->>App: Response
Endpoint Types
| Prefix | Auth Method | Use Case |
|---|---|---|
/auth/* | Cognito JWT | User-facing endpoints (mobile app) |
/internal/* | API Gateway API Key | Service-to-service (e.g., from Jarvis) |
/public/* | HubSpot Signature v3 | HubSpot webhooks |
Key Design Decisions
-
API Gateway validates JWTs - The FastAPI app does NOT verify JWT signatures; it trusts API Gateway has already validated them. It only extracts the
subclaim. -
Path-based authorization - Endpoints like
/auth/users/{cognito_sub}/...require the JWT’ssubto match the path parameter. -
Alembic for migrations - Database schema is managed via Alembic, auto-run on container startup.
Environment Variables
# AWS
AWS_REGION=eu-west-2
COGNITO_USER_POOL_ID=eu-west-2_XXXXXX
USER_IMAGES_BUCKET=your-s3-bucket-name
# DB
DATABASE_URL=xxx
# Jarvis
JARVIS_API_URL=xxx
JARVIS_API_KEY=xxx
# OneSignal
ONESIGNAL_APP_ID=xxx
ONESIGNAL_REST_API_KEY=xxx
# HubSpot
HUBSPOT_CLIENT_SECRET=xxx
# Logging configuration
LOG_LEVEL=INFO
LOG_FORMAT=json
LOG_REDACT_SENSITIVE=trueExternal Service Integration
Jarvis API
Used to submit dentist change requests:
POST {JARVIS_API_URL}/api/smilewhite_app/customer/change-dentist/{email}/
Headers: Authorization: Api-Key {JARVIS_API_KEY}
Request: {"assigned_dentist": <dentist_id>}
Responses:
200: Success, returns{"ticket": {"id": "..."}}409: Dentist change already pending
OneSignal
Used to send scheduled push notifications for progress change reminders:
Send Scheduled Notification:
POST https://api.onesignal.com/notifications
Headers: Authorization: Key {ONESIGNAL_REST_API_KEY}
Request: {
"app_id": "<app_id>",
"include_aliases": {"external_id": ["<cognito_sub>"]},
"target_channel": "push",
"headings": {"en": "Progress Reminder"},
"contents": {"en": "<message>"},
"send_after": "<ISO8601 datetime>",
"data": {"notification_id": "<id>", "type": "progress"}
}
Cancel Notification:
DELETE https://api.onesignal.com/notifications/{onesignal_id}?app_id={app_id}
Headers: Authorization: Key {ONESIGNAL_REST_API_KEY}
Users are targeted via external_id which maps to their cognito_sub_identifier.
CI/CD Pipeline
flowchart LR Push[Push to main] --> Quality[Quality Job] Quality --> |Tests Pass| Build[Build Docker Image] Build --> ECR[Push to ECR] ECR --> Deploy[Deploy to Dev] Deploy --> Infra[Smile-White/Infrastructure]
-
Trigger: Push to
mainbranch -
Quality checks: Alembic migration check, pytest, health check
-
Deploy: Uses reusable workflow from
Smile-White/Infrastructurerepo