Code Documentation Standards
Good documentation helps new team members onboard faster and makes codebases easier to maintain. This guide covers when and how to document code.
Philosophy
- Code should be self-documenting — use clear naming, small functions, and obvious structure
- Document the why, not the what — if you need to explain what the code does, consider rewriting it to be clearer
- Don't over-document — unnecessary comments become noise and go stale
When to Document
Always document:
- REST API endpoints — via Swagger/OpenAPI decorators (see API Documentation)
- GraphQL types and fields — via
descriptionannotations - Complex business logic that isn't obvious from the code
- Non-obvious decisions ("we do X instead of Y because...")
- Workarounds and known limitations
- Configuration options
Skip documentation for:
- Self-evident code (
getUserByIddoesn't need a comment) - Internal utility functions with clear naming
- Code that changes frequently (comments go stale)
Public API Documentation
For REST endpoints, we use Swagger/OpenAPI decorators — not JSDoc. See API Documentation for details on @ApiOperation, @ApiResponse, and @ApiProperty.
For GraphQL, we use the built-in description option on @ObjectType, @Field, @Query, and @Mutation decorators. The schema itself serves as documentation.
Service Method Comments
For internal service methods with non-obvious behavior, use JSDoc comments:
/**
* Creates a new user account and sends a welcome email.
*
* @throws ConflictException if a user with this email already exists
* @throws BadRequestException if the email domain is blacklisted
*/
async createUser(dto: CreateUserDto): Promise<User> {
// ...
}
Guidelines:
- Use
@throwsto document exceptions a caller should handle - Use
@returnswhen the return value isn't obvious from the type signature - Use
@paramonly when parameter names alone aren't sufficient - Skip JSDoc for simple CRUD methods — the types and Swagger decorators say enough
Inline Comments
Use inline comments sparingly, for non-obvious logic:
// PostgreSQL error code 23505 = unique constraint violation
if (error.code === '23505') {
throw new ConflictException('Email already exists')
}
// We fetch N+1 items to determine if there's a next page
// without running a separate COUNT query
const items = await repo.find({ take: limit + 1 })
Avoid:
// BAD: states the obvious
// Get user by ID
const user = await this.usersService.findById(id)
// BAD: restates the type
// The user's email address (string)
email: string
Project README
Every project repository must have a README.md with:
- Project description — What it does, who it's for
- Quick start — Steps to get the project running locally
- Environment variables — Table of required variables with descriptions
- Available scripts — What
yarn dev,yarn test, etc. do - Architecture overview — Brief description of the project structure (for larger projects)
- Deployment — How and where the project is deployed
Template
# Project Name
Brief description of the project.
## Quick Start
1. Clone the repository
2. `cp docker-compose.dist.yml docker-compose.yml`
3. Fill in environment variables
4. `docker compose up -d`
5. `docker compose exec api yarn migrate`
## Environment Variables
| Variable | Description | Required |
|---|---|---|
| `DATABASE_URL` | PostgreSQL connection string | Yes |
| `JWT_SECRET` | Secret for signing JWTs | Yes |
## Scripts
| Script | Description |
|---|---|
| `yarn dev` | Start development server |
| `yarn build` | Build for production |
| `yarn test` | Run tests |
| `yarn lint` | Lint and format check |
## Architecture
Brief overview of the project structure and key modules.
## Deployment
Deployed via GitHub Actions to [platform]. See `.github/workflows/` for details.
Changelog
For projects with external consumers (APIs used by other teams or clients), maintain a CHANGELOG.md following the Keep a Changelog format. For internal projects, git history and PR descriptions are sufficient.