docsservicesBFF ServiceBFF Service

BFF Service

The BFF (Backend for Frontend) service acts as an API Gateway, providing a unified API layer with authentication proxy, request aggregation, caching, and circuit breaker protection.

Overview

Goalixa BFF is built with FastAPI and provides:

  • Unified API entry point (/bff/*)
  • Authentication proxy to Auth Service
  • Request aggregation for optimized data fetching
  • Redis-based caching
  • Circuit breaker protection
  • Prometheus metrics

Technology Stack

ComponentTechnology
FrameworkFastAPI (Python 3.11, async)
HTTP Clienthttpx (async)
CachingRedis
MetricsPrometheus
AuthenticationJWT validation

Project Structure

goalixa-BFF/
├── app/
│   ├── main.py              # Entry point
│   ├── config.py            # Configuration
│   ├── middleware/
│   │   ├── auth_middleware.py
│   │   ├── rate_limit_middleware.py
│   │   └── logging_middleware.py
│   ├── routers/
│   │   ├── health.py
│   │   ├── auth.py
│   │   ├── app_router.py
│   │   └── aggregate.py
│   ├── utils/
│   │   ├── cache.py
│   │   ├── circuit_breaker.py
│   │   └── metrics.py
├── k8s/
└── requirements.txt

API Endpoints

Health Checks

MethodEndpointDescription
GET/healthBasic health check
GET/readinessReadiness probe
GET/livenessLiveness probe
GET/health/deepDeep health (checks backends)
GET/health/circuit-breaker/statusCircuit breaker status

/bff/auth/* (Authentication Proxy)

MethodEndpointDescription
POST/bff/auth/loginUser login
POST/bff/auth/registerUser registration
POST/bff/auth/logoutLogout
POST/bff/auth/refreshRefresh token
GET/bff/auth/meGet current user
POST/bff/auth/forgotPassword reset request
POST/bff/auth/password-reset/confirmConfirm password reset
GET/bff/auth/sessionsList active sessions
POST/bff/auth/sessions/revoke-allRevoke all sessions

/bff/app/* (App Service Proxy)

Proxies to Core-API with circuit breaker protection.

Tasks

MethodEndpoint
GET/bff/app/tasks
POST/bff/app/tasks
POST/bff/app/tasks/{id}/edit
POST/bff/app/tasks/{id}/start
POST/bff/app/tasks/{id}/stop
POST/bff/app/tasks/{id}/complete
POST/bff/app/tasks/{id}/reopen
POST/bff/app/tasks/{id}/delete
POST/bff/app/tasks/bulk

Projects

MethodEndpoint
GET/bff/app/projects
POST/bff/app/projects
POST/bff/app/projects/{id}/update
POST/bff/app/projects/{id}/delete

Goals

MethodEndpoint
GET/bff/app/goals
POST/bff/app/goals
POST/bff/app/goals/{id}/edit
POST/bff/app/goals/{id}/delete
POST/bff/app/goals/{id}/subgoals

Habits

MethodEndpoint
GET/bff/app/habits
POST/bff/app/habits
POST/bff/app/habits/{id}/toggle
POST/bff/app/habits/{id}/update
POST/bff/app/habits/{id}/delete

Timer

MethodEndpoint
GET/bff/app/timer
GET/bff/app/timer/entries
GET/bff/app/timer/dashboard

Reports

MethodEndpoint
GET/bff/app/reports/summary

/bff/aggregate/* (Aggregate Endpoints)

Optimized endpoints that fetch data from multiple services in parallel.

MethodEndpointDescription
GET/bff/aggregate/dashboardComplete dashboard data
GET/bff/aggregate/plannerPlanner view data
GET/bff/aggregate/reportsReports data
GET/bff/aggregate/overviewUser + tasks + summary
GET/bff/aggregate/timer-dashboardTimer dashboard

Authentication

The BFF performs dual JWT validation:

  1. Local Validation (primary, faster):

    • Validates JWT using jwt.decode() with HS256
    • Only accepts type: "access" tokens
    • Checks token expiration
  2. Auth Service Validation (fallback):

    • Calls auth service /me endpoint
    • Used when local validation fails

Public Endpoints (no auth required)

PUBLIC_ENDPOINTS = [
    "/", "/health", "/readiness", "/liveness", "/metrics", "/docs",
    "/bff/auth/login", "/bff/auth/register", "/bff/auth/forgot",
    "/bff/auth/password-reset/*", "/bff/auth/google", "/bff/auth/refresh"
]

Caching

Configuration

VariableDescriptionDefault
redis_enabledEnable Redis cachingfalse
redis_urlRedis connection URLredis://localhost:6379/0
cache_ttl_secondsDefault cache TTL300

TTL by Data Type

Data TypeTTL (seconds)
User profile600 (10 min)
Tasks60 (1 min)
Projects300 (5 min)
Goals300 (5 min)
Labels600 (10 min)
Dashboard120 (2 min)
Aggregate180 (3 min)

Cache Operations

# Get cached value
cached_data = await cache.get("tasks:user123")
 
# Set with TTL
await cache.set("tasks:user123", data, ttl=60)
 
# Invalidate user cache
await cache.invalidate_user_cache(user_id)
 
# Invalidate by pattern
await cache.delete_pattern("tasks:user123:*")

Circuit Breaker

The BFF protects backend services with circuit breaker pattern:

Configuration

ParameterValue
Failure threshold5
Recovery timeout30 seconds
Half-open max calls3

Code Examples

Aggregate Dashboard Request

curl -X GET http://localhost:8000/bff/aggregate/dashboard \
  -H "Authorization: Bearer <access_token>"

Response:

{
  "status": "success",
  "data": {
    "tasks": [...],
    "projects": [...],
    "goals": [...],
    "habits": [...],
    "todos": [...],
    "user": {...}
  },
  "errors": {},
  "timestamp": "2026-04-06T10:00:00Z"
}

Proxy Task Creation

curl -X POST http://localhost:8000/bff/app/tasks \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <access_token>" \
  -d '{
    "title": "New task",
    "priority": "high",
    "project_id": 1
  }'

Circuit Breaker Status

curl -X GET http://localhost:8000/health/circuit-breaker/status

Response:

{
  "auth_service": {
    "state": "CLOSED",
    "failures": 0,
    "last_failure": null
  },
  "app_service": {
    "state": "CLOSED",
    "failures": 0,
    "last_failure": null
  }
}

Configuration

Environment Variables

VariableDescriptionDefault
AUTH_SERVICE_URLAuth service URLhttp://localhost:5001
APP_SERVICE_URLCore-API URLhttp://localhost:5000
AUTH_JWT_SECRETJWT validation secretRequired
REDIS_URLRedis connectionredis://localhost:6379/0
REDIS_ENABLEDEnable Redisfalse
RATE_LIMITRequests per minute100

Docker

docker run -p 8000:8000 \
  -e AUTH_SERVICE_URL=http://auth-service:5001 \
  -e APP_SERVICE_URL=http://core-api:5000 \
  -e AUTH_JWT_SECRET=your-secret \
  -e REDIS_URL=redis://redis:6379/0 \
  -e REDIS_ENABLED=true \
  goalixa-bff:latest

Kubernetes Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: bff
spec:
  replicas: 3
  selector:
    matchLabels:
      app: bff
  template:
    metadata:
      labels:
        app: bff
    spec:
      containers:
      - name: bff
        image: goalixa/bff:latest
        ports:
        - containerPort: 8000
        env:
        - name: AUTH_SERVICE_URL
          value: http://auth-service:5001
        - name: APP_SERVICE_URL
          value: http://core-api:5000
        - name: AUTH_JWT_SECRET
          valueFrom:
            secretKeyRef:
              name: goalixa-secrets
              key: jwt-secret
        - name: REDIS_ENABLED
          value: "true"
        - name: REDIS_URL
          value: redis://redis:6379/0
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /liveness
            port: 8000
        readinessProbe:
          httpGet:
            path: /readiness
            port: 8000
---
apiVersion: v1
kind: Service
metadata:
  name: bff
spec:
  selector:
    app: bff
  ports:
  - port: 80
    targetPort: 8000

Metrics

MetricTypeDescription
bff_requests_totalCounterTotal requests
bff_request_duration_secondsHistogramRequest duration
bff_backend_requests_totalCounterBackend requests
bff_backend_duration_secondsHistogramBackend call duration
bff_circuit_breaker_stateGaugeCircuit breaker state
bff_cache_hits_totalCounterCache hits
bff_cache_misses_totalCounterCache misses
bff_rate_limited_totalCounterRate limited requests