Professional Documentation with Copilot
Documentation is often the most neglected aspect of software development, yet it is fundamental for maintainability and onboarding new developers. Well-written documentation can save hours of debugging and confusion. With GitHub Copilot, writing professional documentation becomes fast and systematic.
In this article we'll explore how to use Copilot to create professional READMEs, API documentation with OpenAPI, Architecture Decision Records, comprehensive JSDoc, and well-structured changelogs.
Series Overview
| # | Article | Focus |
|---|---|---|
| 1 | Foundation and Mindset | Setup and mindset |
| 2 | Ideation and Requirements | From idea to MVP |
| 3 | Backend Architecture | API and database |
| 4 | Frontend Structure | UI and components |
| 5 | Prompt Engineering | Prompts and MCP Agents |
| 6 | Testing and Quality | Unit, integration, E2E |
| 7 | You are here -> Documentation | README, API docs, ADR |
| 8 | Deploy and DevOps | Docker, CI/CD |
| 9 | Evolution | Scalability and maintenance |
Types of Documentation
A professional project requires different types of documentation, each with a specific purpose.
Documentation Map
| Type | Audience | Purpose | Update Frequency |
|---|---|---|---|
| README.md | Everyone | First impression, quick start | Every major release |
| API Docs | API Developers | Endpoint reference | Every API change |
| ADR | Technical team | Architectural decisions | Per decision |
| JSDoc/TSDoc | Developers | Code reference | With the code |
| CHANGELOG | Users/Dev | Change history | Every release |
| CONTRIBUTING | Contributors | How to contribute | Rarely |
| Runbook | Operations | Operational procedures | When they change |
Professional README
The README is the first thing a visitor sees. It should quickly communicate what the project does, how to use it, and how to contribute.
Prompt for Complete README
Create a professional README.md for my project:
PROJECT INFO:
- Name: TaskFlow
- Type: SaaS task management for freelancers
- Stack: Node.js 20, Express 5, TypeScript 5.3, PostgreSQL 16, Angular 17
- Status: Beta (production-ready)
- License: MIT
FEATURES:
1. Project and task management with drag-and-drop
2. Time tracking with automatic reminders
3. Invoice generation from tracked time
4. Team collaboration (up to 5 users)
5. Integrations: Slack, Google Calendar, Stripe
SECTIONS TO INCLUDE:
1. Project title with logo placeholder and badges
2. One-paragraph description (compelling, benefit-focused)
3. Screenshots/demo section
4. Key features list with icons
5. Tech stack with version badges
6. Prerequisites
7. Installation (step-by-step, copy-pasteable)
8. Configuration (environment variables table)
9. Usage examples with code
10. API documentation link
11. Testing instructions
12. Deployment guide
13. Contributing guidelines
14. Roadmap (future features)
15. License
16. Contact/support info
STYLE:
- Use emojis sparingly for visual hierarchy
- Include copy-paste ready commands
- Add collapsible sections for detailed content
- Include badges from shields.io
Complete README Template
# TaskFlow
<p align="center">
<img src="docs/images/logo.png" alt="TaskFlow Logo" width="200">
</p>
<p align="center">
<strong>The smart task management platform for freelancers</strong>
</p>
<p align="center">
<a href="#features">Features</a> •
<a href="#quick-start">Quick Start</a> •
<a href="#documentation">Documentation</a> •
<a href="#contributing">Contributing</a>
</p>
<p align="center">
<img src="https://img.shields.io/badge/version-1.0.0-blue" alt="Version">
<img src="https://img.shields.io/badge/license-MIT-green" alt="License">
<img src="https://img.shields.io/badge/build-passing-brightgreen" alt="Build">
<img src="https://img.shields.io/badge/coverage-87%25-yellow" alt="Coverage">
<img src="https://img.shields.io/badge/node-%3E%3D20-brightgreen" alt="Node">
</p>
---
## Overview
TaskFlow helps freelancers and small teams manage projects, track time,
and generate invoices - all in one place. Stop juggling multiple tools
and focus on what matters: delivering great work.
<p align="center">
<img src="docs/images/screenshot-dashboard.png" alt="Dashboard" width="80%">
</p>
## Features
| Feature | Description |
|---------|-------------|
| **Task Management** | Kanban boards, lists, and calendar views |
| **Time Tracking** | One-click timer with automatic reminders |
| **Invoicing** | Generate professional invoices from tracked time |
| **Team Collaboration** | Real-time sync for teams up to 5 members |
| **Integrations** | Slack, Google Calendar, Stripe |
| **Analytics** | Weekly reports and productivity insights |
## Tech Stack
| Layer | Technology |
|-------|------------|
| **Backend** | Node.js 20, Express 5, TypeScript 5.3 |
| **Database** | PostgreSQL 16, Prisma ORM |
| **Frontend** | Angular 17, Tailwind CSS |
| **Auth** | JWT, OAuth 2.0 (Google, GitHub) |
| **Cache** | Redis 7 |
| **Queue** | BullMQ |
| **Testing** | Jest, Supertest, Playwright |
## Quick Start
### Prerequisites
- Node.js >= 20
- PostgreSQL >= 15
- Redis >= 7
- npm >= 10
### Installation
```bash
# Clone the repository
git clone https://github.com/yourusername/taskflow.git
cd taskflow
# Install dependencies
npm install
# Copy environment file
cp .env.example .env
# Edit .env with your configuration (see Configuration section)
# Run database migrations
npm run db:migrate
# Seed initial data (optional)
npm run db:seed
# Start development server
npm run dev
```
The application will be available at `http://localhost:3000`.
## Configuration
Create a `.env` file based on `.env.example`:
| Variable | Description | Required | Default |
|----------|-------------|----------|---------|
| `NODE_ENV` | Environment (development/production) | Yes | development |
| `PORT` | Server port | No | 3000 |
| `DATABASE_URL` | PostgreSQL connection string | Yes | - |
| `REDIS_URL` | Redis connection string | Yes | - |
| `JWT_SECRET` | Secret for JWT signing (min 32 chars) | Yes | - |
| `JWT_EXPIRES_IN` | Token expiration | No | 7d |
| `GOOGLE_CLIENT_ID` | Google OAuth client ID | No | - |
| `STRIPE_SECRET_KEY` | Stripe API key | No | - |
<details>
<summary>Full environment variables list</summary>
```env
# Server
NODE_ENV=development
PORT=3000
API_PREFIX=/api/v1
# Database
DATABASE_URL=postgresql://user:password@localhost:5432/taskflow
# Redis
REDIS_URL=redis://localhost:6379
# Authentication
JWT_SECRET=your-super-secret-key-at-least-32-characters
JWT_EXPIRES_IN=7d
REFRESH_TOKEN_EXPIRES_IN=30d
# OAuth (optional)
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
# Email (optional)
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=
SMTP_PASS=
# Stripe (optional)
STRIPE_SECRET_KEY=
STRIPE_WEBHOOK_SECRET=
```
</details>
## Usage
### Creating a Project
```bash
curl -X POST http://localhost:3000/api/v1/projects \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{{ "{" }}"name": "Website Redesign", "description": "Client project"{{ "}" }}'
```
### Starting Time Tracking
```bash
curl -X POST http://localhost:3000/api/v1/time-entries/start \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{{ "{" }}"taskId": "task-123"{{ "}" }}'
```
See [API Documentation](docs/API.md) for complete reference.
## Testing
```bash
# Run all tests
npm test
# Run with coverage
npm run test:coverage
# Run specific test suite
npm test -- --grep "UserService"
# Run E2E tests
npm run test:e2e
```
## Deployment
See [Deployment Guide](docs/DEPLOYMENT.md) for detailed instructions.
### Quick Deploy with Docker
```bash
# Build image
docker build -t taskflow:latest .
# Run with docker-compose
docker-compose up -d
```
## Contributing
We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request
## Roadmap
- [x] Core task management
- [x] Time tracking
- [x] Basic invoicing
- [ ] Mobile app (React Native)
- [ ] AI-powered task suggestions
- [ ] Advanced reporting
- [ ] Zapier integration
## License
This project is licensed under the MIT License - see [LICENSE](LICENSE) for details.
## Support
- [Documentation](https://docs.taskflow.dev)
- [Discord Community](https://discord.gg/taskflow)
- [Issue Tracker](https://github.com/yourusername/taskflow/issues)
- [Email Support](mailto:support@taskflow.dev)
---
<p align="center">
Made with love by <a href="https://github.com/yourusername">Your Name</a>
</p>
API Documentation with OpenAPI
API documentation should be auto-generated from code when possible, but Copilot can help write initial OpenAPI specifications or enrich them.
Prompt for OpenAPI Spec
Generate OpenAPI 3.1 specification for these endpoints:
RESOURCE: Tasks
BASE PATH: /api/v1/tasks
ENDPOINTS:
1. POST /tasks - Create task
2. GET /tasks - List tasks (paginated, filterable)
3. GET /tasks/:id - Get task by ID
4. PATCH /tasks/:id - Update task
5. DELETE /tasks/:id - Delete task
6. POST /tasks/:id/start - Start time tracking
7. POST /tasks/:id/stop - Stop time tracking
TASK SCHEMA:
- id: UUID (readonly)
- title: string (required, 3-200 chars)
- description: string (optional, max 5000)
- status: enum [todo, in_progress, done]
- priority: enum [low, medium, high]
- dueDate: ISO8601 datetime (optional)
- projectId: UUID (required)
- assigneeId: UUID (optional)
- estimatedHours: number (optional)
- actualHours: number (readonly, computed)
- createdAt: datetime (readonly)
- updatedAt: datetime (readonly)
INCLUDE:
- Complete request/response schemas
- All query parameters for list endpoint
- Authentication (Bearer token)
- Error responses (400, 401, 403, 404, 500)
- Example values for all fields
- Descriptions for public docs
Complete OpenAPI Example
openapi: 3.1.0
info:
title: TaskFlow API
description: |
API for task and project management.
## Authentication
All requests require a JWT token in the Authorization header:
```
Authorization: Bearer <token>
```
## Rate Limiting
- 100 requests/minute for authenticated users
- 10 requests/minute for unauthenticated IPs
version: 1.0.0
contact:
email: api@taskflow.dev
servers:
- url: https://api.taskflow.dev/v1
description: Production
- url: https://staging-api.taskflow.dev/v1
description: Staging
- url: http://localhost:3000/api/v1
description: Local Development
tags:
- name: Tasks
description: Task management
paths:
/tasks:
post:
tags: [Tasks]
summary: Create a new task
description: Create a task associated with a project.
operationId: createTask
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateTaskRequest'
example:
title: "Implement OAuth login"
description: "Add support for Google and GitHub OAuth"
projectId: "proj-123"
priority: "high"
dueDate: "2025-02-15T10:00:00Z"
responses:
'201':
description: Task created successfully
content:
application/json:
schema:
$ref: '#/components/schemas/TaskResponse'
'400':
$ref: '#/components/responses/ValidationError'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
get:
tags: [Tasks]
summary: List tasks
description: |
Retrieve a paginated list of tasks with optional filters.
Results are sorted by creation date descending.
operationId: listTasks
security:
- bearerAuth: []
parameters:
- name: page
in: query
description: Page number (1-based)
schema:
type: integer
minimum: 1
default: 1
- name: limit
in: query
description: Items per page
schema:
type: integer
minimum: 1
maximum: 100
default: 20
- name: projectId
in: query
description: Filter by project
schema:
type: string
format: uuid
- name: status
in: query
description: Filter by status
schema:
type: string
enum: [todo, in_progress, done]
- name: priority
in: query
description: Filter by priority
schema:
type: string
enum: [low, medium, high]
- name: assigneeId
in: query
description: Filter by assignee
schema:
type: string
format: uuid
- name: search
in: query
description: Search in title and description
schema:
type: string
minLength: 2
responses:
'200':
description: Task list
content:
application/json:
schema:
$ref: '#/components/schemas/TaskListResponse'
/tasks/{{ '{' }}taskId{{ '}' }}:
parameters:
- name: taskId
in: path
required: true
description: Unique task ID
schema:
type: string
format: uuid
get:
tags: [Tasks]
summary: Get task details
operationId: getTask
security:
- bearerAuth: []
responses:
'200':
description: Task found
content:
application/json:
schema:
$ref: '#/components/schemas/TaskResponse'
'404':
$ref: '#/components/responses/NotFound'
patch:
tags: [Tasks]
summary: Update task
description: Update one or more task fields.
operationId: updateTask
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateTaskRequest'
responses:
'200':
description: Task updated
content:
application/json:
schema:
$ref: '#/components/schemas/TaskResponse'
'404':
$ref: '#/components/responses/NotFound'
delete:
tags: [Tasks]
summary: Delete task
description: Soft delete - the task is marked as deleted.
operationId: deleteTask
security:
- bearerAuth: []
responses:
'204':
description: Task deleted
'404':
$ref: '#/components/responses/NotFound'
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
schemas:
CreateTaskRequest:
type: object
required: [title, projectId]
properties:
title:
type: string
minLength: 3
maxLength: 200
description: Task title
description:
type: string
maxLength: 5000
description: Detailed description
projectId:
type: string
format: uuid
description: Project ID
priority:
type: string
enum: [low, medium, high]
default: medium
status:
type: string
enum: [todo, in_progress, done]
default: todo
dueDate:
type: string
format: date-time
assigneeId:
type: string
format: uuid
estimatedHours:
type: number
minimum: 0
UpdateTaskRequest:
type: object
properties:
title:
type: string
minLength: 3
maxLength: 200
description:
type: string
maxLength: 5000
priority:
type: string
enum: [low, medium, high]
status:
type: string
enum: [todo, in_progress, done]
dueDate:
type: string
format: date-time
assigneeId:
type: string
format: uuid
Task:
type: object
properties:
id:
type: string
format: uuid
readOnly: true
title:
type: string
description:
type: string
projectId:
type: string
format: uuid
status:
type: string
enum: [todo, in_progress, done]
priority:
type: string
enum: [low, medium, high]
dueDate:
type: string
format: date-time
assigneeId:
type: string
format: uuid
estimatedHours:
type: number
actualHours:
type: number
readOnly: true
createdAt:
type: string
format: date-time
readOnly: true
updatedAt:
type: string
format: date-time
readOnly: true
TaskResponse:
type: object
properties:
data:
$ref: '#/components/schemas/Task'
TaskListResponse:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/Task'
meta:
type: object
properties:
page:
type: integer
limit:
type: integer
total:
type: integer
totalPages:
type: integer
Error:
type: object
properties:
error:
type: object
properties:
code:
type: string
message:
type: string
details:
type: array
items:
type: object
properties:
field:
type: string
message:
type: string
responses:
ValidationError:
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error:
code: VALIDATION_ERROR
message: Invalid data
details:
- field: title
message: Title must have at least 3 characters
Unauthorized:
description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error:
code: UNAUTHORIZED
message: Missing or invalid token
Forbidden:
description: Access denied
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error:
code: FORBIDDEN
message: You don't have permission for this operation
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error:
code: NOT_FOUND
message: Task not found
Architecture Decision Records (ADR)
ADRs document important architectural decisions, the context in which they were made, and the alternatives considered. They are fundamental to understanding the "why" behind technical choices.
Prompt for ADR
Create an Architecture Decision Record (ADR) for this decision:
DECISION: Use PostgreSQL as database instead of MongoDB
CONTEXT: We're building a task management SaaS
DATE: 2025-01-30
FACTORS CONSIDERED:
1. Strongly relational data (users, projects, tasks, time entries)
2. Need for complex queries and reporting
3. ACID compliance for financial data (invoicing)
4. Team familiarity with SQL
5. Future scaling needs
ALTERNATIVES:
1. MongoDB - NoSQL, flexible schema
2. MySQL - Traditional RDBMS
3. CockroachDB - Distributed SQL
Follow the standard ADR template with:
- Title (ADR-XXX: Brief description)
- Status
- Context
- Decision
- Alternatives Considered (with pros/cons)
- Consequences (positive, negative, risks)
- Notes/Follow-up
Complete ADR Template
# ADR-001: PostgreSQL as Primary Database
## Status
**Accepted** - 2025-01-30
## Context
We're designing the backend for TaskFlow, a SaaS platform for task and project
management aimed at freelancers and small teams. The system must handle:
- **Users and teams:** N:M relationships with roles and permissions
- **Projects and tasks:** Hierarchical structure, statuses, priorities
- **Time tracking:** Work sessions with precise timestamps
- **Billing:** Financial data requiring precision and audit trail
- **Analytics:** Complex queries for reports and dashboards
### Key Requirements
1. **Data integrity:** Financial data requires ACID transactions
2. **Complex queries:** Reports that aggregate data from multiple tables
3. **Vertical scalability:** MVP with 1000 users, target 50,000 in 18 months
4. **Performance:** Dashboard must load in <500ms
5. **Cost:** Limited infrastructure budget
### Constraints
- Team of 2 developers with SQL experience
- MVP timeline: 3 months
- Cloud hosting (preferably managed)
## Decision
We use **PostgreSQL 16** as primary database, with **Prisma ORM** for data access.
### Rationale
1. **Relational model:** Our data is strongly relational (users -> projects -> tasks -> time_entries)
2. **ACID compliance:** Atomic transactions for financial operations
3. **Powerful queries:** JOINs, aggregations, window functions for analytics
4. **JSONB:** Flexibility for metadata without sacrificing structure
5. **Maturity:** 30+ years of development, excellent documentation, active community
6. **Tooling:** Prisma has first-class support, pgAdmin for admin, pg_dump for backup
7. **Managed options:** Available on all cloud providers (Supabase, Neon, RDS)
## Alternatives Considered
### MongoDB
| Aspect | Pro | Con |
|--------|-----|-----|
| Schema | Flexible, evolves easily | Less integrity control |
| Query | Simple on single documents | Expensive JOINs (lookup) |
| Scale | Native horizontal scaling | Overkill for our needs |
| Team | - | No experience |
| Cost | - | Atlas expensive for enterprise features |
**Decision:** Rejected. Our data is relational, MongoDB would add unnecessary complexity.
### MySQL 8
| Aspect | Pro | Con |
|--------|-----|-----|
| Familiarity | Very widespread | Less mature JSON support |
| Performance | Good for OLTP | More limited window functions |
| Cost | Economical | - |
| Tooling | Prisma supports | - |
**Decision:** Valid alternative, but PostgreSQL offers more advanced features (JSONB, arrays, native full-text search).
### CockroachDB
| Aspect | Pro | Con |
|--------|-----|-----|
| Scale | Distributed by default | Operational complexity |
| Resilience | Built-in multi-region | Overkill for MVP |
| Compatibility | PostgreSQL wire protocol | Some differences |
| Cost | - | Limited free tier |
**Decision:** Rejected for MVP. Could be considered for future scale-up.
## Consequences
### Positive
1. **Powerful queries:** We can build complex analytics without caching layer
2. **Guaranteed integrity:** Foreign keys, constraints, transactions
3. **Developer experience:** Prisma migrations, type safety
4. **Ecosystem:** Extensions (PostGIS if needed for geo), pgvector for AI
5. **Predictable cost:** Managed PostgreSQL at reasonable prices
### Negative
1. **Horizontal scaling:** Requires more work (read replicas, manual sharding)
2. **Rigid schema:** Migrations needed for structural changes
3. **Vendor lock-in:** Some PG-specific features (JSONB operators)
### Risks
| Risk | Probability | Impact | Mitigation |
|------|-------------|--------|------------|
| Performance issues at scale | Medium | High | Monitoring, query optimization, read replicas |
| Vendor lock-in | Low | Medium | Use standard SQL where possible |
| Team learning curve | Low | Low | Internal documentation, pair programming |
## Implementation Notes
### Hosting
- **Development:** Local Docker
- **Staging:** Supabase (free tier)
- **Production:** Supabase Pro or Neon (evaluate costs)
### Backup Strategy
- Point-in-time recovery enabled
- Daily automatic snapshots
- Monthly restore test
### Monitoring
- Query performance with pg_stat_statements
- Connection pooling with PgBouncer
- Alerting on slow queries (>1s)
## Follow-up Actions
- [ ] Setup Prisma with PostgreSQL
- [ ] Configure docker-compose for development
- [ ] Define initial schema for User, Project, Task
- [ ] Create monitoring dashboard
## Related Decisions
- ADR-002: ORM Choice (Prisma)
- ADR-003: Caching strategy (Redis)
## References
- [PostgreSQL vs MongoDB 2025](https://example.com/comparison)
- [Prisma PostgreSQL Guide](https://www.prisma.io/docs/concepts/database-connectors/postgresql)
- [Supabase Pricing](https://supabase.com/pricing)
---
**Author:** Federico Calo
**Reviewers:** Team Lead
**Last Updated:** 2025-01-30
JSDoc and Code Documentation
Inline documentation helps developers understand code without having to read the complete implementation.
Prompt for JSDoc
Add comprehensive JSDoc documentation to this TypeScript code:
```typescript
[PASTE CODE HERE]
```
INCLUDE FOR EACH FUNCTION/METHOD:
1. Brief description (one sentence)
2. Detailed explanation (if complex)
3. @param for each parameter with type and description
4. @returns with type and description
5. @throws for each exception that can be thrown
6. @example with realistic usage
7. @see for related functions
8. @since version number
9. @deprecated if applicable
STYLE:
- Use imperative mood ("Creates a user" not "This creates a user")
- Document edge cases in description
- Include validation rules in @param descriptions
- Add @remarks for implementation notes
Complete JSDoc Example
/**
* Service for user management.
*
* Handles CRUD operations, authentication and authorization for users.
* All passwords are hashed with bcrypt before saving.
*
* @remarks
* This service doesn't directly handle JWT tokens. See {@link AuthService}
* for authentication operations.
*
* @example
* ```typescript
* const userService = new UserService(userRepository, emailService);
*
* // Create a new user
* const user = await userService.create({
* name: 'John Doe',
* email: 'john@example.com',
* password: 'SecurePass123!'
* });
*
* // Update a user
* await userService.update(user.id, { name: 'John Smith' });
* ```
*
* @since 1.0.0
*/
export class UserService {
/**
* Creates a new UserService instance.
*
* @param userRepository - Repository for user data access
* @param emailService - Service for sending emails
*/
constructor(
private readonly userRepository: UserRepository,
private readonly emailService: EmailService
) {}
/**
* Creates a new user in the system.
*
* Validates input data, checks that email is not already registered,
* hashes password and sends welcome email.
*
* @param dto - User creation data
* @param dto.name - Full name (2-100 characters)
* @param dto.email - Valid and unique email in the system
* @param dto.password - Password (min 8 char, 1 uppercase, 1 number, 1 special)
*
* @returns The created user (without password)
*
* @throws {ValidationError} If data doesn't pass validation
* @throws {ConflictError} If email is already registered
* @throws {ServiceError} If email sending fails (user created anyway)
*
* @example
* ```typescript
* try {
* const user = await userService.create({
* name: 'John Doe',
* email: 'john@example.com',
* password: 'SecurePass123!'
* });
* console.log(`User created: 






