KAHIBARO
Discord Login Register

Documentation

Why Documentation Matters in a Production Backend

Good documentation turns your backend from a mysterious black box into a system that others can safely use, maintain, and extend. For a production project, documentation is not optional. It is part of the product.

You do not need to write a book. You need clear, focused documents that answer concrete questions for specific audiences: developers, operators, and API consumers.

In this chapter you will learn what to document for your final project, how to structure it, and see concrete examples you can adapt directly.

Rule: If someone cannot deploy, run, use, or debug your backend without talking to you, your documentation is incomplete.


Types of Documentation You Need

For a production backend, aim for at least these main categories:

TypePrimary audiencePurpose
High-level overviewNew developers, stakeholdersWhat the system does and how it is structured
Setup & development guideDevelopersHow to run and work on the project locally
Deployment & operationsDevOps, SRE, you-in-6-monthsHow to deploy, configure, and maintain it
API documentationFrontend devs, integratorsHow to call the API and what to expect
Security & secretsDevelopers, opsHow sensitive data is handled
Testing & QADevelopers, QAHow to run tests and check system health
TroubleshootingOn-call engineersHow to debug common problems

You can put these in different files, or group some together. For a final project, a compact but complete set might be:

You do not have to match these names exactly, but keep the ideas.


Writing a Good README

The README.md is usually the first file someone sees. It must answer:

At minimum, include:

  1. Project description
  2. Quick start (development)
  3. Requirements
  4. Basic usage
  5. Links to other documentation

Example README Structure

Below is a template you can adapt. Replace names and commands with your own.

markdown
# TaskHub Backend
TaskHub is a production-ready REST API for managing tasks, users, and teams.  
Tech stack: FastAPI, PostgreSQL, Redis, Celery, Docker.
## Features
- User registration, login, JWT-based authentication
- Role-based authorization (user, admin)
- Task CRUD endpoints with filtering and pagination
- Background jobs for sending emails and processing reports
- Caching for frequently accessed endpoints
- Dockerized for easy local development and deployment
## Quick Start (Development)
### Prerequisites
- Docker and Docker Compose installed
- `make` (optional, for convenience)
### 1. Clone the repository
```bash
git clone https://github.com/yourname/taskhub-backend.git
cd taskhub-backend

2. Create environment file

Copy the example env file and adjust values if needed:

bash
cp .env.example .env

3. Start services

bash
docker compose up --build

The API will be available at: http://localhost:8000

API docs: http://localhost:8000/docs

4. Run tests

bash
docker compose run --rm api pytest

Project Structure

text
.
β”œβ”€ app/
β”‚  β”œβ”€ api/           # API routes
β”‚  β”œβ”€ core/          # Configuration, security, dependencies
β”‚  β”œβ”€ db/            # Models, migrations, database session
β”‚  β”œβ”€ services/      # Business logic, external integrations
β”‚  β”œβ”€ workers/       # Celery tasks
β”‚  └─ main.py        # FastAPI application entrypoint
β”œβ”€ migrations/       # Alembic migrations
β”œβ”€ tests/            # Test suite
β”œβ”€ docker/           # Docker-related config
└─ docs/             # Additional documentation

Documentation


Focus on making the README actionable. Someone should be able to run the app locally in a few minutes following it.
:::danger
**Rule:** Your README must contain a working, copy-pasteable sequence of commands to start the app locally.
:::
# Architectural Documentation
Your architecture documentation explains how the system is put together and why it is designed that way. It is not a full backend textbook, it is a map for your specific project.
## What to Include
At minimum:
- Short system overview
- Main components and responsibilities
- Data flow through the system
- Key models / entities and main relationships
- External dependencies (databases, queues, storage, etc)
- Important design decisions and tradeoffs
## Example: Architecture Summary
```markdown
# Architecture
## Overview
TaskHub Backend is a monolithic FastAPI application using a layered architecture:
- **API layer**: HTTP endpoints and request/response models.
- **Service layer**: Business logic (tasks, users, notifications).
- **Persistence layer**: SQLAlchemy models and repository classes.
- **Infrastructure**: PostgreSQL, Redis, Celery, S3-compatible storage.
## Components
- **FastAPI application (`app/main.py`)**
  - Creates FastAPI instance
  - Includes API routers
  - Configures middleware, exception handlers, and startup/shutdown hooks
