High-Level Overview
Anchor follows a client-server architecture with offline-first capabilities:Technology Stack
Backend (Server)
- Framework: NestJS - A progressive Node.js framework
- Database: PostgreSQL - Relational database
- ORM: Prisma - Next-generation ORM
- Authentication: JWT (JSON Web Tokens) via Passport
- OIDC Support: OpenID Connect for SSO integration
Web Client
- Framework: Next.js 16 - React framework with App Router
- Language: TypeScript
- Styling: Tailwind CSS
- UI Components: shadcn/ui built on Radix UI
- State Management: Zustand for global state
- Data Fetching: TanStack Query for server state
- HTTP Client: ky - Modern fetch wrapper
- Rich Text Editor: react-quill-new - Quill wrapper
Mobile Client
- Framework: Flutter - Cross-platform UI toolkit
- State Management: Riverpod - Provider-based state management
- Local Database: Drift - Reactive SQLite wrapper
- Navigation: GoRouter - Declarative routing
- HTTP Client: Dio - Powerful HTTP client
- Rich Text Editor: Flutter Quill
Server Architecture
The server follows NestJS modular architecture:Core Modules
Key Features
Database Schema
The database uses Prisma with the following key models:- User: User accounts and profiles
- Note: Notes with rich text content
- Tag: Custom tags for organization
- NoteTag: Many-to-many relationship between notes and tags
- Share: Note sharing permissions (viewer/editor)
- RefreshToken: JWT refresh tokens
- Setting: System-wide settings (OIDC, registration)
Web Architecture
The web app uses Next.js App Router with a feature-based structure:Directory Structure
Data Flow
State Management Strategy
- Server State: Managed by TanStack Query (notes, tags, user data)
- UI State: Local component state with
useState - Global State: Zustand for authentication state and preferences
Mobile Architecture
The mobile app is offline-first with automatic sync:Architecture Pattern
Feature Structure
Offline-First Sync Strategy
Automatic Sync
When online, the app syncs using a bidirectional algorithm:
- Client sends dirty notes with timestamps
- Server returns conflicts and new server-side changes
- Client resolves conflicts (server wins by default)
Authentication Flow
JWT Authentication
- User submits credentials to
/api/auth/login - Server validates and returns:
accessToken(short-lived, 15 min)refreshToken(long-lived, 7 days, stored in DB)
- Client stores both tokens (localStorage for web, secure storage for mobile)
- API requests include
Authorization: Bearer <accessToken> - On expiry, client uses
/api/auth/refreshto get new access token
OIDC Authentication
- Client initiates OIDC flow via
/api/auth/oidc/initiate - User authenticates with external provider (Pocket ID, Authelia, etc.)
- Provider redirects to
/api/auth/oidc/callback - Server exchanges code for tokens and creates/links user account
- Returns Anchor JWT tokens to client
OIDC supports both confidential clients (with secret) and public clients (PKCE for mobile).
API Design
The server exposes a RESTful API with the following conventions:- Base URL:
/api - Authentication: Bearer token in
Authorizationheader - Response Format: JSON
- Error Format:
{ statusCode, message, error }
Endpoint Patterns
Deployment Architecture
For production deployment, Anchor uses a single Docker container:- Serves the Next.js web app (static files)
- Runs the NestJS API server
- Uses embedded PostgreSQL by default (can connect to external DB)
- Stores data in
/datavolume
Security Considerations
- Password Hashing: bcrypt with salt rounds
- JWT Secret: Auto-generated and persisted if not provided
- CORS: Configured per environment
- Helmet: Security headers for Express
- SQL Injection: Protected via Prisma ORM
- XSS: React auto-escaping + Content Security Policy
- OIDC: Supports PKCE for mobile public clients
Performance Optimizations
- Database Indexes: On frequently queried fields (userId, tagId, etc.)
- TanStack Query: Automatic caching and deduplication
- Next.js: Static page generation and code splitting
- Drift: Reactive streams for efficient mobile data access
- Lazy Loading: Components and routes loaded on-demand
Next Steps
Now that you understand the architecture:- Learn how to build for production
- Read the contribution guidelines
- Set up your development environment