Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -206,4 +206,4 @@ logs/
.black_cache/

# Documentation (internal tracking)
docs/temp/
temp/
12 changes: 0 additions & 12 deletions docs/Usage.md

This file was deleted.

247 changes: 118 additions & 129 deletions docs/advanced/architecture.md
Original file line number Diff line number Diff line change
@@ -1,167 +1,156 @@
# Architecture

This document describes the internal architecture of fastappkit.
Internal architecture overview of how fastappkit works.

## System Overview
## Component Overview

```
┌───────────────────────────────────────────────────────────────┐
│ fastappkit │
│ (Framework + CLI + Runtime) │
└───────────────────────────────────────────────────────────────┘
│ │
│ │
┌──────────▼──────────┐ ┌────────▼──────────┐
│ Developer │ │ fastappkit CLI │
│ (project author) │ │ (codegen + mgmt) │
└──────────┬──────────┘ └────────┬──────────┘
│ │
▼ ▼
┌───────────────────┐ ┌───────────────────┐
│ Internal Apps │ │ External Apps │
│ ./apps/<name> │ │ pip-installed │
│ shared timeline │ │ isolated timeline │
└──────────┬────────┘ └─────────┬─────────┘
│ │
▼ ▼
┌─────────────┐ ┌──────────────┐
│ FastAPI │ │ Alembic │
│ router │ │ per-app env │
└──────┬──────┘ └──────┬───────┘
│ │
└──────────┬────────────┘
┌──────────────────────────┐
│ Runtime Engine │
│ (loader + registry + db) │
└──────────────────────────┘
```

## Components

### CLI
fastappkit consists of several key components:

The CLI provides commands for:
- **AppLoader**: Discovers and loads apps from configuration
- **AppResolver**: Resolves app entries to actual locations
- **ManifestLoader**: Loads external app manifests
- **EntrypointLoader**: Loads and validates entrypoint functions
- **RouterAssembler**: Mounts routers to FastAPI app
- **MigrationRunner**: Executes migrations in correct order
- **MigrationOrderer**: Determines migration execution order
- **IsolationValidator**: Validates app isolation rules

- Project creation and management
- App creation and validation
- Migration management
- Development server
## App Loading Process

### Runtime Engine
### 1. Configuration Loading

The runtime engine handles:
```python
# Load fastappkit.toml
config = load_config(project_root)
apps_list = config.get("apps", [])
```

- App discovery and loading
- Manifest validation
- Router mounting
- Migration coordination
### 2. App Resolution

### App Loader
For each app entry:

Loads apps from configuration:
```python
# Internal app: "apps.blog"
if entry.startswith("apps."):
app_name = entry.split(".", 1)[1]
app_path = project_root / "apps" / app_name
# Verify exists and has __init__.py

1. Reads `fastappkit.toml`
2. Resolves app entries (internal vs external)
3. Loads manifests (external apps)
4. Validates apps
5. Builds registry
# External app: "payments"
else:
module = importlib.import_module(entry)
# Verify importable and has manifest
```

### App Registry
### 3. Manifest Loading

Stores metadata about loaded apps:
For external apps:

- App name and type
- Import path
- Migrations path
- Route prefix
- Manifest data
```python
# Load fastappkit.toml from package directory
manifest = load_manifest(app_info)
# Validate required fields
```

### Migration Runner
### 4. Entrypoint Validation

Coordinates migration execution:
```python
# Validate entrypoint is importable
entrypoint = manifest.get("entrypoint", f"{app_name}:register")
load_entrypoint(entrypoint, app_info.import_path)
```

- Core migrations (always first)
- Internal app migrations (shared timeline)
- External app migrations (isolated)
### 5. App Registration

## App Resolution
```python
# Execute register() function
router = register(app)
# Store router for mounting
```

The loader resolves apps in this order:
## Registration Execution

