Skip to content

Architecture Overview

This document describes the technical architecture of FastSvelte, a fullstack SaaS starter kit built with FastAPI and SvelteKit.

System Architecture

FastSvelte is organized as a monorepo containing four main components:

fastsvelte/
├── backend/          # FastAPI + Python (API server)
├── frontend/         # SvelteKit + TypeScript (Admin dashboard)
├── landing/          # SvelteKit (Marketing website)
├── db/              # PostgreSQL + Sqitch (Database migrations)
└── docs/            # MkDocs documentation

Component Interaction Flow

graph TB
    U[Users] --> L[Landing Page]
    U --> F[Frontend Dashboard]
    F --> B[Backend API]
    B --> D[PostgreSQL Database]
    B --> E[External Services]
    E --> S[Stripe, SendGrid, OAuth]

Backend Architecture (FastAPI)

The backend is structured in layers to separate HTTP handling, business logic, and data access.

Layer Structure

app/
├── main.py              # Application entry point
├── config/              # Settings & dependency injection
├── api/                 # HTTP layer
│   ├── route/          # API endpoints
│   ├── middleware/     # Request/response middleware
│   └── router.py       # Route registration
├── service/             # Business logic layer
├── data/repo/           # Data access layer
├── model/               # Request/response models
├── util/                # Shared utilities
└── exception/           # Custom exceptions

Key Design Patterns

Dependency Injection

The application uses dependency-injector to manage component dependencies. Services and repositories are injected rather than instantiated directly, which enables easier testing and loose coupling. Configuration is handled in app/config/container.py.

Repository Pattern

Database operations are encapsulated in repository classes located in app/data/repo/. These repositories return Pydantic models rather than raw database records. Examples include UserRepo and OrganizationRepo.

Service Layer

Business logic resides in service classes in app/service/. Services coordinate between repositories, handle validation and authorization, and implement application workflows.

Request Flow

flowchart LR
    A[HTTP Request] --> B[Route] --> C[Service] --> D[Repository] --> E[Database]

    B -.-> F[Validation]
    C -.-> G[Business Logic]

Frontend Architecture (SvelteKit)

The frontend is a Single Page Application built with SvelteKit that handles authentication through API calls.

Directory Structure

src/
├── routes/              # SvelteKit file-based routing
│   ├── (auth)/         # Login, signup, password reset
│   ├── (protected)/    # Dashboard, admin pages
│   └── +layout.svelte  # Global layout
├── lib/
│   ├── api/            # Generated API client
│   ├── auth/           # Authentication state
│   ├── components/     # Reusable UI components
│   └── utils/          # Shared utilities
└── app.html            # Root HTML template

Key Features

1. Session-Based Authentication

  • Backend creates HTTP-only session cookies (not JWT tokens)
  • With each API call, browser automatically sends the session cookie (see: frontend/src/lib/api/axios.js)
  • Frontend checks authentication by calling /users/me endpoint (see: frontend/src/lib/auth/session.ts)
  • Auth state managed with Svelte 5 runes in client-side store (see: frontend/src/lib/auth/auth.svelte.ts)
  • When API returns 401, frontend automatically clears auth state and redirects to login (see: frontend/src/lib/api/axios.js)
  • Cross-tab session synchronization via BroadcastChannel API (see: frontend/src/lib/auth/session.ts)
  • Rate-limited authentication checks to prevent excessive API calls (see: frontend/src/lib/auth/session.ts)

API Client Generation

The TypeScript API client is generated using Orval, which reads the backend's OpenAPI specification and creates type-safe request functions. This provides compile-time type checking for all API interactions. Generated code is located in src/lib/api/gen/.

Route Protection

Routes are organized into two groups: (auth) for public pages like login and signup, and (protected) for authenticated areas. The (auth) layout redirects already-authenticated users to the dashboard (see: frontend/src/routes/(auth)/+layout.svelte). The (protected) layout calls ensureAuthenticated() on mount to verify the user's session (see: frontend/src/routes/(protected)/+layout.svelte).

Both layouts use reactive authStore.isAuthenticated checks to show appropriate content or loading states. When the API returns a 401 error, the axios interceptor automatically clears the auth state and redirects to login (see: frontend/src/lib/api/axios.js). The backend validates sessions on every API request, ensuring data security regardless of frontend state.

State Management

// Auth store using Svelte 5 runes
class AuthStore {
  user = $state<UserWithRole | null>(null);
  isLoading = $state(true);

