Backend
- We work with uv. You can install it here
- Docker with docker compose. Install instructions.
Start the development server and start building!
If finished, shutdown the development server.
Development
make prod # Run a local production server
make docs # Run a local mkdocs server for documentation
make lint # Lint the code
make format # Format the code
Testing
Under the hood this runs:
The coverage report is printed on the console and is also generated as an HTML file found in htmlcov/index.html and can be directly viewable in a browser or by using a web server like the VSCode extension Five Server.
Project Organization
├── docs # A default mkdocs project; see www.mkdocs.org for details
├── docuisine # Source code for use in this project
├── scripts/dev # Docker-compose files for development database
├── tests # Unit tests
├── Makefile # Makefile with convenience commands like `make test` or `make format`
└── pyproject.toml # Dependencies list and project configuration
Building docker images
Building a production ready image from the repo:
docker build \
--no-cache \
--build-arg COMMIT_HASH=$(git rev-parse --short HEAD) \
--build-arg VERSION=$(uv version --short) \
-t iragca/docuisine:backend-$(uv version --short) \
-t iragca/docuisine:backend \
.
Then push to Docker Hub
Optionally remove them after pushing.
or build and run using docker compose:
docker compose build \
--no-cache \
--build-arg COMMIT_HASH=$(git rev-parse --short HEAD) \
--build-arg VERSION=$(uv version --short)
docker compose up
Microservices API
- The PostgreSQL should be accessible at port 5432
- The FastAPI backend should be accessible at port 7000
- The frontend should be accessible at port 8000
- The MinIO object storage should be at port 9000, web interface at 9001
Cloud Instances
Production backend: https://docuisine.vercel.app S3 Storage: https://f33f20a99cc658a06fff07a8ec5188ee.r2.cloudflarestorage.com S3 Public acces: https://pub-d3ef28b83a854575bfa54225e768a452.r2.dev
Identity Access Specification
Currently there are 3 roles with differing levels of access
Public- The default role, can view the website, but can't do much.User- Authenticated and identifiable user with permissions to create recipes. Has access to editing their own account or content they themselves have created.Admin- Can do everything, such as manage users, or manage content of other users.
Role permissions are simply a subset of the permissions of a higher level access role.
Everything Public can do, can be done by User and then some. Everything that can be done by User can be done by Admin and then some.
Route Access
No PUT or DELETE method should be accessible to Public aside from POST - /users/ when creating a user or POST - /auth/token when logging in.
Default developer accounts:
| Username | Role | Password | Password SHA256 hash | |
|---|---|---|---|---|
| dev-user | dev-user@docuisine.org | User | DevPassword1P! | 1920b94cd7cee322eaa299e703301f6a446c5ffe8da65e09b110880c9a02747e |
| dev-admin | dev-admin@docuisine.org | Admin | DevPassword2P! | 752b50d7be2843f1f3b2f6879e5c4fc235c32109781c21fdc938d1f1ce2b17be |
Users
| Method | Route | Access |
|---|---|---|
POST |
/users/ | Public |
PUT |
/users/email | Admin, User |
PUT |
/users/password | Admin, User |
DELETE |
/users/{user_id} | Admin, User |
Categories
| Method | Route | Access |
|---|---|---|
POST |
/categories/ | Admin |
PUT |
/categories/{category_id} | Admin |
DELETE |
/categories/{category_id} | Admin |
Stores
| Method | Route | Access |
|---|---|---|
POST |
/stores/ | Admin, User |
PUT |
/stores/{store_id} | Admin, User |
DELETE |
/stores/{store_id} | Admin, User |
Ingredients
| Method | Route | Access |
|---|---|---|
POST |
/ingredients/ | Admin, User |
PUT |
/ingredients/{ingredient_id} | Admin, User |
DELETE |
/ingredients/{ingredient_id} | Admin, User |
Recipes
| Method | Route | Access |
|---|---|---|
POST |
/recipes/ | Admin, User |
PUT |
/recipes/{recipe_id} | Admin, User |
DELETE |
/recipes/{recipe_id} | Admin, User |
Style Guide
These are style guides for both Python code and the database schema.
Project, Folder & File Names
Rules
- lowercase
- snake_case
- nouns for folders
- verbs only when it’s an action module
- no hyphens
Examples
app/
├── main.py
├── api/
│ ├── v1/
│ │ ├── routes/
│ │ │ ├── users.py
│ │ │ ├── recipes.py
│ │ │ └── auth.py
│ │ ├── dependencies.py
│ │ └── schemas/
│ │ ├── user.py
│ │ └── recipe.py
├── core/
│ ├── config.py
│ ├── security.py
│ └── logging.py
├── models/
│ ├── user.py
│ ├── recipe.py
│ └── ingredient.py
├── services/
│ ├── user_service.py
│ └── recipe_service.py
├── db/
│ ├── base.py
│ ├── session.py
│ └── migrations/
└── tests/
Avoid
Python Class Names
Use PascalCase
- Pydantic models
- SQLAlchemy models
- Service classes
- Exceptions
Avoid
Function & Method Names
Use snake_case
- Verbs for actions
- Clear, explicit names
FastAPI path operations
Variable Names
Rules
snake_case- Descriptive
- Avoid abbreviations unless common (
id,db,api)
Avoid
Constants
Use UPPER_SNAKE_CASE
Database Table Names
-
Use snake_case
-
Use plural nouns
-
Be consistent
This matches:
- PostgreSQL conventions
- SQLAlchemy defaults
- REST naming
Avoid
Database Column Names
Rules
snake_case- Descriptive
- No table name prefix
- Avoid reserved words
Avoid
SQLAlchemy Model Naming (Best Practice)
Class ↔ Table mapping
class Recipe(Base):
__tablename__ = "recipes"
id = Column(Integer, primary_key=True)
user_id = Column(ForeignKey("users.id"))
title = Column(String)
Pydantic Schema Naming
Suffix-based clarity
API Route Naming
REST-style, plural nouns
GET /api/v1/recipes
POST /api/v1/recipes
GET /api/v1/recipes/{id}
PUT /api/v1/recipes/{id}
DELETE /api/v1/recipes/{id}
Avoid
Test File Naming (pytest)
Test functions:
Type Hints & Docstrings (Strongly Recommended)
def create_recipe(
db: Session,
user_id: int,
data: RecipeCreate,
) -> Recipe:
"""Create a new recipe for a user."""
Linters & Formatters
Required
Recommended config
API response messages
Messages that contain string variable values should be single-quoted, otherwise if numeric use no quotes at all.
String response:
Numeric response:
Docstrings
We use the NumPy style for writing docstrigns
Golden Rule (Very Important)
Python names → snake_case > Classes → PascalCase > DB tables → plural snake_case > DB columns → snake_case