Initial commit
This commit is contained in:
25
skills/documentation-architecture/SKILL.md
Normal file
25
skills/documentation-architecture/SKILL.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Documentation Architecture Skill
|
||||
|
||||
Comprehensive documentation systems design including structure, generation, maintenance, and automation.
|
||||
|
||||
## Description
|
||||
|
||||
Design and maintain scalable documentation architectures with automated generation, versioning, and search.
|
||||
|
||||
## What's Included
|
||||
|
||||
- **Examples**: Documentation structures, automated generation
|
||||
- **Reference**: Documentation best practices, architecture patterns
|
||||
- **Templates**: Documentation templates, style guides
|
||||
|
||||
## Use When
|
||||
|
||||
- Designing documentation systems
|
||||
- Automating documentation
|
||||
- Large-scale doc projects
|
||||
|
||||
## Related Agents
|
||||
|
||||
- `docs-architect`
|
||||
|
||||
**Skill Version**: 1.0
|
||||
@@ -0,0 +1,152 @@
|
||||
# Documentation Quality Checklist
|
||||
|
||||
**Use when creating or reviewing documentation.**
|
||||
|
||||
## Accuracy
|
||||
|
||||
- [ ] All code examples are tested and verified
|
||||
- [ ] API contracts match actual implementation
|
||||
- [ ] Version numbers are correct and up-to-date
|
||||
- [ ] External links are valid (not 404)
|
||||
- [ ] Screenshots reflect current UI
|
||||
- [ ] Configuration examples are accurate
|
||||
- [ ] Environment variables are correctly documented
|
||||
- [ ] Dependency versions match package.json/requirements.txt
|
||||
|
||||
## Completeness
|
||||
|
||||
- [ ] All public APIs are documented
|
||||
- [ ] All required parameters are explained
|
||||
- [ ] All optional parameters have defaults documented
|
||||
- [ ] Response formats are specified with examples
|
||||
- [ ] Error cases are covered with status codes
|
||||
- [ ] Authentication requirements are clear
|
||||
- [ ] Rate limiting is documented
|
||||
- [ ] Deprecation notices are included where needed
|
||||
- [ ] Migration guides for breaking changes
|
||||
- [ ] Changelog is up-to-date
|
||||
|
||||
## API Documentation
|
||||
|
||||
- [ ] OpenAPI 3.1 specification is valid
|
||||
- [ ] All endpoints have descriptions
|
||||
- [ ] Request/response schemas are complete
|
||||
- [ ] Multi-language code examples (TypeScript, Python, cURL)
|
||||
- [ ] Authentication flows documented
|
||||
- [ ] Error responses documented
|
||||
- [ ] Interactive documentation (Swagger UI/Redoc) works
|
||||
- [ ] Try-it-now functionality tested
|
||||
|
||||
## Architecture Documentation
|
||||
|
||||
- [ ] Executive summary for stakeholders
|
||||
- [ ] Mermaid system architecture diagram
|
||||
- [ ] Sequence diagrams for key flows
|
||||
- [ ] Data flow diagrams
|
||||
- [ ] Integration points documented
|
||||
- [ ] Security model explained
|
||||
- [ ] ADRs (Architectural Decision Records) included
|
||||
- [ ] Database schema documented
|
||||
|
||||
## Code Examples
|
||||
|
||||
- [ ] TypeScript examples follow Grey Haven patterns
|
||||
- [ ] Python examples follow Grey Haven patterns
|
||||
- [ ] cURL examples are complete and correct
|
||||
- [ ] Examples use realistic data
|
||||
- [ ] Examples show error handling
|
||||
- [ ] Examples demonstrate authentication
|
||||
- [ ] Examples are syntax-highlighted
|
||||
- [ ] Examples are copy-paste ready
|
||||
|
||||
## Consistency
|
||||
|
||||
- [ ] Uniform terminology throughout
|
||||
- [ ] Consistent formatting (headings, lists, code blocks)
|
||||
- [ ] Standard code example format
|
||||
- [ ] Unified voice and tone
|
||||
- [ ] Consistent naming conventions
|
||||
- [ ] Cross-references use standard format
|
||||
- [ ] Diagrams follow consistent style
|
||||
|
||||
## Accessibility
|
||||
|
||||
- [ ] Content is searchable
|
||||
- [ ] Clear navigation structure
|
||||
- [ ] Mobile-responsive design
|
||||
- [ ] WCAG 2.1 AA compliant
|
||||
- [ ] Alt text for images and diagrams
|
||||
- [ ] Keyboard navigation works
|
||||
- [ ] Color contrast meets standards
|
||||
- [ ] Screen reader compatible
|
||||
|
||||
## Usability
|
||||
|
||||
- [ ] Progressive disclosure (simple → complex)
|
||||
- [ ] Practical examples and use cases
|
||||
- [ ] Troubleshooting guides included
|
||||
- [ ] Quick reference sections provided
|
||||
- [ ] Table of contents for long docs
|
||||
- [ ] Search functionality works
|
||||
- [ ] Clear call-to-action buttons
|
||||
- [ ] Getting started guide present
|
||||
|
||||
## Documentation Coverage
|
||||
|
||||
- [ ] Function coverage >80%
|
||||
- [ ] API coverage >80%
|
||||
- [ ] Type coverage >80%
|
||||
- [ ] No critical gaps in documentation
|
||||
- [ ] Coverage report generated
|
||||
- [ ] CI/CD validation passes
|
||||
|
||||
## Grey Haven Standards
|
||||
|
||||
- [ ] Cloudflare Workers patterns documented
|
||||
- [ ] TanStack Start patterns included
|
||||
- [ ] FastAPI patterns covered
|
||||
- [ ] Multi-tenant patterns explained
|
||||
- [ ] tenant_id filtering documented
|
||||
- [ ] RLS policies explained
|
||||
- [ ] Doppler secrets management documented
|
||||
- [ ] bun package manager (NOT npm!)
|
||||
|
||||
## CI/CD Integration
|
||||
|
||||
- [ ] Documentation generates automatically on merge
|
||||
- [ ] Pre-commit hooks validate coverage
|
||||
- [ ] Broken link checker runs
|
||||
- [ ] Code examples are tested
|
||||
- [ ] Coverage threshold enforced (<80% fails build)
|
||||
- [ ] Deployment to Cloudflare Pages configured
|
||||
|
||||
## Deployment
|
||||
|
||||
- [ ] Deployed to correct environment (staging/production)
|
||||
- [ ] Custom domain configured
|
||||
- [ ] SSL certificate valid
|
||||
- [ ] Redirects configured (if needed)
|
||||
- [ ] Analytics tracking enabled
|
||||
- [ ] Search indexing configured
|
||||
- [ ] CDN caching configured
|
||||
|
||||
## Maintenance
|
||||
|
||||
- [ ] Quarterly documentation audit scheduled
|
||||
- [ ] User feedback collection in place
|
||||
- [ ] Version support matrix documented
|
||||
- [ ] Deprecation timeline clear
|
||||
- [ ] Migration guides for breaking changes
|
||||
- [ ] Contact information for support
|
||||
- [ ] Contribution guidelines present
|
||||
|
||||
## Pre-Release
|
||||
|
||||
- [ ] All checklist items above completed
|
||||
- [ ] Documentation reviewed by team
|
||||
- [ ] Examples tested on staging
|
||||
- [ ] Coverage meets >80% threshold
|
||||
- [ ] No broken links
|
||||
- [ ] Mobile testing completed
|
||||
- [ ] Accessibility audit passed
|
||||
- [ ] User testing feedback incorporated
|
||||
67
skills/documentation-architecture/examples/INDEX.md
Normal file
67
skills/documentation-architecture/examples/INDEX.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Documentation Architecture Examples
|
||||
|
||||
Real-world examples of comprehensive documentation generation, architecture documentation, and coverage validation.
|
||||
|
||||
## Available Examples
|
||||
|
||||
### [OpenAPI 3.1 Generation from FastAPI](openapi-generation.md)
|
||||
|
||||
Complete workflow for automatic API documentation generation from FastAPI codebase.
|
||||
|
||||
**Scenario**: E-commerce API with 47 undocumented endpoints causing 12 integration issues/week
|
||||
|
||||
**Solution**: Enhanced OpenAPI generation, multi-language examples, interactive Swagger UI, CI/CD auto-generation
|
||||
|
||||
**Results**: Integration issues 12/week → 0.5/week (96% reduction), manual doc time 4hrs → 0 (automated)
|
||||
|
||||
**Key Techniques**: FastAPI OpenAPI customization, Pydantic v2 field validators, example generation scripts
|
||||
|
||||
---
|
||||
|
||||
### [System Architecture Documentation with Mermaid](architecture-docs.md)
|
||||
|
||||
Comprehensive system architecture documentation reducing onboarding time from 3-4 weeks to 4-5 days.
|
||||
|
||||
**Scenario**: No architecture docs, tribal knowledge spread across 8 developers, 3-4 week onboarding
|
||||
|
||||
**Solution**: 8 Mermaid diagrams, Architecture Decision Records, progressive disclosure, version-controlled
|
||||
|
||||
**Results**: Onboarding 3-4 weeks → 4-5 days (75% reduction), architecture questions 15hrs/week → 2hrs/week
|
||||
|
||||
**Key Techniques**: Mermaid diagrams (system, sequence, data flow, ER), ADR template, multi-tenant flow docs
|
||||
|
||||
---
|
||||
|
||||
### [Documentation Coverage Validation](coverage-validation.md)
|
||||
|
||||
Automated documentation coverage analysis with 80% threshold enforcement in CI/CD.
|
||||
|
||||
**Scenario**: Unknown coverage, 147 undocumented functions, no visibility into gaps
|
||||
|
||||
**Solution**: TypeScript coverage (ts-morph), Python coverage (AST), HTML reports, CI/CD enforcement
|
||||
|
||||
**Results**: TS 42% → 87%, Python 38% → 91%, API 51% → 95%, undocumented 147 → 18
|
||||
|
||||
**Key Techniques**: AST parsing, OpenAPI schema analysis, coverage threshold enforcement, HTML reports
|
||||
|
||||
---
|
||||
|
||||
## Common Patterns
|
||||
|
||||
1. **Automation First**: All documentation generated/validated automatically
|
||||
2. **CI/CD Integration**: Updates on every commit, coverage checks block PRs
|
||||
3. **Multi-Language Support**: Examples in TypeScript, Python, cURL
|
||||
4. **Visual Documentation**: Mermaid diagrams for architecture, sequences, data models
|
||||
5. **Progressive Disclosure**: Start with overview, drill into details
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Need | Example | Key Tool |
|
||||
|------|---------|----------|
|
||||
| API Documentation | [openapi-generation.md](openapi-generation.md) | FastAPI + Pydantic v2 |
|
||||
| System Architecture | [architecture-docs.md](architecture-docs.md) | Mermaid + ADRs |
|
||||
| Coverage Analysis | [coverage-validation.md](coverage-validation.md) | ts-morph + Python AST |
|
||||
|
||||
---
|
||||
|
||||
Related: [Reference Guides](../reference/INDEX.md) | [Templates](../templates/) | [Return to Agent](../docs-architect.md)
|
||||
442
skills/documentation-architecture/examples/architecture-docs.md
Normal file
442
skills/documentation-architecture/examples/architecture-docs.md
Normal file
@@ -0,0 +1,442 @@
|
||||
# Example: System Architecture Documentation with Mermaid Diagrams
|
||||
|
||||
Complete workflow for creating comprehensive system architecture documentation for a distributed Grey Haven application.
|
||||
|
||||
## Context
|
||||
|
||||
**Project**: Multi-Tenant SaaS Platform (TanStack Start + Cloudflare Workers + FastAPI + PostgreSQL)
|
||||
**Problem**: New developers taking 3-4 weeks to understand system architecture, high onboarding cost
|
||||
**Goal**: Create comprehensive architecture documentation that reduces onboarding time to <1 week
|
||||
|
||||
**Initial State**:
|
||||
- No architecture documentation
|
||||
- Tribal knowledge spread across 8 senior developers
|
||||
- New hires asking same questions repeatedly
|
||||
- 3-4 weeks until new developer productive
|
||||
- Architecture decisions not documented (ADRs missing)
|
||||
|
||||
## Step 1: System Overview with Mermaid
|
||||
|
||||
### High-Level Architecture Diagram
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Client Layer"
|
||||
Browser[Web Browser]
|
||||
Mobile[Mobile App]
|
||||
end
|
||||
|
||||
subgraph "Edge Layer (Cloudflare Workers)"
|
||||
Gateway[API Gateway]
|
||||
Auth[Auth Service]
|
||||
Cache[KV Cache]
|
||||
end
|
||||
|
||||
subgraph "Application Layer"
|
||||
Frontend[TanStack Start<br/>React 19]
|
||||
Backend[FastAPI Backend<br/>Python 3.12]
|
||||
end
|
||||
|
||||
subgraph "Data Layer"
|
||||
PostgreSQL[(PostgreSQL<br/>PlanetScale)]
|
||||
Redis[(Redis Cache<br/>Upstash)]
|
||||
S3[(R2 Object Storage<br/>Cloudflare)]
|
||||
end
|
||||
|
||||
subgraph "External Services"
|
||||
Stripe[Stripe<br/>Payments]
|
||||
SendGrid[SendGrid<br/>Email]
|
||||
DataDog[DataDog<br/>Monitoring]
|
||||
end
|
||||
|
||||
Browser --> Gateway
|
||||
Mobile --> Gateway
|
||||
Gateway --> Auth
|
||||
Gateway --> Frontend
|
||||
Gateway --> Backend
|
||||
Auth --> Cache
|
||||
Frontend --> PostgreSQL
|
||||
Backend --> PostgreSQL
|
||||
Backend --> Redis
|
||||
Backend --> S3
|
||||
Backend --> Stripe
|
||||
Backend --> SendGrid
|
||||
Backend -.telemetry.-> DataDog
|
||||
```
|
||||
|
||||
## Step 2: Request Flow Sequence Diagrams
|
||||
|
||||
### User Authentication Flow
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
actor User
|
||||
participant Browser
|
||||
participant Gateway as API Gateway<br/>(Cloudflare Worker)
|
||||
participant Auth as Auth Service<br/>(Cloudflare Worker)
|
||||
participant KV as KV Cache
|
||||
participant DB as PostgreSQL
|
||||
|
||||
User->>Browser: Enter email/password
|
||||
Browser->>Gateway: POST /auth/login
|
||||
Gateway->>Auth: Validate credentials
|
||||
Auth->>DB: Query user by email
|
||||
DB-->>Auth: User record
|
||||
|
||||
alt Valid Credentials
|
||||
Auth->>Auth: Hash password & verify
|
||||
Auth->>Auth: Generate JWT token
|
||||
Auth->>KV: Store session (token -> user_id)
|
||||
KV-->>Auth: OK
|
||||
Auth-->>Gateway: {token, user}
|
||||
Gateway-->>Browser: 200 OK {token, user}
|
||||
Browser->>Browser: Store token in localStorage
|
||||
Browser-->>User: Redirect to dashboard
|
||||
else Invalid Credentials
|
||||
Auth-->>Gateway: 401 Unauthorized
|
||||
Gateway-->>Browser: {error: "INVALID_CREDENTIALS"}
|
||||
Browser-->>User: Show error message
|
||||
end
|
||||
```
|
||||
|
||||
### Multi-Tenant Data Access Flow
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client
|
||||
participant Gateway
|
||||
participant Backend as FastAPI Backend
|
||||
participant DB as PostgreSQL<br/>(Row-Level Security)
|
||||
|
||||
Client->>Gateway: GET /api/orders<br/>Authorization: Bearer <token>
|
||||
Gateway->>Gateway: Validate JWT token
|
||||
Gateway->>Gateway: Extract tenant_id from token
|
||||
Gateway->>Backend: Forward request<br/>X-Tenant-ID: tenant_123
|
||||
|
||||
Backend->>Backend: Set session context<br/>SET app.tenant_id = 'tenant_123'
|
||||
Backend->>DB: SELECT * FROM orders<br/>(RLS automatically filters by tenant)
|
||||
|
||||
Note over DB: Row-Level Security Policy:<br/>CREATE POLICY tenant_isolation ON orders<br/>FOR SELECT USING (tenant_id = current_setting('app.tenant_id'))
|
||||
|
||||
DB-->>Backend: Orders for tenant_123 only
|
||||
Backend-->>Gateway: {orders: [...]}
|
||||
Gateway-->>Client: 200 OK {orders: [...]}
|
||||
```
|
||||
|
||||
## Step 3: Data Flow Diagram
|
||||
|
||||
### Order Processing Data Flow
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
User[User Creates Order] --> Validation[Validate Order Data]
|
||||
Validation --> Stock{Check Stock<br/>Availability}
|
||||
|
||||
Stock -->|Insufficient| Error[Return 400 Error]
|
||||
Stock -->|Available| Reserve[Reserve Inventory]
|
||||
|
||||
Reserve --> Payment[Process Payment<br/>via Stripe]
|
||||
Payment -->|Failed| Release[Release Reservation]
|
||||
Release --> Error
|
||||
|
||||
Payment -->|Success| CreateOrder[Create Order<br/>in Database]
|
||||
CreateOrder --> Queue[Queue Email<br/>Confirmation]
|
||||
Queue --> Cache[Invalidate<br/>User Cache]
|
||||
Cache --> Success[Return Order]
|
||||
|
||||
Success --> Async[Async: Send Email<br/>via SendGrid]
|
||||
Success --> Metrics[Update Metrics<br/>in DataDog]
|
||||
```
|
||||
|
||||
## Step 4: Database Schema ER Diagram
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
TENANT ||--o{ USER : has
|
||||
TENANT ||--o{ ORDER : has
|
||||
USER ||--o{ ORDER : places
|
||||
ORDER ||--|{ ORDER_ITEM : contains
|
||||
PRODUCT ||--o{ ORDER_ITEM : included_in
|
||||
TENANT ||--o{ PRODUCT : owns
|
||||
|
||||
TENANT {
|
||||
uuid id PK
|
||||
string name
|
||||
string subdomain UK
|
||||
timestamp created_at
|
||||
}
|
||||
|
||||
USER {
|
||||
uuid id PK
|
||||
uuid tenant_id FK
|
||||
string email UK
|
||||
string hashed_password
|
||||
string role
|
||||
timestamp created_at
|
||||
}
|
||||
|
||||
PRODUCT {
|
||||
uuid id PK
|
||||
uuid tenant_id FK
|
||||
string name
|
||||
decimal price
|
||||
int stock
|
||||
}
|
||||
|
||||
ORDER {
|
||||
uuid id PK
|
||||
uuid tenant_id FK
|
||||
uuid user_id FK
|
||||
decimal subtotal
|
||||
decimal tax
|
||||
decimal total
|
||||
string status
|
||||
timestamp created_at
|
||||
}
|
||||
|
||||
ORDER_ITEM {
|
||||
uuid id PK
|
||||
uuid order_id FK
|
||||
uuid product_id FK
|
||||
int quantity
|
||||
decimal unit_price
|
||||
}
|
||||
```
|
||||
|
||||
## Step 5: Deployment Architecture
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Development"
|
||||
DevBranch[Feature Branch]
|
||||
DevEnv[Dev Environment<br/>Cloudflare Preview]
|
||||
end
|
||||
|
||||
subgraph "Staging"
|
||||
MainBranch[Main Branch]
|
||||
StageEnv[Staging Environment<br/>staging.greyhaven.com]
|
||||
StageDB[(Staging PostgreSQL)]
|
||||
end
|
||||
|
||||
subgraph "Production"
|
||||
Release[Release Tag]
|
||||
ProdWorkers[Cloudflare Workers<br/>300+ Datacenters]
|
||||
ProdDB[(Production PostgreSQL<br/>PlanetScale)]
|
||||
ProdCache[(Redis Cache<br/>Upstash)]
|
||||
end
|
||||
|
||||
DevBranch -->|git push| CI1[GitHub Actions]
|
||||
CI1 -->|Deploy| DevEnv
|
||||
|
||||
DevBranch -->|PR Merged| MainBranch
|
||||
MainBranch -->|Deploy| CI2[GitHub Actions]
|
||||
CI2 -->|Run Tests| TestSuite
|
||||
TestSuite -->|Success| StageEnv
|
||||
StageEnv --> StageDB
|
||||
|
||||
MainBranch -->|git tag v1.0.0| Release
|
||||
Release -->|Deploy| CI3[GitHub Actions]
|
||||
CI3 -->|Canary 10%| ProdWorkers
|
||||
CI3 -->|Monitor 10 min| Metrics
|
||||
Metrics -->|Success| FullDeploy[100% Rollout]
|
||||
FullDeploy --> ProdWorkers
|
||||
ProdWorkers --> ProdDB
|
||||
ProdWorkers --> ProdCache
|
||||
```
|
||||
|
||||
## Step 6: State Machine Diagram for Order Status
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Pending: Order Created
|
||||
Pending --> Processing: Payment Confirmed
|
||||
Pending --> Cancelled: Payment Failed
|
||||
|
||||
Processing --> Shipped: Fulfillment Complete
|
||||
Processing --> Cancelled: Out of Stock
|
||||
|
||||
Shipped --> Delivered: Tracking Confirmed
|
||||
Shipped --> Returned: Customer Return
|
||||
|
||||
Delivered --> Returned: Return Requested
|
||||
Returned --> Refunded: Return Approved
|
||||
|
||||
Cancelled --> [*]
|
||||
Delivered --> [*]
|
||||
Refunded --> [*]
|
||||
|
||||
note right of Pending
|
||||
Inventory reserved
|
||||
Payment processing
|
||||
end note
|
||||
|
||||
note right of Processing
|
||||
Items picked
|
||||
Preparing shipment
|
||||
end note
|
||||
|
||||
note right of Shipped
|
||||
Tracking number assigned
|
||||
In transit
|
||||
end note
|
||||
```
|
||||
|
||||
## Step 7: Architecture Decision Records (ADRs)
|
||||
|
||||
### ADR-001: Choose Cloudflare Workers for Edge Computing
|
||||
|
||||
```markdown
|
||||
# ADR-001: Use Cloudflare Workers for API Gateway and Auth
|
||||
|
||||
**Date**: 2024-01-15
|
||||
**Status**: Accepted
|
||||
**Decision Makers**: Engineering Team
|
||||
|
||||
## Context
|
||||
|
||||
We need an edge computing platform for API gateway, authentication, and caching that:
|
||||
- Provides global low latency (<50ms p95)
|
||||
- Scales automatically without management
|
||||
- Integrates with our CDN infrastructure
|
||||
- Supports multi-tenant architecture
|
||||
|
||||
## Decision
|
||||
|
||||
We will use Cloudflare Workers for edge computing with KV for session storage.
|
||||
|
||||
## Alternatives Considered
|
||||
|
||||
1. **AWS Lambda@Edge**: Good performance but vendor lock-in, higher cost
|
||||
2. **Traditional Load Balancer**: Single region, no edge caching
|
||||
3. **Self-hosted Edge Nodes**: Complex deployment, maintenance overhead
|
||||
|
||||
## Consequences
|
||||
|
||||
**Positive**:
|
||||
- Global deployment (300+ datacenters) with <50ms latency worldwide
|
||||
- Auto-scaling to zero cost when idle
|
||||
- Built-in DDoS protection and WAF
|
||||
- KV storage for session caching (sub-millisecond reads)
|
||||
- 1ms CPU time limit forces efficient code
|
||||
|
||||
**Negative**:
|
||||
- 1ms CPU time limit requires careful optimization
|
||||
- Cold starts (though <10ms typically)
|
||||
- Limited to JavaScript/TypeScript/Rust/Python (via Pyodide)
|
||||
- No native PostgreSQL driver (must use HTTP-based client)
|
||||
|
||||
## Implementation
|
||||
|
||||
- API Gateway: Handles routing, CORS, rate limiting
|
||||
- Auth Service: JWT validation, session management (KV)
|
||||
- Cache Layer: API response caching (KV + Cache API)
|
||||
|
||||
## Monitoring
|
||||
|
||||
- Worker CPU time (aim for <500μs p95)
|
||||
- KV cache hit rate (aim for >95%)
|
||||
- Edge response time (aim for <50ms p95)
|
||||
```
|
||||
|
||||
### ADR-002: PostgreSQL with Row-Level Security for Multi-Tenancy
|
||||
|
||||
```markdown
|
||||
# ADR-002: PostgreSQL Row-Level Security (RLS) for Multi-Tenant Isolation
|
||||
|
||||
**Date**: 2024-01-20
|
||||
**Status**: Accepted
|
||||
|
||||
## Context
|
||||
|
||||
Multi-tenant SaaS requires strict data isolation. Accidental cross-tenant data access would be a critical security breach.
|
||||
|
||||
## Decision
|
||||
|
||||
Use PostgreSQL Row-Level Security (RLS) policies to enforce tenant isolation at the database level.
|
||||
|
||||
## Implementation
|
||||
|
||||
```sql
|
||||
-- Enable RLS on all tables
|
||||
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Create policy that filters by session tenant_id
|
||||
CREATE POLICY tenant_isolation ON orders
|
||||
FOR ALL
|
||||
USING (tenant_id = current_setting('app.tenant_id', true)::uuid);
|
||||
|
||||
-- Application sets tenant context per request
|
||||
SET app.tenant_id = '<tenant_id_from_jwt>';
|
||||
```
|
||||
|
||||
## Consequences
|
||||
|
||||
**Positive**:
|
||||
- Database-level enforcement (cannot be bypassed by application bugs)
|
||||
- Automatic filtering on all queries (including ORMs)
|
||||
- Performance: RLS uses indexes efficiently
|
||||
|
||||
**Negative**:
|
||||
- Requires setting session context per connection
|
||||
- Slightly more complex query plans
|
||||
|
||||
## Monitoring
|
||||
|
||||
- Weekly audit: Check for tables missing RLS
|
||||
- Quarterly penetration test: Attempt cross-tenant access
|
||||
```
|
||||
|
||||
## Results
|
||||
|
||||
### Before
|
||||
|
||||
- No architecture documentation
|
||||
- 3-4 weeks until new developer productive
|
||||
- 15+ hours/week answering architecture questions
|
||||
- Architecture decisions lost to time
|
||||
- Difficult to identify bottlenecks
|
||||
|
||||
### After
|
||||
|
||||
- Comprehensive architecture docs with 8 Mermaid diagrams
|
||||
- 5 Architecture Decision Records documenting key choices
|
||||
- Documentation in Git (versioned, reviewed)
|
||||
- Interactive diagrams (clickable, navigable)
|
||||
|
||||
### Improvements
|
||||
|
||||
- Onboarding time: 3-4 weeks → 4-5 days (75% reduction)
|
||||
- Architecture questions: 15 hrs/week → 2 hrs/week (87% reduction)
|
||||
- New developer productivity: Week 4 → Week 1
|
||||
- Time to understand data flow: 2 weeks → 1 day
|
||||
|
||||
### Developer Feedback
|
||||
|
||||
- "The sequence diagrams made auth flow crystal clear"
|
||||
- "ERD diagram helped me understand relationships immediately"
|
||||
- "ADRs answered 'why did we choose X?' questions"
|
||||
|
||||
## Key Lessons
|
||||
|
||||
1. **Mermaid Diagrams**: Version-controlled, reviewable, always up-to-date
|
||||
2. **Multiple Perspectives**: System, sequence, data flow, deployment diagrams all needed
|
||||
3. **ADRs are Critical**: "Why" is as important as "what"
|
||||
4. **Progressive Disclosure**: Overview first, then drill into details
|
||||
5. **Keep Diagrams Simple**: One concept per diagram, not everything at once
|
||||
|
||||
## Prevention Measures
|
||||
|
||||
**Implemented**:
|
||||
- [x] All architecture docs in Git (versioned)
|
||||
- [x] Mermaid diagrams (not static images)
|
||||
- [x] ADR template for all major decisions
|
||||
- [x] Onboarding checklist includes reading architecture docs
|
||||
|
||||
**Ongoing**:
|
||||
- [ ] Auto-generate diagrams from code (infrastructure as code)
|
||||
- [ ] Quarterly architecture review (docs up-to-date?)
|
||||
- [ ] New ADR for every major technical decision
|
||||
|
||||
---
|
||||
|
||||
Related: [openapi-generation.md](openapi-generation.md) | [coverage-validation.md](coverage-validation.md) | [Return to INDEX](INDEX.md)
|
||||
@@ -0,0 +1,411 @@
|
||||
# Example: Documentation Coverage Validation and Gap Analysis
|
||||
|
||||
Complete workflow for analyzing documentation coverage, identifying gaps, and establishing quality gates in CI/CD.
|
||||
|
||||
## Context
|
||||
|
||||
**Project**: FastAPI + TanStack Start SaaS Platform
|
||||
**Problem**: Documentation coverage unknown, many functions and API endpoints undocumented
|
||||
**Goal**: Establish 80% documentation coverage with CI/CD enforcement
|
||||
|
||||
**Initial State**:
|
||||
- No visibility into documentation coverage
|
||||
- 147 undocumented functions and 23 undocumented API endpoints
|
||||
- New code merged without documentation requirements
|
||||
- Partners complained about missing API documentation
|
||||
|
||||
## Step 1: TypeScript Documentation Coverage Analysis
|
||||
|
||||
```typescript
|
||||
// scripts/analyze-ts-coverage.ts
|
||||
import { Project } from "ts-morph";
|
||||
|
||||
function analyzeTypeScriptCoverage(projectPath: string) {
|
||||
const project = new Project({ tsConfigFilePath: `${projectPath}/tsconfig.json` });
|
||||
|
||||
const result = { total: 0, documented: 0, undocumented: [] };
|
||||
|
||||
project.getSourceFiles().forEach((sourceFile) => {
|
||||
// Analyze exported functions
|
||||
sourceFile.getFunctions().filter((fn) => fn.isExported()).forEach((fn) => {
|
||||
result.total++;
|
||||
const jsDocs = fn.getJsDocs();
|
||||
|
||||
if (jsDocs.length > 0 && jsDocs[0].getDescription().trim().length > 0) {
|
||||
result.documented++;
|
||||
} else {
|
||||
result.undocumented.push({
|
||||
name: fn.getName() || "(anonymous)",
|
||||
location: `${sourceFile.getFilePath()}:${fn.getStartLineNumber()}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Analyze interfaces
|
||||
sourceFile.getInterfaces().forEach((iface) => {
|
||||
if (!iface.isExported()) return;
|
||||
result.total++;
|
||||
if (iface.getJsDocs().length > 0) {
|
||||
result.documented++;
|
||||
} else {
|
||||
result.undocumented.push({
|
||||
name: iface.getName(),
|
||||
location: `${sourceFile.getFilePath()}:${iface.getStartLineNumber()}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const coverage = (result.documented / result.total) * 100;
|
||||
|
||||
console.log(`TypeScript Coverage: ${coverage.toFixed(1)}%`);
|
||||
console.log(`Documented: ${result.documented} / ${result.total}`);
|
||||
|
||||
if (result.undocumented.length > 0) {
|
||||
console.log("\nMissing documentation:");
|
||||
result.undocumented.forEach((item) => console.log(` - ${item.name} (${item.location})`));
|
||||
}
|
||||
|
||||
if (coverage < 80) {
|
||||
console.error(`❌ Coverage ${coverage.toFixed(1)}% below threshold 80%`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`✅ Coverage ${coverage.toFixed(1)}% meets threshold`);
|
||||
}
|
||||
|
||||
analyzeTypeScriptCoverage("./app");
|
||||
```
|
||||
|
||||
## Step 2: Python Documentation Coverage Analysis
|
||||
|
||||
```python
|
||||
# scripts/analyze_py_coverage.py
|
||||
import ast
|
||||
from pathlib import Path
|
||||
from typing import List, Dict
|
||||
|
||||
class DocstringAnalyzer(ast.NodeVisitor):
|
||||
def __init__(self):
|
||||
self.total = 0
|
||||
self.documented = 0
|
||||
self.undocumented: List[Dict] = []
|
||||
self.current_file = ""
|
||||
|
||||
def visit_FunctionDef(self, node: ast.FunctionDef):
|
||||
if node.name.startswith("_"): # Skip private functions
|
||||
return
|
||||
|
||||
self.total += 1
|
||||
docstring = ast.get_docstring(node)
|
||||
|
||||
if docstring and len(docstring.strip()) > 10:
|
||||
self.documented += 1
|
||||
else:
|
||||
self.undocumented.append({
|
||||
"name": node.name,
|
||||
"type": "function",
|
||||
"location": f"{self.current_file}:{node.lineno}"
|
||||
})
|
||||
self.generic_visit(node)
|
||||
|
||||
def visit_ClassDef(self, node: ast.ClassDef):
|
||||
self.total += 1
|
||||
docstring = ast.get_docstring(node)
|
||||
|
||||
if docstring and len(docstring.strip()) > 10:
|
||||
self.documented += 1
|
||||
else:
|
||||
self.undocumented.append({
|
||||
"name": node.name,
|
||||
"type": "class",
|
||||
"location": f"{self.current_file}:{node.lineno}"
|
||||
})
|
||||
self.generic_visit(node)
|
||||
|
||||
def analyze_python_coverage(project_path: str):
|
||||
analyzer = DocstringAnalyzer()
|
||||
|
||||
for py_file in Path(project_path).rglob("*.py"):
|
||||
if "__pycache__" in str(py_file):
|
||||
continue
|
||||
|
||||
analyzer.current_file = str(py_file)
|
||||
with open(py_file, "r") as f:
|
||||
try:
|
||||
tree = ast.parse(f.read())
|
||||
analyzer.visit(tree)
|
||||
except SyntaxError:
|
||||
print(f"⚠️ Syntax error in {py_file}")
|
||||
|
||||
coverage = (analyzer.documented / analyzer.total * 100) if analyzer.total > 0 else 0
|
||||
|
||||
print(f"Python Coverage: {coverage:.1f}%")
|
||||
print(f"Documented: {analyzer.documented} / {analyzer.total}")
|
||||
|
||||
if analyzer.undocumented:
|
||||
print("\nMissing documentation:")
|
||||
for item in analyzer.undocumented:
|
||||
print(f" - {item['type']} {item['name']} ({item['location']})")
|
||||
|
||||
if coverage < 80:
|
||||
print(f"❌ Coverage {coverage:.1f}% below threshold 80%")
|
||||
exit(1)
|
||||
|
||||
print(f"✅ Coverage {coverage:.1f}% meets threshold")
|
||||
|
||||
analyze_python_coverage("./app")
|
||||
```
|
||||
|
||||
## Step 3: API Endpoint Documentation Coverage
|
||||
|
||||
```python
|
||||
# scripts/analyze_api_coverage.py
|
||||
from fastapi import FastAPI
|
||||
|
||||
def analyze_api_documentation(app: FastAPI):
|
||||
result = {"total_endpoints": 0, "documented": 0, "undocumented": []}
|
||||
|
||||
openapi = app.openapi()
|
||||
|
||||
for path, methods in openapi["paths"].items():
|
||||
for method, details in methods.items():
|
||||
result["total_endpoints"] += 1
|
||||
|
||||
has_summary = bool(details.get("summary"))
|
||||
has_description = bool(details.get("description"))
|
||||
|
||||
if has_summary and has_description:
|
||||
result["documented"] += 1
|
||||
else:
|
||||
missing = []
|
||||
if not has_summary: missing.append("summary")
|
||||
if not has_description: missing.append("description")
|
||||
|
||||
result["undocumented"].append({
|
||||
"method": method.upper(),
|
||||
"path": path,
|
||||
"missing": missing
|
||||
})
|
||||
|
||||
coverage = (result["documented"] / result["total_endpoints"] * 100)
|
||||
|
||||
print(f"API Coverage: {coverage:.1f}%")
|
||||
print(f"Documented: {result['documented']} / {result['total_endpoints']}")
|
||||
|
||||
if result["undocumented"]:
|
||||
print("\nMissing documentation:")
|
||||
for endpoint in result["undocumented"]:
|
||||
missing = ", ".join(endpoint["missing"])
|
||||
print(f" - {endpoint['method']} {endpoint['path']} (missing: {missing})")
|
||||
|
||||
if coverage < 80:
|
||||
print(f"❌ Coverage {coverage:.1f}% below threshold 80%")
|
||||
exit(1)
|
||||
|
||||
print(f"✅ Coverage {coverage:.1f}% meets threshold")
|
||||
|
||||
from app.main import app
|
||||
analyze_api_documentation(app)
|
||||
```
|
||||
|
||||
## Step 4: Comprehensive HTML Coverage Report
|
||||
|
||||
```python
|
||||
# scripts/generate_coverage_report.py
|
||||
from jinja2 import Template
|
||||
from datetime import datetime
|
||||
|
||||
def generate_coverage_report(ts_coverage, py_coverage, api_coverage):
|
||||
template = Template('''
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Documentation Coverage Report</title>
|
||||
<style>
|
||||
body { font-family: Arial; margin: 40px; }
|
||||
.summary { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
|
||||
.card { border: 1px solid #ddd; padding: 20px; border-radius: 8px; }
|
||||
.card.pass { border-left: 4px solid #28a745; }
|
||||
.card.fail { border-left: 4px solid #dc3545; }
|
||||
.coverage { font-size: 48px; font-weight: bold; margin: 10px 0; }
|
||||
.undocumented { margin-top: 40px; }
|
||||
.undocumented li { padding: 8px; background: #f8f9fa; margin: 4px 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Documentation Coverage Report</h1>
|
||||
<p>Generated: {{ timestamp }}</p>
|
||||
|
||||
<div class="summary">
|
||||
<div class="card {{ 'pass' if ts_coverage.coverage >= 80 else 'fail' }}">
|
||||
<h3>TypeScript</h3>
|
||||
<div class="coverage">{{ "%.1f"|format(ts_coverage.coverage) }}%</div>
|
||||
<p>{{ ts_coverage.documented }} / {{ ts_coverage.total }}</p>
|
||||
</div>
|
||||
<div class="card {{ 'pass' if py_coverage.coverage >= 80 else 'fail' }}">
|
||||
<h3>Python</h3>
|
||||
<div class="coverage">{{ "%.1f"|format(py_coverage.coverage) }}%</div>
|
||||
<p>{{ py_coverage.documented }} / {{ py_coverage.total }}</p>
|
||||
</div>
|
||||
<div class="card {{ 'pass' if api_coverage.coverage >= 80 else 'fail' }}">
|
||||
<h3>API</h3>
|
||||
<div class="coverage">{{ "%.1f"|format(api_coverage.coverage) }}%</div>
|
||||
<p>{{ api_coverage.documented }} / {{ api_coverage.total_endpoints }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% for section in [ts_coverage, py_coverage] %}
|
||||
{% if section.undocumented %}
|
||||
<div class="undocumented">
|
||||
<h2>{{ section.name }} - Missing Documentation</h2>
|
||||
<ul>
|
||||
{% for item in section.undocumented %}
|
||||
<li><strong>{{ item.name }}</strong> - {{ item.location }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</body>
|
||||
</html>
|
||||
''')
|
||||
|
||||
html = template.render(
|
||||
timestamp=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
ts_coverage=ts_coverage,
|
||||
py_coverage=py_coverage,
|
||||
api_coverage=api_coverage
|
||||
)
|
||||
|
||||
with open("docs/coverage-report.html", "w") as f:
|
||||
f.write(html)
|
||||
|
||||
print("📊 Coverage report generated: docs/coverage-report.html")
|
||||
```
|
||||
|
||||
## Step 5: CI/CD Integration
|
||||
|
||||
```yaml
|
||||
# .github/workflows/documentation-coverage.yml
|
||||
name: Documentation Coverage
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
documentation-coverage:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
npm install
|
||||
pip install -r requirements.txt jinja2
|
||||
|
||||
- name: Check TypeScript coverage
|
||||
run: npx ts-node scripts/analyze-ts-coverage.ts
|
||||
|
||||
- name: Check Python coverage
|
||||
run: python scripts/analyze_py_coverage.py
|
||||
|
||||
- name: Check API coverage
|
||||
run: python scripts/analyze_api_coverage.py
|
||||
|
||||
- name: Generate report
|
||||
if: always()
|
||||
run: python scripts/generate_coverage_report.py
|
||||
|
||||
- name: Upload report
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coverage-report
|
||||
path: docs/coverage-report.html
|
||||
|
||||
- name: Comment on PR
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: '📊 Documentation coverage report generated. Check artifacts.'
|
||||
});
|
||||
```
|
||||
|
||||
## Results
|
||||
|
||||
### Before
|
||||
|
||||
- Documentation coverage: unknown
|
||||
- No visibility into gaps
|
||||
- 147 undocumented functions
|
||||
- 23 undocumented API endpoints
|
||||
- New code merged without docs
|
||||
- Partners complained about missing docs
|
||||
|
||||
### After
|
||||
|
||||
- TypeScript coverage: 42% → 87%
|
||||
- Python coverage: 38% → 91%
|
||||
- API endpoint coverage: 51% → 95%
|
||||
- CI/CD enforcement (fails build if <80%)
|
||||
- Automated HTML reports
|
||||
|
||||
### Improvements
|
||||
|
||||
- Undocumented functions: 147 → 18 (88% reduction)
|
||||
- Undocumented endpoints: 23 → 1 (96% reduction)
|
||||
- Time to find function docs: 15 min → instant
|
||||
- Partner onboarding: 2 weeks → 3 days
|
||||
- Documentation debt: eliminated weekly
|
||||
|
||||
### Developer Feedback
|
||||
|
||||
- "Coverage reports made it clear what needed docs"
|
||||
- "CI/CD enforcement prevented new undocumented code"
|
||||
- "HTML report showed exactly what was missing"
|
||||
- "80% threshold is challenging but achievable"
|
||||
|
||||
## Key Lessons
|
||||
|
||||
1. **Automated Analysis**: Manual tracking doesn't scale
|
||||
2. **CI/CD Enforcement**: Prevents documentation regression
|
||||
3. **Visibility**: Reports show exactly what's missing
|
||||
4. **Threshold-Based**: 80% coverage is achievable and meaningful
|
||||
5. **Multi-Language**: Each language needs appropriate tooling (ts-morph, AST, OpenAPI)
|
||||
6. **HTML Reports**: Visual representation drives action
|
||||
|
||||
## Prevention Measures
|
||||
|
||||
**Implemented**:
|
||||
- [x] TypeScript coverage analysis (ts-morph)
|
||||
- [x] Python coverage analysis (AST)
|
||||
- [x] API endpoint documentation check
|
||||
- [x] HTML coverage reports
|
||||
- [x] CI/CD integration (fails below 80%)
|
||||
- [x] PR comments with coverage status
|
||||
|
||||
**Ongoing**:
|
||||
- [ ] Pre-commit hooks (warn if adding undocumented code)
|
||||
- [ ] Dashboard showing coverage trends over time
|
||||
- [ ] Team documentation KPIs (quarterly review)
|
||||
- [ ] Automated "most undocumented files" weekly report
|
||||
|
||||
---
|
||||
|
||||
Related: [openapi-generation.md](openapi-generation.md) | [architecture-docs.md](architecture-docs.md) | [Return to INDEX](INDEX.md)
|
||||
437
skills/documentation-architecture/examples/openapi-generation.md
Normal file
437
skills/documentation-architecture/examples/openapi-generation.md
Normal file
@@ -0,0 +1,437 @@
|
||||
# Example: OpenAPI 3.1 Generation from FastAPI Codebase
|
||||
|
||||
Complete workflow showing automatic OpenAPI specification generation from a FastAPI codebase with Pydantic v2 models.
|
||||
|
||||
## Context
|
||||
|
||||
**Project**: E-commerce API (FastAPI + Pydantic v2 + SQLModel)
|
||||
**Problem**: Manual API documentation was 3 months out of date, causing integration failures for 2 partner teams
|
||||
**Goal**: Generate comprehensive OpenAPI 3.1 spec automatically from code with multi-language examples
|
||||
|
||||
**Initial State**:
|
||||
- 47 API endpoints with no documentation
|
||||
- 12 integration issues per week from stale documentation
|
||||
- Manual doc updates taking 4+ hours per release
|
||||
- Partners blocked waiting for updated contracts
|
||||
|
||||
## Step 1: Pydantic v2 Models with Rich Schemas
|
||||
|
||||
```python
|
||||
# app/models/orders.py
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import List
|
||||
from datetime import datetime
|
||||
|
||||
class OrderItem(BaseModel):
|
||||
product_id: str = Field(..., description="Product identifier")
|
||||
quantity: int = Field(..., gt=0, description="Quantity to order")
|
||||
unit_price: float = Field(..., gt=0, description="Price per unit in USD")
|
||||
|
||||
class OrderCreate(BaseModel):
|
||||
"""Create a new order for the authenticated user."""
|
||||
items: List[OrderItem] = Field(..., min_length=1, description="Order line items")
|
||||
shipping_address_id: str = Field(..., description="ID of shipping address")
|
||||
|
||||
model_config = {
|
||||
"json_schema_extra": {
|
||||
"examples": [{
|
||||
"items": [{"product_id": "prod_123", "quantity": 2, "unit_price": 29.99}],
|
||||
"shipping_address_id": "addr_456"
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
class Order(BaseModel):
|
||||
"""Order with calculated totals."""
|
||||
id: str
|
||||
user_id: str
|
||||
items: List[OrderItem]
|
||||
subtotal: float = Field(..., description="Sum of all item prices")
|
||||
tax: float = Field(..., description="Calculated tax amount")
|
||||
total: float = Field(..., description="Final order total")
|
||||
status: str = Field(..., description="pending, processing, shipped, delivered, cancelled")
|
||||
created_at: datetime
|
||||
```
|
||||
|
||||
## Step 2: Enhanced OpenAPI Generation
|
||||
|
||||
```python
|
||||
# app/main.py
|
||||
from fastapi import FastAPI
|
||||
from fastapi.openapi.utils import get_openapi
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
def custom_openapi():
|
||||
if app.openapi_schema:
|
||||
return app.openapi_schema
|
||||
|
||||
openapi_schema = get_openapi(
|
||||
title="Grey Haven E-Commerce API",
|
||||
version="1.0.0",
|
||||
description="E-commerce API with JWT auth. Rate limit: 1000 req/hour (authenticated).",
|
||||
routes=app.routes,
|
||||
)
|
||||
|
||||
# Add security schemes
|
||||
openapi_schema["components"]["securitySchemes"] = {
|
||||
"BearerAuth": {
|
||||
"type": "http",
|
||||
"scheme": "bearer",
|
||||
"bearerFormat": "JWT",
|
||||
"description": "JWT token from /auth/login"
|
||||
}
|
||||
}
|
||||
openapi_schema["security"] = [{"BearerAuth": []}]
|
||||
|
||||
# Add error response schema
|
||||
openapi_schema["components"]["schemas"]["ErrorResponse"] = {
|
||||
"type": "object",
|
||||
"required": ["error", "message"],
|
||||
"properties": {
|
||||
"error": {"type": "string", "example": "INSUFFICIENT_STOCK"},
|
||||
"message": {"type": "string", "example": "Product has insufficient stock"},
|
||||
"details": {"type": "object", "additionalProperties": True}
|
||||
}
|
||||
}
|
||||
|
||||
# Add rate limit headers
|
||||
openapi_schema["components"]["headers"] = {
|
||||
"X-RateLimit-Limit": {"description": "Request limit per hour", "schema": {"type": "integer"}},
|
||||
"X-RateLimit-Remaining": {"description": "Remaining requests", "schema": {"type": "integer"}},
|
||||
"X-RateLimit-Reset": {"description": "Reset timestamp", "schema": {"type": "integer"}}
|
||||
}
|
||||
|
||||
app.openapi_schema = openapi_schema
|
||||
return app.openapi_schema
|
||||
|
||||
app.openapi = custom_openapi
|
||||
```
|
||||
|
||||
## Step 3: FastAPI Route with Complete Documentation
|
||||
|
||||
```python
|
||||
# app/routers/orders.py
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
|
||||
router = APIRouter(prefix="/api/v1/orders", tags=["orders"])
|
||||
|
||||
@router.post("/", response_model=Order, status_code=201)
|
||||
async def create_order(
|
||||
order_data: OrderCreate,
|
||||
current_user: User = Depends(get_current_user),
|
||||
session: Session = Depends(get_session)
|
||||
) -> Order:
|
||||
"""
|
||||
Create a new order for the authenticated user.
|
||||
|
||||
The order will be created in 'pending' status and total calculated
|
||||
including applicable taxes based on shipping address.
|
||||
|
||||
**Requires**:
|
||||
- Valid JWT authentication token
|
||||
- At least one item in the order
|
||||
- Valid shipping address ID owned by the user
|
||||
|
||||
**Returns**: Created order with calculated totals
|
||||
|
||||
**Raises**:
|
||||
- **401 Unauthorized**: If user is not authenticated
|
||||
- **404 Not Found**: If shipping address not found
|
||||
- **400 Bad Request**: If product stock insufficient or validation fails
|
||||
- **429 Too Many Requests**: If rate limit exceeded
|
||||
"""
|
||||
# Validate shipping address belongs to user
|
||||
address = session.get(ShippingAddress, order_data.shipping_address_id)
|
||||
if not address or address.user_id != current_user.id:
|
||||
raise HTTPException(404, detail="Shipping address not found")
|
||||
|
||||
# Check stock availability
|
||||
for item in order_data.items:
|
||||
product = session.get(Product, item.product_id)
|
||||
if not product or product.stock < item.quantity:
|
||||
raise HTTPException(
|
||||
400,
|
||||
detail={
|
||||
"error": "INSUFFICIENT_STOCK",
|
||||
"message": f"Product {item.product_id} has insufficient stock",
|
||||
"details": {
|
||||
"product_id": item.product_id,
|
||||
"requested": item.quantity,
|
||||
"available": product.stock if product else 0
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
# Create order and calculate totals
|
||||
order = Order(
|
||||
user_id=current_user.id,
|
||||
items=order_data.items,
|
||||
subtotal=sum(item.quantity * item.unit_price for item in order_data.items)
|
||||
)
|
||||
order.tax = order.subtotal * 0.08 # 8% tax
|
||||
order.total = order.subtotal + order.tax
|
||||
order.status = "pending"
|
||||
|
||||
session.add(order)
|
||||
session.commit()
|
||||
return order
|
||||
```
|
||||
|
||||
## Step 4: Multi-Language Code Examples
|
||||
|
||||
### Automated Example Generation
|
||||
|
||||
```python
|
||||
# scripts/generate_examples.py
|
||||
def generate_examples(openapi_spec):
|
||||
"""Generate TypeScript, Python, and cURL examples for each endpoint."""
|
||||
|
||||
examples = {}
|
||||
|
||||
for path, methods in openapi_spec["paths"].items():
|
||||
for method, details in methods.items():
|
||||
operation_id = details.get("operationId", f"{method}_{path}")
|
||||
|
||||
# TypeScript example
|
||||
examples[f"{operation_id}_typescript"] = f'''
|
||||
const response = await fetch('https://api.greyhaven.com{path}', {{
|
||||
method: '{method.upper()}',
|
||||
headers: {{
|
||||
'Authorization': 'Bearer YOUR_API_TOKEN',
|
||||
'Content-Type': 'application/json'
|
||||
}},
|
||||
body: JSON.stringify({{
|
||||
items: [{{ product_id: "prod_123", quantity: 2, unit_price: 29.99 }}],
|
||||
shipping_address_id: "addr_456"
|
||||
}})
|
||||
}});
|
||||
const order = await response.json();
|
||||
'''
|
||||
|
||||
# Python example
|
||||
examples[f"{operation_id}_python"] = f'''
|
||||
import requests
|
||||
|
||||
response = requests.{method}(
|
||||
'https://api.greyhaven.com{path}',
|
||||
headers={{'Authorization': 'Bearer YOUR_API_TOKEN'}},
|
||||
json={{
|
||||
'items': [{{'product_id': 'prod_123', 'quantity': 2, 'unit_price': 29.99}}],
|
||||
'shipping_address_id': 'addr_456'
|
||||
}}
|
||||
)
|
||||
order = response.json()
|
||||
'''
|
||||
|
||||
# cURL example
|
||||
examples[f"{operation_id}_curl"] = f'''
|
||||
curl -X {method.upper()} https://api.greyhaven.com{path} \\
|
||||
-H "Authorization: Bearer YOUR_API_TOKEN" \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-d '{{"items": [{{"product_id": "prod_123", "quantity": 2, "unit_price": 29.99}}], "shipping_address_id": "addr_456"}}'
|
||||
'''
|
||||
|
||||
return examples
|
||||
```
|
||||
|
||||
## Step 5: Interactive Swagger UI
|
||||
|
||||
```python
|
||||
# app/main.py (enhanced)
|
||||
from fastapi.openapi.docs import get_swagger_ui_html
|
||||
|
||||
@app.get("/docs", include_in_schema=False)
|
||||
async def custom_swagger_ui_html():
|
||||
return get_swagger_ui_html(
|
||||
openapi_url="/openapi.json",
|
||||
title=f"{app.title} - API Documentation",
|
||||
swagger_js_url="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js",
|
||||
swagger_css_url="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css",
|
||||
swagger_ui_parameters={
|
||||
"persistAuthorization": True, # Remember auth token
|
||||
"displayRequestDuration": True, # Show request timing
|
||||
"filter": True, # Enable filtering
|
||||
"tryItOutEnabled": True # Enable try-it-out by default
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
## Step 6: CI/CD Auto-Generation
|
||||
|
||||
```yaml
|
||||
# .github/workflows/generate-docs.yml
|
||||
name: Generate API Documentation
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths: ['app/**/*.py']
|
||||
|
||||
jobs:
|
||||
generate-docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Generate OpenAPI spec
|
||||
run: |
|
||||
pip install -r requirements.txt
|
||||
python -c "
|
||||
from app.main import app
|
||||
import json
|
||||
with open('docs/openapi.json', 'w') as f:
|
||||
json.dump(app.openapi(), f, indent=2)
|
||||
"
|
||||
|
||||
- name: Generate code examples
|
||||
run: python scripts/generate_examples.py
|
||||
|
||||
- name: Validate OpenAPI
|
||||
run: npx @redocly/cli lint docs/openapi.json
|
||||
|
||||
- name: Deploy to Cloudflare Pages
|
||||
run: |
|
||||
npm install -g wrangler
|
||||
wrangler pages deploy docs/ --project-name=api-docs
|
||||
env:
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
```
|
||||
|
||||
## Generated OpenAPI Specification (Excerpt)
|
||||
|
||||
```yaml
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
title: Grey Haven E-Commerce API
|
||||
version: 1.0.0
|
||||
description: E-commerce API with JWT auth. Rate limit: 1000 req/hour.
|
||||
|
||||
servers:
|
||||
- url: https://api.greyhaven.com
|
||||
description: Production
|
||||
|
||||
paths:
|
||||
/api/v1/orders:
|
||||
post:
|
||||
summary: Create a new order
|
||||
description: Create order in 'pending' status with calculated totals
|
||||
operationId: createOrder
|
||||
tags: [orders]
|
||||
security:
|
||||
- BearerAuth: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/OrderCreate'
|
||||
responses:
|
||||
'201':
|
||||
description: Order created successfully
|
||||
headers:
|
||||
X-RateLimit-Limit:
|
||||
$ref: '#/components/headers/X-RateLimit-Limit'
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Order'
|
||||
'400':
|
||||
description: Validation error or insufficient stock
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
'401':
|
||||
description: Unauthorized (invalid token)
|
||||
'429':
|
||||
description: Rate limit exceeded
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
BearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
|
||||
schemas:
|
||||
OrderItem:
|
||||
type: object
|
||||
required: [product_id, quantity, unit_price]
|
||||
properties:
|
||||
product_id:
|
||||
type: string
|
||||
example: "prod_123"
|
||||
quantity:
|
||||
type: integer
|
||||
minimum: 1
|
||||
example: 2
|
||||
unit_price:
|
||||
type: number
|
||||
minimum: 0.01
|
||||
example: 29.99
|
||||
```
|
||||
|
||||
## Results
|
||||
|
||||
### Before
|
||||
|
||||
- Manual documentation 3 months out of date
|
||||
- 47 endpoints with no docs
|
||||
- 12 integration issues per week
|
||||
- 4+ hours manual doc updates per release
|
||||
- Partners blocked waiting for updated contracts
|
||||
|
||||
### After
|
||||
|
||||
- OpenAPI spec auto-generated on every commit
|
||||
- 100% endpoint coverage with examples
|
||||
- Interactive Swagger UI with try-it-out
|
||||
- Multi-language examples (TypeScript, Python, cURL)
|
||||
- Complete error response documentation
|
||||
|
||||
### Improvements
|
||||
|
||||
- Integration issues: 12/week → 0.5/week (96% reduction)
|
||||
- Doc update time: 4 hours → 0 minutes (automated)
|
||||
- Partner satisfaction: 45% → 98%
|
||||
- Time-to-integration: 2 weeks → 2 days
|
||||
|
||||
### Partner Feedback
|
||||
|
||||
- "The interactive docs with try-it-out saved us days of testing"
|
||||
- "Code examples in our language made integration trivial"
|
||||
- "Error responses are fully documented - no guesswork"
|
||||
|
||||
## Key Lessons
|
||||
|
||||
1. **Automation is Critical**: Manual docs will always drift from code
|
||||
2. **Pydantic v2 Schema**: Excellent OpenAPI generation with field validators
|
||||
3. **Multi-Language Examples**: Dramatically improved partner integration speed
|
||||
4. **Interactive Docs**: Try-it-out functionality reduced support tickets
|
||||
5. **CI/CD Integration**: Documentation stays current automatically
|
||||
6. **Error Documentation**: Complete error schemas eliminated guesswork
|
||||
|
||||
## Prevention Measures
|
||||
|
||||
**Implemented**:
|
||||
- [x] Auto-generation on every commit (GitHub Actions)
|
||||
- [x] OpenAPI spec validation in CI/CD
|
||||
- [x] Interactive Swagger UI deployed to Cloudflare Pages
|
||||
- [x] Multi-language code examples generated
|
||||
- [x] Complete error response schemas
|
||||
- [x] Rate limiting documentation
|
||||
|
||||
**Ongoing**:
|
||||
- [ ] SDK auto-generation from OpenAPI spec (TypeScript, Python clients)
|
||||
- [ ] Contract testing (validate API matches OpenAPI spec)
|
||||
- [ ] Changelog generation from git commits
|
||||
|
||||
---
|
||||
|
||||
Related: [architecture-docs.md](architecture-docs.md) | [coverage-validation.md](coverage-validation.md) | [Return to INDEX](INDEX.md)
|
||||
55
skills/documentation-architecture/reference/INDEX.md
Normal file
55
skills/documentation-architecture/reference/INDEX.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Documentation Reference
|
||||
|
||||
Quick-lookup guides for OpenAPI patterns, Mermaid diagrams, and documentation quality standards.
|
||||
|
||||
## Available References
|
||||
|
||||
### [OpenAPI 3.1 Patterns](openapi-patterns.md)
|
||||
|
||||
Comprehensive OpenAPI 3.1 specification patterns for Grey Haven stack.
|
||||
|
||||
**Covers**: Complete schemas, authentication (JWT/OAuth2/API Key), error responses, pagination, multi-language examples, webhooks, FastAPI integration
|
||||
|
||||
**Use for**: API documentation generation, OpenAPI schema creation, endpoint documentation standards
|
||||
|
||||
---
|
||||
|
||||
### [Mermaid Diagram Templates](mermaid-diagrams.md)
|
||||
|
||||
Complete templates for all Mermaid diagram types with Grey Haven examples.
|
||||
|
||||
**Covers**: System architecture, sequence diagrams, data flow, ER diagrams, state machines, deployment diagrams, class diagrams
|
||||
|
||||
**Use for**: Architecture documentation, visualizing data flows, documenting state transitions, database schemas
|
||||
|
||||
---
|
||||
|
||||
### [Documentation Standards](documentation-standards.md)
|
||||
|
||||
Quality standards and best practices for technical documentation.
|
||||
|
||||
**Covers**: Writing style, code examples, API documentation templates, function documentation (JSDoc/docstrings), README structure, quality checklist
|
||||
|
||||
**Use for**: Ensuring consistency, setting quality thresholds, creating maintainable documentation
|
||||
|
||||
---
|
||||
|
||||
## Common Patterns
|
||||
|
||||
1. **API Documentation**: Use OpenAPI patterns + documentation standards
|
||||
2. **Architecture Docs**: Use Mermaid diagrams + ADR template from standards
|
||||
3. **Coverage Validation**: Use standards checklist + automated tools
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Need | Reference | Key Section |
|
||||
|------|-----------|-------------|
|
||||
| API endpoint docs | [openapi-patterns.md](openapi-patterns.md) | Endpoint Documentation Template |
|
||||
| System diagrams | [mermaid-diagrams.md](mermaid-diagrams.md) | Architecture Diagrams |
|
||||
| Quality checklist | [documentation-standards.md](documentation-standards.md) | Quality Checklist |
|
||||
| Code examples | [documentation-standards.md](documentation-standards.md) | Code Examples |
|
||||
| Error responses | [openapi-patterns.md](openapi-patterns.md) | Error Response Schema |
|
||||
|
||||
---
|
||||
|
||||
Related: [Examples](../examples/INDEX.md) | [Templates](../templates/) | [Return to Agent](../docs-architect.md)
|
||||
@@ -0,0 +1,496 @@
|
||||
# Documentation Standards and Quality Guidelines
|
||||
|
||||
Comprehensive standards for creating high-quality technical documentation for Grey Haven projects.
|
||||
|
||||
## Documentation Principles
|
||||
|
||||
### 1. Progressive Disclosure
|
||||
Start with overview, provide details on demand.
|
||||
|
||||
**Good**:
|
||||
```markdown
|
||||
# User Authentication
|
||||
|
||||
Quick overview: Our authentication uses JWT tokens with refresh rotation.
|
||||
|
||||
## Getting Started
|
||||
[Simple example]
|
||||
|
||||
## Advanced Usage
|
||||
[Detailed configuration options]
|
||||
|
||||
## Security Considerations
|
||||
[Deep dive into security]
|
||||
```
|
||||
|
||||
### 2. Show, Don't Tell
|
||||
Use code examples instead of lengthy explanations.
|
||||
|
||||
**Bad**: "To create a user, you need to instantiate a User class with email and password, then call the save method."
|
||||
|
||||
**Good**:
|
||||
```python
|
||||
user = User(email="user@example.com", password="secure123")
|
||||
user.save()
|
||||
```
|
||||
|
||||
### 3. Keep It Current
|
||||
Documentation that's out of date is worse than no documentation.
|
||||
|
||||
Use automation:
|
||||
- Auto-generate API docs from code
|
||||
- CI/CD validation (fail if docs outdated)
|
||||
- Link to code for truth source
|
||||
|
||||
## Writing Style
|
||||
|
||||
### Voice and Tone
|
||||
|
||||
**Use Active Voice**:
|
||||
- ❌ "The order will be processed by the system"
|
||||
- ✅ "The system processes the order"
|
||||
|
||||
**Be Direct**:
|
||||
- ❌ "It might be a good idea to consider using..."
|
||||
- ✅ "Use X when Y"
|
||||
|
||||
**Avoid Jargon**:
|
||||
- ❌ "Leverage our enterprise-grade synergistic platform"
|
||||
- ✅ "Use our API to manage users"
|
||||
|
||||
### Structure
|
||||
|
||||
**Every Page Should Have**:
|
||||
1. **Title**: Clear, descriptive
|
||||
2. **Summary**: 1-2 sentence overview
|
||||
3. **Prerequisites**: What user needs to know/have
|
||||
4. **Step-by-Step**: Numbered instructions
|
||||
5. **Code Examples**: Working, copy-paste ready
|
||||
6. **Troubleshooting**: Common errors and solutions
|
||||
7. **Next Steps**: Where to go next
|
||||
|
||||
### Code Examples
|
||||
|
||||
**Always Include**:
|
||||
- ✅ Complete, working examples
|
||||
- ✅ Expected output/result
|
||||
- ✅ Error handling
|
||||
- ✅ Comments explaining why, not what
|
||||
|
||||
**Example Template**:
|
||||
```python
|
||||
# Create a new user
|
||||
# Requires: Admin authentication
|
||||
# Returns: User object or raises ValidationError
|
||||
|
||||
try:
|
||||
user = User.objects.create(
|
||||
email="user@example.com",
|
||||
password="secure123",
|
||||
role="member" # Default role for new users
|
||||
)
|
||||
print(f"User created: {user.id}")
|
||||
except ValidationError as e:
|
||||
print(f"Validation failed: {e.message}")
|
||||
```
|
||||
|
||||
## API Documentation Standards
|
||||
|
||||
### Endpoint Documentation Template
|
||||
|
||||
```markdown
|
||||
## POST /api/v1/users
|
||||
|
||||
Create a new user account.
|
||||
|
||||
### Authentication
|
||||
Requires: Admin JWT token in Authorization header
|
||||
|
||||
### Request
|
||||
|
||||
**Headers**:
|
||||
- `Authorization: Bearer <token>` (required)
|
||||
- `Content-Type: application/json` (required)
|
||||
|
||||
**Body**:
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| email | string | Yes | Valid email address |
|
||||
| password | string | Yes | Min 8 characters |
|
||||
| role | string | No | Default: "member" |
|
||||
|
||||
**Example**:
|
||||
```json
|
||||
{
|
||||
"email": "user@example.com",
|
||||
"password": "secure123",
|
||||
"role": "member"
|
||||
}
|
||||
```
|
||||
|
||||
### Response
|
||||
|
||||
**Success (201 Created)**:
|
||||
```json
|
||||
{
|
||||
"id": "usr_123abc",
|
||||
"email": "user@example.com",
|
||||
"role": "member",
|
||||
"created_at": "2024-01-15T10:30:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
**Errors**:
|
||||
- `400 Bad Request`: Validation failed (email invalid, password too short)
|
||||
- `401 Unauthorized`: Missing or invalid auth token
|
||||
- `403 Forbidden`: User lacks admin role
|
||||
- `409 Conflict`: Email already exists
|
||||
- `429 Too Many Requests`: Rate limit exceeded
|
||||
|
||||
**Error Response**:
|
||||
```json
|
||||
{
|
||||
"error": "VALIDATION_ERROR",
|
||||
"message": "Email address is invalid",
|
||||
"details": {
|
||||
"field": "email",
|
||||
"value": "invalid-email"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Rate Limiting
|
||||
- Authenticated: 1000 requests/hour
|
||||
- Unauthenticated: 100 requests/hour
|
||||
|
||||
### Code Examples
|
||||
|
||||
**TypeScript**:
|
||||
```typescript
|
||||
const response = await fetch("https://api.greyhaven.com/users", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Authorization": `Bearer ${token}`,
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email: "user@example.com",
|
||||
password: "secure123"
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.message);
|
||||
}
|
||||
|
||||
const user = await response.json();
|
||||
console.log(`User created: ${user.id}`);
|
||||
```
|
||||
|
||||
**Python**:
|
||||
```python
|
||||
import httpx
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.post(
|
||||
"https://api.greyhaven.com/users",
|
||||
headers={"Authorization": f"Bearer {token}"},
|
||||
json={"email": "user@example.com", "password": "secure123"}
|
||||
)
|
||||
response.raise_for_status()
|
||||
user = response.json()
|
||||
print(f"User created: {user['id']}")
|
||||
```
|
||||
```
|
||||
|
||||
## Function Documentation Standards
|
||||
|
||||
### JSDoc (TypeScript)
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Calculate order total including tax and shipping.
|
||||
*
|
||||
* @param items - Array of order items with quantity and price
|
||||
* @param shippingAddress - Address for tax calculation
|
||||
* @returns Total amount in USD cents
|
||||
* @throws {ValidationError} If items array is empty
|
||||
* @throws {TaxCalculationError} If tax lookup fails
|
||||
*
|
||||
* @example
|
||||
* const total = calculateTotal(
|
||||
* [{ quantity: 2, price: 2999 }],
|
||||
* { zip: "94105", country: "US" }
|
||||
* );
|
||||
* // Returns: 6398 (5998 + 400 tax + 0 shipping)
|
||||
*/
|
||||
export function calculateTotal(
|
||||
items: OrderItem[],
|
||||
shippingAddress: Address
|
||||
): number {
|
||||
if (items.length === 0) {
|
||||
throw new ValidationError("Items array cannot be empty");
|
||||
}
|
||||
|
||||
const subtotal = items.reduce((sum, item) =>
|
||||
sum + (item.quantity * item.price), 0
|
||||
);
|
||||
|
||||
const tax = calculateTax(subtotal, shippingAddress);
|
||||
const shipping = calculateShipping(items, shippingAddress);
|
||||
|
||||
return subtotal + tax + shipping;
|
||||
}
|
||||
```
|
||||
|
||||
### Python Docstrings (Google Style)
|
||||
|
||||
```python
|
||||
def calculate_total(items: List[OrderItem], shipping_address: Address) -> int:
|
||||
"""Calculate order total including tax and shipping.
|
||||
|
||||
Args:
|
||||
items: Array of order items with quantity and price.
|
||||
shipping_address: Address for tax calculation.
|
||||
|
||||
Returns:
|
||||
Total amount in USD cents.
|
||||
|
||||
Raises:
|
||||
ValidationError: If items array is empty.
|
||||
TaxCalculationError: If tax lookup fails.
|
||||
|
||||
Example:
|
||||
>>> items = [OrderItem(quantity=2, price=2999)]
|
||||
>>> address = Address(zip="94105", country="US")
|
||||
>>> total = calculate_total(items, address)
|
||||
>>> print(total)
|
||||
6398 # 5998 + 400 tax + 0 shipping
|
||||
"""
|
||||
if not items:
|
||||
raise ValidationError("Items array cannot be empty")
|
||||
|
||||
subtotal = sum(item.quantity * item.price for item in items)
|
||||
tax = calculate_tax(subtotal, shipping_address)
|
||||
shipping = calculate_shipping(items, shipping_address)
|
||||
|
||||
return subtotal + tax + shipping
|
||||
```
|
||||
|
||||
## README Structure
|
||||
|
||||
Every project should have a comprehensive README:
|
||||
|
||||
```markdown
|
||||
# Project Name
|
||||
|
||||
One-line description of what this project does.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Visit http://localhost:3000
|
||||
|
||||
## Features
|
||||
|
||||
- Feature 1: Brief description
|
||||
- Feature 2: Brief description
|
||||
- Feature 3: Brief description
|
||||
|
||||
## Installation
|
||||
|
||||
### Prerequisites
|
||||
- Node.js 20+
|
||||
- PostgreSQL 14+
|
||||
- Redis (optional)
|
||||
|
||||
### Steps
|
||||
|
||||
1. Clone repository
|
||||
```bash
|
||||
git clone https://github.com/greyhaven/project.git
|
||||
cd project
|
||||
```
|
||||
|
||||
2. Install dependencies
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
3. Configure environment
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# Edit .env with your values
|
||||
```
|
||||
|
||||
4. Run migrations
|
||||
```bash
|
||||
npm run migrate
|
||||
```
|
||||
|
||||
5. Start development server
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|----------|----------|---------|-------------|
|
||||
| `DATABASE_URL` | Yes | - | PostgreSQL connection string |
|
||||
| `REDIS_URL` | No | - | Redis connection string |
|
||||
| `API_KEY` | Yes | - | API key for external service |
|
||||
|
||||
## Architecture
|
||||
|
||||
[Link to architecture docs or include Mermaid diagram]
|
||||
|
||||
## Development
|
||||
|
||||
### Running Tests
|
||||
```bash
|
||||
npm test
|
||||
```
|
||||
|
||||
### Code Quality
|
||||
```bash
|
||||
npm run lint
|
||||
npm run type-check
|
||||
```
|
||||
|
||||
### Building
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
[Link to deployment guide or include basic steps]
|
||||
|
||||
## Contributing
|
||||
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||
|
||||
## License
|
||||
|
||||
MIT License - see [LICENSE](LICENSE)
|
||||
```
|
||||
|
||||
## Documentation Coverage
|
||||
|
||||
### Minimum Requirements
|
||||
|
||||
**Code Coverage**:
|
||||
- Public functions: 100%
|
||||
- Exported types: 100%
|
||||
- API endpoints: 100%
|
||||
|
||||
**Content Coverage**:
|
||||
- Every function has description
|
||||
- Every parameter documented
|
||||
- Return value documented
|
||||
- Errors/exceptions documented
|
||||
- At least one example
|
||||
|
||||
### Validation
|
||||
|
||||
Use automated tools:
|
||||
- TypeScript: ts-morph for AST analysis
|
||||
- Python: AST module for docstring coverage
|
||||
- API: OpenAPI schema validation
|
||||
|
||||
```bash
|
||||
# Check coverage
|
||||
npm run docs:coverage
|
||||
|
||||
# Expected output
|
||||
TypeScript: 87% (124/142 documented)
|
||||
Python: 91% (98/108 documented)
|
||||
API Endpoints: 95% (42/44 documented)
|
||||
```
|
||||
|
||||
## Quality Checklist
|
||||
|
||||
Before publishing documentation:
|
||||
|
||||
- [ ] All code examples work (copy-paste tested)
|
||||
- [ ] Links are valid (no 404s)
|
||||
- [ ] Screenshots are current
|
||||
- [ ] Version numbers are correct
|
||||
- [ ] Prerequisite versions are accurate
|
||||
- [ ] Examples use realistic data
|
||||
- [ ] Error messages match actual errors
|
||||
- [ ] Spelling and grammar checked
|
||||
- [ ] Follows style guide
|
||||
- [ ] Reviewed by another person
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
### 1. Outdated Examples
|
||||
|
||||
❌ **Bad**: Uses deprecated API
|
||||
```typescript
|
||||
// This was removed in v2.0
|
||||
const user = User.create({ email, password });
|
||||
```
|
||||
|
||||
✅ **Good**: Current API with version note
|
||||
```typescript
|
||||
// As of v2.0, use createUser instead of User.create
|
||||
const user = await createUser({ email, password });
|
||||
```
|
||||
|
||||
### 2. Missing Error Handling
|
||||
|
||||
❌ **Bad**: Happy path only
|
||||
```typescript
|
||||
const user = await api.getUser(id);
|
||||
console.log(user.email);
|
||||
```
|
||||
|
||||
✅ **Good**: Error handling included
|
||||
```typescript
|
||||
try {
|
||||
const user = await api.getUser(id);
|
||||
console.log(user.email);
|
||||
} catch (error) {
|
||||
if (error.code === 'NOT_FOUND') {
|
||||
console.error(`User ${id} not found`);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Vague Instructions
|
||||
|
||||
❌ **Bad**: "Configure the database"
|
||||
|
||||
✅ **Good**: Specific steps
|
||||
```markdown
|
||||
1. Create database: `createdb myapp`
|
||||
2. Run migrations: `npm run migrate`
|
||||
3. Verify: `psql myapp -c "\dt"`
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Update docs with code**: Documentation changes in same PR as code changes
|
||||
2. **Link to code**: Reference specific files and line numbers
|
||||
3. **Version everything**: Document which version each feature was added
|
||||
4. **Test examples**: All code examples must be tested
|
||||
5. **Screenshots with captions**: Always explain what image shows
|
||||
6. **Consistent terminology**: Use same terms throughout
|
||||
7. **Mobile-friendly**: Documentation should work on phones
|
||||
8. **Search-optimized**: Use descriptive headings and keywords
|
||||
9. **Accessible**: Alt text for images, semantic HTML
|
||||
10. **Feedback loops**: Easy way for users to report doc issues
|
||||
|
||||
---
|
||||
|
||||
Related: [openapi-patterns.md](openapi-patterns.md) | [mermaid-diagrams.md](mermaid-diagrams.md) | [Return to INDEX](INDEX.md)
|
||||
500
skills/documentation-architecture/reference/mermaid-diagrams.md
Normal file
500
skills/documentation-architecture/reference/mermaid-diagrams.md
Normal file
@@ -0,0 +1,500 @@
|
||||
# Mermaid Diagram Templates for Architecture Documentation
|
||||
|
||||
Comprehensive guide to Mermaid diagram types for visualizing system architecture, data flows, and interactions.
|
||||
|
||||
## Why Mermaid?
|
||||
|
||||
- **Version Controlled**: Diagrams in code, reviewable in PRs
|
||||
- **Always Up-to-Date**: Easy to update alongside code changes
|
||||
- **No Image Files**: Rendered dynamically in documentation
|
||||
- **GitHub Native**: Renders in README.md and issues
|
||||
- **Interactive**: Clickable links, zooming
|
||||
|
||||
## System Architecture Diagrams
|
||||
|
||||
### Basic Architecture
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Frontend"
|
||||
UI[React UI]
|
||||
end
|
||||
|
||||
subgraph "Backend"
|
||||
API[FastAPI]
|
||||
DB[(PostgreSQL)]
|
||||
end
|
||||
|
||||
UI --> API
|
||||
API --> DB
|
||||
```
|
||||
|
||||
### Multi-Tier Architecture
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Client"
|
||||
Browser[Web Browser]
|
||||
Mobile[Mobile App]
|
||||
end
|
||||
|
||||
subgraph "Edge (Cloudflare)"
|
||||
Gateway[API Gateway]
|
||||
Cache[KV Cache]
|
||||
end
|
||||
|
||||
subgraph "Application"
|
||||
Frontend[TanStack Start]
|
||||
Backend[FastAPI]
|
||||
end
|
||||
|
||||
subgraph "Data"
|
||||
DB[(PostgreSQL)]
|
||||
Redis[(Redis)]
|
||||
R2[(Object Storage)]
|
||||
end
|
||||
|
||||
Browser --> Gateway
|
||||
Mobile --> Gateway
|
||||
Gateway --> Frontend
|
||||
Gateway --> Backend
|
||||
Gateway --> Cache
|
||||
Backend --> DB
|
||||
Backend --> Redis
|
||||
Backend --> R2
|
||||
```
|
||||
|
||||
### Microservices Architecture
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
Gateway[API Gateway]
|
||||
|
||||
subgraph "Services"
|
||||
Auth[Auth Service]
|
||||
Users[User Service]
|
||||
Orders[Order Service]
|
||||
Payments[Payment Service]
|
||||
end
|
||||
|
||||
subgraph "Data"
|
||||
AuthDB[(Auth DB)]
|
||||
UserDB[(User DB)]
|
||||
OrderDB[(Order DB)]
|
||||
end
|
||||
|
||||
Gateway --> Auth
|
||||
Gateway --> Users
|
||||
Gateway --> Orders
|
||||
Gateway --> Payments
|
||||
|
||||
Auth --> AuthDB
|
||||
Users --> UserDB
|
||||
Orders --> OrderDB
|
||||
Payments -.Stripe.-> External[External API]
|
||||
```
|
||||
|
||||
## Sequence Diagrams
|
||||
|
||||
### Authentication Flow
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
actor User
|
||||
participant Browser
|
||||
participant Gateway
|
||||
participant Auth
|
||||
participant DB
|
||||
|
||||
User->>Browser: Enter credentials
|
||||
Browser->>Gateway: POST /auth/login
|
||||
Gateway->>Auth: Validate credentials
|
||||
Auth->>DB: Query user
|
||||
DB-->>Auth: User record
|
||||
|
||||
alt Valid
|
||||
Auth->>Auth: Generate JWT
|
||||
Auth-->>Gateway: {token, user}
|
||||
Gateway-->>Browser: 200 OK
|
||||
Browser-->>User: Redirect
|
||||
else Invalid
|
||||
Auth-->>Gateway: 401
|
||||
Gateway-->>Browser: Error
|
||||
Browser-->>User: Show error
|
||||
end
|
||||
```
|
||||
|
||||
### API Request Flow
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client
|
||||
participant Gateway
|
||||
participant Backend
|
||||
participant DB
|
||||
participant Cache
|
||||
|
||||
Client->>Gateway: GET /users/123
|
||||
Gateway->>Gateway: Validate JWT
|
||||
Gateway->>Cache: Check cache
|
||||
|
||||
alt Cache Hit
|
||||
Cache-->>Gateway: User data
|
||||
Gateway-->>Client: 200 OK (cached)
|
||||
else Cache Miss
|
||||
Gateway->>Backend: Forward request
|
||||
Backend->>DB: Query user
|
||||
DB-->>Backend: User data
|
||||
Backend-->>Gateway: Response
|
||||
Gateway->>Cache: Store in cache
|
||||
Gateway-->>Client: 200 OK
|
||||
end
|
||||
```
|
||||
|
||||
### Payment Processing
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client
|
||||
participant API
|
||||
participant PaymentSvc
|
||||
participant Stripe
|
||||
participant DB
|
||||
|
||||
Client->>API: POST /orders
|
||||
API->>PaymentSvc: Process payment
|
||||
PaymentSvc->>Stripe: Create payment intent
|
||||
Stripe-->>PaymentSvc: Payment intent
|
||||
PaymentSvc-->>API: Intent created
|
||||
API-->>Client: {client_secret}
|
||||
|
||||
Client->>Stripe: Confirm payment
|
||||
Stripe->>PaymentSvc: Webhook: payment.succeeded
|
||||
PaymentSvc->>DB: Update order status
|
||||
PaymentSvc->>API: Notify completion
|
||||
API->>Client: Send confirmation email
|
||||
```
|
||||
|
||||
## Data Flow Diagrams
|
||||
|
||||
### Order Processing Flow
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Start[User Creates Order] --> Validate[Validate Data]
|
||||
Validate --> Stock{Check Stock}
|
||||
|
||||
Stock -->|Insufficient| Error[Return Error]
|
||||
Stock -->|Available| Reserve[Reserve Items]
|
||||
|
||||
Reserve --> Payment[Process Payment]
|
||||
Payment -->|Failed| Release[Release Items]
|
||||
Release --> Error
|
||||
|
||||
Payment -->|Success| Create[Create Order]
|
||||
Create --> Queue[Queue Email]
|
||||
Queue --> Cache[Invalidate Cache]
|
||||
Cache --> Success[Return Order]
|
||||
|
||||
Success --> Async[Async: Send Email]
|
||||
```
|
||||
|
||||
### Data Transformation Pipeline
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Raw[Raw Data] --> Extract[Extract]
|
||||
Extract --> Transform[Transform]
|
||||
Transform --> Validate{Validate}
|
||||
|
||||
Validate -->|Invalid| Log[Log Error]
|
||||
Validate -->|Valid| Enrich[Enrich Data]
|
||||
|
||||
Enrich --> Normalize[Normalize]
|
||||
Normalize --> Store[(Store in DB)]
|
||||
Store --> Index[Update Search Index]
|
||||
Index --> Cache[Update Cache]
|
||||
```
|
||||
|
||||
## Entity Relationship Diagrams
|
||||
|
||||
### Multi-Tenant E-Commerce
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
TENANT ||--o{ USER : has
|
||||
TENANT ||--o{ ORDER : has
|
||||
TENANT ||--o{ PRODUCT : has
|
||||
USER ||--o{ ORDER : places
|
||||
ORDER ||--|{ ORDER_ITEM : contains
|
||||
PRODUCT ||--o{ ORDER_ITEM : included_in
|
||||
|
||||
TENANT {
|
||||
uuid id PK
|
||||
string name
|
||||
string subdomain UK
|
||||
timestamp created_at
|
||||
}
|
||||
|
||||
USER {
|
||||
uuid id PK
|
||||
uuid tenant_id FK
|
||||
string email UK
|
||||
string role
|
||||
}
|
||||
|
||||
PRODUCT {
|
||||
uuid id PK
|
||||
uuid tenant_id FK
|
||||
string name
|
||||
decimal price
|
||||
int stock
|
||||
}
|
||||
|
||||
ORDER {
|
||||
uuid id PK
|
||||
uuid tenant_id FK
|
||||
uuid user_id FK
|
||||
decimal total
|
||||
string status
|
||||
}
|
||||
|
||||
ORDER_ITEM {
|
||||
uuid id PK
|
||||
uuid order_id FK
|
||||
uuid product_id FK
|
||||
int quantity
|
||||
decimal unit_price
|
||||
}
|
||||
```
|
||||
|
||||
### User Authentication Schema
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
USER ||--o{ SESSION : has
|
||||
USER ||--o{ API_KEY : has
|
||||
USER ||--o{ OAUTH_TOKEN : has
|
||||
USER }|--|| USER_PROFILE : has
|
||||
|
||||
USER {
|
||||
uuid id PK
|
||||
string email UK
|
||||
string hashed_password
|
||||
bool email_verified
|
||||
}
|
||||
|
||||
SESSION {
|
||||
uuid id PK
|
||||
uuid user_id FK
|
||||
string token UK
|
||||
timestamp expires_at
|
||||
}
|
||||
|
||||
API_KEY {
|
||||
uuid id PK
|
||||
uuid user_id FK
|
||||
string key_hash UK
|
||||
string name
|
||||
timestamp last_used
|
||||
}
|
||||
```
|
||||
|
||||
## State Diagrams
|
||||
|
||||
### Order State Machine
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Pending: Order Created
|
||||
Pending --> Processing: Payment Confirmed
|
||||
Pending --> Cancelled: Payment Failed
|
||||
|
||||
Processing --> Shipped: Fulfillment Complete
|
||||
Processing --> Cancelled: Out of Stock
|
||||
|
||||
Shipped --> Delivered: Tracking Confirmed
|
||||
Shipped --> Returned: Customer Return
|
||||
|
||||
Delivered --> Returned: Return Requested
|
||||
Returned --> Refunded: Return Approved
|
||||
|
||||
Cancelled --> [*]
|
||||
Delivered --> [*]
|
||||
Refunded --> [*]
|
||||
```
|
||||
|
||||
### User Lifecycle
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Invited: User Invited
|
||||
Invited --> Active: Accept Invitation
|
||||
Invited --> Expired: 7 Days Passed
|
||||
|
||||
Active --> Suspended: Policy Violation
|
||||
Active --> Inactive: 90 Days No Login
|
||||
|
||||
Suspended --> Active: Appeal Approved
|
||||
Inactive --> Active: User Logs In
|
||||
|
||||
Active --> Deleted: User Deletes Account
|
||||
Suspended --> Deleted: Admin Deletes
|
||||
|
||||
Expired --> [*]
|
||||
Deleted --> [*]
|
||||
```
|
||||
|
||||
## Deployment Diagrams
|
||||
|
||||
### CI/CD Pipeline
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
Dev[Feature Branch] -->|PR| CI[GitHub Actions]
|
||||
CI -->|Tests| Tests{Tests Pass?}
|
||||
|
||||
Tests -->|No| Fail[❌ Fail]
|
||||
Tests -->|Yes| Build[Build]
|
||||
|
||||
Build --> Stage[Deploy to Staging]
|
||||
Stage -->|Smoke Tests| SmokeTest{Pass?}
|
||||
|
||||
SmokeTest -->|No| Fail
|
||||
SmokeTest -->|Yes| Approve{Manual Approve?}
|
||||
|
||||
Approve -->|No| Wait[Wait]
|
||||
Approve -->|Yes| Canary[Canary Deploy 10%]
|
||||
|
||||
Canary -->|Monitor| Monitor{Healthy?}
|
||||
Monitor -->|No| Rollback[Rollback]
|
||||
Monitor -->|Yes| Prod[Deploy 100%]
|
||||
```
|
||||
|
||||
### Multi-Region Deployment
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Region: US-East"
|
||||
USWorker[Cloudflare Workers]
|
||||
USDB[(Primary DB)]
|
||||
end
|
||||
|
||||
subgraph "Region: Europe"
|
||||
EUWorker[Cloudflare Workers]
|
||||
EUDB[(Read Replica)]
|
||||
end
|
||||
|
||||
subgraph "Region: Asia"
|
||||
AsiaWorker[Cloudflare Workers]
|
||||
AsiaDB[(Read Replica)]
|
||||
end
|
||||
|
||||
subgraph "Global"
|
||||
DNS[Global DNS]
|
||||
CDN[Cloudflare CDN]
|
||||
end
|
||||
|
||||
DNS --> USWorker
|
||||
DNS --> EUWorker
|
||||
DNS --> AsiaWorker
|
||||
|
||||
CDN --> USWorker
|
||||
CDN --> EUWorker
|
||||
CDN --> AsiaWorker
|
||||
|
||||
USDB -.replication.-> EUDB
|
||||
USDB -.replication.-> AsiaDB
|
||||
```
|
||||
|
||||
## Class Diagrams (TypeScript/Python)
|
||||
|
||||
### Service Architecture
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class OrderService {
|
||||
-repository: OrderRepository
|
||||
-payment: PaymentService
|
||||
+createOrder(data) Order
|
||||
+getOrder(id) Order
|
||||
+cancelOrder(id) void
|
||||
}
|
||||
|
||||
class OrderRepository {
|
||||
-db: Database
|
||||
+save(order) Order
|
||||
+findById(id) Order
|
||||
+findByUser(userId) Order[]
|
||||
}
|
||||
|
||||
class PaymentService {
|
||||
-stripe: StripeClient
|
||||
+processPayment(amount) PaymentResult
|
||||
+refund(paymentId) void
|
||||
}
|
||||
|
||||
class Order {
|
||||
+id: string
|
||||
+userId: string
|
||||
+total: number
|
||||
+status: OrderStatus
|
||||
}
|
||||
|
||||
OrderService --> OrderRepository
|
||||
OrderService --> PaymentService
|
||||
OrderRepository --> Order
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Keep Diagrams Simple**: One concept per diagram
|
||||
2. **Use Subgraphs**: Group related components
|
||||
3. **Consistent Naming**: Use same names as code
|
||||
4. **Color Coding**: Use colors sparingly for emphasis
|
||||
5. **Labels**: Add descriptive labels to edges
|
||||
6. **Legend**: Include legend for complex diagrams
|
||||
7. **Direction**: LR (left-right) or TB (top-bottom) based on flow
|
||||
8. **Update Regularly**: Keep in sync with code changes
|
||||
|
||||
## Rendering in Documentation
|
||||
|
||||
### GitHub Markdown
|
||||
|
||||
````markdown
|
||||
```mermaid
|
||||
graph TB
|
||||
A[Start] --> B[Process]
|
||||
B --> C[End]
|
||||
```
|
||||
````
|
||||
|
||||
### Docusaurus
|
||||
|
||||
Install plugin:
|
||||
```bash
|
||||
npm install @docusaurus/theme-mermaid
|
||||
```
|
||||
|
||||
### MkDocs
|
||||
|
||||
Install plugin:
|
||||
```bash
|
||||
pip install mkdocs-mermaid2-plugin
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Request/Response Flow
|
||||
Use sequence diagrams with alt/opt for error handling
|
||||
|
||||
### Data Relationships
|
||||
Use ER diagrams with proper cardinality (||--o{)
|
||||
|
||||
### State Transitions
|
||||
Use state diagrams for order status, user lifecycle
|
||||
|
||||
### System Overview
|
||||
---
|
||||
|
||||
Related: [openapi-patterns.md](openapi-patterns.md) | [documentation-standards.md](documentation-standards.md) | [Return to INDEX](INDEX.md)
|
||||
491
skills/documentation-architecture/reference/openapi-patterns.md
Normal file
491
skills/documentation-architecture/reference/openapi-patterns.md
Normal file
@@ -0,0 +1,491 @@
|
||||
# OpenAPI 3.1 Patterns and Best Practices
|
||||
|
||||
Comprehensive guide to OpenAPI 3.1 specification patterns for Grey Haven stack (FastAPI + TanStack Start).
|
||||
|
||||
## OpenAPI 3.1 Overview
|
||||
|
||||
OpenAPI 3.1 is fully compatible with JSON Schema Draft 2020-12.
|
||||
|
||||
**Key Differences from 3.0**: Full JSON Schema compatibility, `examples` replaces `example`, `webhooks` support, better discriminator
|
||||
|
||||
## Basic Structure
|
||||
|
||||
```yaml
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
title: Grey Haven API
|
||||
version: 1.0.0
|
||||
|
||||
servers:
|
||||
- url: https://api.greyhaven.com
|
||||
|
||||
paths:
|
||||
/users:
|
||||
get:
|
||||
operationId: listUsers
|
||||
tags: [users]
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/User'
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
### JWT Bearer
|
||||
|
||||
```yaml
|
||||
components:
|
||||
securitySchemes:
|
||||
BearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
|
||||
security:
|
||||
- BearerAuth: []
|
||||
```
|
||||
|
||||
### OAuth2
|
||||
|
||||
```yaml
|
||||
components:
|
||||
securitySchemes:
|
||||
OAuth2:
|
||||
type: oauth2
|
||||
flows:
|
||||
authorizationCode:
|
||||
authorizationUrl: https://auth.greyhaven.com/oauth/authorize
|
||||
tokenUrl: https://auth.greyhaven.com/oauth/token
|
||||
scopes:
|
||||
read:users: Read user data
|
||||
```
|
||||
|
||||
### API Key
|
||||
|
||||
```yaml
|
||||
components:
|
||||
securitySchemes:
|
||||
ApiKey:
|
||||
type: apiKey
|
||||
in: header
|
||||
name: X-API-Key
|
||||
```
|
||||
|
||||
## Schema Patterns
|
||||
|
||||
### Pydantic v2 to OpenAPI
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Literal
|
||||
|
||||
class User(BaseModel):
|
||||
id: str = Field(..., pattern="^usr_[a-z0-9]{16}$")
|
||||
email: str = Field(..., examples=["user@example.com"])
|
||||
role: Literal["admin", "member", "guest"] = "member"
|
||||
```
|
||||
|
||||
Generates:
|
||||
|
||||
```yaml
|
||||
User:
|
||||
type: object
|
||||
required: [id, email]
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
pattern: ^usr_[a-z0-9]{16}$
|
||||
email:
|
||||
type: string
|
||||
examples: ["user@example.com"]
|
||||
role:
|
||||
type: string
|
||||
enum: [admin, member, guest]
|
||||
default: member
|
||||
```
|
||||
|
||||
### Nullable and Optional
|
||||
|
||||
```yaml
|
||||
# Optional (can be omitted)
|
||||
username:
|
||||
type: string
|
||||
|
||||
# Nullable (can be null)
|
||||
middle_name:
|
||||
type: [string, 'null']
|
||||
|
||||
# Both
|
||||
nickname:
|
||||
type: [string, 'null']
|
||||
```
|
||||
|
||||
### Discriminated Unions
|
||||
|
||||
```yaml
|
||||
PaymentMethod:
|
||||
type: object
|
||||
required: [type]
|
||||
discriminator:
|
||||
propertyName: type
|
||||
mapping:
|
||||
card: '#/components/schemas/CardPayment'
|
||||
bank: '#/components/schemas/BankPayment'
|
||||
|
||||
CardPayment:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/PaymentMethod'
|
||||
- type: object
|
||||
properties:
|
||||
card_number:
|
||||
type: string
|
||||
pattern: ^\d{16}$
|
||||
```
|
||||
|
||||
## Response Patterns
|
||||
|
||||
### Error Response
|
||||
|
||||
```yaml
|
||||
ErrorResponse:
|
||||
type: object
|
||||
required: [error, message]
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
examples: ["VALIDATION_ERROR"]
|
||||
message:
|
||||
type: string
|
||||
details:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
|
||||
# Use in responses
|
||||
responses:
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
```
|
||||
|
||||
### Paginated Response
|
||||
|
||||
```yaml
|
||||
PaginatedUsers:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/User'
|
||||
pagination:
|
||||
type: object
|
||||
properties:
|
||||
page:
|
||||
type: integer
|
||||
minimum: 1
|
||||
per_page:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 100
|
||||
total:
|
||||
type: integer
|
||||
total_pages:
|
||||
type: integer
|
||||
```
|
||||
|
||||
### Multiple Status Codes
|
||||
|
||||
```yaml
|
||||
responses:
|
||||
'201':
|
||||
description: Created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
'202':
|
||||
description: Accepted (async)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
job_id:
|
||||
type: string
|
||||
```
|
||||
|
||||
## Request Body
|
||||
|
||||
### Required vs Optional
|
||||
|
||||
```yaml
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [email, password] # Required
|
||||
properties:
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
password:
|
||||
type: string
|
||||
minLength: 8
|
||||
name:
|
||||
type: string # Optional
|
||||
```
|
||||
|
||||
### File Upload
|
||||
|
||||
```yaml
|
||||
requestBody:
|
||||
content:
|
||||
multipart/form-data:
|
||||
schema:
|
||||
properties:
|
||||
file:
|
||||
type: string
|
||||
format: binary
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
### Path
|
||||
|
||||
```yaml
|
||||
parameters:
|
||||
- name: user_id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
pattern: ^usr_[a-z0-9]{16}$
|
||||
```
|
||||
|
||||
### Query
|
||||
|
||||
```yaml
|
||||
parameters:
|
||||
- name: status
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
enum: [pending, processing, shipped]
|
||||
- name: created_after
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
format: date-time
|
||||
- name: sort
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
enum: [created_at:asc, created_at:desc]
|
||||
default: created_at:desc
|
||||
```
|
||||
|
||||
### Headers
|
||||
|
||||
```yaml
|
||||
components:
|
||||
parameters:
|
||||
TenantId:
|
||||
name: X-Tenant-ID
|
||||
in: header
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
|
||||
paths:
|
||||
/orders:
|
||||
post:
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/TenantId'
|
||||
```
|
||||
|
||||
## Response Headers
|
||||
|
||||
```yaml
|
||||
responses:
|
||||
'200':
|
||||
headers:
|
||||
X-RateLimit-Limit:
|
||||
schema:
|
||||
type: integer
|
||||
X-RateLimit-Remaining:
|
||||
schema:
|
||||
type: integer
|
||||
X-Request-ID:
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
```
|
||||
|
||||
## Multi-Language Examples
|
||||
|
||||
```yaml
|
||||
x-codeSamples:
|
||||
- lang: TypeScript
|
||||
source: |
|
||||
const response = await fetch("https://api.greyhaven.com/users", {
|
||||
method: "POST",
|
||||
headers: { "Authorization": `Bearer ${token}` },
|
||||
body: JSON.stringify({ email, password })
|
||||
});
|
||||
|
||||
- lang: Python
|
||||
source: |
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.post(
|
||||
"https://api.greyhaven.com/users",
|
||||
headers={"Authorization": f"Bearer {token}"},
|
||||
json={"email": email, "password": password}
|
||||
)
|
||||
|
||||
- lang: Shell
|
||||
source: |
|
||||
curl -X POST https://api.greyhaven.com/users \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-d '{"email": "user@example.com"}'
|
||||
```
|
||||
|
||||
## Webhooks (OpenAPI 3.1)
|
||||
|
||||
```yaml
|
||||
webhooks:
|
||||
orderCreated:
|
||||
post:
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [event, data]
|
||||
properties:
|
||||
event:
|
||||
type: string
|
||||
const: order.created
|
||||
data:
|
||||
$ref: '#/components/schemas/Order'
|
||||
responses:
|
||||
'200':
|
||||
description: Received
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use $ref**: Define schemas once, reference everywhere
|
||||
2. **Examples**: Realistic examples for all schemas
|
||||
3. **Error Schemas**: Consistent error format
|
||||
4. **Validation**: Use pattern, minLength, minimum
|
||||
5. **Descriptions**: Document every field
|
||||
6. **operationId**: Unique for SDK generation
|
||||
7. **Tags**: Group related endpoints
|
||||
8. **Deprecation**: Mark with `deprecated: true`
|
||||
9. **Security**: Define at global or operation level
|
||||
10. **Versioning**: Include in URL (/api/v1/)
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Multi-Tenant
|
||||
|
||||
```yaml
|
||||
components:
|
||||
parameters:
|
||||
TenantId:
|
||||
name: X-Tenant-ID
|
||||
in: header
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
```
|
||||
|
||||
### Idempotency
|
||||
|
||||
```yaml
|
||||
components:
|
||||
parameters:
|
||||
IdempotencyKey:
|
||||
name: Idempotency-Key
|
||||
in: header
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
```
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
```yaml
|
||||
responses:
|
||||
'429':
|
||||
description: Rate limit exceeded
|
||||
headers:
|
||||
X-RateLimit-Reset:
|
||||
schema:
|
||||
type: integer
|
||||
```
|
||||
|
||||
## FastAPI Integration
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI(
|
||||
title="Grey Haven API",
|
||||
version="1.0.0",
|
||||
openapi_version="3.1.0"
|
||||
)
|
||||
|
||||
# Customize OpenAPI
|
||||
def custom_openapi():
|
||||
if app.openapi_schema:
|
||||
return app.openapi_schema
|
||||
|
||||
openapi_schema = get_openapi(
|
||||
title=app.title,
|
||||
version=app.version,
|
||||
routes=app.routes
|
||||
)
|
||||
|
||||
# Add security schemes
|
||||
openapi_schema["components"]["securitySchemes"] = {
|
||||
"BearerAuth": {
|
||||
"type": "http",
|
||||
"scheme": "bearer",
|
||||
"bearerFormat": "JWT"
|
||||
}
|
||||
}
|
||||
|
||||
app.openapi_schema = openapi_schema
|
||||
return app.openapi_schema
|
||||
|
||||
app.openapi = custom_openapi
|
||||
```
|
||||
|
||||
## Validation
|
||||
|
||||
Use @redocly/cli for validation:
|
||||
|
||||
```bash
|
||||
npx @redocly/cli lint openapi.yaml
|
||||
```
|
||||
|
||||
Common issues:
|
||||
- Missing operationId
|
||||
- Missing response descriptions
|
||||
- Inconsistent naming
|
||||
- Missing examples
|
||||
- Invalid $ref paths
|
||||
|
||||
---
|
||||
|
||||
Related: [mermaid-diagrams.md](mermaid-diagrams.md) | [documentation-standards.md](documentation-standards.md) | [Return to INDEX](INDEX.md)
|
||||
59
skills/documentation-architecture/templates/INDEX.md
Normal file
59
skills/documentation-architecture/templates/INDEX.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# Documentation Templates
|
||||
|
||||
Copy-paste ready templates for API documentation, architecture docs, and OpenAPI specifications.
|
||||
|
||||
## Available Templates
|
||||
|
||||
### [API Endpoint Documentation](api-endpoint.md)
|
||||
|
||||
Complete template for documenting a single API endpoint with all required sections.
|
||||
|
||||
**Includes**: Method/path, description, authentication, request/response formats, error codes, rate limits, code examples
|
||||
|
||||
**Use when**: Documenting REST API endpoints, creating API reference pages
|
||||
|
||||
---
|
||||
|
||||
### [Architecture Document](architecture-doc.md)
|
||||
|
||||
Comprehensive template for system architecture documentation with Mermaid diagrams.
|
||||
|
||||
**Includes**: Executive summary, system overview, component descriptions, data flow, ADRs, security model
|
||||
|
||||
**Use when**: Documenting new systems, onboarding materials, architecture reviews
|
||||
|
||||
---
|
||||
|
||||
### [OpenAPI Specification](openapi-spec.yaml)
|
||||
|
||||
Starter OpenAPI 3.1 specification with common patterns and best practices.
|
||||
|
||||
**Includes**: Info object, servers, authentication, common schemas (errors, pagination), example endpoint
|
||||
|
||||
**Use when**: Starting new API documentation, generating from scratch
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. Copy template file to your documentation directory
|
||||
2. Replace all `[FILL IN]` placeholders
|
||||
3. Remove optional sections if not needed
|
||||
4. Validate and test
|
||||
|
||||
## Template Customization
|
||||
|
||||
**For your project**:
|
||||
- Update company/project names
|
||||
- Adjust authentication schemes
|
||||
- Add project-specific error codes
|
||||
- Include relevant examples
|
||||
|
||||
**For your team**:
|
||||
- Add team-specific sections
|
||||
- Include internal links
|
||||
- Reference team tools/dashboards
|
||||
|
||||
---
|
||||
|
||||
Related: [Examples](../examples/INDEX.md) | [Reference](../reference/INDEX.md) | [Return to Agent](../docs-architect.md)
|
||||
191
skills/documentation-architecture/templates/api-endpoint.md
Normal file
191
skills/documentation-architecture/templates/api-endpoint.md
Normal file
@@ -0,0 +1,191 @@
|
||||
# [METHOD] /api/v1/[resource]
|
||||
|
||||
[One sentence description of what this endpoint does]
|
||||
|
||||
## Authentication
|
||||
|
||||
**Required**: [Yes/No]
|
||||
**Roles**: [Admin, Member, Guest] _(if applicable)_
|
||||
**Scopes**: [read:resource, write:resource] _(if applicable)_
|
||||
|
||||
## Request
|
||||
|
||||
### Headers
|
||||
|
||||
| Header | Required | Description |
|
||||
|--------|----------|-------------|
|
||||
| `Authorization` | Yes | Bearer token: `Bearer <token>` |
|
||||
| `Content-Type` | Yes | `application/json` |
|
||||
| `X-Tenant-ID` | Yes | Tenant identifier _(if multi-tenant)_ |
|
||||
|
||||
### Path Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| `[param_name]` | string | [Description] |
|
||||
|
||||
### Query Parameters
|
||||
|
||||
| Parameter | Type | Required | Default | Description |
|
||||
|-----------|------|----------|---------|-------------|
|
||||
| `[param_name]` | string | No | [default] | [Description] |
|
||||
| `page` | integer | No | 1 | Page number (min: 1) |
|
||||
| `per_page` | integer | No | 20 | Items per page (min: 1, max: 100) |
|
||||
|
||||
### Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `[field_name]` | string | Yes | [Description, validation rules] |
|
||||
| `[field_name]` | integer | No | [Description, validation rules] |
|
||||
|
||||
**Example**:
|
||||
```json
|
||||
{
|
||||
"[field_name]": "value",
|
||||
"[field_name]": 123
|
||||
}
|
||||
```
|
||||
|
||||
## Response
|
||||
|
||||
### Success (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "res_1234567890abcdef",
|
||||
"[field_name]": "value",
|
||||
"created_at": "2024-01-15T10:30:00Z",
|
||||
"updated_at": "2024-01-15T10:30:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Success (201 Created)
|
||||
|
||||
**Headers**:
|
||||
- `Location: /api/v1/[resource]/res_1234567890abcdef`
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "res_1234567890abcdef",
|
||||
"[field_name]": "value",
|
||||
"created_at": "2024-01-15T10:30:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Error Responses
|
||||
|
||||
| Code | Description | Example |
|
||||
|------|-------------|---------|
|
||||
| 400 | Bad Request - Validation failed | `{"error": "VALIDATION_ERROR", "message": "Field 'email' is invalid"}` |
|
||||
| 401 | Unauthorized - Missing or invalid token | `{"error": "UNAUTHORIZED", "message": "Invalid or missing authentication token"}` |
|
||||
| 403 | Forbidden - Insufficient permissions | `{"error": "FORBIDDEN", "message": "User lacks required role"}` |
|
||||
| 404 | Not Found - Resource doesn't exist | `{"error": "NOT_FOUND", "message": "Resource with id 'xyz' not found"}` |
|
||||
| 409 | Conflict - Resource already exists | `{"error": "CONFLICT", "message": "Resource with this identifier already exists"}` |
|
||||
| 429 | Too Many Requests - Rate limit exceeded | `{"error": "RATE_LIMIT_EXCEEDED", "message": "Rate limit exceeded, retry after 60 seconds"}` |
|
||||
| 500 | Internal Server Error | `{"error": "INTERNAL_ERROR", "message": "An unexpected error occurred"}` |
|
||||
|
||||
**Error Response Schema**:
|
||||
```json
|
||||
{
|
||||
"error": "ERROR_CODE",
|
||||
"message": "Human-readable error message",
|
||||
"details": {
|
||||
"field": "field_name",
|
||||
"reason": "specific reason"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Rate Limiting
|
||||
|
||||
- **Authenticated**: [1000] requests per hour
|
||||
- **Unauthenticated**: [100] requests per hour
|
||||
|
||||
**Response Headers**:
|
||||
- `X-RateLimit-Limit`: Maximum requests per hour
|
||||
- `X-RateLimit-Remaining`: Remaining requests in current window
|
||||
- `X-RateLimit-Reset`: Unix timestamp when limit resets
|
||||
|
||||
## Pagination
|
||||
|
||||
_(If endpoint returns paginated results)_
|
||||
|
||||
**Request**: Use `page` and `per_page` query parameters
|
||||
**Response**: Includes `pagination` object
|
||||
|
||||
```json
|
||||
{
|
||||
"data": [...],
|
||||
"pagination": {
|
||||
"page": 1,
|
||||
"per_page": 20,
|
||||
"total": 145,
|
||||
"total_pages": 8,
|
||||
"next_page": 2,
|
||||
"prev_page": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Code Examples
|
||||
|
||||
### TypeScript
|
||||
|
||||
```typescript
|
||||
const response = await fetch('https://api.greyhaven.com/[resource]', {
|
||||
method: '[METHOD]',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
[field_name]: 'value'
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.message);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log('[Resource] created:', data.id);
|
||||
```
|
||||
|
||||
### Python
|
||||
|
||||
```python
|
||||
import httpx
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.[method](
|
||||
'https://api.greyhaven.com/[resource]',
|
||||
headers={'Authorization': f'Bearer {token}'},
|
||||
json={'[field_name]': 'value'}
|
||||
)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
print(f'[Resource] created: {data["id"]}')
|
||||
```
|
||||
|
||||
### cURL
|
||||
|
||||
```bash
|
||||
curl -X [METHOD] https://api.greyhaven.com/[resource] \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"[field_name]": "value"
|
||||
}'
|
||||
```
|
||||
|
||||
## Changelog
|
||||
|
||||
| Version | Date | Changes |
|
||||
|---------|------|---------|
|
||||
| v1.0.0 | 2024-01-15 | Initial release |
|
||||
|
||||
---
|
||||
|
||||
[Return to API Reference](../README.md)
|
||||
307
skills/documentation-architecture/templates/architecture-doc.md
Normal file
307
skills/documentation-architecture/templates/architecture-doc.md
Normal file
@@ -0,0 +1,307 @@
|
||||
# [System Name] Architecture
|
||||
|
||||
**Version**: [1.0.0]
|
||||
**Last Updated**: [YYYY-MM-DD]
|
||||
**Status**: [Draft / In Review / Approved]
|
||||
**Authors**: [Names]
|
||||
|
||||
## Executive Summary
|
||||
|
||||
[2-3 paragraph high-level overview suitable for non-technical stakeholders. Include:]
|
||||
- What the system does
|
||||
- Key business value
|
||||
- Major technical decisions
|
||||
- Scale/performance characteristics
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [System Overview](#system-overview)
|
||||
- [Architecture Overview](#architecture-overview)
|
||||
- [Core Components](#core-components)
|
||||
- [Data Flow](#data-flow)
|
||||
- [Integration Points](#integration-points)
|
||||
- [Security Model](#security-model)
|
||||
- [Deployment Architecture](#deployment-architecture)
|
||||
- [Architecture Decision Records](#architecture-decision-records)
|
||||
- [Appendix](#appendix)
|
||||
|
||||
## System Overview
|
||||
|
||||
### Purpose
|
||||
|
||||
[What problem does this system solve?]
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Feature 1**: [Description]
|
||||
- **Feature 2**: [Description]
|
||||
- **Feature 3**: [Description]
|
||||
|
||||
### Non-Functional Requirements
|
||||
|
||||
| Requirement | Target | Current |
|
||||
|-------------|--------|---------|
|
||||
| Availability | 99.9% | 99.95% |
|
||||
| Response Time (p95) | <500ms | 320ms |
|
||||
| Throughput | 1000 req/s | 850 req/s |
|
||||
| Data Retention | 7 years | 7 years |
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### High-Level Architecture
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Client Layer"
|
||||
Browser[Web Browser]
|
||||
Mobile[Mobile App]
|
||||
end
|
||||
|
||||
subgraph "Edge Layer"
|
||||
Gateway[API Gateway]
|
||||
CDN[CDN]
|
||||
end
|
||||
|
||||
subgraph "Application Layer"
|
||||
Frontend[Frontend Service]
|
||||
Backend[Backend Service]
|
||||
end
|
||||
|
||||
subgraph "Data Layer"
|
||||
DB[(Database)]
|
||||
Cache[(Cache)]
|
||||
Storage[(Object Storage)]
|
||||
end
|
||||
|
||||
Browser --> Gateway
|
||||
Mobile --> Gateway
|
||||
Gateway --> Frontend
|
||||
Gateway --> Backend
|
||||
Frontend --> DB
|
||||
Backend --> DB
|
||||
Backend --> Cache
|
||||
Backend --> Storage
|
||||
```
|
||||
|
||||
### Technology Stack
|
||||
|
||||
| Layer | Technology | Version | Rationale |
|
||||
|-------|------------|---------|-----------|
|
||||
| Frontend | [Framework] | [x.y.z] | [Why chosen] |
|
||||
| Backend | [Framework] | [x.y.z] | [Why chosen] |
|
||||
| Database | [Database] | [x.y.z] | [Why chosen] |
|
||||
| Cache | [Cache] | [x.y.z] | [Why chosen] |
|
||||
| Deployment | [Platform] | [x.y.z] | [Why chosen] |
|
||||
|
||||
## Core Components
|
||||
|
||||
### [Component 1]: [Name]
|
||||
|
||||
**Purpose**: [What this component does]
|
||||
|
||||
**Responsibilities**:
|
||||
- [Responsibility 1]
|
||||
- [Responsibility 2]
|
||||
- [Responsibility 3]
|
||||
|
||||
**Technology**: [Framework/Language]
|
||||
**Repository**: [Link to repo]
|
||||
|
||||
**Key Interfaces**:
|
||||
- REST API: `POST /api/v1/[endpoint]`
|
||||
- WebSocket: `wss://[domain]/[path]`
|
||||
- Message Queue: `[queue-name]`
|
||||
|
||||
### [Component 2]: [Name]
|
||||
|
||||
[Same structure as Component 1]
|
||||
|
||||
## Data Flow
|
||||
|
||||
### [Flow 1]: [Name]
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
actor User
|
||||
participant Frontend
|
||||
participant Backend
|
||||
participant DB
|
||||
|
||||
User->>Frontend: [Action]
|
||||
Frontend->>Backend: POST /api/[endpoint]
|
||||
Backend->>DB: Query/Update
|
||||
DB-->>Backend: Result
|
||||
Backend-->>Frontend: Response
|
||||
Frontend-->>User: Display result
|
||||
```
|
||||
|
||||
**Steps**:
|
||||
1. [Step 1 description]
|
||||
2. [Step 2 description]
|
||||
3. [Step 3 description]
|
||||
|
||||
**Error Handling**:
|
||||
- [Error scenario 1]: [How handled]
|
||||
- [Error scenario 2]: [How handled]
|
||||
|
||||
## Integration Points
|
||||
|
||||
### External Service 1: [Service Name]
|
||||
|
||||
**Purpose**: [Why we integrate with this service]
|
||||
**Protocol**: [REST API / GraphQL / gRPC]
|
||||
**Authentication**: [Method]
|
||||
**Rate Limits**: [X requests per Y]
|
||||
**SLA**: [Uptime guarantee]
|
||||
|
||||
**Endpoints Used**:
|
||||
- `[METHOD] /[path]` - [Purpose]
|
||||
- `[METHOD] /[path]` - [Purpose]
|
||||
|
||||
**Fallback Strategy**: [What happens if service unavailable]
|
||||
|
||||
### External Service 2: [Service Name]
|
||||
|
||||
[Same structure as External Service 1]
|
||||
|
||||
## Security Model
|
||||
|
||||
### Authentication
|
||||
|
||||
**Method**: [JWT / OAuth2 / API Key]
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User
|
||||
participant Auth
|
||||
participant Service
|
||||
|
||||
User->>Auth: Login with credentials
|
||||
Auth-->>User: JWT token
|
||||
User->>Service: Request + JWT
|
||||
Service->>Service: Validate token
|
||||
Service-->>User: Response
|
||||
```
|
||||
|
||||
### Authorization
|
||||
|
||||
**Model**: [RBAC / ABAC / ACL]
|
||||
|
||||
**Roles**:
|
||||
- `admin`: [Permissions]
|
||||
- `member`: [Permissions]
|
||||
- `guest`: [Permissions]
|
||||
|
||||
### Data Protection
|
||||
|
||||
**Encryption**:
|
||||
- At rest: [Method, algorithm]
|
||||
- In transit: TLS 1.3
|
||||
- Database: [Encryption method]
|
||||
|
||||
**Multi-Tenancy**:
|
||||
- Isolation method: [Row-Level Security / Separate DBs / Separate Schemas]
|
||||
- Tenant identification: [Header / Subdomain / Path]
|
||||
|
||||
## Deployment Architecture
|
||||
|
||||
### Environments
|
||||
|
||||
| Environment | Purpose | URL | Auto-Deploy |
|
||||
|-------------|---------|-----|-------------|
|
||||
| Development | Feature development | https://dev.[domain] | On PR |
|
||||
| Staging | Pre-production testing | https://staging.[domain] | On merge to main |
|
||||
| Production | Live system | https://[domain] | On release tag |
|
||||
|
||||
### Infrastructure
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Production"
|
||||
LB[Load Balancer]
|
||||
App1[App Server 1]
|
||||
App2[App Server 2]
|
||||
App3[App Server 3]
|
||||
DB[(Primary DB)]
|
||||
Replica[(Read Replica)]
|
||||
end
|
||||
|
||||
LB --> App1
|
||||
LB --> App2
|
||||
LB --> App3
|
||||
App1 --> DB
|
||||
App2 --> DB
|
||||
App3 --> DB
|
||||
App1 -.read.-> Replica
|
||||
App2 -.read.-> Replica
|
||||
App3 -.read.-> Replica
|
||||
DB -.replication.-> Replica
|
||||
```
|
||||
|
||||
**Resources**:
|
||||
- App Servers: [X instances, Y CPU, Z GB RAM]
|
||||
- Database: [Specifications]
|
||||
- Cache: [Specifications]
|
||||
|
||||
### CI/CD Pipeline
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
Code[Code Push] --> Tests[Run Tests]
|
||||
Tests --> Build[Build]
|
||||
Build --> Deploy[Deploy to Staging]
|
||||
Deploy --> Smoke[Smoke Tests]
|
||||
Smoke --> Approve{Manual Approve?}
|
||||
Approve -->|Yes| Prod[Deploy to Production]
|
||||
Approve -->|No| Wait[Wait]
|
||||
```
|
||||
|
||||
## Architecture Decision Records
|
||||
|
||||
### ADR-001: [Decision Title]
|
||||
|
||||
**Date**: [YYYY-MM-DD]
|
||||
**Status**: [Accepted / Superseded / Deprecated]
|
||||
**Decision Makers**: [Names]
|
||||
|
||||
**Context**: [What circumstances led to this decision?]
|
||||
|
||||
**Decision**: [What was decided?]
|
||||
|
||||
**Alternatives Considered**:
|
||||
1. **[Option 1]**: [Pros/Cons]
|
||||
2. **[Option 2]**: [Pros/Cons]
|
||||
|
||||
**Consequences**:
|
||||
- **Positive**: [Benefit 1], [Benefit 2]
|
||||
- **Negative**: [Trade-off 1], [Trade-off 2]
|
||||
|
||||
**Implementation**: [How was this implemented?]
|
||||
|
||||
### ADR-002: [Decision Title]
|
||||
|
||||
[Same structure as ADR-001]
|
||||
|
||||
## Appendix
|
||||
|
||||
### Glossary
|
||||
|
||||
| Term | Definition |
|
||||
|------|------------|
|
||||
| [Term] | [Definition] |
|
||||
|
||||
### References
|
||||
|
||||
- Architecture Diagrams: [Link]
|
||||
- API Documentation: [Link]
|
||||
- Runbooks: [Link]
|
||||
- Monitoring Dashboard: [Link]
|
||||
|
||||
### Related Documentation
|
||||
|
||||
- [Link to related doc 1]
|
||||
- [Link to related doc 2]
|
||||
|
||||
---
|
||||
|
||||
[Return to Documentation Index](../README.md)
|
||||
429
skills/documentation-architecture/templates/openapi-spec.yaml
Normal file
429
skills/documentation-architecture/templates/openapi-spec.yaml
Normal file
@@ -0,0 +1,429 @@
|
||||
openapi: 3.1.0
|
||||
|
||||
info:
|
||||
title: [Your API Name]
|
||||
version: 1.0.0
|
||||
description: |
|
||||
[Brief description of your API]
|
||||
|
||||
## Authentication
|
||||
All endpoints require JWT authentication via Bearer token in Authorization header.
|
||||
|
||||
## Rate Limiting
|
||||
- Authenticated: 1000 requests/hour
|
||||
- Unauthenticated: 100 requests/hour
|
||||
|
||||
## Base URL
|
||||
Production: https://api.yourdomain.com
|
||||
Staging: https://api-staging.yourdomain.com
|
||||
|
||||
contact:
|
||||
name: [Your Team Name]
|
||||
email: support@yourdomain.com
|
||||
url: https://docs.yourdomain.com
|
||||
|
||||
license:
|
||||
name: MIT
|
||||
url: https://opensource.org/licenses/MIT
|
||||
|
||||
servers:
|
||||
- url: https://api.yourdomain.com
|
||||
description: Production
|
||||
- url: https://api-staging.yourdomain.com
|
||||
description: Staging
|
||||
- url: http://localhost:3000
|
||||
description: Local development
|
||||
|
||||
# Global security requirement (can be overridden per endpoint)
|
||||
security:
|
||||
- BearerAuth: []
|
||||
|
||||
tags:
|
||||
- name: users
|
||||
description: User management operations
|
||||
- name: authentication
|
||||
description: Authentication and authorization
|
||||
|
||||
paths:
|
||||
/auth/login:
|
||||
post:
|
||||
summary: User login
|
||||
description: Authenticate user with email and password
|
||||
operationId: login
|
||||
tags:
|
||||
- authentication
|
||||
security: [] # No auth required for login
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/LoginRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Login successful
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/LoginResponse'
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'429':
|
||||
$ref: '#/components/responses/TooManyRequests'
|
||||
|
||||
/users:
|
||||
get:
|
||||
summary: List users
|
||||
description: Retrieve a paginated list of users
|
||||
operationId: listUsers
|
||||
tags:
|
||||
- users
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/PageParam'
|
||||
- $ref: '#/components/parameters/PerPageParam'
|
||||
- name: role
|
||||
in: query
|
||||
description: Filter by user role
|
||||
schema:
|
||||
type: string
|
||||
enum: [admin, member, guest]
|
||||
responses:
|
||||
'200':
|
||||
description: Users retrieved successfully
|
||||
headers:
|
||||
X-RateLimit-Limit:
|
||||
$ref: '#/components/headers/X-RateLimit-Limit'
|
||||
X-RateLimit-Remaining:
|
||||
$ref: '#/components/headers/X-RateLimit-Remaining'
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PaginatedUsers'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'429':
|
||||
$ref: '#/components/responses/TooManyRequests'
|
||||
|
||||
post:
|
||||
summary: Create user
|
||||
description: Create a new user account
|
||||
operationId: createUser
|
||||
tags:
|
||||
- users
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/UserCreate'
|
||||
responses:
|
||||
'201':
|
||||
description: User created successfully
|
||||
headers:
|
||||
Location:
|
||||
description: URL of created user
|
||||
schema:
|
||||
type: string
|
||||
example: /users/usr_1234567890abcdef
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'409':
|
||||
$ref: '#/components/responses/Conflict'
|
||||
|
||||
/users/{user_id}:
|
||||
get:
|
||||
summary: Get user by ID
|
||||
description: Retrieve a single user by their unique identifier
|
||||
operationId: getUser
|
||||
tags:
|
||||
- users
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/UserIdParam'
|
||||
responses:
|
||||
'200':
|
||||
description: User retrieved successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
BearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
description: JWT token obtained from /auth/login endpoint
|
||||
|
||||
parameters:
|
||||
UserIdParam:
|
||||
name: user_id
|
||||
in: path
|
||||
required: true
|
||||
description: User identifier
|
||||
schema:
|
||||
type: string
|
||||
pattern: ^usr_[a-z0-9]{16}$
|
||||
example: usr_1234567890abcdef
|
||||
|
||||
PageParam:
|
||||
name: page
|
||||
in: query
|
||||
description: Page number (1-indexed)
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 1
|
||||
default: 1
|
||||
example: 1
|
||||
|
||||
PerPageParam:
|
||||
name: per_page
|
||||
in: query
|
||||
description: Items per page
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 100
|
||||
default: 20
|
||||
example: 20
|
||||
|
||||
headers:
|
||||
X-RateLimit-Limit:
|
||||
description: Maximum requests per hour
|
||||
schema:
|
||||
type: integer
|
||||
example: 1000
|
||||
|
||||
X-RateLimit-Remaining:
|
||||
description: Remaining requests in current window
|
||||
schema:
|
||||
type: integer
|
||||
example: 847
|
||||
|
||||
X-RateLimit-Reset:
|
||||
description: Unix timestamp when limit resets
|
||||
schema:
|
||||
type: integer
|
||||
example: 1699564800
|
||||
|
||||
schemas:
|
||||
LoginRequest:
|
||||
type: object
|
||||
required: [email, password]
|
||||
properties:
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
examples: [user@example.com]
|
||||
password:
|
||||
type: string
|
||||
minLength: 8
|
||||
examples: [secure123]
|
||||
|
||||
LoginResponse:
|
||||
type: object
|
||||
required: [token, user]
|
||||
properties:
|
||||
token:
|
||||
type: string
|
||||
description: JWT authentication token
|
||||
user:
|
||||
$ref: '#/components/schemas/User'
|
||||
|
||||
UserCreate:
|
||||
type: object
|
||||
required: [email, password]
|
||||
properties:
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
examples: [user@example.com]
|
||||
password:
|
||||
type: string
|
||||
minLength: 8
|
||||
examples: [secure123]
|
||||
name:
|
||||
type: string
|
||||
examples: [John Doe]
|
||||
role:
|
||||
type: string
|
||||
enum: [admin, member, guest]
|
||||
default: member
|
||||
|
||||
User:
|
||||
type: object
|
||||
required: [id, email, role, created_at]
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
pattern: ^usr_[a-z0-9]{16}$
|
||||
examples: [usr_1234567890abcdef]
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
examples: [user@example.com]
|
||||
name:
|
||||
type: [string, 'null']
|
||||
examples: [John Doe]
|
||||
role:
|
||||
type: string
|
||||
enum: [admin, member, guest]
|
||||
examples: [member]
|
||||
created_at:
|
||||
type: string
|
||||
format: date-time
|
||||
examples: ["2024-01-15T10:30:00Z"]
|
||||
updated_at:
|
||||
type: string
|
||||
format: date-time
|
||||
examples: ["2024-01-15T10:30:00Z"]
|
||||
|
||||
PaginatedUsers:
|
||||
type: object
|
||||
required: [data, pagination]
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/User'
|
||||
pagination:
|
||||
$ref: '#/components/schemas/PaginationMeta'
|
||||
|
||||
PaginationMeta:
|
||||
type: object
|
||||
required: [page, per_page, total, total_pages]
|
||||
properties:
|
||||
page:
|
||||
type: integer
|
||||
minimum: 1
|
||||
examples: [1]
|
||||
per_page:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 100
|
||||
examples: [20]
|
||||
total:
|
||||
type: integer
|
||||
examples: [145]
|
||||
total_pages:
|
||||
type: integer
|
||||
examples: [8]
|
||||
next_page:
|
||||
type: [integer, 'null']
|
||||
examples: [2]
|
||||
prev_page:
|
||||
type: [integer, 'null']
|
||||
examples: [null]
|
||||
|
||||
ErrorResponse:
|
||||
type: object
|
||||
required: [error, message]
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
description: Error code (UPPERCASE_SNAKE_CASE)
|
||||
examples: [VALIDATION_ERROR, UNAUTHORIZED, NOT_FOUND]
|
||||
message:
|
||||
type: string
|
||||
description: Human-readable error message
|
||||
examples: [Validation failed for field 'email']
|
||||
details:
|
||||
type: object
|
||||
description: Additional error context
|
||||
additionalProperties: true
|
||||
examples:
|
||||
- field: email
|
||||
reason: Invalid format
|
||||
|
||||
responses:
|
||||
BadRequest:
|
||||
description: Bad request (validation error)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
examples:
|
||||
validation_error:
|
||||
value:
|
||||
error: VALIDATION_ERROR
|
||||
message: Validation failed for field 'email'
|
||||
details:
|
||||
field: email
|
||||
reason: Invalid email format
|
||||
|
||||
Unauthorized:
|
||||
description: Unauthorized (invalid or missing authentication)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
examples:
|
||||
missing_token:
|
||||
value:
|
||||
error: UNAUTHORIZED
|
||||
message: Authentication token required
|
||||
invalid_token:
|
||||
value:
|
||||
error: UNAUTHORIZED
|
||||
message: Invalid or expired authentication token
|
||||
|
||||
Forbidden:
|
||||
description: Forbidden (insufficient permissions)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
examples:
|
||||
insufficient_role:
|
||||
value:
|
||||
error: FORBIDDEN
|
||||
message: User lacks required role
|
||||
|
||||
NotFound:
|
||||
description: Resource not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
examples:
|
||||
not_found:
|
||||
value:
|
||||
error: NOT_FOUND
|
||||
message: Resource with id 'xyz' not found
|
||||
|
||||
Conflict:
|
||||
description: Conflict (resource already exists)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
examples:
|
||||
already_exists:
|
||||
value:
|
||||
error: CONFLICT
|
||||
message: Resource with this identifier already exists
|
||||
|
||||
TooManyRequests:
|
||||
description: Rate limit exceeded
|
||||
headers:
|
||||
X-RateLimit-Reset:
|
||||
$ref: '#/components/headers/X-RateLimit-Reset'
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
examples:
|
||||
rate_limit:
|
||||
value:
|
||||
error: RATE_LIMIT_EXCEEDED
|
||||
message: Rate limit exceeded, retry after 60 seconds
|
||||
Reference in New Issue
Block a user