1. **Check `apps.*` pattern** (Internal apps)
- Example: `apps.blog` → Internal app
- Located in `./apps/blog/`
- Must have `__init__.py` in the directory
When `FastAppKit.create_app()` is called:

2. **Try as dotted import** (Python package name - External apps)
- Example: `fastapi_blog` → `import fastapi_blog` using `importlib.import_module()`
- If successful → External app (pip-installed)
- Must have `fastappkit.toml` manifest in package directory
1. **Create FastAPI app instance**
2. **Load all apps** via `AppLoader`
3. **Execute registrations** for each app:
```python
for app_metadata in registry.list():
router = execute_registration(app_metadata, app)
app_metadata.router = router
```
4. **Mount routers** via `RouterAssembler`

3. **Fail if:**
- Folder missing (internal apps)
- No Python package root (missing `__init__.py`)
- Cannot import module (external apps)
- No manifest (external apps only)
- Cannot determine app type
## Router Assembly

## App Loading (Fail-Fast)
After all apps are registered:

If ANY app fails to load, startup aborts.
1. **Mount routers** in order from `fastappkit.toml`
2. **Check for collisions** after all mounts
3. **Emit warnings** if collisions detected (not fatal)

Error details include:
```python
for app_metadata in registry.list():
if app_metadata.router:
prefix = app_metadata.prefix # From manifest or default
app.include_router(app_metadata.router, prefix=prefix)
```

- App identifier (path or name)
- Stage where failure occurred (resolve/load/register)
- Manifest snapshot
- Python traceback excerpt
- Suggested fixes
## Settings Management

### Initialization Flow

1. **Project defines Settings** in `core/config.py`
2. **Settings initialized** in `core/app.py`:
```python
settings = Settings() # Loads from .env
```
3. **FastAppKit created** with settings:
```python
kit = FastAppKit(settings=settings)
# Calls set_settings() internally
```
4. **Global access** via `get_settings()`:
```python
settings = get_settings() # Returns global instance
```

### CLI Commands

CLI commands use `ensure_settings_loaded()`:

```python
def ensure_settings_loaded(project_root: Path) -> None:
# Imports core.app, which initializes Settings
import core.app
```

There is no "skip this app and continue."
This ensures settings are available for migration commands.

## Settings System
## Migration System Internals

Settings flow:
### Migration Ordering

1. **Settings Definition** (in `core/config.py`)
- Uses Pydantic `BaseSettings`
- Loads from `.env` automatically
1. **Core** (always first)
2. **Internal apps** (from `fastappkit.toml` or `[tool.fastappkit.migration.order]`)
3. **External apps** (from `fastappkit.toml`)

2. **Settings Initialization** (in `core/app.py`)
- `Settings()` instance created
- `FastAppKit` initialized with settings
- `set_settings()` called (makes settings globally available)
### Version Tables

3. **Runtime Access**
- `get_settings()` retrieves global settings
- Available throughout application
- **Core + Internal**: `alembic_version` (shared)
- **External**: `alembic_version_<appname>` (per-app)

## Migration Engine Architecture
### Migration Execution

```
┌─────────────────────────────────────────────┐
│ Unified Migration Runner │
└─────────────────────────────────────────────┘
┌──────────┴──────────┐
▼ ▼
CORE MIGRATIONS APP MIGRATIONS
(per app)
internal → external
shared → isolated
│ │
└──────────┬──────────┘
┌───────────────────────┐
│ Alembic Multi-Env API │
└───────────────────────┘
DATABASE
```
For each app:
1. Build Alembic config
2. Load migration scripts
3. Check database state
4. Determine upgrade path
5. Execute migrations

## Learn More

- [Migration System](../topics/migration-system.md) - Migration architecture details
- [Extending fastappkit](extending-fastappkit.md) - How to extend fastappkit
- [Extending FastAppKit](extending-fastappkit.md) - Customization guide
- [Best Practices](best-practices.md) - Recommended patterns
Loading