Skip to content

Folder Structure

cms-backend/
├── app/
│   ├── main.py                                  # FastAPI app, CORS, middleware, router registration
│   ├── api/
│   │   └── router.py                            # Aggregates all feature routers
│   ├── core/
│   │   ├── config.py                            # Pydantic settings, .env parsing
│   │   ├── database.py                          # Engine, SessionLocal, get_db()
│   │   ├── security.py                          # Password hashing, JWT encode/decode
│   │   ├── dependencies.py                      # get_current_user, require_permission
│   │   ├── exceptions.py                        # Custom HTTP exceptions
│   │   ├── pagination.py                        # paginate(), page_to_skip()
│   │   ├── permissions.py                       # Permission constants
│   │   ├── logging.py                           # Structured logging setup
│   │   ├── seed.py                              # Main seed entry point
│   │   ├── seed_users.py                        # User/role seed data
│   │   └── seed_translations.py                 # Translation seed data
│   ├── middleware/
│   │   └── logging_middleware.py                # Request/response logging
│   ├── features/
│   │   ├── shared/                              # Shared base classes
│   │   │   ├── base_model.py                    # Base, UUIDMixin, TimestampMixin, SoftDeleteMixin
│   │   │   ├── base_repository.py               # BaseRepository with common CRUD
│   │   │   ├── base_schema.py                   # BaseSchema, UUIDSchema, TimestampSchema
│   │   │   └── pagination.py                    # PaginationMeta, PaginatedResponse
│   │   │
│   │   ├── auth/                                # Authentication & authorization domain
│   │   │   ├── router.py                        # /auth endpoints
│   │   │   ├── service.py                       # register, login, refresh, logout
│   │   │   ├── schemas.py                       # LoginRequest, TokenResponse, LoginResponse
│   │   │   ├── users/
│   │   │   │   ├── model.py                     # User model + user_roles pivot table
│   │   │   │   ├── repository.py
│   │   │   │   ├── schema.py                    # UserCreate, UserUpdate, UserResponse...
│   │   │   │   ├── service.py                   # CRUD, password change, role assignment
│   │   │   │   └── router.py                    # /users endpoints
│   │   │   ├── roles/
│   │   │   │   ├── model.py                     # Role model + role_permissions pivot table
│   │   │   │   ├── repository.py
│   │   │   │   ├── schema.py
│   │   │   │   ├── service.py
│   │   │   │   └── router.py                    # /roles endpoints
│   │   │   ├── permissions/
│   │   │   │   ├── model.py
│   │   │   │   ├── repository.py
│   │   │   │   ├── schema.py
│   │   │   │   ├── service.py
│   │   │   │   └── router.py                    # /permissions endpoints
│   │   │   └── tokens/
│   │   │       ├── model.py                     # RefreshToken model
│   │   │       └── repository.py
│   │   │
│   │   ├── translations/                        # Translation domain
│   │   │   ├── router.py                        # /translations public endpoints
│   │   │   ├── languages/
│   │   │   │   ├── model.py
│   │   │   │   ├── repository.py
│   │   │   │   ├── schema.py
│   │   │   │   ├── service.py
│   │   │   │   └── router.py                    # /languages endpoints
│   │   │   ├── labels/
│   │   │   │   ├── model.py
│   │   │   │   ├── repository.py
│   │   │   │   ├── schema.py
│   │   │   │   ├── service.py
│   │   │   │   └── router.py                    # /translation-labels endpoints
│   │   │   └── versions/
│   │   │       ├── model.py
│   │   │       ├── repository.py
│   │   │       ├── schema.py
│   │   │       ├── service.py
│   │   │       └── router.py                    # /translation-versions endpoints
│   │   │
│   │   └── cms/                                 # CMS domain
│   │       ├── categories/
│   │       │   ├── model.py
│   │       │   ├── translation_model.py
│   │       │   ├── repository.py
│   │       │   ├── translation_repository.py
│   │       │   ├── schema.py
│   │       │   ├── translation_schema.py
│   │       │   ├── service.py
│   │       │   └── router.py
│   │       ├── tags/
│   │       │   ├── model.py
│   │       │   ├── translation_model.py
│   │       │   ├── repository.py
│   │       │   ├── translation_repository.py
│   │       │   ├── schema.py
│   │       │   ├── translation_schema.py
│   │       │   ├── service.py
│   │       │   └── router.py
│   │       ├── media/
│   │       │   ├── model.py
│   │       │   ├── repository.py
│   │       │   ├── schema.py
│   │       │   ├── service.py
│   │       │   └── router.py
│   │       ├── posts/
│   │       │   ├── model.py                     # Post model + post_categories, post_tags pivots
│   │       │   ├── translation_model.py
│   │       │   ├── repository.py
│   │       │   ├── translation_repository.py
│   │       │   ├── schema.py
│   │       │   ├── translation_schema.py
│   │       │   ├── public_schema.py
│   │       │   ├── service.py
│   │       │   ├── public_service.py
│   │       │   ├── router.py
│   │       │   └── public_router.py
│   │       ├── pages/
│   │       │   ├── model.py
│   │       │   ├── section_model.py
│   │       │   ├── translation_model.py
│   │       │   ├── repository.py
│   │       │   ├── section_repository.py
│   │       │   ├── translation_repository.py
│   │       │   ├── schema.py
│   │       │   ├── section_schema.py
│   │       │   ├── translation_schema.py
│   │       │   ├── public_schema.py
│   │       │   ├── service.py
│   │       │   ├── section_service.py
│   │       │   ├── public_service.py
│   │       │   ├── router.py
│   │       │   └── public_router.py
│   │       ├── galleries/
│   │       │   ├── model.py
│   │       │   ├── media_model.py
│   │       │   ├── translation_model.py
│   │       │   ├── repository.py
│   │       │   ├── media_repository.py
│   │       │   ├── translation_repository.py
│   │       │   ├── schema.py
│   │       │   ├── media_schema.py
│   │       │   ├── translation_schema.py
│   │       │   ├── public_schema.py
│   │       │   ├── service.py
│   │       │   ├── public_service.py
│   │       │   ├── router.py
│   │       │   └── public_router.py
│   │       ├── sliders/
│   │       │   ├── model.py
│   │       │   ├── repository.py
│   │       │   ├── schema.py
│   │       │   ├── public_schema.py
│   │       │   ├── service.py
│   │       │   ├── public_service.py
│   │       │   ├── router.py
│   │       │   └── public_router.py
│   │       ├── navigation/
│   │       │   ├── model.py
│   │       │   ├── repository.py
│   │       │   ├── schema.py
│   │       │   ├── service.py
│   │       │   └── router.py
│   │       ├── site_settings/
│   │       │   ├── model.py
│   │       │   ├── repository.py
│   │       │   ├── schema.py
│   │       │   ├── service.py
│   │       │   └── router.py
│   │       └── forms/
│   │           ├── model.py
│   │           ├── repository.py
│   │           ├── schema.py
│   │           ├── service.py
│   │           └── router.py
│   └── mkdocs/                                  # This documentation
├── alembic/
│   ├── env.py                                   # Alembic environment config
│   ├── script.py.mako                           # Migration template
│   └── versions/                                # Generated migration files
├── .env                                         # Local environment (never commit)
├── .env.example                                 # Template for .env
├── alembic.ini
├── docker-compose.yml
├── Dockerfile
└── requirements.txt

Key Conventions

Naming — files are snake_case, classes are PascalCase, constants are UPPER_CASE.

Module structure — each module has its own folder with model.py, repository.py, schema.py, service.py, router.py. Modules with public (unauthenticated) endpoints have separate public_router.py and public_service.py files.

Pivot tables — many-to-many association tables are defined inside the model.py of the owning module (e.g. user_roles in auth/users/model.py, post_categories in cms/posts/model.py).

Imports — every folder has an __init__.py. Always import from the full module path, e.g. from app.features.cms.posts.model import Post.

One responsibility — every file does one thing. Routers contain no logic, services contain no SQL queries, repositories contain no business decisions.

Versioned API — all routes are under /api/v1/. When a breaking change is introduced, /api/v2/ is added in a new router without removing v1.

Public vs admin routes — public (unauthenticated) routes are in public_router.py and are registered before parameterized routes to avoid FastAPI path conflicts.