Backend Integration & Infrastructure

Backend API, database, infrastructure, and integration points for Peregrine mobile app.

Backend Integration & Infrastructure

This document details the backend infrastructure, database architecture, and integration requirements for the Peregrine mobile application.

Current Status

Development Stage: Mobile app uses MockDataAdapter with no real backend

  • Frontend: Complete React Native app (React Native 0.81.5, Expo 54.0.31)
  • Backend: Infrastructure code exists but not integrated
  • Database: No schema implementation
  • Status: MVP/Prototype stage - not production-ready

Infrastructure Overview

Phenom Infrastructure Repository

Location: ~/projects/thephenom-app/phenom-infra

The infrastructure is managed using Terraform (Infrastructure as Code) for AWS deployment.

Stack Components

graph TB
    Mobile[Mobile App<br/>React Native] --> ALB[Application Load Balancer]
    ALB --> GraphQL[Hasura GraphQL Engine<br/>Port 8080]
    ALB --> Auth[Hasura Auth<br/>Port 4000]
    ALB --> Storage[Hasura Storage<br/>Port 5000]
    ALB --> Functions[Nhost Functions<br/>Port 3000]

    GraphQL --> RDS[(PostgreSQL + PostGIS<br/>RDS)]
    Auth --> RDS
    Storage --> S3[S3 Media Storage]
    Functions --> Lambda[Lambda Functions]

    Auth --> Cognito[AWS Cognito]
    Lambda -.Sync.-> Cognito

    style Mobile fill:#e1f5fe
    style ALB fill:#fff3e0
    style GraphQL fill:#f3e5f5
    style Auth fill:#f3e5f5
    style Storage fill:#f3e5f5
    style Functions fill:#f3e5f5
    style RDS fill:#c8e6c9
    style S3 fill:#fff9c4
    style Cognito fill:#fce4ec

Terraform Modules

Networking Module (modules/networking/)

  • VPC with public/private subnets
  • Multi-availability zone deployment
  • NAT gateways for private subnet internet access
  • Security groups for service isolation

ALB Module (modules/alb/)

  • Application Load Balancer configuration
  • Target groups for each service
  • Path-based routing rules
  • HTTPS/SSL termination

ECS Module (modules/ecs/)

  • ECS Fargate cluster
  • Task definitions for Hasura services
  • Service auto-scaling configuration
  • CloudWatch integration

RDS Module (modules/rds/)

  • PostgreSQL database setup
  • PostGIS extension for geospatial queries
  • Automated backups
  • Multi-AZ deployment for high availability

Video Upload Module (modules/video-upload/)

  • Serverless media upload pipeline
  • S3 staging and final buckets
  • Lambda validation functions
  • API Gateway integration

Media Upload Architecture

graph TB
    User[Mobile App User] -->|1. Request Upload URL| API[API Gateway]
    API -->|2. Authenticate| Lambda1[Pre-signed URL<br/>Generator Lambda]
    Lambda1 -->|3. Validate| Secrets[AWS Secrets Manager]
    Lambda1 -->|4. Generate URL| S3Staging[(S3 Staging Bucket<br/>24h Auto-Delete)]
    Lambda1 -->|5. Return URL| User

    User -->|6. Upload Media| S3Staging
    S3Staging -->|7. Trigger| Lambda2[File Validator Lambda]

    Lambda2 -->|8a. Check Magic Bytes| Lambda2
    Lambda2 -->|8b. Virus Scan Optional| Lambda2
    Lambda2 -->|8c. Size Validation| Lambda2

    Lambda2 -->|9. Valid File| S3Final[(S3 Final Bucket<br/>Organized by Type)]
    Lambda2 -->|10. Invalid| Delete[Delete & Log]

    S3Final -->|11. CDN Delivery| CloudFront[CloudFront CDN]
    CloudFront --> Mobile[Mobile App Display]

    style User fill:#e1f5fe
    style API fill:#fff3e0
    style Lambda1 fill:#f3e5f5
    style Lambda2 fill:#f3e5f5
    style Secrets fill:#fce4ec
    style S3Staging fill:#ffecb3
    style S3Final fill:#c8e6c9
    style Delete fill:#ffccbc
    style CloudFront fill:#e8eaf6