  get isAuthenticated(): boolean {
    return this.user !== null;
  }
}

Database Architecture

The application uses PostgreSQL with Sqitch for schema version management.

Schema Design

The database schema centers around users and organizations for multi-tenancy. Core tables include user for authentication, organization for tenant separation, role for permissions, and session for active user sessions. Business logic is supported by tables like plan for subscriptions, organization_plan for current subscriptions, settings tables (user_setting, organization_setting, system_setting) for configuration, and invitation for team member invitations.

Migration Management

Database schema changes are managed through Sqitch migrations in the db/ directory, with deploy/ scripts for forward changes, revert/ scripts for rollbacks, and verify/ scripts for validation.

Multi-Tenancy

The system supports both B2B (multiple users per organization) and B2C (one user per organization) modes. Data isolation is enforced through organization_id foreign keys. The mode is configured via the FS_MODE environment variable.

Authentication & Security

Session Management

sequenceDiagram
    participant F as Frontend
    participant Br as Browser
    participant B as Backend
    participant D as Database

    Note over F,D: User Login Flow
    F->>Br: POST /auth/login (credentials)
    Br->>B: Forward request
    B->>D: Validate user credentials
    D-->>B: User data
    B->>D: Create session record
    B->>B: Generate session token & hash it
    B-->>Br: Set HTTP-only cookie + response
    Br-->>F: Login success response

    Note over F,D: Authenticated Request Flow
    F->>Br: API request (withCredentials: true)
    Br->>B: Request + session cookie
    B->>B: Extract & validate cookie
    B->>D: Check session exists & not expired
    D-->>B: Session valid
    B-->>Br: Protected data response
    Br-->>F: Forward response

    Note over F,D: Session Validation
    F->>Br: GET /users/me (check auth status)
    Br->>B: Request + session cookie
    B->>D: Validate session
    D-->>B: User + role data
    B-->>Br: Current user response
    Br-->>F: Forward response
    F->>F: Update authStore.user

Security Implementation:

Session cookies are configured as HTTP-only with secure and SameSite settings to prevent XSS and CSRF attacks. Session tokens are stored hashed in the database and expire automatically. CORS protection is enabled with configurable allowed origins.

Authorization

The system implements role-based access control with three roles: member for basic user permissions, org_admin for organization management, and sys_admin for system-wide administration.

API endpoints are protected using FastAPI's Depends(get_current_user) dependency injection pattern. Role validation occurs at the service layer before processing requests.

External Integrations

The application integrates with third-party services for email, payments, and authentication.

Email (SendGrid)

Transactional emails for account verification and password reset are sent via SendGrid. Email templates are managed through the SendGrid dashboard, with environment-specific sender configurations.

Payments (Stripe)

Stripe handles subscription billing, including webhook processing for payment events, plan changes, and usage tracking. The integration supports both subscription and usage-based billing models.

OAuth (Google)

Google OAuth provides social login functionality. The implementation uses secure state parameters to prevent CSRF attacks and synchronizes user profile information from Google accounts.

Development Workflow

Type Safety

Type consistency is maintained from backend to frontend through code generation. Backend Pydantic models define the data structures, FastAPI automatically generates an OpenAPI specification, and Orval converts this specification into TypeScript client functions.

API Generation Flow

The development workflow involves three steps: updating backend models or endpoints, running npm run generate to regenerate the TypeScript client, and using the generated client in frontend code.

Environment Configuration

The application supports three deployment environments: dev for local development with Docker containers, beta for staging and pre-production testing, and prod for the live application.

Testing Strategy

Backend testing uses pytest for unit tests, repository tests run against a test database, and service tests use mocked dependencies. Frontend testing includes unit tests with Vitest, component tests using Vitest browser mode, and end-to-end tests with Playwright.

Configuration Management

Environment Variables

All configuration uses the FS_ prefix:

# Database
FS_DB_URL="postgres://..."

# Authentication
FS_JWT_SECRET_KEY="..."

# External services
FS_STRIPE_API_KEY="sk_..."
FS_SENDGRID_API_KEY="SG..."

Settings Architecture

The application implements a three-tier settings hierarchy: system settings for global configuration (stored in system_setting + system_setting_definition tables, managed via /admin/settings), organization settings for per-tenant configuration (using organization_setting + organization_setting_definition tables), and user settings for individual preferences (using user_setting + user_setting_definition tables, managed via /settings/user).

Settings do not cascade or fallback between levels. Each scope maintains explicit values for security and predictability.