- **API Routers (`app/api/`)**
  - Group endpoints by domain: `users`, `auth`, `tasks`, `admin`
  - Handle input validation using Pydantic models
  - Delegate to services for business logic
- **Services (`app/services/`)**
  - `user_service.py`: registration, login, profile management
  - `task_service.py`: create/update/complete tasks, permissions
  - `email_service.py`: send verification and reset-password emails
  - Services depend on repositories and other services
- **Repositories (`app/db/repositories/`)**
  - Encapsulate all direct database access
  - Expose methods like `get_user_by_email`, `list_tasks_for_user`
  - Implemented using SQLAlchemy ORM and sessions
- **Database models (`app/db/models.py`)**
  - SQLAlchemy models describing PostgreSQL tables
  - Main entities: `User`, `Role`, `Task`, `Project`, `RefreshToken`
- **Background Workers (`app/workers/`)**
  - Celery tasks: `send_email`, `cleanup_expired_tokens`
  - Use Redis as message broker and result backend
- **Caching**
  - Redis used to cache:
    - Auth token blacklist
    - Frequently accessed task lists for dashboards
## Data Flow Example: Creating a Task
1. Client sends `POST /tasks` with JSON payload.
2. `api.tasks.create_task` endpoint validates input using `TaskCreate` model.
3. Endpoint calls `task_service.create_task(user_id, task_in)`.
4. Service performs permission checks, then calls `task_repository.create(...)`.
5. Repository creates SQLAlchemy `Task` instance and commits to PostgreSQL.
6. Service may trigger background `send_task_created_email` Celery task.
7. Endpoint returns `TaskRead` response model to the client.
## External Dependencies
- **PostgreSQL**
  - Primary relational database
  - Stores users, tasks, projects, and audit logs
- **Redis**
  - Cache, Celery message broker, and rate limiting store
- **Object Storage**
  - S3-compatible storage for file attachments
  - Accessed via `storage_service` abstraction
## Key Design Decisions
- **Monolith instead of microservices**
  - Single codebase and deployment is simpler for this project size.
  - Easier local development and testing.
- **Service + Repository pattern**
  - Keeps business logic separate from API and database details.
  - Makes it easier to test services without hitting the database.
- **JWT for stateless auth**
  - Scales horizontally without sticky sessions.
  - Refresh tokens stored in database for security.

Use diagrams if you like, but simple text descriptions are fine for a small to medium project.


API Documentation and OpenAPI

Your API is how others interact with your backend. For production, you must clearly describe:

For a FastAPI project, you already get OpenAPI and interactive docs at /docs. You should still add:

Documenting Authentication and Conventions

Create docs/api.md to explain how to use the API overall, without listing every field twice.

Example:

markdown
# API Usage Guide
Base URL (production):
- `https://api.taskhub.example.com`
Base URL (development):
- `http://localhost:8000`
## Authentication
Most endpoints require a Bearer token.
1. Register: `POST /auth/register`
2. Login: `POST /auth/login`
3. Use the `access_token` in the `Authorization` header:
```http
Authorization: Bearer <access_token>

Access tokens expire after 15 minutes. Use POST /auth/refresh with your refresh token to get a new access token.

Error Format

All errors follow this JSON structure:

json
{
  "detail": "Human-readable error message",
  "code": "ERROR_CODE",
  "fields": {
    "field_name": ["description of problem"]
  }
}

Examples:

Pagination

List endpoints are paginated using limit and offset query parameters:

Response format:

json
{
  "items": [ ... ],
  "total": 123,
  "limit": 20,
  "offset": 0
}

Common Endpoints

For full interactive documentation see /docs.

Tasks

Query params:

Request body:

json
  {
    "title": "Write documentation",
    "description": "Document the TaskHub API",
    "due_date": "2026-09-01T12:00:00Z",
    "priority": "high"
  }

Response 201 Created:

json
  {
    "id": 42,
    "title": "Write documentation",
    "description": "Document the TaskHub API",
    "status": "open",
    "priority": "high",
    "due_date": "2026-09-01T12:00:00Z",
    "created_at": "2026-08-28T10:00:00Z",
    "updated_at": "2026-08-28T10:00:00Z"
  }

You do not need to write every single endpoint by hand if your OpenAPI spec is clear, but a guide like this helps users understand the general rules quickly.
:::danger
**Rule:** Document how to authenticate, how pagination works, and what error format you use, even if the OpenAPI schema exists.
:::
# Configuration and Environment Documentation
Your app uses configuration through environment variables or config files. If these are not documented, deployment and local setup become guesswork.
Create a section or a file such as `docs/configuration.md` (or include it in deployment docs) that lists:
- All required environment variables
- Optional ones and their defaults
- Accepted values and purpose
## Example: Environment Variables Table
```markdown
# Configuration
The application is configured through environment variables. For development you can use the `.env` file.
| Variable                     | Required | Default                    | Description                                      |
|-----------------------------|----------|----------------------------|--------------------------------------------------|
| `APP_ENV`                   | no       | `development`              | Environment name (`development`, `production`)   |
| `APP_PORT`                  | no       | `8000`                     | Port for the API server                          |
| `DATABASE_URL`              | yes      |                            | PostgreSQL URL, e.g. `postgresql+psycopg://...`  |
| `REDIS_URL`                 | yes      |                            | Redis URL for cache and Celery                   |
| `SECRET_KEY`                | yes      |                            | Random secret key for JWT signing                |
| `ACCESS_TOKEN_EXPIRE_MIN`   | no       | `15`                       | Access token lifetime in minutes                 |
| `REFRESH_TOKEN_EXPIRE_DAYS` | no       | `7`                        | Refresh token lifetime in days                   |
| `SMTP_HOST`                 | yes*     |                            | SMTP server for sending email                    |
| `SMTP_PORT`                 | no       | `587`                      | SMTP server port                                 |
| `SMTP_USER`                 | yes*     |                            | SMTP username                                    |
| `SMTP_PASSWORD`             | yes*     |                            | SMTP password                                    |
| `EMAIL_FROM`                | yes*     |                            | Default from address for emails                  |
| `S3_ENDPOINT_URL`           | no       |                            | S3-compatible storage endpoint                   |
| `S3_ACCESS_KEY_ID`          | no       |                            | S3 access key                                    |
| `S3_SECRET_ACCESS_KEY`      | no       |                            | S3 secret key                                    |
| `S3_BUCKET_NAME`            | no       |                            | S3 bucket for file uploads                       |
\*Required only if email features are enabled.

Document any configuration that affects behavior in production, such as feature flags or rate limiting thresholds.


Deployment and Operations Documentation

Deployment documentation is for running your app in production, not just locally. It should describe:

You can keep this in docs/deployment.md.

Example: Basic Deployment Guide