Security Features:

  • Password authentication via AWS Secrets Manager
  • Time-limited pre-signed URLs (1 hour default)
  • Magic byte validation (checks actual file type)
  • Optional ClamAV virus scanning
  • File size limits (500MB default)
  • API rate limiting (10 req/sec)
  • Encryption at rest (AES256)
  • Private bucket access only

Supported Formats:

  • Images: JPEG, PNG, GIF, WebP, SVG, TIFF, BMP
  • Videos: MP4, MPEG, QuickTime, AVI, WMV, WebM

Database Architecture

Required Schema (Not Yet Implemented)

PostgreSQL + PostGIS for geospatial queries

erDiagram
    users ||--o{ phenom_reports : creates
    users ||--o{ user_favorites : has
    users {
        uuid id PK
        string email UK
        string password_hash
        jsonb profile
        timestamp created_at
        timestamp updated_at
    }

    phenom_reports ||--o{ phenom_media : contains
    phenom_reports ||--o{ user_favorites : favorited_by
    phenom_reports }o--o{ categories : has
    phenom_reports {
        uuid id PK
        uuid user_id FK
        geography location
        jsonb coordinates
        timestamp timestamp
        string h3_index
        int h3_resolution
        text description
    }

    phenom_media {
        uuid id PK
        uuid report_id FK
        string url
        string type
        jsonb metadata
        string thumbnail_url
    }

    categories {
        uuid id PK
        string name UK
        text description
        string icon
    }

    user_favorites {
        uuid user_id FK
        uuid report_id FK
        timestamp created_at
    }

Key Features:

  • PostGIS Geography Type for location (earth-aware calculations)
  • H3 Index for efficient hex-based spatial queries
  • JSONB for flexible coordinate arrays and metadata
  • UUID primary keys for distributed system compatibility

Geospatial Indexing Strategy

H3 Hexagonal Indexing:

  • Resolution levels 0-15 (0 = continent, 15 = building)
  • Mobile app uses resolution 2 for map display (~1,534 km² per hex)
  • Database stores both exact coordinates and H3 index for queries

Query Patterns:

-- Find phenoms in specific hex cell
SELECT * FROM phenom_reports WHERE h3_index = '872a1072fffffff';

-- Find phenoms within radius
SELECT * FROM phenom_reports
WHERE ST_DWithin(
    location::geography,
    ST_MakePoint(-73.9857, 40.7484)::geography,
    10000  -- 10km radius
);

-- Find phenoms in neighboring hexes
SELECT * FROM phenom_reports
WHERE h3_index = ANY(h3_k_ring('872a1072fffffff', 1));

API Integration Points

Current Mobile App Architecture

graph LR
    subgraph Mobile App
        Screens[Screens<br/>Home/Map/Record] --> API[PhenomAPI.current]
        API --> Adapter{API Adapter}
        Adapter --> Mock[MockDataAdapter<br/>CURRENT]
        Adapter -.Future.-> Real[Real Backend Adapter<br/>NEEDED]
    end

    Real -.-> GraphQL[Hasura GraphQL API]
    Real -.-> REST[REST Endpoints]
    Real -.-> WS[WebSocket Subscriptions]

    style Mock fill:#ffccbc
    style Real fill:#c8e6c9
    style GraphQL fill:#e8eaf6
    style REST fill:#e8eaf6
    style WS fill:#e8eaf6

Current State: MockDataAdapter.ts

  • Generates random mock data
  • No network requests
  • Hardcoded test data

Required: Real adapter implementing IAPIAdapter interface:

interface IAPIAdapter {
  // Phenom queries
  getPhenoms(size?: number, since?: Date): Promise<PhenomItem[]>
  getPhenom(id: string): Promise<PhenomItem>
  getPhenomByH3Cell(h3Index: string): Promise<PhenomItem[]>

  // User operations
  getUserProfile(userId: string): Promise<PhenomProfile>
  updateUserProfile(profile: PhenomProfile): Promise<void>

  // Media upload
  uploadRecording(recording: RecordingData): Promise<string>

  // Search
  search(query: string): Promise<PhenomItem[]>
}

Hasura GraphQL Integration

GraphQL Endpoint: https://graphql.phenom.app/v1/graphql

Example Queries:

# Get recent phenoms
query GetRecentPhenoms($limit: Int!) {
  phenom_reports(
    order_by: { timestamp: desc }
    limit: $limit
  ) {
    id
    description
    timestamp
    location
    h3_index
    user {
      id
      profile
    }
    media {
      url
      type
      thumbnail_url
    }
    categories {
      name
      icon
    }
  }
}

# Get phenoms by H3 cell
query GetPhenomsByHex($h3Index: String!) {
  phenom_reports(
    where: { h3_index: { _eq: $h3Index } }
  ) {
    id
    location
    timestamp
    media {
      thumbnail_url
    }
  }
}

# Create new phenom report
mutation CreatePhenomReport($report: phenom_reports_insert_input!) {
  insert_phenom_reports_one(object: $report) {
    id
    timestamp
  }
}

# Subscribe to new phenoms (real-time)
subscription NewPhenoms {
  phenom_reports(
    order_by: { timestamp: desc }
    limit: 10
  ) {
    id
    timestamp
    location
  }
}

Authentication:

  • JWT token from Hasura Auth service
  • Stored in MMKV encrypted storage
  • Sent as Authorization: Bearer <token> header

Authentication Flow

sequenceDiagram
    participant App as Mobile App
    participant Auth as Hasura Auth
    participant Cognito as AWS Cognito
    participant GraphQL as Hasura GraphQL

    App->>Auth: POST /signup<br/>{email, password}
    Auth->>Cognito: Create user
    Cognito-->>Auth: User created
    Auth->>GraphQL: Create user profile
    Auth-->>App: {accessToken, refreshToken}

    Note over App: Store tokens in<br/>MMKV (encrypted)

    App->>GraphQL: Query with JWT
    GraphQL->>GraphQL: Validate token
    GraphQL-->>App: Protected data

    Note over App: Token expires

    App->>Auth: POST /token/refresh<br/>{refreshToken}
    Auth-->>App: {newAccessToken}

Token Management:

  • Access token: 15 minutes expiry
  • Refresh token: 30 days expiry
  • Automatic refresh before expiration
  • Secure storage in MMKV (encrypted)

Mobile App Integration:

// app/context/AuthContext.tsx (enhanced needed)
const login = async (email: string, password: string) => {
  const response = await fetch('https://auth.phenom.app/signin/email-password', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ email, password })
  })
  const { session } = await response.json()

  // Store tokens
  await storage.save('authToken', session.accessToken)
  await storage.save('refreshToken', session.refreshToken)

  setAuthToken(session.accessToken)
  setAuthEmail(email)
}

Required Backend Work

Phase 1: Core Infrastructure (DevOps)

Tasks:

  1. ✅ Terraform infrastructure code (COMPLETE)
  2. ⏳ Deploy development environment
  3. ⏳ Configure DNS and SSL certificates
  4. ⏳ Set up monitoring (CloudWatch)
  5. ⏳ Configure backups and disaster recovery

Owner: DevOps Engineer Timeline: 2-3 weeks Dependencies: AWS account, domain registration

Phase 2: Database Setup (DBA)

Tasks:

  1. ⏳ Design complete database schema
  2. ⏳ Create migration scripts
  3. ⏳ Set up PostGIS extension
  4. ⏳ Implement H3 functions
  5. ⏳ Create indexes for performance
  6. ⏳ Set up replication and backups

Owner: Database Administrator Timeline: 2 weeks Dependencies: Phase 1 complete

Database Optimization:

-- Spatial index for location queries
CREATE INDEX idx_phenom_reports_location
ON phenom_reports USING GIST(location);

-- H3 index for hex queries
CREATE INDEX idx_phenom_reports_h3
ON phenom_reports(h3_index);

-- Timestamp index for recent queries
CREATE INDEX idx_phenom_reports_timestamp
ON phenom_reports(timestamp DESC);

-- User reports index
CREATE INDEX idx_phenom_reports_user
ON phenom_reports(user_id);

Phase 3: API Integration (Backend Developer)

Tasks:

  1. ⏳ Implement GraphQL adapter in mobile app
  2. ⏳ Add authentication flow
  3. ⏳ Implement media upload
  4. ⏳ Add real-time subscriptions
  5. ⏳ Error handling and retry logic
  6. ⏳ Offline queue for uploads

Owner: API Developer Timeline: 3-4 weeks Dependencies: Phase 1 & 2 complete

Phase 4: Sensor & Media Integration (Mobile Developer)

Tasks:

  1. ⏳ Integrate Expo Location API
  2. ⏳ Implement camera/video capture
  3. ⏳ Add sensor data collection (accelerometer, compass)
  4. ⏳ Implement media compression
  5. ⏳ Background upload queue

Owner: Frontend Developer Timeline: 2-3 weeks Dependencies: Phase 3 complete

Environment Configuration

Development Environment

# Mobile App (.env.development)
API_URL=https://dev-api.phenom.app
GRAPHQL_URL=https://dev-graphql.phenom.app/v1/graphql
AUTH_URL=https://dev-auth.phenom.app
STORAGE_URL=https://dev-storage.phenom.app
MAPBOX_TOKEN=pk.eyJ1IjoicGhlbm9tam9uIi...

# Backend (Terraform variables)
environment = "development"
aws_region = "us-east-1"
vpc_cidr = "10.0.0.0/16"
enable_nat_gateway = true
database_instance_class = "db.t3.medium"

Production Environment

# Mobile App (.env.production)
API_URL=https://api.phenom.app
GRAPHQL_URL=https://graphql.phenom.app/v1/graphql
AUTH_URL=https://auth.phenom.app
STORAGE_URL=https://storage.phenom.app
MAPBOX_TOKEN=pk.eyJ1IjoicGhlbm9tam9uIi...

# Backend (Terraform variables)
environment = "production"
aws_region = "us-east-1"
vpc_cidr = "10.0.0.0/16"
enable_nat_gateway = true
enable_multi_az = true
database_instance_class = "db.r5.large"
backup_retention_days = 30

Deployment Process

Infrastructure Deployment

# Navigate to environment
cd ~/projects/thephenom-app/phenom-infra/environments/development

# Initialize Terraform
terraform init

# Review plan
terraform plan

# Apply infrastructure
terraform apply

# Get outputs
terraform output

Outputs:

alb_dns_name = "phenom-dev-alb-123456789.us-east-1.elb.amazonaws.com"
graphql_endpoint = "http://phenom-dev-alb-123456789.us-east-1.elb.amazonaws.com:8080"
auth_endpoint = "http://phenom-dev-alb-123456789.us-east-1.elb.amazonaws.com:4000"

Mobile App Configuration

After backend deployment, update mobile app config:

// app/config/config.prod.ts
export const config = {
  apiUrl: process.env.API_URL || "https://api.phenom.app",
  graphqlUrl: process.env.GRAPHQL_URL || "https://graphql.phenom.app/v1/graphql",
  authUrl: process.env.AUTH_URL || "https://auth.phenom.app",
  storageUrl: process.env.STORAGE_URL || "https://storage.phenom.app",
}

Monitoring & Observability

CloudWatch Metrics:

  • ECS service health
  • API response times
  • Database connections
  • Error rates

Logging:

  • Application logs → CloudWatch Logs
  • Access logs → S3
  • Audit logs → CloudWatch Insights

Alerts:

  • High error rate (>5%)
  • Database CPU >80%
  • Service downtime
  • Failed deployments

Security Considerations

Infrastructure:

  • Private subnets for services
  • Security groups with least privilege
  • AWS Secrets Manager for credentials
  • Encryption at rest and in transit
  • Regular security patches

Application:

  • JWT authentication
  • Rate limiting
  • Input validation
  • SQL injection prevention (Hasura parameterized queries)
  • XSS protection

Cost Estimates

Development Environment (Monthly):

  • ECS Fargate: $50-100
  • RDS PostgreSQL: $50-150
  • ALB: $20-30
  • S3 Storage: $10-30
  • Data Transfer: $20-50
  • Total: ~$150-360/month

Production Environment (Monthly):

  • ECS Fargate (with auto-scaling): $200-500
  • RDS PostgreSQL (Multi-AZ, larger instance): $300-600
  • ALB: $30-50
  • S3 Storage + CloudFront: $100-300
  • Data Transfer: $100-300
  • Total: ~$730-1,750/month

Next Steps

  1. Review infrastructure code in phenom-infra repository
  2. Deploy development environment
  3. Implement database schema
  4. Build GraphQL adapter for mobile app
  5. Integrate authentication flow
  6. Test end-to-end data flow
  7. Deploy staging environment
  8. Conduct load testing
  9. Plan production deployment

Internal Resources