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
This commit is contained in:
138
docs/decisions/ADR-001-python-framework-selection.md
Normal file
138
docs/decisions/ADR-001-python-framework-selection.md
Normal file
@@ -0,0 +1,138 @@
|
||||
# 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
|
||||
```python
|
||||
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.
|
||||
Reference in New Issue
Block a user