# Project Structure

When you run `paxx bootstrap myproject`, the following structure is created:

```
myproject/
├── main.py              # Application entry point & factory
├── settings.py          # Configuration (pydantic-settings)
├── conftest.py          # Pytest fixtures
├── alembic.ini          # Alembic configuration
├── pyproject.toml       # Project dependencies
├── .env                 # Environment variables (git-ignored)
├── .env.example         # Example environment variables
├── .gitignore           # Git ignore rules
├── README.md            # Project readme
├── core/                # Core utilities
│   ├── __init__.py
│   ├── exceptions.py    # Custom exceptions
│   ├── middleware.py    # Custom middleware
│   ├── dependencies.py  # FastAPI dependencies
│   └── schemas.py       # Shared Pydantic schemas
├── db/                  # Database
│   ├── __init__.py
│   ├── database.py      # Database setup & session
│   └── migrations/      # Alembic migrations
│       ├── env.py       # Alembic environment
│       ├── script.py.mako
│       └── versions/    # Migration files
└── features/            # Domain features
    └── .gitkeep
```

## Key Files

### `main.py`

The application entry point using the factory pattern:

```python
from fastapi import FastAPI

def create_app() -> FastAPI:
    app = FastAPI(title="myproject")

    # Register routers here
    # app.include_router(users_router, prefix="/users", tags=["Users"])

    return app

app = create_app()
```

### `settings.py`

Configuration using Pydantic Settings:

```python
from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    database_url: str = "sqlite+aiosqlite:///./app.db"
    debug: bool = False

    class Config:
        env_file = ".env"

settings = Settings()
```

### `db/database.py`

Async SQLAlchemy setup:

```python
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker, declarative_base

engine = create_async_engine(settings.database_url)
AsyncSessionLocal = sessionmaker(engine, class_=AsyncSession)
Base = declarative_base()
```

## Feature Structure

Each feature in `features/` follows this structure:

```
features/<name>/
├── __init__.py      # Feature exports
├── config.py        # Router configuration
├── models.py        # SQLAlchemy models
├── schemas.py       # Pydantic schemas
├── services.py      # Business logic
└── routes.py        # API endpoints
```

### `config.py`

Defines the router prefix and OpenAPI tags:

```python
from dataclasses import dataclass, field

@dataclass
class FeatureConfig:
    prefix: str = "/users"
    tags: list[str] = field(default_factory=lambda: ["Users"])
```

### `models.py`

SQLAlchemy models for the feature:

```python
from sqlalchemy import Column, Integer, String
from db.database import Base

class User(Base):
    __tablename__ = "users"

    id = Column(Integer, primary_key=True)
    email = Column(String, unique=True, nullable=False)
    name = Column(String)
```

### `schemas.py`

Pydantic schemas for request/response:

```python
from pydantic import BaseModel

class UserCreate(BaseModel):
    email: str
    name: str | None = None

class UserResponse(BaseModel):
    id: int
    email: str
    name: str | None

    class Config:
        from_attributes = True
```

### `services.py`

Business logic layer:

```python
from sqlalchemy.ext.asyncio import AsyncSession
from .models import User
from .schemas import UserCreate

async def create_user(db: AsyncSession, data: UserCreate) -> User:
    user = User(**data.model_dump())
    db.add(user)
    await db.commit()
    await db.refresh(user)
    return user
```

### `routes.py`

FastAPI router with endpoints:

```python
from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from core.dependencies import get_db
from . import services, schemas

router = APIRouter()

@router.post("/", response_model=schemas.UserResponse)
async def create_user(
    data: schemas.UserCreate,
    db: AsyncSession = Depends(get_db)
):
    return await services.create_user(db, data)
```

## Directory Conventions

| Directory | Purpose |
|-----------|---------|
| `core/` | Shared utilities, middleware, dependencies |
| `db/` | Database configuration and migrations |
| `features/` | Domain features (business logic) |

## Adding a Feature to main.py

After creating a feature, register it in `main.py`:

```python
from features.users.routes import router as users_router

def create_app() -> FastAPI:
    app = FastAPI()

    app.include_router(users_router, prefix="/users", tags=["Users"])

    return app
```

!!! tip "Automatic Registration"
    When using `paxx feature add`, the router is automatically registered in `main.py`.