markdown
# Deployment Guide
This document describes how to deploy TaskHub Backend to a Linux server using Docker Compose.
## Requirements
- Linux server (Ubuntu 22.04 or similar)
- Docker and Docker Compose installed
- Domain name pointing to server IP (optional, for HTTPS)
## 1. Clone the repository on the server
```bash
git clone https://github.com/yourname/taskhub-backend.git
cd taskhub-backend

2. Create production environment file

bash
cp .env.example .env
nano .env

Set at least:

3. Start services

bash
docker compose -f docker-compose.prod.yml up -d

This will start:

4. Run database migrations

bash
docker compose -f docker-compose.prod.yml exec api alembic upgrade head

5. Health Check

json
{ "status": "ok" }
bash
docker compose -f docker-compose.prod.yml logs worker

6. Updating the Application

  1. Pull latest code:
bash
   git pull origin main
  1. Rebuild and restart:
bash
   docker compose -f docker-compose.prod.yml up -d --build
  1. Run migrations:
bash
   docker compose -f docker-compose.prod.yml exec api alembic upgrade head

If something goes wrong, you can roll back to the previous image tag in Docker or use Git to revert.


Also document:
- Where logs go, and how to view them.
- Any cron jobs or external schedulers.
- Backup procedures for the database and storage, if relevant.
# Security and Secrets Documentation
Security documentation should not contain secrets. It should describe:
- What secrets exist and where they must be stored
- How authentication and authorization work at a high level
- How to rotate secrets and tokens
- Any security features you have implemented (rate limiting, CORS, etc)
## Example: Security Overview
```markdown
# Security
## Secrets Management
The following sensitive values must never be committed to Git:
- `SECRET_KEY`
- Database passwords
- Redis passwords
- SMTP credentials
- S3 credentials
In production we recommend:
- Using environment variables managed by the deployment platform
- Limiting access to `.env` files to the application user only
- Rotating credentials periodically
## Authentication
- Access tokens are JWTs signed with `SECRET_KEY` using HS256.
- Access token lifetime: 15 minutes.
- Refresh tokens are stored in the database and can be revoked individually.
- A token blacklist is stored in Redis to immediately invalidate compromised tokens.
## Authorization
- Role-based access control:
  - `user`: regular user, access only own tasks and profile.
  - `admin`: manage all users and tasks, access to `/admin/*` endpoints.
- Some endpoints check resource ownership using the `user_id` associated with the task.
## Rate Limiting
- Per-IP rate limits for login and other auth endpoints.
- Limits are enforced using Redis counters:
  - Example: max 5 login attempts per minute per IP.
## CORS
- Allowed origins are configured via `CORS_ALLOWED_ORIGINS` environment variable.
- In production, only the official frontend origins are allowed.
## HTTPS
- HTTPS is terminated at Nginx using Let's Encrypt certificates.
- HTTP traffic is redirected to HTTPS.

This document tells others how security is supposed to work and where they must be careful.

Rule: Never store real secrets in your repository. Document how to provide them instead.


Testing and Quality Documentation

Explain how to run tests and what kind of tests you have. This helps others validate changes and understand quality expectations.

What to Document

Example: Testing Section

markdown
# Testing
We use `pytest` for testing.
## Running Tests Locally
```bash
# With Docker
docker compose run --rm api pytest
# On host (without Docker), with virtualenv activated
pytest

Running Specific Tests

Run tests in a specific file:

bash
pytest tests/api/test_tasks.py

Run a single test:

bash
pytest tests/api/test_tasks.py::test_create_task

Coverage

To generate a coverage report:

bash
pytest --cov=app --cov-report=term-missing

Aim for at least 80% coverage on core modules:

Integration Tests

Some tests require running PostgreSQL and Redis.

With Docker this is automatic. Without Docker:


# Troubleshooting and Common Issues
A short troubleshooting guide can save a lot of time. Capture common failure modes and how to debug them.
## What to Include
- Common startup errors and their causes
- Database and migration issues
- Authentication problems
- Worker and queue issues
## Example: Troubleshooting
```markdown
# Troubleshooting
## API container exits immediately
Check logs:
```bash
docker compose logs api

Common causes:

"Database is locked" or connection errors

bash
  docker compose ps
  docker compose logs db

"Invalid token" errors in API responses

Possible causes:

Celery tasks not executing

bash
  docker compose logs worker

Emails not sent


Views: 8

Comments

Please login to add a comment.

Don't have an account? Register now!