Skip to content

Backend Architecture

Purpose

This document defines the backend architecture patterns, service communication, and domain boundaries for the Farmer1st platform.

Current State

Architecture Overview

┌─────────────────────────────────────────────────────────────────────────────┐
│                         BACKEND ARCHITECTURE                                │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   CLIENTS                                                                   │
│   ┌─────────────────┐    ┌─────────────────┐                               │
│   │   Farmer PWA    │    │ Stakeholder     │                               │
│   │   (React)       │    │ Portals (React) │                               │
│   └────────┬────────┘    └────────┬────────┘                               │
│            │                      │                                         │
│            └──────────┬───────────┘                                         │
│                       │ GraphQL                                             │
│                       ▼                                                     │
│   ┌─────────────────────────────────────────────────────────────────────┐  │
│   │                    BFF LAYER (GraphQL)                               │  │
│   │                                                                      │  │
│   │  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐   │  │
│   │  │  user-bff   │ │relationship-│ │ surveys-bff │ │payments-bff │   │  │
│   │  │             │ │    bff      │ │             │ │             │   │  │
│   │  │  GraphQL    │ │  GraphQL    │ │  GraphQL    │ │  GraphQL    │   │  │
│   │  └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘   │  │
│   │         │               │               │               │          │  │
│   └─────────┼───────────────┼───────────────┼───────────────┼──────────┘  │
│             │ REST          │ REST          │ REST          │ REST        │
│             ▼               ▼               ▼               ▼             │
│   ┌─────────────────────────────────────────────────────────────────────┐  │
│   │                 MICROSERVICES LAYER (REST)                          │  │
│   │                                                                      │  │
│   │  ┌─────────────────────────────────────────────────────────────┐    │  │
│   │  │ user-management namespace                                    │    │  │
│   │  │  ┌───────────┐ ┌───────────┐ ┌───────────┐                  │    │  │
│   │  │  │ auth-svc  │ │profile-svc│ │ prefs-svc │  ...             │    │  │
│   │  │  └───────────┘ └───────────┘ └───────────┘                  │    │  │
│   │  └─────────────────────────────────────────────────────────────┘    │  │
│   │                                                                      │  │
│   │  ┌─────────────────────────────────────────────────────────────┐    │  │
│   │  │ access-management namespace                                  │    │  │
│   │  │  ┌───────────┐ ┌───────────┐ ┌───────────┐                  │    │  │
│   │  │  │invite-svc │ │ fga-svc   │ │entity-svc │  ...             │    │  │
│   │  │  └───────────┘ └───────────┘ └───────────┘                  │    │  │
│   │  └─────────────────────────────────────────────────────────────┘    │  │
│   │                                                                      │  │
│   │  ┌─────────────────────────────────────────────────────────────┐    │  │
│   │  │ surveys namespace                                            │    │  │
│   │  │  ┌───────────┐ ┌───────────┐ ┌───────────┐                  │    │  │
│   │  │  │survey-svc │ │response-sv│ │analytics  │  ...             │    │  │
│   │  │  └───────────┘ └───────────┘ └───────────┘                  │    │  │
│   │  └─────────────────────────────────────────────────────────────┘    │  │
│   │                                                                      │  │
│   │  ┌─────────────────────────────────────────────────────────────┐    │  │
│   │  │ payments namespace                                           │    │  │
│   │  │  ┌───────────┐ ┌───────────┐ ┌───────────┐                  │    │  │
│   │  │  │points-svc │ │payout-svc │ │provider-sv│  ...             │    │  │
│   │  │  └───────────┘ └───────────┘ └───────────┘                  │    │  │
│   │  └─────────────────────────────────────────────────────────────┘    │  │
│   │                                                                      │  │
│   └─────────────────────────────────────────────────────────────────────┘  │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Decisions and Rationale

BFF Pattern (Backend for Frontend)

Decision Rationale
One BFF per domain Clear ownership, independent scaling, domain-specific GraphQL schemas
GraphQL at BFF layer Flexible queries for clients, reduces over-fetching, strong typing
BFF aggregates microservices Single entry point per domain, hides internal service complexity

Communication Patterns

Layer Protocol Rationale
Client → BFF GraphQL Flexible queries, client-driven data needs, strong typing
BFF → Microservices REST Simple, stateless, well-understood, easy to test
Service → Service REST + Kafka REST for sync, Kafka for async/events

Request Flow

┌─────────────────────────────────────────────────────────────────────────────┐
│                           REQUEST FLOW EXAMPLE                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   1. Farmer opens app, views their profile and surveys                      │
│      │                                                                      │
│      ▼                                                                      │
│   2. PWA sends GraphQL query:                                               │
│      query {                                                                │
│        me { name, farm { name, location } }      → user-bff                │
│        mySurveys { id, title, status }           → surveys-bff             │
│      }                                                                      │
│      │                                                                      │
│      ▼                                                                      │
│   3. user-bff receives "me" query                                          │
│      │                                                                      │
│      ├── GET /users/{id}           → profile-service                       │
│      └── GET /farms?owner={id}     → farm-service (or entity-service)      │
│      │                                                                      │
│      ▼                                                                      │
│   4. surveys-bff receives "mySurveys" query                                │
│      │                                                                      │
│      └── GET /surveys?user={id}    → survey-service                        │
│      │                                                                      │
│      ▼                                                                      │
│   5. BFFs aggregate responses, return unified GraphQL response             │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Domain Boundaries

