Files
Gondulf/docs/decisions/ADR-001-python-framework-selection.md
Phil Skentelbery 6d21442705 chore: initialize gondulf project structure
Set up Python project with uv environment management and FastAPI stack.

Project structure:
- src/gondulf/ - Main application package
- tests/ - Test suite directory
- pyproject.toml - Project configuration with dependencies
- README.md - Project documentation
- uv.lock - Dependency lock file

Dependencies configured:
- FastAPI + Uvicorn for web framework
- SQLAlchemy for database ORM
- pytest + coverage for testing
- ruff, black, mypy, flake8 for code quality
- Development environment using uv direct execution model

All project standards reviewed and implemented per:
- /docs/standards/coding.md
- /docs/standards/testing.md
- /docs/standards/git.md
- /docs/standards/development-environment.md
- /docs/standards/versioning.md
2025-11-20 10:42:10 -07:00

4.8 KiB

0001. Python Framework Selection for IndieAuth Server

Date: 2025-11-20

Status

Proposed

Context

We need to select a Python web framework for implementing the IndieAuth server. The requirements are:

  1. Must support OAuth 2.0/IndieAuth protocol implementation
  2. Must be simple and maintainable (avoiding Django per user requirement)
  3. Must handle async operations efficiently
  4. Must have good security features
  5. Must be production-ready and well-maintained
  6. Must not add unnecessary complexity

We evaluated several Python web frameworks considering our core value of simplicity.

Decision

Recommended Stack:

Web Framework: FastAPI

FastAPI is the recommended framework for this project.

Rationale:

  • Simplicity with Power: Clean, Pythonic API design that doesn't hide complexity
  • Type Hints: Native support for Python type hints with automatic validation
  • OAuth 2.0 Ready: Built-in OAuth 2.0 support that we can adapt for IndieAuth
  • Async First: Native async/await support for better performance
  • Automatic Documentation: OpenAPI/Swagger documentation generated automatically
  • Modern Python: Requires Python 3.10+ which aligns with our standards
  • No Magic: Explicit routing and dependency injection, no hidden behavior
  • Production Ready: Used by Microsoft, Netflix, Uber - battle-tested

Data Storage: SQLite with SQLAlchemy Core

Rationale:

  • Simplicity: SQLite for single-admin use case is perfect
  • SQLAlchemy Core: Direct SQL-like interface without ORM complexity
  • No Migrations Needed Initially: Simple schema we can manage directly
  • Upgrade Path: Can switch to PostgreSQL later if needed without code changes

Additional Libraries:

  • python-jose[cryptography]: For JWT token handling if needed
  • python-multipart: For form data handling
  • httpx: For HTTP client operations (fetching client metadata)
  • pydantic: Data validation (comes with FastAPI)
  • python-dotenv: Environment variable management
  • uvicorn: ASGI server for running FastAPI

Alternatives Considered

Flask

  • Pros: Minimal, mature, extensive ecosystem
  • Cons: Requires many extensions, no native async, more boilerplate for our needs

Starlette (FastAPI's base)

  • Pros: Even more minimal than FastAPI
  • Cons: Would need to build too much ourselves, against our simplicity principle

Tornado

  • Pros: Good async support, mature
  • Cons: Older patterns, less modern Python features, smaller ecosystem

aiohttp

  • Pros: Excellent async support
  • Cons: Lower-level, would require more custom code for OAuth flows

Consequences

Positive Consequences

  1. Rapid Development: FastAPI's automatic validation and documentation saves time
  2. Type Safety: Type hints catch errors early
  3. Clear Architecture: Explicit dependency injection makes data flow obvious
  4. Good Testing: FastAPI has excellent testing support with TestClient
  5. Performance: Async support handles concurrent requests efficiently
  6. Maintainability: Clear, explicit code that's easy to understand

Negative Consequences

  1. Newer Framework: FastAPI is newer than Flask (but very stable)
  2. Async Complexity: Developers need to understand async/await
  3. Fewer Examples: Fewer IndieAuth examples in FastAPI than Flask

Mitigation Strategies

  1. Use sync functions where async isn't needed - FastAPI supports both
  2. Provide clear documentation and examples
  3. Start with simple synchronous code, add async where beneficial

Implementation Plan

Basic Application Structure

from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import OAuth2AuthorizationCodeBearer

app = FastAPI(title="IndieAuth Server")

# Authorization endpoint
@app.get("/auth")
async def authorization_endpoint(
    response_type: str,
    client_id: str,
    redirect_uri: str,
    state: str,
    code_challenge: Optional[str] = None,
    code_challenge_method: Optional[str] = None
):
    """Handle IndieAuth authorization requests."""
    pass

# Token endpoint
@app.post("/token")
async def token_endpoint(
    grant_type: str,
    code: str,
    client_id: str,
    redirect_uri: str,
    code_verifier: Optional[str] = None
):
    """Exchange authorization code for access token."""
    pass

# Client registration endpoint
@app.post("/client/register")
async def client_registration_endpoint(
    client_name: str,
    redirect_uris: List[str]
):
    """Allow clients to self-register."""
    pass

This structure is clean, explicit, and follows the IndieAuth specification closely.

Recommendation

FastAPI provides the best balance of simplicity, modern features, and production-readiness for our IndieAuth server implementation. It aligns perfectly with our core value of simplicity while providing all necessary features for a compliant implementation.