Architecture
Overview
Closegram follows a monorepo structure managed by Turborepo. The frontend communicates with the backend exclusively through a GraphQL API, using Apollo Client for data fetching, caching, and real-time subscriptions.
Applications
| App | Port | Stack | Description |
|---|---|---|---|
apps/frontend-nextjs | 3000 | Next.js 14, App Router | Main web client |
apps/frontend-public | 3002 | CRA, React | Alternative/public web client |
apps/backend | 4000 | Apollo Server, Express | GraphQL API |
apps/docs | 3003 | Docusaurus 3 | This documentation site (English/Spanish) |
apps/ios | — | SwiftUI, Apollo iOS | Native iOS app |
Request flow
Web Browser / iOS App
↓
Apollo Client ←→ WebSocket (subscriptions)
↓
GraphQL API — apps/backend (Apollo Server + Express)
↓
Database / External Services (Firebase, Stripe, Google Cloud)
Frontend structure
The main web app (apps/frontend-nextjs) uses the Next.js App Router:
src/
app/ # Routes (App Router)
home/ # Feed page
messages/ # Chat page
profile/ # User profile
settings/ # Settings (nested routes)
coins/ # Coins & transactions
payments/ # Stripe payments
login/ # Auth
components/ # Shared UI components
page-components/ # Full-page components
hooks/ # Custom React hooks
contexts/ # React contexts (auth, theme)
apollo/ # Apollo client setup
i18n/ # Translation files
lib/ # Utilities
Backend structure
graphql/
types/ # GraphQL type definitions (one file per domain)
resolvers/ # Resolvers (one file per domain)
context/ # Auth helpers and WebSocket context
typeDefs.js # Combines all types
resolvers.js # Combines all resolvers
data-access-services/ # DB queries (one file per model)
validators/ # Input validation
constants/ # App-wide constants
utils/ # Helpers (Google Cloud, Stripe, etc.)
workers/ # Background jobs (notification.worker.js)
State management
- Server state: Apollo Client (normalized InMemoryCache)
- UI state: React Context (auth, theme, toasts)
- Form state: Local component state
Authentication flow
- User signs in via email/password, Apple, Google, or phone OTP
- Firebase validates credentials and returns an ID token
- The token is attached to every GraphQL request via Apollo's
authLink(Authorization: Bearer <token>) - The backend validates the token on each request using the Firebase Admin SDK
- The resolved user is placed in the GraphQL context and available to all resolvers
Real-time architecture
WebSocket subscriptions handle:
- New messages and message updates
- Typing indicators and read receipts
- Incoming calls and call status changes
- New conversations
The frontend uses Apollo's GraphQLWsLink for subscriptions and HttpLink for queries/mutations. A splitLink routes each operation to the correct transport.
iOS architecture
The iOS app (apps/ios) follows MVVM + Redux + Clean Architecture. Each feature module has its own Redux Store (State + Action + Reducer), a Repository abstraction, and SwiftUI views. See the iOS App technical doc for the full breakdown.
External services
| Service | Purpose |
|---|---|
| Firebase Auth | Identity and token management |
| Firebase Admin SDK | Token verification on the backend |
| Firebase Cloud Messaging | Push notifications (Android + Web) |
| Apple VoIP Push | Incoming call notifications on iOS |
| Stripe | Payment processing |
| Google Cloud Vision | Automatic image NSFW detection |
| Google Cloud Video Intelligence | Automatic video NSFW detection |