Known Domains

Domain Namespace BFF Responsibilities
User Management user-management user-bff User profiles, authentication integration, preferences, farmer/stakeholder data
Access Management access-management relationship-bff Invitations, OpenFGA tuple management, entity relationships, data access authorization
Surveys surveys surveys-bff Survey creation, distribution, responses, analytics
Payments payments payments-bff Points system, payouts, payment provider integrations

Future Domains (TBD)

Potential Domain Possible Responsibilities
Farms Farm management, plots, crops, certifications
Traceability Supply chain tracking, product journey
Notifications Push notifications, SMS, email
Analytics Reporting, dashboards, insights

BFF Design Principles

1. Domain Ownership

Each BFF owns its GraphQL schema and is the single entry point for that domain.

user-bff          → owns: User, Profile, Preferences types
relationship-bff  → owns: Invitation, Relationship, Access types
surveys-bff       → owns: Survey, Question, Response types
payments-bff      → owns: Points, Payout, Transaction types

2. No Cross-BFF Calls

BFFs should not call each other. If data from multiple domains is needed: - Client makes parallel GraphQL queries to multiple BFFs - Or use Kafka events for eventual consistency

3. BFF Responsibilities

  • GraphQL schema definition and resolvers
  • Request validation
  • Aggregating data from multiple microservices
  • Response transformation for client needs
  • Caching (optional, at BFF level)

4. BFF Should NOT

  • Contain business logic (belongs in microservices)
  • Directly access databases (go through services)
  • Make synchronous calls to other BFFs

Microservice Design Principles

1. Single Responsibility

Each microservice handles one specific capability within its domain.

2. Own Your Data

Each microservice owns its data and exposes it only via APIs.

3. Stateless

Services are stateless; state lives in databases, caches, or message queues.

4. REST API Standards

  • RESTful resource naming
  • Standard HTTP methods (GET, POST, PUT, DELETE)
  • Consistent error responses
  • OpenAPI/Swagger documentation

Service Communication

Synchronous (REST)

Used for: Real-time queries, CRUD operations, immediate responses needed.

BFF → Service:     GET /users/{id}
Service → Service: POST /internal/validate-access

Asynchronous (Kafka)

Used for: Events, notifications, cross-domain updates, audit logging.

user-service → Kafka: UserCreated event
                ↓
access-management listens → Creates default OpenFGA tuples
surveys listens          → Initializes user survey preferences
payments listens         → Creates points account

Event-Driven Patterns

Event Producer Consumers
UserCreated user-management access-management, surveys, payments
InvitationAccepted access-management user-management, notifications
SurveyCompleted surveys payments (award points), analytics
PointsRedeemed payments notifications, analytics

Authorization Integration

All services integrate with OpenFGA for authorization checks:

┌─────────────────────────────────────────────────────────────────────────────┐
│                      AUTHORIZATION FLOW                                     │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   1. Request arrives at BFF with JWT                                        │
│      │                                                                      │
│   2. BFF extracts user ID from JWT                                         │
│      │                                                                      │
│   3. BFF (or service) calls OpenFGA:                                       │
│      Check(user:X, view, farm:Y)                                           │
│      │                                                                      │
│      ├── Allowed → Continue with request                                   │
│      └── Denied  → Return 403 Forbidden                                    │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Where to check authorization: - BFF level: For coarse-grained access (can user access this domain?) - Service level: For fine-grained access (can user access this specific resource?)

Technology Stack (Backend)

Component Technology Notes
Language Python All backend services
Web Framework TBD FastAPI recommended for REST services
GraphQL Framework TBD Strawberry, Ariadne, or Graphene
API Documentation OpenAPI/Swagger For REST microservices

Trade-offs Considered

GraphQL at BFF vs Gateway

BFF GraphQL (Chosen) Gateway GraphQL
✅ Domain-specific schemas ⚠️ Single massive schema
✅ Independent deployments ❌ Gateway becomes bottleneck
✅ Clear ownership ⚠️ Schema conflicts
⚠️ Multiple endpoints for clients ✅ Single endpoint

Decision: BFF-level GraphQL for clear domain boundaries and independent scaling.

REST vs GraphQL for Service-to-Service

REST (Chosen) GraphQL
✅ Simple, well-understood ⚠️ Overhead for internal calls
✅ Easy to test and debug ⚠️ Schema complexity
✅ Caching friendly ✅ Flexible queries
✅ OpenAPI tooling ⚠️ Less tooling for internal

Decision: REST for internal service communication; GraphQL complexity not needed internally.

Open Questions

  • Python GraphQL framework: Strawberry vs Ariadne vs Graphene?
  • Python REST framework: FastAPI vs Django REST vs Flask?
  • API versioning strategy?
  • Service mesh needed? (Istio, Linkerd)
  • Rate limiting strategy per BFF?
  • GraphQL federation needed in future?

Dependencies

  • Kubernetes namespaces (see 03-infrastructure-architecture.md)
  • Repository structure (see 11-repository-structure.md)
  • OpenFGA for authorization (see 08-authorization-architecture.md)
  • Kafka for async events (see 05-data-architecture.md)

Last Updated: 2025-12-25