Archive completed GraphQL API implementation proposal: - Move proposal to openspec/changes/archive/2025-11-20-add-graphql-member-api/ - Create capability specs in openspec/specs/: - database-layer: SQLAlchemy async with Alembic migrations - graphql-api: Strawberry GraphQL with FastAPI integration - member-crud: Member management with conditional validation - project-setup: Python 3.11+ with uv package manager All 73 tasks completed and validated. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
6.9 KiB
project-setup Specification
Purpose
TBD - created by archiving change add-graphql-member-api. Update Purpose after archive.
Requirements
Requirement: Python project structure with uv dependency management
The project MUST use Python 3.11+ with uv for fast, reliable dependency management and provide a standard src/ layout for code organization.
Scenario: Developer initializes new development environment
Given a developer has cloned the repository
When they run uv sync
Then all dependencies are installed in a virtual environment
And the environment is ready for development within 30 seconds
Scenario: Developer runs the application
Given dependencies are installed
When developer runs uv run uvicorn src.main:app --reload
Then the FastAPI server starts on http://localhost:8000
And GraphQL playground is available at http://localhost:8000/graphql
Requirement: Project configuration in pyproject.toml
The project MUST define all metadata, dependencies, and tool configurations in pyproject.toml following modern Python packaging standards.
Dependencies required:
- fastapi >= 0.104.0 (Web framework)
- strawberry-graphql[fastapi] >= 0.215.0 (GraphQL integration)
- sqlalchemy[asyncio] >= 2.0.0 (ORM with async support)
- aiosqlite >= 0.19.0 (Async SQLite driver)
- alembic >= 1.12.0 (Database migrations)
- pydantic-settings >= 2.0.0 (Configuration management)
- uvicorn[standard] >= 0.24.0 (ASGI server)
Development dependencies required:
- pytest >= 7.4.0 (Test framework)
- pytest-asyncio >= 0.21.0 (Async test support)
- black >= 23.0.0 (Code formatting)
- ruff >= 0.1.0 (Linting)
- isort >= 5.12.0 (Import sorting)
Scenario: Dependencies are declared with version constraints
Given pyproject.toml exists When developer inspects [project.dependencies] Then all required packages are listed with minimum versions And version constraints allow patch/minor updates
Scenario: Development tools are configured
Given pyproject.toml contains tool configurations
When developer runs black .
Then code is formatted with line length 88
When developer runs ruff check .
Then code is linted against configured rules
Requirement: Source directory structure following layered architecture
The project MUST organize code into src/ directory with clear separation of concerns across API, business logic, and data layers.
Required directory structure:
src/
├── __init__.py
├── main.py # FastAPI application, startup/shutdown
├── config.py # Settings and configuration
├── database.py # Database connection, session factory
├── models/ # SQLAlchemy ORM models
│ ├── __init__.py
│ └── member.py
├── schemas/ # Strawberry GraphQL types
│ ├── __init__.py
│ └── member.py
└── resolvers/ # GraphQL query/mutation resolvers
├── __init__.py
└── member.py
Scenario: Code is organized by architectural layer
Given the src/ directory exists When a developer navigates the codebase Then models/ contains only SQLAlchemy ORM definitions And schemas/ contains only Strawberry GraphQL type definitions And resolvers/ contains only GraphQL resolver functions And each module has clear, single responsibility
Scenario: Main application entry point is defined
Given src/main.py exists
When the file is imported
Then it exports a FastAPI app instance
And app includes GraphQL route at /graphql
And app includes startup event to verify database connection
Requirement: Testing infrastructure with pytest
The project MUST provide pytest configuration for running async tests with database fixtures and code coverage reporting.
Scenario: Async tests can be executed
Given pytest and pytest-asyncio are installed
When developer runs pytest
Then all tests in tests/ directory are discovered
And async test functions execute correctly
And test results are displayed with pass/fail status
Scenario: Database fixtures are available for tests
Given tests/conftest.py defines database fixtures
When a test function requests db_session fixture
Then an isolated test database session is provided
And session is rolled back after test completion
And no test data persists between test runs
Requirement: Code quality tooling configuration
The project MUST configure black, ruff, and isort for consistent code formatting and linting with settings in pyproject.toml.
Black configuration:
- Line length: 88 characters
- Target version: Python 3.11
- Skip string normalization: false
Ruff configuration:
- Line length: 88 characters
- Select: E, F, W, I (pycodestyle, pyflakes, warnings, isort)
- Ignore: E501 (line too long, handled by black)
Isort configuration:
- Profile: black (compatible settings)
- Multi-line output: 3 (vertical hanging indent)
Scenario: Code formatting is enforced
Given black is configured in pyproject.toml
When developer runs black --check .
Then all Python files are checked for formatting
And exit code is 0 if all files are formatted correctly
And exit code is 1 if any files need formatting
Scenario: Code quality checks pass
Given ruff is configured in pyproject.toml
When developer runs ruff check .
Then all Python files are linted
And no errors are reported for compliant code
And clear error messages are shown for violations
Requirement: Environment configuration with .env support
The project MUST support environment-based configuration using .env files with pydantic-settings for type-safe config values.
Scenario: Default configuration works for development
Given no .env file exists When application starts Then it uses default SQLite database path And it runs in debug mode And application starts successfully
Scenario: Environment variables override defaults
Given .env file contains DATABASE_URL=sqlite+aiosqlite:///./test.db
When application loads configuration
Then settings.database_url equals "sqlite+aiosqlite:///./test.db"
And custom database path is used
Scenario: Configuration is type-safe
Given src/config.py defines Settings class When invalid configuration value is provided Then pydantic validation raises clear error And application fails fast on startup
Requirement: Development scripts for common tasks
The project MUST provide executable scripts for database seeding and common development tasks.
Required scripts:
- scripts/seed.py - Populate database with sample member
Scenario: Seed script creates sample data
Given database schema exists from migrations
When developer runs uv run python scripts/seed.py
Then sample member is created in database
And script is idempotent (safe to run multiple times)
And success message is displayed