A production-ready FastAPI boilerplate framework for building multi-tenant SaaS applications with JWT authentication, RBAC, payments, and more
Project description
Apex SaaS Framework
Build production-ready SaaS applications in minutes, not months!
A modern FastAPI framework for building multi-tenant SaaS applications. Get authentication, user management, organizations, roles, permissions, payments, and more with just 2 lines of code!
โก Super Quick Start
from apex import Apex
app = Apex().app
# That's it! You now have a complete SaaS backend! ๐
# Run with: uvicorn app:app --reload
You instantly get:
- โ Complete authentication (signup, login, password reset)
- โ User management with JSONB settings
- โ Organization management with multi-tenancy
- โ Role-based permissions (RBAC)
- โ PayPal payment integration
- โ Auto-created database tables
- โ
Interactive API docs at
/docs
๐ฆ Installation
From PyPI (Production - Recommended)
Simple installation:
pip install apex-saas-framework
That's it! No special flags needed! โ
From Test PyPI (For Testing)
If you want to test pre-release versions:
pip install --index-url https://pypi.org/simple/ --extra-index-url https://test.pypi.org/simple/ apex-saas-framework
๐ Features
- ๐ฏ Simple API - Minimal imports, maximum functionality
- ๐ข Multi-tenant Architecture - Organizations with row-level isolation
- ๐ฅ User Management - Complete user system with JWT authentication
- ๐ Authentication - Signup, login, forgot/reset password, change password
- ๐ก๏ธ RBAC - Role-based access control with permissions
- ๐ฆ Extensible Models - Extend base models using ORM inheritance
- ๐๏ธ PostgreSQL - SQLAlchemy 2.0 with async support
- ๐ณ PayPal Integration - Subscription management and webhooks
- โ๏ธ JSONB Settings - Flexible user and organization settings
- ๐จ Feature Flags - Module system for enabling/disabling features
- ๐ง Email Integration - SendGrid adapter with templates
- ๐ ๏ธ CLI Tools - Command-line utilities
- ๐ Auto-Documentation - Interactive API docs with FastAPI
๐ก Simple Examples
Minimal App (2 Lines!)
from apex import Apex
app = Apex().app
With Custom Models
from apex import Apex, User, Organization
from sqlalchemy import Column, String
class MyUser(User):
__tablename__ = "users"
department = Column(String(100))
app = Apex(models=[MyUser]).app
With Custom Endpoints
from apex import Apex, auth_required, User
app = Apex().app
@app.get("/api/profile")
@auth_required
async def get_profile(user: User):
return {"email": user.email, "name": user.first_name}
Fluent API Style
from apex import Apex
app = (
Apex()
.with_auth()
.with_payments()
.with_rbac()
.build()
)
๐ฏ Quick Start Guide
1. Create Your Models
Start by re-exporting the Apex defaults so each table is only registered once:
# app/models.py
from apex.app.models.default import (
Organization,
OrganizationLocation,
Permission,
Role,
User,
)
__all__ = ["Organization", "OrganizationLocation", "Permission", "Role", "User"]
Need custom columns? Create new subclasses (e.g.
class CustomUser(User): ...) in a separate module and update the dependency overrides (get_user_service,get_organization_model, etc.) to point at them. Avoid redefining the stock tables in placeโSQLAlchemy will raise โTable โฆ already definedโ otherwise.
2. Configure Settings
Copy .env.example to .env and update with your values:
cp .env.example .env
Minimum required configuration:
# Database (Required)
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
# Security (Required)
SECRET_KEY=your-secret-key-here-minimum-32-characters
Generate a secure secret key:
python -c "import secrets; print(secrets.token_urlsafe(32))"
See Configuration Reference below for all available options.
3. Set Up Database
# app/database.py
from apex.infrastructure.database import Base, engine
from app.models import User, Organization, Role, Permission
# Create tables
async def init_db():
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
4. Create Your FastAPI App
# app.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from apex.api.v1.auth.router import router as auth_router
from apex.core.authentication.dependencies import get_auth_service
from apex.core.config import get_settings
from app.dependencies import get_auth_service as project_get_auth_service
settings = get_settings()
app = FastAPI(
title=settings.APP_NAME,
version=settings.APP_VERSION,
debug=settings.DEBUG,
)
app.add_middleware(
CORSMiddleware,
allow_origins=settings.CORS_ORIGINS,
allow_credentials=settings.CORS_ALLOW_CREDENTIALS,
allow_methods=settings.CORS_ALLOW_METHODS,
allow_headers=settings.CORS_ALLOW_HEADERS,
)
app.dependency_overrides[get_auth_service] = project_get_auth_service
app.include_router(auth_router, prefix=settings.API_V1_PREFIX)
@app.get("/")
async def root():
return {"message": "Apex"}
5. Override Auth Service
# app/services.py
from apex.domain.services.auth import AuthService
from app.models import User
from sqlalchemy.ext.asyncio import AsyncSession
def get_auth_service(db: AsyncSession) -> AuthService:
return AuthService(session=db, user_model=User)
6. Run Migrations
Set up Alembic:
alembic init migrations
Copy apex/migrations/env.py to your project and modify it to import your models:
# migrations/env.py
from apex.infrastructure.database.base import Base
from app.models import User, Organization, Role, Permission
target_metadata = Base.metadata
Create and run migrations:
alembic revision --autogenerate -m "Initial migration"
alembic upgrade head
Architecture
Project Structure
apex/
โโโ core/ # Core functionality
โ โโโ config/ # Settings (Pydantic BaseSettings)
โ โโโ security/ # Password hashing, JWT utilities
โ โโโ authentication/ # Auth dependencies (get_current_user, etc.)
โ โโโ permissions/ # RBAC dependencies (require_role, require_permission)
โ โโโ utils/ # Utility functions
โโโ domain/ # Business logic layer
โ โโโ models/ # Base domain models (abstract)
โ โ โโโ user.py # BaseUser model
โ โ โโโ organization.py # BaseOrganization, BaseOrganizationLocation
โ โ โโโ role.py # BaseRole model
โ โ โโโ permission.py # BasePermission model
โ โโโ repositories/ # Repository pattern (BaseRepository)
โ โโโ services/ # Business services (AuthService, UserService)
โโโ infrastructure/ # External adapters
โ โโโ database/ # Database setup (SQLAlchemy async, session mgmt)
โ โโโ email/ # Email adapters (SMTP, abstract interface)
โ โโโ storage/ # File storage adapters (Local, S3-ready)
โ โโโ payments/ # Payment scaffolding (Stripe-ready)
โโโ api/ # API layer
โ โโโ v1/ # API version 1
โ โโโ auth/ # Authentication routes
โ โ โโโ router.py # Login, logout, refresh, me endpoints
โ โโโ schemas/ # Pydantic request/response schemas
โ โโโ auth.py # Auth schemas
โ โโโ user.py # User schemas
โโโ migrations/ # Alembic templates
โ โโโ env.py # Alembic environment (copy to user project)
โ โโโ script.py.mako # Migration script template
โโโ cli/ # CLI utilities (Typer)
โโโ main.py # CLI commands (version, check, init-db, etc.)
Design Principles
- Clean Architecture - Separation of concerns with clear layers
- Extensibility - Extend base classes, don't modify them
- Type Safety - Full type hints throughout
- Async First - Built for async/await patterns
- Framework Agnostic Core - Business logic independent of FastAPI
Usage Examples
Authentication
from apex.domain.services.auth import AuthService
from app.models import User
# Login
auth_service = AuthService(session=db, user_model=User)
user = await auth_service.authenticate_user("user@example.com", "password")
tokens = await auth_service.create_tokens(user)
User Management
from apex.domain.services.user import UserService
user_service = UserService(session=db, user_model=User)
# Create user
user = await user_service.create_user(
email="user@example.com",
password="securepassword",
full_name="John Doe",
)
# Update user
await user_service.update_user(user, full_name="Jane Doe")
# Change password
await user_service.change_password(user, "oldpass", "newpass")
Permissions
from apex.core.permissions import require_permission, require_role
# In your router
@router.post("/users")
async def create_user(
current_user: dict = Depends(require_permission("users", "create"))
):
# User has "users:create" permission
pass
@router.delete("/users/{id}")
async def delete_user(
id: str,
current_user: dict = Depends(require_role("admin"))
):
# User has "admin" role
pass
File Storage
from apex.infrastructure.storage import LocalStorageAdapter
storage = LocalStorageAdapter()
# Upload file
file_path = await storage.upload_file(
file=uploaded_file,
filename="document.pdf",
folder="documents"
)
# Get file URL
url = await storage.get_file_url(file_path)
from apex.infrastructure.email import SMTPEmailAdapter
email = SMTPEmailAdapter()
await email.send_email(
to="user@example.com",
subject="Welcome!",
body="Welcome to our platform",
html="<h1>Welcome!</h1>"
)
Configuration
All configuration is done via environment variables or .env file. Copy .env.example to .env and customize.
Required Settings
| Variable | Description | Example |
|---|---|---|
DATABASE_URL |
PostgreSQL connection string | postgresql://user:pass@localhost:5432/db |
SECRET_KEY |
JWT secret key (min 32 chars) | Generate with secrets.token_urlsafe(32) |
Application Settings
| Variable | Description | Default |
|---|---|---|
APP_NAME |
Application name | "Apex Backend" |
DEBUG |
Debug mode | False |
API_V1_PREFIX |
API version 1 prefix | "/api/v1" |
Database Settings
| Variable | Description | Default |
|---|---|---|
DB_ECHO |
Log SQL queries | False |
DB_POOL_SIZE |
Connection pool size | 5 |
DB_MAX_OVERFLOW |
Max overflow connections | 10 |
JWT/Auth Settings
| Variable | Description | Default |
|---|---|---|
ALGORITHM |
JWT algorithm | "HS256" |
ACCESS_TOKEN_EXPIRE_MINUTES |
Access token lifetime | 30 |
REFRESH_TOKEN_EXPIRE_DAYS |
Refresh token lifetime | 7 |
CORS Settings
| Variable | Description | Default |
|---|---|---|
CORS_ORIGINS |
Allowed origins (comma-separated) | "http://localhost:3000" |
CORS_ALLOW_CREDENTIALS |
Allow credentials | True |
CORS_ALLOW_METHODS |
Allowed HTTP methods | "GET,POST,PUT,DELETE,PATCH,OPTIONS" |
CORS_ALLOW_HEADERS |
Allowed headers | "*" |
Email Settings (Optional)
| Variable | Description | Example |
|---|---|---|
SMTP_HOST |
SMTP server | smtp.gmail.com |
SMTP_PORT |
SMTP port | 587 |
SMTP_USER |
SMTP username | your-email@gmail.com |
SMTP_PASSWORD |
SMTP password | Your app password |
SMTP_FROM_EMAIL |
From email address | noreply@yourdomain.com |
SMTP_USE_TLS |
Use TLS | True |
Storage Settings
| Variable | Description | Default |
|---|---|---|
STORAGE_TYPE |
Storage type (local or s3) |
"local" |
STORAGE_LOCAL_PATH |
Local storage path | "./uploads" |
AWS_ACCESS_KEY_ID |
AWS access key (if using S3) | - |
AWS_SECRET_ACCESS_KEY |
AWS secret key (if using S3) | - |
AWS_REGION |
AWS region (if using S3) | "us-east-1" |
AWS_S3_BUCKET |
S3 bucket name (if using S3) | - |
Payment Settings (Optional)
| Variable | Description | Example |
|---|---|---|
STRIPE_SECRET_KEY |
Stripe secret key | sk_test_... |
STRIPE_PUBLISHABLE_KEY |
Stripe publishable key | pk_test_... |
STRIPE_WEBHOOK_SECRET |
Stripe webhook secret | whsec_... |
Multi-tenancy
| Variable | Description | Default |
|---|---|---|
MULTI_TENANT_MODE |
Enable multi-tenancy | True |
CLI Commands
The apex command-line tool provides utilities for managing your application:
# Show package version
apex version
# Check configuration and database connection
apex check
# Initialize database (base implementation - extend in your app)
apex init-db
# Create superuser (base implementation - extend in your app)
apex create-superuser --email admin@example.com --password
Note: init-db and create-superuser are base implementations. You should extend these commands in your application to work with your specific User model.
Extending the Framework
Custom User Model
class User(BaseUser):
__tablename__ = "users"
# Add custom fields
avatar_url: Mapped[str | None] = None
bio: Mapped[str | None] = None
Custom Service
from apex.domain.services.user import UserService
class CustomUserService(UserService):
async def get_users_by_organization(self, org_id: str):
# Custom logic
pass
Custom Repository
from apex.domain.repositories.base import BaseRepository
class UserRepository(BaseRepository[User]):
async def get_by_email(self, email: str) -> User | None:
# Custom query
pass
Testing
from fastapi.testclient import TestClient
from apex.infrastructure.database import get_db
# Override database dependency
app.dependency_overrides[get_db] = get_test_db
client = TestClient(app)
response = client.post("/api/v1/auth/login", json={
"email": "test@example.com",
"password": "password"
})
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT License - see LICENSE file for details.
Project Files
pyproject.toml- Package configuration and dependencies.env.example- Template for environment variables (copy to.env).gitignore- Git ignore patterns.cursor/rules/cursorrules.mdc- Cursor AI editing rulesREADME.md- This file
Support
- ๐ Documentation
- ๐ Issue Tracker
- ๐ฌ Discussions
Roadmap
- S3 storage adapter implementation
- Stripe payment integration
- Audit logging system
- Module/feature flag system
- WebSocket support
- GraphQL support
- More comprehensive tests
- Docker deployment examples
Built with โค๏ธ using FastAPI, SQLAlchemy, and modern Python practices.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file apex_saas_framework-0.1.5.tar.gz.
File metadata
- Download URL: apex_saas_framework-0.1.5.tar.gz
- Upload date:
- Size: 86.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7c07fb851a3279567f873162fe4343fe36dc342e9491329936b5e093b8e598fb
|
|
| MD5 |
e421b101c3e9701982233b862b2c0c4d
|
|
| BLAKE2b-256 |
0302666c6c0f041dbbec2af0afa0030e27e2bfd1fd2ff445fd651c46896de612
|
File details
Details for the file apex_saas_framework-0.1.5-py3-none-any.whl.
File metadata
- Download URL: apex_saas_framework-0.1.5-py3-none-any.whl
- Upload date:
- Size: 111.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3c9f6351d8d036723326a34b867a3125eba4a08131fb5dce1e423cd0d04cb0b1
|
|
| MD5 |
f1984b09c2de27fc7ccbd579a33a18e5
|
|
| BLAKE2b-256 |
12a49eaa32d04530497a70322ea7e93b84e0f332ead43b291f7e717e7727afa0
|