Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:29:15 +08:00
commit be476a3fea
76 changed files with 12812 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
{
"name": "developer-experience",
"description": "Developer experience and team collaboration tools including onboarding automation, documentation generation, async standups with Linear integration, and knowledge management",
"version": "1.0.0",
"author": {
"name": "Grey Haven Studio"
},
"skills": [
"./skills/api-design-standards",
"./skills/code-style",
"./skills/documentation-architecture",
"./skills/onboarding-coordination",
"./skills/ontological-documentation",
"./skills/pr-template",
"./skills/project-structure"
]
}

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
# developer-experience
Developer experience and team collaboration tools including onboarding automation, documentation generation, async standups with Linear integration, and knowledge management

333
plugin.lock.json Normal file
View File

@@ -0,0 +1,333 @@
{
"$schema": "internal://schemas/plugin.lock.v1.json",
"pluginId": "gh:greyhaven-ai/claude-code-config:grey-haven-plugins/developer-experience",
"normalized": {
"repo": null,
"ref": "refs/tags/v20251128.0",
"commit": "382f952f867a3240da5793cf4e0969e10d519654",
"treeHash": "51c21b2c4157042854383f81ae706ca51846c25f90b6d4865b3a80b9f950e16c",
"generatedAt": "2025-11-28T10:17:03.858002Z",
"toolVersion": "publish_plugins.py@0.2.0"
},
"origin": {
"remote": "git@github.com:zhongweili/42plugin-data.git",
"branch": "master",
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
},
"manifest": {
"name": "developer-experience",
"description": "Developer experience and team collaboration tools including onboarding automation, documentation generation, async standups with Linear integration, and knowledge management",
"version": "1.0.0"
},
"content": {
"files": [
{
"path": "README.md",
"sha256": "4625c80929ebcbca5dd49347eddbe882c4b970ad04b910932d7ef12cdb96eafd"
},
{
"path": ".claude-plugin/plugin.json",
"sha256": "f3e99e441ec7836e0752274f5f93051be3855979922b8ae87730e2ba2d893508"
},
{
"path": "skills/api-design-standards/SKILL.md",
"sha256": "502488f938236df62ca739706a8fb22af156df310d292fa092cae2dd579ffc1b"
},
{
"path": "skills/api-design-standards/checklists/security-review.md",
"sha256": "3a239b4edb905c3418f342504c842e4e9a620a99c51534e18122f1ba582dbab9"
},
{
"path": "skills/api-design-standards/checklists/api-design-checklist.md",
"sha256": "1db3c2c9e2d45b0f797b45643104092e5b4ccf1bcd5310df03fce562bfae90eb"
},
{
"path": "skills/api-design-standards/examples/pydantic-schemas.md",
"sha256": "06d10bb37ff544bb19ea0c104eeb342767cc93dd6d40611a6a4171fb31172457"
},
{
"path": "skills/api-design-standards/examples/fastapi-crud.md",
"sha256": "48ed7e7554e0668d59508749f5650889d813ca29f51c68b8e70b874b2155f065"
},
{
"path": "skills/api-design-standards/examples/pagination.md",
"sha256": "a3d5bb435548e6123270f825e8acaf549d66a96ab361021822586bedb4714fc0"
},
{
"path": "skills/api-design-standards/examples/testing.md",
"sha256": "60f8a0ebb121d27627f2899001dc95f416f42743d72ce87de735df194a9a4bd6"
},
{
"path": "skills/api-design-standards/examples/tanstack-start.md",
"sha256": "4c20160b0a93c2b2b03e73a54036aa319818344f369e8ec043c71790efd82dd8"
},
{
"path": "skills/api-design-standards/examples/INDEX.md",
"sha256": "59f8b71dc0e5ad1c47b35bca28b2a06832424efb4d4f9f8c00b7e4777b11df7c"
},
{
"path": "skills/api-design-standards/templates/repository-pattern.py",
"sha256": "d3918975b70d5721c98e975d66ad8ba1b2c58b8658b50639abac166652a310e2"
},
{
"path": "skills/api-design-standards/templates/rate-limiter.py",
"sha256": "e973f344999d39e1877a8e242c461c4cff0b2813a35a91ba8dc13100b34e9859"
},
{
"path": "skills/api-design-standards/templates/pydantic-schemas.py",
"sha256": "7ca11e5145c0f7c63cff08b0d891c88a658779b0257c0f397088dc6a8e76eb6f"
},
{
"path": "skills/api-design-standards/templates/fastapi-crud-endpoint.py",
"sha256": "fb287b8e6eb79e1a3f8c975e894e95c2acc20df8c64c942205542e9b3104f971"
},
{
"path": "skills/api-design-standards/templates/error-handler.py",
"sha256": "0de1a732dcb7b67d7f9d9119566cec7f37b8826ce80343da34973bf4b26eb3e6"
},
{
"path": "skills/api-design-standards/templates/tanstack-server-function.ts",
"sha256": "027ba481af0ad8c62610002ad51ba9dfb3018cf400724c86cbe4fdf53e13df56"
},
{
"path": "skills/api-design-standards/reference/authentication.md",
"sha256": "ab85a5deeec98e237f76334a702ecbc78c7a1eb7a4c3b1235f796ce7dc58d6b3"
},
{
"path": "skills/api-design-standards/reference/cors-rate-limiting.md",
"sha256": "218aab01fca085c60f94bb5d76246899a1ee6c40ed207375e8c5915935fc0f25"
},
{
"path": "skills/api-design-standards/reference/fastapi-setup.md",
"sha256": "ba9187313da1e02bbc85ab172482cef5f140145b666bfbc1625bd93ee2dd84de"
},
{
"path": "skills/api-design-standards/reference/error-handlers.md",
"sha256": "4644e1baa08893c0b157cc4034963bfddee5c5b0ffd6f295fbbc54d5f65477fb"
},
{
"path": "skills/api-design-standards/reference/INDEX.md",
"sha256": "7c252ae328f28a82c9ab9c695a956145c4f5f492f4058b754996c4591733bf52"
},
{
"path": "skills/api-design-standards/reference/openapi.md",
"sha256": "715654b6c57c511476f8205e0406ba1040470fad7b1df27bacaa4e0df81b8c02"
},
{
"path": "skills/pr-template/SKILL.md",
"sha256": "36d4187f82e46c82a69e7d55c0ecb59e7a123dc532e82aa2d40057f2170cac44"
},
{
"path": "skills/pr-template/checklists/pr-checklist.md",
"sha256": "fae708a5e5ba6945c510dd1ac558f2e1b1198a779dea2353c66a95fca2222677"
},
{
"path": "skills/pr-template/templates/feature-template.md",
"sha256": "4001ad70a77de76e351b66509af3c897433055f7e9c3eae9bff14f1c3f2a8b52"
},
{
"path": "skills/ontological-documentation/README.md",
"sha256": "8e762699f91f2e33a621fca42d0445f6f7bacaaa6d192c0c8b06bdc1d149b9ca"
},
{
"path": "skills/ontological-documentation/SKILL.md",
"sha256": "3d6b80205d3322a338e17047c3ddfb72e9a712a8b417d0c9ee2c6dafb26d464f"
},
{
"path": "skills/ontological-documentation/checklists/ontology-documentation-checklist.md",
"sha256": "42b3b947b7a29445e825a3945f40a64255f9567ff26c8670b18f05b28daddf23"
},
{
"path": "skills/ontological-documentation/examples/ecommerce-ontology.md",
"sha256": "2a6f18dbc8464bcb18c4610146293da86d5e433d3613f265a99edc97b5f2b413"
},
{
"path": "skills/ontological-documentation/examples/INDEX.md",
"sha256": "494611f1b8e5918aa0e404afc3bd2cd4151122eb83a0071cb511b2bddf304d3c"
},
{
"path": "skills/ontological-documentation/scripts/generate_ontology_diagram.py",
"sha256": "72b0e84ab906ce9cadbd11087365bae19d4eec3d72ec54276080fc66d061b30f"
},
{
"path": "skills/ontological-documentation/scripts/README.md",
"sha256": "f1fbe7e1f1204a804b53af53b6fb21552e5f966f75813744358573e884152e8c"
},
{
"path": "skills/ontological-documentation/scripts/extract_concepts.py",
"sha256": "67397467c86c3b1f2eeba7ffe38ab53223244aa358430d61c3597f4d9caacdbf"
},
{
"path": "skills/ontological-documentation/templates/assets-README.md",
"sha256": "33fa54d4da095c36cb98324276261bff799f1b487b1b66464d58016726a20480"
},
{
"path": "skills/ontological-documentation/templates/domain-ontology.md",
"sha256": "54f6faaba617f709915963ea744851c539522b94b94267ef8eae2ee0185e2da2"
},
{
"path": "skills/ontological-documentation/reference/concept_extraction_guide.md",
"sha256": "831e0ba24dda053a2e1d6ad049beef5f2b8e464a28d197b8a3ccfa9370891a81"
},
{
"path": "skills/ontological-documentation/reference/ontology_patterns.md",
"sha256": "36145f294e1d316198dea178f9a6c64605120144cb58adf69dcc8934bd1389ee"
},
{
"path": "skills/ontological-documentation/reference/README.md",
"sha256": "df8fc60c65ddf4e94b75b1514eb70a03a979fa21f5912ce91c1b65868a125d95"
},
{
"path": "skills/ontological-documentation/reference/INDEX.md",
"sha256": "b0d715f473f6a618bf01c3824b07fcaa0ea36b4eb14bed6269a0bfac42e78ba2"
},
{
"path": "skills/ontological-documentation/reference/documentation_templates.md",
"sha256": "59a120c9b812338c15c008522a5e0e99308b8df1ac55eee9999afef2450d0068"
},
{
"path": "skills/project-structure/SKILL.md",
"sha256": "76e6c568af7efe357041e2525f546dbaa8a79c3689934860f6e9434402f3b396"
},
{
"path": "skills/project-structure/checklists/project-setup-checklist.md",
"sha256": "7b54cca9b77c13a82ea2f6a1b9d3892ad778046b5275dec88fb21353ebb91a0c"
},
{
"path": "skills/project-structure/examples/INDEX.md",
"sha256": "62b81c66e19647bf2e0518111abb020cb75604740750beb94b22c3edd3f0c75e"
},
{
"path": "skills/project-structure/reference/INDEX.md",
"sha256": "1674663009d90e565e8cdb4b13495be9532cc9f567ad6841da379bc9da276f10"
},
{
"path": "skills/onboarding-coordination/SKILL.md",
"sha256": "35c2a48b6d53865e832e52047049461a55efdf3283a75ba4915d52ade0b0388e"
},
{
"path": "skills/onboarding-coordination/examples/INDEX.md",
"sha256": "839ac38874b65f569d05cf84b743fd63f837bf974c903ee48c2d9f8a7146dbc4"
},
{
"path": "skills/onboarding-coordination/templates/INDEX.md",
"sha256": "2af8827d1ea2943368ed7be7dcc13963b1d38b6b673844b142d819d47c2ce8a7"
},
{
"path": "skills/onboarding-coordination/reference/INDEX.md",
"sha256": "72833a433e47c814286dc13ef10785fd035a7e95ec23f418c1060561b3d11d29"
},
{
"path": "skills/code-style/EXAMPLES.md",
"sha256": "675ffc254bd74e019a0ec5d7b51bfb5e27c659d8f9f0aeaade42bcdbeb2e21fa"
},
{
"path": "skills/code-style/REFERENCE.md",
"sha256": "43904b5d8597b676677641de845a667a4f5c3f89a7ea47a50eba565105c8e7d9"
},
{
"path": "skills/code-style/SKILL.md",
"sha256": "6602a54886c8315705f9654a6768b92ee2dc93a1ec6af53d482a1bc2a8b8fb19"
},
{
"path": "skills/code-style/checklists/python-review.md",
"sha256": "8810802c882e73d4f9a00e16eb9f95e62a505e41a0f0856d58ba555e82e30726"
},
{
"path": "skills/code-style/checklists/typescript-review.md",
"sha256": "b23cc57b91cfb41a49fd694ba6a2f0666e46ebd7da9a8ea76fa52749ff829d16"
},
{
"path": "skills/code-style/templates/typescript-component.tsx",
"sha256": "1270d35dddeb7a6dffc125b47dfc60ef00838f48e868470177010ff78048a74a"
},
{
"path": "skills/code-style/templates/python-model.py",
"sha256": "6a575992f2b25993d7f005a71022b6280640b44342c51c953c61b31fc8d3119a"
},
{
"path": "skills/code-style/templates/typescript-server-function.ts",
"sha256": "c91202362eb2257be052319bfe3c023cba144ed0736cc5980224cf2e57060bbe"
},
{
"path": "skills/code-style/templates/python-endpoint.py",
"sha256": "199749bee12cc9894c0067bd9c135ce762cc3fd02efdc039963c971673bc3505"
},
{
"path": "skills/code-style/templates/.prettierrc.json",
"sha256": "dfbd47294d39568b0e933089c4c5be3d91ddd12a7b385a6d68d5337aafc512b5"
},
{
"path": "skills/code-style/templates/ruff.toml",
"sha256": "7b1e9d695e4e3a455acd61b98bc31ff86d936989daf16a783e7089a504537cc7"
},
{
"path": "skills/code-style/templates/.eslintrc.json",
"sha256": "57db390995cc0938f81298248d272e9686b96e9c6eabf85b26e6581db3f2c39c"
},
{
"path": "skills/documentation-architecture/SKILL.md",
"sha256": "46ea8d28041c321c367e937b6d61bb62ad1e4a4a3dd5b9deed0a8bcd8ddcd8cf"
},
{
"path": "skills/documentation-architecture/checklists/documentation-quality-checklist.md",
"sha256": "f144397d848f7d67ba1926da2ef8e22c1568914bfdfd0835069722d71502e7d4"
},
{
"path": "skills/documentation-architecture/examples/architecture-docs.md",
"sha256": "3bbbba3c9b52429e395ab116f73545c3dd1631a690d05a5035dbbef3a64edf5a"
},
{
"path": "skills/documentation-architecture/examples/openapi-generation.md",
"sha256": "402c402e3afe373677fa81fff14759d2c14cc003b26e4b5815c2f01933a86fc9"
},
{
"path": "skills/documentation-architecture/examples/INDEX.md",
"sha256": "f6854bb2df3a7f4277db7372a7328e6a95d62c20e8a6abe6b646571674c0d7c7"
},
{
"path": "skills/documentation-architecture/examples/coverage-validation.md",
"sha256": "a52da791f52accdacb3d5f9a5fda0861d0495935d86d979dbc99ee6f3024d877"
},
{
"path": "skills/documentation-architecture/templates/openapi-spec.yaml",
"sha256": "9971ea0aec2ba505cc7d86cdbe203d235cbd016f18be62eaf1c79b5051c452bb"
},
{
"path": "skills/documentation-architecture/templates/api-endpoint.md",
"sha256": "ae4d3d8e08b300f3f6570d4e985edffe0a54a310feb1a8b662b8b5bc83274323"
},
{
"path": "skills/documentation-architecture/templates/architecture-doc.md",
"sha256": "7e207ef69ec2c8b7fcf9dabfc1c94ab202d74a815d1cb43c2b6b9b6a172cece0"
},
{
"path": "skills/documentation-architecture/templates/INDEX.md",
"sha256": "09e59e94be27f582c75c0d5579d1bb8a7508b148e1a1c4582e1a1383f4e73f71"
},
{
"path": "skills/documentation-architecture/reference/mermaid-diagrams.md",
"sha256": "b43cedd8370a2556d79976f7fb44514de9e458bdf0a6b21beac6171c19290960"
},
{
"path": "skills/documentation-architecture/reference/documentation-standards.md",
"sha256": "3e5ed6c0887bf43fe1fadf53420269f20d449007953d74b32018979de27c8fe7"
},
{
"path": "skills/documentation-architecture/reference/INDEX.md",
"sha256": "f78452c5dc51406cde72499d4bd65af8bc59d16d5c3b5c5ac5d96dead9ec8e87"
},
{
"path": "skills/documentation-architecture/reference/openapi-patterns.md",
"sha256": "2ae229c7f3415cde4dfc0384911259dedc037fc9f1f7b46e7cdcb743b49b3728"
}
],
"dirSha256": "51c21b2c4157042854383f81ae706ca51846c25f90b6d4865b3a80b9f950e16c"
},
"security": {
"scannedAt": null,
"scannerVersion": null,
"flags": []
}
}

View File

@@ -0,0 +1,288 @@
---
name: grey-haven-api-design
description: "Design RESTful APIs following Grey Haven standards - FastAPI routes, Pydantic schemas, HTTP status codes, pagination, filtering, error responses, OpenAPI docs, and multi-tenant patterns. Use when creating API endpoints, designing REST resources, implementing server functions, configuring FastAPI, writing Pydantic schemas, setting up error handling, implementing pagination, or when user mentions 'API', 'endpoint', 'REST', 'FastAPI', 'Pydantic', 'server function', 'OpenAPI', 'pagination', 'validation', 'error handling', 'rate limiting', 'CORS', or 'authentication'."
---
# Grey Haven API Design Standards
**RESTful API design for FastAPI backends and TanStack Start server functions.**
Follow these standards when creating API endpoints, defining schemas, and handling errors in Grey Haven projects.
## Supporting Documentation
- **[examples/](examples/)** - Complete endpoint examples (all files <500 lines)
- [fastapi-crud.md](examples/fastapi-crud.md) - CRUD endpoints with repository pattern
- [pydantic-schemas.md](examples/pydantic-schemas.md) - Request/response schemas
- [tanstack-start.md](examples/tanstack-start.md) - Server functions
- [pagination.md](examples/pagination.md) - Pagination patterns
- [testing.md](examples/testing.md) - API testing
- **[reference/](reference/)** - Configuration references (all files <500 lines)
- [fastapi-setup.md](reference/fastapi-setup.md) - Main app configuration
- [openapi.md](reference/openapi.md) - OpenAPI customization
- [error-handlers.md](reference/error-handlers.md) - Exception handlers
- [authentication.md](reference/authentication.md) - JWT configuration
- [cors-rate-limiting.md](reference/cors-rate-limiting.md) - CORS and rate limiting
- **[templates/](templates/)** - Copy-paste ready endpoint templates
- **[checklists/](checklists/)** - API design and security checklists
## Quick Reference
### RESTful Resource Design
**URL Patterns:**
-`/api/v1/users` (plural nouns, lowercase with hyphens)
-`/api/v1/organizations/{org_id}/teams` (hierarchical)
-`/api/v1/getUsers` (no verbs in URLs)
-`/api/v1/user_profiles` (no underscores)
**HTTP Verbs:**
- `GET` - Retrieve resources
- `POST` - Create new resources
- `PUT` - Update entire resource
- `PATCH` - Update partial resource
- `DELETE` - Remove resource
### HTTP Status Codes
**Success:**
- `200 OK` - GET, PUT, PATCH requests
- `201 Created` - POST request (resource created)
- `204 No Content` - DELETE request
**Client Errors:**
- `400 Bad Request` - Invalid request data
- `401 Unauthorized` - Missing/invalid authentication
- `403 Forbidden` - Insufficient permissions
- `404 Not Found` - Resource doesn't exist
- `409 Conflict` - Duplicate resource, concurrent update
- `422 Unprocessable Entity` - Validation errors
**Server Errors:**
- `500 Internal Server Error` - Unhandled exception
- `503 Service Unavailable` - Database/service down
### Multi-Tenant Isolation
**Always enforce tenant isolation:**
```python
# Extract tenant_id from JWT
repository = UserRepository(db, tenant_id=current_user.tenant_id)
# All queries automatically filtered by tenant_id
users = await repository.list() # Only returns users in this tenant
```
### FastAPI Route Pattern
```python
from fastapi import APIRouter, Depends, HTTPException, status
router = APIRouter(prefix="/api/v1/users", tags=["users"])
@router.post("", response_model=UserRead, status_code=status.HTTP_201_CREATED)
async def create_user(
user_data: UserCreate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
) -> UserRead:
"""Create a new user in the current tenant."""
repository = UserRepository(db, tenant_id=current_user.tenant_id)
user = await repository.create(user_data)
return user
```
**See [examples/fastapi-crud.md](examples/fastapi-crud.md) for complete CRUD endpoints.**
### Pydantic Schema Pattern
```python
from pydantic import BaseModel, EmailStr, Field, ConfigDict
class UserCreate(BaseModel):
"""Schema for creating a new user."""
email: EmailStr
full_name: str = Field(..., min_length=1, max_length=255)
password: str = Field(..., min_length=8)
class UserRead(BaseModel):
"""Schema for reading user data (public fields only)."""
id: str
tenant_id: str
email: EmailStr
full_name: str
created_at: datetime
model_config = ConfigDict(from_attributes=True)
```
**See [examples/pydantic-schemas.md](examples/pydantic-schemas.md) for validation patterns.**
### TanStack Start Server Functions
```typescript
// app/routes/api/users.ts
import { createServerFn } from "@tanstack/start";
import { z } from "zod";
const createUserSchema = z.object({
email: z.string().email(),
fullName: z.string().min(1).max(255),
});
export const createUser = createServerFn({ method: "POST" })
.validator(createUserSchema)
.handler(async ({ data, context }) => {
const authUser = await getAuthUser(context);
// Create user with tenant isolation
});
```
**See [examples/tanstack-start.md](examples/tanstack-start.md) for complete examples.**
### Error Response Format
```json
{
"error": "User with ID abc123 not found",
"status_code": 404
}
```
**Validation errors:**
```json
{
"error": "Validation error",
"detail": [
{
"field": "email",
"message": "value is not a valid email address",
"code": "value_error.email"
}
],
"status_code": 422
}
```
**See [reference/error-handlers.md](reference/error-handlers.md) for exception handlers.**
### Pagination
**Offset-based (simple):**
```python
@router.get("", response_model=PaginatedResponse[UserRead])
async def list_users(skip: int = 0, limit: int = 100):
users = await repository.list(skip=skip, limit=limit)
total = await repository.count()
return PaginatedResponse(items=users, total=total, skip=skip, limit=limit)
```
**Cursor-based (recommended for large datasets):**
```python
@router.get("")
async def list_users(cursor: Optional[str] = None, limit: int = 100):
users = await repository.list_cursor(cursor=cursor, limit=limit)
next_cursor = users[-1].id if len(users) == limit else None
return {"items": users, "next_cursor": next_cursor}
```
**See [examples/pagination.md](examples/pagination.md) for complete implementations.**
## Core Principles
### 1. Repository Pattern
**Always use tenant-aware repositories:**
- Extract `tenant_id` from JWT claims
- Pass to repository constructor
- All queries automatically filtered
- Prevents cross-tenant data leaks
### 2. Pydantic Validation
**Define schemas for all requests/responses:**
- `{Model}Create` - Fields for creation
- `{Model}Read` - Public fields for responses
- `{Model}Update` - Optional fields for updates
- Never return password hashes or sensitive data
### 3. OpenAPI Documentation
**FastAPI auto-generates docs:**
- Add docstrings to all endpoints
- Use `summary`, `description`, `response_description`
- Document all parameters and responses
- Available at `/docs` (Swagger UI) and `/redoc` (ReDoc)
**See [reference/openapi.md](reference/openapi.md) for customization.**
### 4. Rate Limiting
**Protect public endpoints:**
```python
from app.core.rate_limit import rate_limit
@router.get("", dependencies=[Depends(rate_limit)])
async def list_users():
"""List users (rate limited to 100 req/min)."""
pass
```
**See [templates/rate-limiter.py](templates/rate-limiter.py) for Upstash Redis implementation.**
### 5. CORS Configuration
**Use Doppler for allowed origins:**
```python
# NEVER hardcode origins in production!
allowed_origins = os.getenv("CORS_ALLOWED_ORIGINS", "").split(",")
app.add_middleware(
CORSMiddleware,
allow_origins=allowed_origins,
allow_credentials=True,
)
```
**See [reference/cors-rate-limiting.md](reference/cors-rate-limiting.md) for complete setup.**
## When to Apply This Skill
Use this skill when:
- ✅ Creating new FastAPI endpoints or TanStack Start server functions
- ✅ Designing RESTful resource hierarchies
- ✅ Writing Pydantic schemas for validation
- ✅ Implementing pagination, filtering, or sorting
- ✅ Configuring error response formats
- ✅ Setting up OpenAPI documentation
- ✅ Implementing rate limiting or CORS
- ✅ Designing multi-tenant API isolation
- ✅ Testing API endpoints with pytest
- ✅ Reviewing API design in pull requests
- ✅ User mentions: "API", "endpoint", "REST", "FastAPI", "Pydantic", "server function", "OpenAPI", "pagination", "validation"
## Template References
These API design patterns come from Grey Haven's actual templates:
- **Backend**: `cvi-backend-template` (FastAPI + SQLModel + Repository Pattern)
- **Frontend**: `cvi-template` (TanStack Start server functions)
## Critical Reminders
1. **Repository pattern** - Always use tenant-aware repositories for multi-tenant isolation
2. **Pydantic schemas** - Never return password hashes or sensitive fields in responses
3. **HTTP status codes** - 201 for create, 204 for delete, 404 for not found, 422 for validation errors
4. **Pagination** - Use cursor-based for large datasets (better performance than offset)
5. **Error format** - Consistent error structure with `error`, `detail`, and `status_code` fields
6. **OpenAPI docs** - Document all parameters, responses, and errors with docstrings
7. **Rate limiting** - Protect public endpoints with Upstash Redis (100 req/min default)
8. **CORS** - Use Doppler for allowed origins, never hardcode in production
9. **JWT authentication** - Extract `tenant_id` from JWT claims for multi-tenant isolation
10. **Testing** - Use FastAPI TestClient with `doppler run --config test -- pytest`
## Next Steps
- **Need endpoint examples?** See [examples/](examples/) for FastAPI CRUD and TanStack Start
- **Need configurations?** See [reference/](reference/) for OpenAPI, CORS, error handlers
- **Need templates?** See [templates/](templates/) for copy-paste ready endpoint code
- **Need checklists?** Use [checklists/](checklists/) for systematic API design reviews

View File

@@ -0,0 +1,118 @@
# API Design Checklist
**Use this checklist before creating PR for new API endpoints.**
## RESTful Design
- [ ] URLs use plural nouns (`/users` not `/user`)
- [ ] URLs use lowercase with hyphens (`/user-profiles` not `/userProfiles`)
- [ ] No verbs in URLs (`/users` not `/getUsers`)
- [ ] Hierarchical resources follow pattern `/parent/{id}/child`
- [ ] HTTP verbs used correctly (GET=read, POST=create, PUT=update, DELETE=delete)
## Multi-Tenant Isolation
- [ ] All queries filtered by `tenant_id` from JWT
- [ ] Repository pattern used with automatic tenant filtering
- [ ] No direct database queries bypassing repository
- [ ] Cross-tenant access blocked (except superuser endpoints)
- [ ] Test cases verify tenant isolation
## Request/Response Schemas
- [ ] Pydantic schemas defined for all requests
- [ ] Pydantic schemas defined for all responses
- [ ] Password hashes never returned in responses
- [ ] Sensitive fields excluded from public schemas
- [ ] Validation rules enforced (min/max length, format, etc.)
- [ ] Field-level validation implemented where needed
- [ ] Model-level validation for cross-field rules
## HTTP Status Codes
- [ ] 200 OK for successful GET/PUT/PATCH
- [ ] 201 Created for successful POST
- [ ] 204 No Content for successful DELETE
- [ ] 400 Bad Request for invalid data
- [ ] 401 Unauthorized for missing/invalid auth
- [ ] 403 Forbidden for insufficient permissions
- [ ] 404 Not Found for missing resources
- [ ] 409 Conflict for duplicates
- [ ] 422 Validation Error for schema failures
## Error Handling
- [ ] Consistent error response format (`error`, `status_code`, `detail`)
- [ ] Custom exception handlers registered
- [ ] Validation errors return field-level details
- [ ] Integrity errors handled gracefully (409 Conflict)
- [ ] Generic exceptions caught and logged
## Pagination
- [ ] List endpoints support pagination (`skip`, `limit`)
- [ ] Maximum limit enforced (100 default)
- [ ] Paginated response includes `total`, `has_more`
- [ ] Cursor-based pagination for large datasets
- [ ] Pagination tested with edge cases
## Authentication
- [ ] JWT authentication required on protected endpoints
- [ ] `tenant_id` extracted from JWT claims
- [ ] Superuser flag checked for admin endpoints
- [ ] Public endpoints explicitly marked (no auth)
- [ ] Authentication tested in integration tests
## OpenAPI Documentation
- [ ] Endpoint docstrings describe purpose
- [ ] All parameters documented
- [ ] Response schemas documented
- [ ] Error responses documented (409, 422, etc.)
- [ ] Examples provided for complex schemas
- [ ] Tags assigned for logical grouping
## Rate Limiting
- [ ] Public endpoints have rate limiting
- [ ] Critical endpoints (create, update) have stricter limits
- [ ] Rate limit uses Upstash Redis
- [ ] Rate limit headers included in response
## Testing
- [ ] Unit tests for repository methods
- [ ] Integration tests for all CRUD operations
- [ ] Tenant isolation verified in tests
- [ ] Duplicate detection tested (409 Conflict)
- [ ] Validation errors tested (422 Unprocessable)
- [ ] Authentication tested (401 Unauthorized)
- [ ] Tests run with Doppler (`doppler run --config test`)
## Security
- [ ] No SQL injection vulnerabilities (using ORM)
- [ ] No hardcoded secrets or credentials
- [ ] CORS origins from Doppler (not hardcoded)
- [ ] Input validation on all fields
- [ ] Output encoding prevents XSS
- [ ] Rate limiting protects against abuse
## Performance
- [ ] Database queries use indexes
- [ ] N+1 queries avoided
- [ ] Pagination prevents loading all records
- [ ] Heavy operations use background jobs
- [ ] Caching implemented where appropriate
## Before Merging
- [ ] All tests pass (`pytest`)
- [ ] Coverage >80% for new code
- [ ] OpenAPI docs reviewed at `/docs`
- [ ] Tested locally with Doppler
- [ ] Code reviewed by teammate
- [ ] No console.log or debug prints
- [ ] Migration created if schema changed

View File

@@ -0,0 +1,84 @@
# API Security Review Checklist
**Security-focused review for API endpoints.**
## Authentication & Authorization
- [ ] JWT required on all protected endpoints
- [ ] Token expiration enforced
- [ ] Superuser flag checked for admin operations
- [ ] No authentication bypass vulnerabilities
- [ ] Session management secure
## Multi-Tenant Security
- [ ] All queries filter by `tenant_id`
- [ ] No cross-tenant data leaks possible
- [ ] Repository pattern enforces isolation
- [ ] Admin endpoints verify superuser
- [ ] Test cases prove isolation
## Input Validation
- [ ] All inputs validated with Pydantic
- [ ] SQL injection prevented (using ORM)
- [ ] XSS prevented (output encoding)
- [ ] File uploads validated (type, size)
- [ ] Email format validated
- [ ] URL format validated
- [ ] Integer ranges validated
- [ ] String lengths validated
## Sensitive Data
- [ ] Passwords hashed with bcrypt
- [ ] Password hashes never returned
- [ ] Secrets from Doppler (not hardcoded)
- [ ] PII properly handled
- [ ] No sensitive data in logs
- [ ] No sensitive data in error messages
## Rate Limiting
- [ ] Public endpoints rate limited
- [ ] Login endpoints strictly rate limited
- [ ] Rate limit uses Redis
- [ ] Rate limit tested
## CORS
- [ ] Allowed origins from Doppler
- [ ] No `allow_origins=["*"]` in production
- [ ] Credentials allowed only for trusted origins
- [ ] Preflight requests handled
## Error Handling
- [ ] No stack traces in production responses
- [ ] Generic errors for security issues
- [ ] Detailed errors only in dev/test
- [ ] Errors logged server-side
## OWASP Top 10
- [ ] A01: Broken Access Control - ✅ Tenant isolation
- [ ] A02: Cryptographic Failures - ✅ Bcrypt, Doppler
- [ ] A03: Injection - ✅ ORM, validation
- [ ] A04: Insecure Design - ✅ Repository pattern
- [ ] A05: Security Misconfiguration - ✅ CORS, secrets
- [ ] A06: Vulnerable Components - ✅ Updated dependencies
- [ ] A07: Identification Failures - ✅ JWT, rate limiting
- [ ] A08: Integrity Failures - ✅ Input validation
- [ ] A09: Logging Failures - ✅ Error logging
- [ ] A10: SSRF - ✅ URL validation
## Before Production Deploy
- [ ] Security scan passed
- [ ] No hardcoded secrets
- [ ] Doppler secrets configured
- [ ] CORS origins configured
- [ ] Rate limiting enabled
- [ ] HTTPS enforced
- [ ] Error handling tested
- [ ] Penetration test completed

View File

@@ -0,0 +1,17 @@
# API Design Examples Index
**All example files are under 500 lines for optimal loading.**
## Available Examples
- **[fastapi-crud.md](fastapi-crud.md)** - Complete CRUD endpoints with repository pattern (332 lines)
- **[pydantic-schemas.md](pydantic-schemas.md)** - Request/response schemas with validation
- **[tanstack-start.md](tanstack-start.md)** - TanStack Start server functions
- **[pagination.md](pagination.md)** - Offset and cursor-based pagination
- **[testing.md](testing.md)** - API endpoint testing with pytest
## Quick Links
- **Templates**: See [../templates/](../templates/) for copy-paste ready code
- **Reference**: See [../reference/](../reference/) for complete configurations
- **Checklists**: See [../checklists/](../checklists/) for API design validation

View File

@@ -0,0 +1,332 @@
# FastAPI CRUD Endpoints
**Complete CRUD endpoint examples with repository pattern and tenant isolation.**
## Complete User CRUD
```python
# app/api/routes/users.py
from fastapi import APIRouter, Depends, HTTPException, status
from sqlmodel import Session
from typing import Optional
from app.core.dependencies import get_current_user, get_db
from app.models.user import User
from app.repositories.user_repository import UserRepository
from app.schemas.user import UserCreate, UserRead, UserUpdate, PaginatedResponse
router = APIRouter(prefix="/api/v1/users", tags=["users"])
@router.get("", response_model=PaginatedResponse[UserRead], status_code=status.HTTP_200_OK)
async def list_users(
skip: int = 0,
limit: int = 100,
is_active: Optional[bool] = None,
email_contains: Optional[str] = None,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
) -> PaginatedResponse[UserRead]:
"""
List all users in the current tenant with pagination and filtering.
- **skip**: Number of records to skip (pagination offset)
- **limit**: Maximum number of records to return (max 100)
- **is_active**: Filter by active status (optional)
- **email_contains**: Filter by email substring (optional)
- **Returns**: Paginated list of users with public fields only
"""
repository = UserRepository(db, tenant_id=current_user.tenant_id)
# Build filter criteria
filters = {}
if is_active is not None:
filters["is_active"] = is_active
if email_contains:
filters["email_contains"] = email_contains
users = await repository.list(filters=filters, skip=skip, limit=limit)
total = await repository.count(filters=filters)
return PaginatedResponse(
items=users,
total=total,
skip=skip,
limit=limit,
has_more=(skip + limit) < total,
)
@router.get("/{user_id}", response_model=UserRead, status_code=status.HTTP_200_OK)
async def get_user(
user_id: str,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
) -> UserRead:
"""Get a single user by ID (tenant-isolated)."""
repository = UserRepository(db, tenant_id=current_user.tenant_id)
user = await repository.get_by_id(user_id)
if not user:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"User with ID {user_id} not found",
)
return user
@router.post("", response_model=UserRead, status_code=status.HTTP_201_CREATED)
async def create_user(
user_data: UserCreate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
) -> UserRead:
"""
Create a new user in the current tenant.
- **email**: Valid email address (unique per tenant)
- **full_name**: User's full name (1-255 characters)
- **password**: At least 8 characters
- **Returns**: Created user with ID, timestamps, and public fields
**Errors**:
- 409 Conflict: Email already exists in tenant
- 422 Validation Error: Invalid email or weak password
"""
repository = UserRepository(db, tenant_id=current_user.tenant_id)
try:
user = await repository.create(user_data)
return user
except IntegrityError:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail=f"User with email {user_data.email} already exists",
)
@router.put("/{user_id}", response_model=UserRead, status_code=status.HTTP_200_OK)
async def update_user(
user_id: str,
user_data: UserUpdate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
) -> UserRead:
"""
Update an existing user (tenant-isolated).
All fields are optional - only provided fields will be updated.
"""
repository = UserRepository(db, tenant_id=current_user.tenant_id)
user = await repository.update(user_id, user_data)
if not user:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"User with ID {user_id} not found",
)
return user
@router.patch("/{user_id}", response_model=UserRead, status_code=status.HTTP_200_OK)
async def partial_update_user(
user_id: str,
user_data: UserUpdate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
) -> UserRead:
"""
Partially update an existing user (tenant-isolated).
Same as PUT but semantically indicates partial update.
"""
repository = UserRepository(db, tenant_id=current_user.tenant_id)
user = await repository.update(user_id, user_data)
if not user:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"User with ID {user_id} not found",
)
return user
@router.delete("/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_user(
user_id: str,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
) -> None:
"""
Soft-delete a user (tenant-isolated).
Returns 204 No Content on success (no response body).
"""
repository = UserRepository(db, tenant_id=current_user.tenant_id)
success = await repository.delete(user_id)
if not success:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"User with ID {user_id} not found",
)
```
## Repository Pattern with Tenant Isolation
```python
# app/repositories/user_repository.py
from sqlmodel import Session, select, func
from typing import Optional
from datetime import datetime
from app.models.user import User
from app.schemas.user import UserCreate, UserUpdate
class UserRepository:
"""Repository with automatic tenant filtering."""
def __init__(self, db: Session, tenant_id: str):
self.db = db
self.tenant_id = tenant_id
async def list(
self, filters: dict = None, skip: int = 0, limit: int = 100
) -> list[User]:
"""List users (automatically filtered by tenant_id)."""
statement = select(User).where(User.tenant_id == self.tenant_id)
# Apply additional filters
if filters:
if "is_active" in filters:
statement = statement.where(User.is_active == filters["is_active"])
if "email_contains" in filters:
statement = statement.where(User.email.contains(filters["email_contains"]))
statement = statement.offset(skip).limit(limit).order_by(User.created_at.desc())
result = await self.db.execute(statement)
return result.scalars().all()
async def count(self, filters: dict = None) -> int:
"""Count users (tenant-isolated)."""
statement = select(func.count(User.id)).where(User.tenant_id == self.tenant_id)
# Apply same filters as list()
if filters:
if "is_active" in filters:
statement = statement.where(User.is_active == filters["is_active"])
if "email_contains" in filters:
statement = statement.where(User.email.contains(filters["email_contains"]))
result = await self.db.execute(statement)
return result.scalar_one()
async def get_by_id(self, user_id: str) -> User | None:
"""Get user by ID (tenant-isolated)."""
statement = select(User).where(
User.id == user_id,
User.tenant_id == self.tenant_id,
)
result = await self.db.execute(statement)
return result.scalar_one_or_none()
async def create(self, user_data: UserCreate) -> User:
"""Create a new user in the current tenant."""
from app.utils.password import hash_password
user = User(
email=user_data.email,
full_name=user_data.full_name,
hashed_password=hash_password(user_data.password),
tenant_id=self.tenant_id, # Automatic tenant assignment
)
self.db.add(user)
await self.db.commit()
await self.db.refresh(user)
return user
async def update(self, user_id: str, user_data: UserUpdate) -> User | None:
"""Update an existing user (tenant-isolated)."""
user = await self.get_by_id(user_id)
if not user:
return None
# Update only provided fields
update_data = user_data.model_dump(exclude_unset=True)
for field, value in update_data.items():
setattr(user, field, value)
await self.db.commit()
await self.db.refresh(user)
return user
async def delete(self, user_id: str) -> bool:
"""Soft-delete a user (tenant-isolated)."""
user = await self.get_by_id(user_id)
if not user:
return False
# Soft delete by setting deleted_at timestamp
user.deleted_at = datetime.utcnow()
await self.db.commit()
return True
```
## Nested Resources
```python
# app/api/routes/organizations.py
from fastapi import APIRouter, Depends, HTTPException, status
router = APIRouter(prefix="/api/v1/organizations", tags=["organizations"])
@router.get("/{org_id}/teams", response_model=list[TeamRead])
async def list_organization_teams(
org_id: str,
skip: int = 0,
limit: int = 100,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
) -> list[TeamRead]:
"""List all teams in an organization (tenant-isolated)."""
# Verify organization exists and belongs to tenant
org_repo = OrganizationRepository(db, tenant_id=current_user.tenant_id)
org = await org_repo.get_by_id(org_id)
if not org:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Organization with ID {org_id} not found",
)
# Fetch teams for organization
team_repo = TeamRepository(db, tenant_id=current_user.tenant_id)
teams = await team_repo.list_by_organization(org_id, skip=skip, limit=limit)
return teams
@router.post("/{org_id}/teams", response_model=TeamRead, status_code=status.HTTP_201_CREATED)
async def create_organization_team(
org_id: str,
team_data: TeamCreate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
) -> TeamRead:
"""Create a new team in an organization."""
# Verify organization exists
org_repo = OrganizationRepository(db, tenant_id=current_user.tenant_id)
org = await org_repo.get_by_id(org_id)
if not org:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Organization with ID {org_id} not found",
)
# Create team
team_repo = TeamRepository(db, tenant_id=current_user.tenant_id)
team = await team_repo.create(team_data, organization_id=org_id)
return team
```
**See also:**
- [pydantic-schemas.md](pydantic-schemas.md) - Request/response schema patterns
- [pagination.md](pagination.md) - Pagination and filtering examples
- [../templates/fastapi-crud-endpoint.py](../templates/fastapi-crud-endpoint.py) - CRUD template

View File

@@ -0,0 +1,38 @@
# Pagination Patterns
**Offset-based and cursor-based pagination examples.**
## Offset-Based Pagination
```python
class PaginatedResponse[T](BaseModel):
items: list[T]
total: int
skip: int
limit: int
has_more: bool
@router.get("", response_model=PaginatedResponse[UserRead])
async def list_users(skip: int = 0, limit: int = 100):
repository = UserRepository(db, tenant_id=current_user.tenant_id)
users = await repository.list(skip=skip, limit=limit)
total = await repository.count()
return PaginatedResponse(items=users, total=total, skip=skip, limit=limit, has_more=(skip + limit) < total)
```
## Cursor-Based Pagination (Recommended)
```python
class CursorPaginatedResponse[T](BaseModel):
items: list[T]
next_cursor: Optional[str]
has_more: bool
@router.get("")
async def list_users(cursor: Optional[str] = None, limit: int = 100):
users = await repository.list_cursor(cursor=cursor, limit=limit)
next_cursor = users[-1].id if len(users) == limit else None
return CursorPaginatedResponse(items=users, next_cursor=next_cursor, has_more=next_cursor is not None)
```
**See also:** [fastapi-crud.md](fastapi-crud.md) for complete examples

View File

@@ -0,0 +1,149 @@
# Pydantic Schema Examples
**Complete Pydantic schema patterns for request/response validation.**
## Request/Response Schemas
```python
# app/schemas/user.py
from pydantic import BaseModel, EmailStr, Field, ConfigDict, field_validator, model_validator
from datetime import datetime
from typing import Optional
class UserBase(BaseModel):
"""Shared fields for User schemas."""
email: EmailStr
full_name: str = Field(..., min_length=1, max_length=255)
is_active: bool = True
class UserCreate(UserBase):
"""Schema for creating a new user."""
password: str = Field(..., min_length=8, max_length=100)
password_confirm: str = Field(..., min_length=8, max_length=100)
@field_validator("password")
@classmethod
def validate_password_strength(cls, v: str) -> str:
"""Ensure password meets complexity requirements."""
if len(v) < 8:
raise ValueError("Password must be at least 8 characters")
if not any(char.isdigit() for char in v):
raise ValueError("Password must contain at least one digit")
if not any(char.isupper() for char in v):
raise ValueError("Password must contain at least one uppercase letter")
if not any(char.islower() for char in v):
raise ValueError("Password must contain at least one lowercase letter")
return v
@model_validator(mode="after")
def passwords_match(self) -> "UserCreate":
"""Ensure password and password_confirm match."""
if self.password != self.password_confirm:
raise ValueError("Passwords do not match")
return self
class UserUpdate(BaseModel):
"""Schema for updating an existing user (all fields optional)."""
email: Optional[EmailStr] = None
full_name: Optional[str] = Field(None, min_length=1, max_length=255)
is_active: Optional[bool] = None
class UserRead(UserBase):
"""Schema for reading user data (public fields only)."""
id: str
tenant_id: str
created_at: datetime
updated_at: datetime
model_config = ConfigDict(from_attributes=True)
class PaginatedResponse[T](BaseModel):
"""Generic paginated response."""
items: list[T]
total: int
skip: int
limit: int
has_more: bool
```
## Nested Schemas
```python
# app/schemas/organization.py
from pydantic import BaseModel, ConfigDict, Field
from datetime import datetime
from typing import Optional
from app.schemas.team import TeamRead
class OrganizationBase(BaseModel):
"""Shared fields for Organization schemas."""
name: str = Field(..., min_length=1, max_length=255)
description: Optional[str] = None
class OrganizationCreate(OrganizationBase):
"""Schema for creating a new organization."""
pass
class OrganizationRead(OrganizationBase):
"""Organization with nested teams."""
id: str
tenant_id: str
teams: list[TeamRead] = [] # Nested teams
created_at: datetime
updated_at: datetime
model_config = ConfigDict(from_attributes=True)
```
## Custom Validation
```python
# app/schemas/user.py
from pydantic import field_validator, model_validator
import re
class UserCreate(BaseModel):
email: EmailStr
username: str
password: str
@field_validator("username")
@classmethod
def validate_username(cls, v: str) -> str:
"""Ensure username is alphanumeric."""
if not re.match(r"^[a-zA-Z0-9_-]+$", v):
raise ValueError("Username must contain only letters, numbers, hyphens, and underscores")
if len(v) < 3:
raise ValueError("Username must be at least 3 characters")
return v
@field_validator("email")
@classmethod
def validate_email_domain(cls, v: str) -> str:
"""Ensure email is from allowed domain."""
allowed_domains = ["example.com", "greyhaven.studio"]
domain = v.split("@")[1]
if domain not in allowed_domains:
raise ValueError(f"Email must be from {', '.join(allowed_domains)}")
return v
@model_validator(mode="after")
def validate_username_not_in_email(self) -> "UserCreate":
"""Ensure username is not part of email."""
if self.username.lower() in self.email.lower():
raise ValueError("Username cannot be part of email address")
return self
```
**See also:**
- [fastapi-crud.md](fastapi-crud.md) - CRUD endpoints using these schemas
- [../templates/pydantic-schemas.py](../templates/pydantic-schemas.py) - Schema template

View File

@@ -0,0 +1,71 @@
# TanStack Start Server Functions
**Complete server function examples with Drizzle ORM and tenant isolation.**
See [../templates/tanstack-server-function.ts](../templates/tanstack-server-function.ts) for full template.
## Complete CRUD Server Functions
```typescript
// app/routes/api/users.ts
import { createServerFn } from "@tanstack/start";
import { z } from "zod";
import { db } from "~/utils/db.server";
import { usersTable } from "~/db/schema";
import { getAuthUser } from "~/utils/auth.server";
import { eq, and, like, count, desc } from "drizzle-orm";
import { hashPassword } from "~/utils/password.server";
// Validation schemas
const createUserSchema = z.object({
email: z.string().email(),
fullName: z.string().min(1).max(255),
password: z.string().min(8),
});
const updateUserSchema = z.object({
email: z.string().email().optional(),
fullName: z.string().min(1).max(255).optional(),
isActive: z.boolean().optional(),
});
// List users
export const listUsers = createServerFn({ method: "GET" })
.validator(z.object({ skip: z.number().min(0).default(0), limit: z.number().min(1).max(100).default(100) }))
.handler(async ({ data, context }) => {
const authUser = await getAuthUser(context);
if (!authUser) throw new Error("Unauthorized", { status: 401 });
const users = await db.select().from(usersTable)
.where(eq(usersTable.tenantId, authUser.tenantId))
.orderBy(desc(usersTable.createdAt))
.limit(data.limit).offset(data.skip);
const [{ count: total }] = await db.select({ count: count() })
.from(usersTable).where(eq(usersTable.tenantId, authUser.tenantId));
return {
items: users.map(({ hashedPassword, ...user }) => user),
total, skip: data.skip, limit: data.limit,
hasMore: data.skip + data.limit < total,
};
});
// Create user
export const createUser = createServerFn({ method: "POST" })
.validator(createUserSchema)
.handler(async ({ data, context }) => {
const authUser = await getAuthUser(context);
if (!authUser) throw new Error("Unauthorized", { status: 401 });
const [user] = await db.insert(usersTable).values({
...data, hashedPassword: await hashPassword(data.password),
tenantId: authUser.tenantId,
}).returning();
const { hashedPassword: _, ...userPublic } = user;
return userPublic;
});
```
**See also:** [fastapi-crud.md](fastapi-crud.md) for FastAPI examples

View File

@@ -0,0 +1,22 @@
# API Testing Examples
**pytest examples for FastAPI endpoints.**
```python
# tests/api/test_users.py
import pytest
from fastapi.testclient import TestClient
@pytest.mark.integration
def test_create_user(test_token: str):
response = client.post("/api/v1/users", json={"email": "test@example.com", "full_name": "Test", "password": "Pass123"}, headers={"Authorization": f"Bearer {test_token}"})
assert response.status_code == 201
assert "id" in response.json()
@pytest.mark.integration
def test_tenant_isolation(test_token: str):
response = client.get(f"/api/v1/users/{other_tenant_user_id}", headers={"Authorization": f"Bearer {test_token}"})
assert response.status_code == 404 # Cannot access other tenant's data
```
Run with: `doppler run --config test -- pytest tests/api/ -v`

View File

@@ -0,0 +1,11 @@
# API Design Reference Index
**All reference files are under 500 lines for optimal loading.**
## Available References
- **[fastapi-setup.md](fastapi-setup.md)** - Main FastAPI configuration
- **[openapi.md](openapi.md)** - OpenAPI customization
- **[error-handlers.md](error-handlers.md)** - Exception handlers
- **[authentication.md](authentication.md)** - JWT configuration
- **[cors-rate-limiting.md](cors-rate-limiting.md)** - CORS and rate limiting

View File

@@ -0,0 +1,24 @@
# Authentication Configuration
**JWT setup with bcrypt password hashing.**
```python
# app/core/auth.py
import jwt
from passlib.context import CryptContext
from datetime import datetime, timedelta
import os
JWT_SECRET_KEY = os.getenv("JWT_SECRET_KEY")
JWT_ALGORITHM = "HS256"
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def create_access_token(user_id: str, tenant_id: str) -> str:
expire = datetime.utcnow() + timedelta(minutes=30)
return jwt.encode({"sub": user_id, "tenant_id": tenant_id, "exp": expire}, JWT_SECRET_KEY, algorithm=JWT_ALGORITHM)
def hash_password(password: str) -> str:
return pwd_context.hash(password)
```
**Doppler:** `JWT_SECRET_KEY` must be set in Doppler secrets.

View File

@@ -0,0 +1,26 @@
# CORS and Rate Limiting
**CORS middleware and Upstash Redis rate limiter.**
## CORS
```python
allowed_origins = os.getenv("CORS_ALLOWED_ORIGINS", "").split(",")
app.add_middleware(CORSMiddleware, allow_origins=allowed_origins, allow_credentials=True)
```
**Doppler:** `CORS_ALLOWED_ORIGINS="https://app.example.com"`
## Rate Limiting
See [../templates/rate-limiter.py](../templates/rate-limiter.py) for full implementation.
```python
from app.core.rate_limit import rate_limit_normal
@router.get("", dependencies=[Depends(rate_limit_normal)])
async def list_users():
pass # Rate limited to 100 req/min
```
**Doppler:** `REDIS_URL` must be set for Upstash Redis.

View File

@@ -0,0 +1,17 @@
# Error Handlers
**Complete exception handler configuration.**
See [../templates/error-handler.py](../templates/error-handler.py) for full implementation.
```python
async def http_exception_handler(request, exc):
return JSONResponse(status_code=exc.status_code, content={"error": exc.detail, "status_code": exc.status_code})
async def validation_exception_handler(request, exc):
errors = [{"field": ".".join(str(loc) for loc in e["loc"]), "message": e["msg"], "code": e["type"]} for e in exc.errors()]
return JSONResponse(status_code=422, content={"error": "Validation error", "detail": errors, "status_code": 422})
app.add_exception_handler(HTTPException, http_exception_handler)
app.add_exception_handler(RequestValidationError, validation_exception_handler)
```

View File

@@ -0,0 +1,34 @@
# FastAPI Setup
**Complete main application configuration.**
```python
# app/main.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import os
app = FastAPI(
title="Grey Haven API",
description="RESTful API for multi-tenant SaaS",
version="1.0.0",
docs_url="/docs",
redoc_url="/redoc",
)
# CORS
allowed_origins = os.getenv("CORS_ALLOWED_ORIGINS", "").split(",")
app.add_middleware(CORSMiddleware, allow_origins=allowed_origins, allow_credentials=True)
# Exception handlers (see error-handlers.md)
# app.add_exception_handler(...)
# Include routers
app.include_router(users.router)
@app.get("/health")
async def health_check():
return {"status": "healthy"}
```
**Doppler config:** `doppler run --config dev -- uvicorn app.main:app --reload`

View File

@@ -0,0 +1,17 @@
# OpenAPI Customization
**Custom OpenAPI schema with security.**
```python
def custom_openapi(app):
openapi_schema = get_openapi(title=app.title, version=app.version, routes=app.routes)
openapi_schema["components"]["securitySchemes"] = {
"BearerAuth": {"type": "http", "scheme": "bearer", "bearerFormat": "JWT"}
}
openapi_schema["security"] = [{"BearerAuth": []}]
return openapi_schema
app.openapi = lambda: custom_openapi(app)
```
Access docs at `/docs` (Swagger UI) or `/redoc` (ReDoc).

View File

@@ -0,0 +1,115 @@
# Grey Haven Studio - Error Handler Template
# Add this to app/core/exceptions.py
from fastapi import HTTPException, Request, status
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError
from sqlalchemy.exc import IntegrityError, OperationalError
import logging
logger = logging.getLogger(__name__)
async def http_exception_handler(request: Request, exc: HTTPException) -> JSONResponse:
"""Handle HTTPException with standard error format."""
logger.warning(f"HTTP exception: {exc.status_code} - {exc.detail}")
return JSONResponse(
status_code=exc.status_code,
content={
"error": exc.detail,
"status_code": exc.status_code,
},
headers=exc.headers,
)
async def validation_exception_handler(
request: Request, exc: RequestValidationError
) -> JSONResponse:
"""Handle Pydantic validation errors."""
errors = []
for error in exc.errors():
field_path = ".".join(str(loc) for loc in error["loc"] if loc != "body")
errors.append(
{
"field": field_path if field_path else None,
"message": error["msg"],
"code": error["type"],
}
)
logger.warning(f"Validation error: {errors}")
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content={
"error": "Validation error",
"detail": errors,
"status_code": 422,
},
)
async def integrity_error_handler(
request: Request, exc: IntegrityError
) -> JSONResponse:
"""Handle database integrity errors."""
logger.error(f"Integrity error: {exc}")
error_detail = "A resource with this unique value already exists"
if "foreign key" in str(exc).lower():
error_detail = "Referenced resource does not exist"
return JSONResponse(
status_code=status.HTTP_409_CONFLICT,
content={
"error": error_detail,
"status_code": 409,
},
)
async def operational_error_handler(
request: Request, exc: OperationalError
) -> JSONResponse:
"""Handle database operational errors."""
logger.error(f"Database operational error: {exc}")
return JSONResponse(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
content={
"error": "Service temporarily unavailable",
"detail": "Database connection error. Please try again later.",
"status_code": 503,
},
)
async def generic_exception_handler(request: Request, exc: Exception) -> JSONResponse:
"""Catch-all handler for unexpected exceptions."""
logger.exception(f"Unhandled exception: {exc}")
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content={
"error": "Internal server error",
"status_code": 500,
},
)
# Register in main.py:
# from app.core.exceptions import (
# http_exception_handler,
# validation_exception_handler,
# integrity_error_handler,
# operational_error_handler,
# generic_exception_handler,
# )
#
# app.add_exception_handler(HTTPException, http_exception_handler)
# app.add_exception_handler(RequestValidationError, validation_exception_handler)
# app.add_exception_handler(IntegrityError, integrity_error_handler)
# app.add_exception_handler(OperationalError, operational_error_handler)
# app.add_exception_handler(Exception, generic_exception_handler)

View File

@@ -0,0 +1,130 @@
# Grey Haven Studio - FastAPI CRUD Endpoint Template
# Copy this template for new resource endpoints
from fastapi import APIRouter, Depends, HTTPException, status
from sqlmodel import Session
from typing import Optional
from app.core.dependencies import get_current_user, get_db
from app.models.user import User
from app.repositories.resource_repository import ResourceRepository # TODO: Update import
from app.schemas.resource import ResourceCreate, ResourceRead, ResourceUpdate, PaginatedResponse # TODO: Update import
# TODO: Update prefix, tags, and model name
router = APIRouter(prefix="/api/v1/resources", tags=["resources"])
@router.get("", response_model=PaginatedResponse[ResourceRead], status_code=status.HTTP_200_OK)
async def list_resources(
skip: int = 0,
limit: int = 100,
# TODO: Add filter parameters as needed
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
) -> PaginatedResponse[ResourceRead]:
"""
List all resources in the current tenant with pagination.
- **skip**: Number of records to skip (pagination offset)
- **limit**: Maximum number of records to return (max 100)
- **Returns**: Paginated list of resources
"""
repository = ResourceRepository(db, tenant_id=current_user.tenant_id)
# TODO: Build filter criteria if needed
filters = {}
resources = await repository.list(filters=filters, skip=skip, limit=limit)
total = await repository.count(filters=filters)
return PaginatedResponse(
items=resources,
total=total,
skip=skip,
limit=limit,
has_more=(skip + limit) < total,
)
@router.get("/{resource_id}", response_model=ResourceRead, status_code=status.HTTP_200_OK)
async def get_resource(
resource_id: str,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
) -> ResourceRead:
"""Get a single resource by ID (tenant-isolated)."""
repository = ResourceRepository(db, tenant_id=current_user.tenant_id)
resource = await repository.get_by_id(resource_id)
if not resource:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Resource with ID {resource_id} not found",
)
return resource
@router.post("", response_model=ResourceRead, status_code=status.HTTP_201_CREATED)
async def create_resource(
resource_data: ResourceCreate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
) -> ResourceRead:
"""
Create a new resource in the current tenant.
**Errors**:
- 409 Conflict: Duplicate resource
- 422 Validation Error: Invalid data
"""
repository = ResourceRepository(db, tenant_id=current_user.tenant_id)
try:
resource = await repository.create(resource_data)
return resource
except IntegrityError:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="Resource with this identifier already exists",
)
@router.put("/{resource_id}", response_model=ResourceRead, status_code=status.HTTP_200_OK)
async def update_resource(
resource_id: str,
resource_data: ResourceUpdate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
) -> ResourceRead:
"""
Update an existing resource (tenant-isolated).
All fields are optional - only provided fields will be updated.
"""
repository = ResourceRepository(db, tenant_id=current_user.tenant_id)
resource = await repository.update(resource_id, resource_data)
if not resource:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Resource with ID {resource_id} not found",
)
return resource
@router.delete("/{resource_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_resource(
resource_id: str,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
) -> None:
"""
Soft-delete a resource (tenant-isolated).
Returns 204 No Content on success (no response body).
"""
repository = ResourceRepository(db, tenant_id=current_user.tenant_id)
success = await repository.delete(resource_id)
if not success:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Resource with ID {resource_id} not found",
)

View File

@@ -0,0 +1,61 @@
# Grey Haven Studio - Pydantic Schema Template
# Copy this template for new resource schemas
from pydantic import BaseModel, EmailStr, Field, ConfigDict, field_validator
from datetime import datetime
from typing import Optional
# TODO: Update model name
class ResourceBase(BaseModel):
"""Shared fields for Resource schemas."""
# TODO: Add your base fields here
name: str = Field(..., min_length=1, max_length=255)
description: Optional[str] = None
is_active: bool = True
class ResourceCreate(ResourceBase):
"""Schema for creating a new resource."""
# TODO: Add creation-specific fields
# Example: password, external_id, etc.
@field_validator("name")
@classmethod
def validate_name(cls, v: str) -> str:
"""Add custom validation if needed."""
if not v.strip():
raise ValueError("Name cannot be empty or whitespace")
return v.strip()
class ResourceUpdate(BaseModel):
"""Schema for updating an existing resource (all fields optional)."""
# TODO: Add updateable fields (all optional)
name: Optional[str] = Field(None, min_length=1, max_length=255)
description: Optional[str] = None
is_active: Optional[bool] = None
class ResourceRead(ResourceBase):
"""Schema for reading resource data (public fields only)."""
id: str
tenant_id: str
created_at: datetime
updated_at: datetime
model_config = ConfigDict(from_attributes=True)
class PaginatedResponse[T](BaseModel):
"""Generic paginated response."""
items: list[T]
total: int
skip: int
limit: int
has_more: bool

View File

@@ -0,0 +1,82 @@
# Grey Haven Studio - Rate Limiter Template
# Add this to app/core/rate_limit.py
from fastapi import Request, HTTPException, status
from upstash_redis import Redis
import os
# Doppler provides REDIS_URL
redis = Redis.from_url(os.getenv("REDIS_URL"))
class RateLimiter:
"""
Rate limiter using Upstash Redis.
Usage:
rate_limit_strict = RateLimiter(max_requests=10, window=60)
rate_limit_normal = RateLimiter(max_requests=100, window=60)
@router.post("", dependencies=[Depends(rate_limit_strict)])
async def create_resource():
pass
"""
def __init__(self, max_requests: int = 100, window: int = 60):
"""
Initialize rate limiter.
Args:
max_requests: Maximum requests allowed in window
window: Time window in seconds
"""
self.max_requests = max_requests
self.window = window
async def __call__(self, request: Request):
"""Check rate limit for current request."""
# Get client identifier (IP address or user ID from JWT)
client_id = self._get_client_id(request)
# Rate limit key
key = f"rate_limit:{client_id}:{request.url.path}"
# Increment counter
count = redis.incr(key)
# Set expiration on first request
if count == 1:
redis.expire(key, self.window)
# Check if limit exceeded
if count > self.max_requests:
retry_after = redis.ttl(key)
raise HTTPException(
status_code=status.HTTP_429_TOO_MANY_REQUESTS,
detail=f"Rate limit exceeded. Try again in {retry_after} seconds.",
headers={"Retry-After": str(retry_after)},
)
def _get_client_id(self, request: Request) -> str:
"""Get client identifier (IP or user ID)."""
# Prefer user ID from JWT if available
if hasattr(request.state, "user") and request.state.user:
return f"user:{request.state.user.id}"
# Fallback to IP address
return f"ip:{request.client.host}"
# Rate limit configurations
rate_limit_strict = RateLimiter(max_requests=10, window=60) # 10 req/min
rate_limit_normal = RateLimiter(max_requests=100, window=60) # 100 req/min
rate_limit_relaxed = RateLimiter(max_requests=1000, window=60) # 1000 req/min
# Apply to routes:
# from app.core.rate_limit import rate_limit_strict, rate_limit_normal
#
# @router.post("", dependencies=[Depends(rate_limit_strict)])
# async def create_user():
# """Create user (10 req/min limit)."""
# pass

View File

@@ -0,0 +1,101 @@
# Grey Haven Studio - Repository Pattern Template
# Copy this template for new resource repositories
from sqlmodel import Session, select, func
from typing import Optional
from uuid import UUID
from app.models.resource import Resource # TODO: Update import
from app.schemas.resource import ResourceCreate, ResourceUpdate # TODO: Update import
# TODO: Update class name
class ResourceRepository:
"""Repository with automatic tenant filtering for Resource model."""
def __init__(self, db: Session, tenant_id: str):
self.db = db
self.tenant_id = tenant_id
async def list(
self, filters: dict = None, skip: int = 0, limit: int = 100
) -> list[Resource]:
"""List resources (automatically filtered by tenant_id)."""
statement = select(Resource).where(Resource.tenant_id == self.tenant_id)
# Apply additional filters
if filters:
# TODO: Add your filter logic here
# Example:
# if "is_active" in filters:
# statement = statement.where(Resource.is_active == filters["is_active"])
pass
statement = statement.offset(skip).limit(limit).order_by(Resource.created_at.desc())
result = await self.db.execute(statement)
return result.scalars().all()
async def count(self, filters: dict = None) -> int:
"""Count resources (tenant-isolated)."""
statement = select(func.count(Resource.id)).where(
Resource.tenant_id == self.tenant_id
)
# Apply same filters as list()
if filters:
# TODO: Add same filter logic as list()
pass
result = await self.db.execute(statement)
return result.scalar_one()
async def get_by_id(self, resource_id: str) -> Resource | None:
"""Get resource by ID (tenant-isolated)."""
statement = select(Resource).where(
Resource.id == resource_id,
Resource.tenant_id == self.tenant_id,
)
result = await self.db.execute(statement)
return result.scalar_one_or_none()
async def create(self, resource_data: ResourceCreate) -> Resource:
"""Create a new resource in the current tenant."""
resource = Resource(
**resource_data.model_dump(),
tenant_id=self.tenant_id, # Automatic tenant assignment
)
self.db.add(resource)
await self.db.commit()
await self.db.refresh(resource)
return resource
async def update(
self, resource_id: str, resource_data: ResourceUpdate
) -> Resource | None:
"""Update an existing resource (tenant-isolated)."""
resource = await self.get_by_id(resource_id)
if not resource:
return None
# Update only provided fields
update_data = resource_data.model_dump(exclude_unset=True)
for field, value in update_data.items():
setattr(resource, field, value)
await self.db.commit()
await self.db.refresh(resource)
return resource
async def delete(self, resource_id: str) -> bool:
"""Soft-delete a resource (tenant-isolated)."""
resource = await self.get_by_id(resource_id)
if not resource:
return False
# Soft delete by setting deleted_at timestamp
from datetime import datetime
resource.deleted_at = datetime.utcnow()
await self.db.commit()
return True

View File

@@ -0,0 +1,186 @@
// Grey Haven Studio - TanStack Start Server Function Template
// Copy this template for new TanStack Start server functions
import { createServerFn } from "@tanstack/start";
import { z } from "zod";
import { db } from "~/utils/db.server";
import { resourcesTable } from "~/db/schema"; // TODO: Update import
import { getAuthUser } from "~/utils/auth.server";
import { eq, and, like, count, desc } from "drizzle-orm";
// TODO: Update validation schemas
const createResourceSchema = z.object({
name: z.string().min(1).max(255),
description: z.string().optional(),
});
const updateResourceSchema = z.object({
name: z.string().min(1).max(255).optional(),
description: z.string().optional(),
isActive: z.boolean().optional(),
});
const listResourcesSchema = z.object({
skip: z.number().min(0).default(0),
limit: z.number().min(1).max(100).default(100),
// TODO: Add filter fields
});
// List resources
export const listResources = createServerFn({ method: "GET" })
.validator(listResourcesSchema)
.handler(async ({ data, context }) => {
const authUser = await getAuthUser(context);
if (!authUser) {
throw new Error("Unauthorized", { status: 401 });
}
// Build query with tenant filter
let query = db
.select()
.from(resourcesTable)
.where(eq(resourcesTable.tenantId, authUser.tenantId));
// TODO: Apply additional filters
// Apply pagination
const resources = await query
.orderBy(desc(resourcesTable.createdAt))
.limit(data.limit)
.offset(data.skip);
// Get total count
const [{ count: total }] = await db
.select({ count: count() })
.from(resourcesTable)
.where(eq(resourcesTable.tenantId, authUser.tenantId));
return {
items: resources,
total,
skip: data.skip,
limit: data.limit,
hasMore: data.skip + data.limit < total,
};
});
// Get resource by ID
export const getResource = createServerFn({ method: "GET" })
.validator(z.object({ resourceId: z.string() }))
.handler(async ({ data, context }) => {
const authUser = await getAuthUser(context);
if (!authUser) {
throw new Error("Unauthorized", { status: 401 });
}
const [resource] = await db
.select()
.from(resourcesTable)
.where(
and(
eq(resourcesTable.id, data.resourceId),
eq(resourcesTable.tenantId, authUser.tenantId)
)
)
.limit(1);
if (!resource) {
throw new Error("Resource not found", { status: 404 });
}
return resource;
});
// Create resource
export const createResource = createServerFn({ method: "POST" })
.validator(createResourceSchema)
.handler(async ({ data, context }) => {
const authUser = await getAuthUser(context);
if (!authUser) {
throw new Error("Unauthorized", { status: 401 });
}
// TODO: Check for duplicates if needed
// Create resource (tenant_id from auth context)
const [resource] = await db
.insert(resourcesTable)
.values({
...data,
tenantId: authUser.tenantId,
})
.returning();
return resource;
});
// Update resource
export const updateResource = createServerFn({ method: "PUT" })
.validator(
z.object({
resourceId: z.string(),
data: updateResourceSchema,
})
)
.handler(async ({ data, context }) => {
const authUser = await getAuthUser(context);
if (!authUser) {
throw new Error("Unauthorized", { status: 401 });
}
// Verify resource exists and belongs to tenant
const [existing] = await db
.select()
.from(resourcesTable)
.where(
and(
eq(resourcesTable.id, data.resourceId),
eq(resourcesTable.tenantId, authUser.tenantId)
)
)
.limit(1);
if (!existing) {
throw new Error("Resource not found", { status: 404 });
}
// Update resource
const [resource] = await db
.update(resourcesTable)
.set({
...data.data,
updatedAt: new Date(),
})
.where(eq(resourcesTable.id, data.resourceId))
.returning();
return resource;
});
// Delete resource
export const deleteResource = createServerFn({ method: "DELETE" })
.validator(z.object({ resourceId: z.string() }))
.handler(async ({ data, context }) => {
const authUser = await getAuthUser(context);
if (!authUser) {
throw new Error("Unauthorized", { status: 401 });
}
// Soft delete by setting deletedAt
const result = await db
.update(resourcesTable)
.set({ deletedAt: new Date() })
.where(
and(
eq(resourcesTable.id, data.resourceId),
eq(resourcesTable.tenantId, authUser.tenantId)
)
)
.returning();
if (result.length === 0) {
throw new Error("Resource not found", { status: 404 });
}
return { success: true };
});

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,586 @@
# Technical Reference
Complete configuration files and detailed technical information for Grey Haven coding standards.
## TypeScript/React Configuration Files
### .prettierrc
Complete Prettier configuration from cvi-template:
```json
{
"tabWidth": 2,
"semi": true,
"printWidth": 90,
"singleQuote": false,
"endOfLine": "lf",
"trailingComma": "all",
"plugins": ["prettier-plugin-organize-imports", "prettier-plugin-tailwindcss"]
}
```
**Field Explanations:**
- `tabWidth: 2` - Use 2 spaces for indentation (NOT 4)
- `semi: true` - Always add semicolons at the end of statements
- `printWidth: 90` - Wrap lines at 90 characters (NOT 80 or 120)
- `singleQuote: false` - Use double quotes for strings
- `endOfLine: "lf"` - Use Unix-style line endings (\\n)
- `trailingComma: "all"` - Add trailing commas wherever possible
- `prettier-plugin-organize-imports` - Auto-organize imports by type
- `prettier-plugin-tailwindcss` - Auto-sort Tailwind CSS classes
### .eslintrc
Complete ESLint configuration from cvi-template:
```json
{
"root": true,
"env": { "browser": true, "es2020": true },
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react-hooks/recommended"
],
"parser": "@typescript-eslint/parser",
"plugins": ["react-refresh"],
"rules": {
"react-hooks/exhaustive-deps": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": "off",
"no-unused-vars": "off",
"react-refresh/only-export-components": "off"
}
}
```
**Rule Explanations:**
- `react-hooks/exhaustive-deps: "off"` - Don't enforce exhaustive deps in useEffect (manage manually)
- `@typescript-eslint/no-explicit-any: "off"` - Allow `any` type for flexibility
- `@typescript-eslint/no-unused-vars: "off"` - Don't error on unused variables (clean up manually)
- `no-unused-vars: "off"` - Same as above for non-TypeScript files
- `react-refresh/only-export-components: "off"` - Allow exporting non-components from module
**Philosophy:** Grey Haven takes a pragmatic approach over pedantic enforcement. The codebase values developer velocity and allows `any` types, unused variables, and manual dependency management when appropriate.
### tsconfig.json
Complete TypeScript configuration from cvi-template:
```json
{
"compilerOptions": {
"strict": true,
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Bundler",
"jsx": "react-jsx",
"esModuleInterop": true,
"isolatedModules": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"allowJs": true,
"forceConsistentCasingInFileNames": true,
"baseUrl": ".",
"paths": {
"~/*": ["./src/*"]
},
"noEmit": true,
"lib": ["ES2022", "DOM", "DOM.Iterable"]
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", ".wrangler", ".output"]
}
```
**Key Settings:**
- `strict: true` - Enable all strict type checking options
- `target: "ES2022"` - Compile to ES2022 JavaScript
- `module: "ESNext"` - Use ESNext module syntax
- `moduleResolution: "Bundler"` - Use bundler resolution for Vite/TanStack
- `jsx: "react-jsx"` - Use React 17+ JSX transform
- `paths: { "~/*": ["./src/*"] }` - Path alias for imports (e.g., `import { foo } from "~/lib/utils"`)
- `noEmit: true` - Don't emit compiled files (Vite handles this)
### package.json Scripts
Standard scripts from cvi-template:
```json
{
"scripts": {
"dev": "vinxi dev",
"build": "vinxi build",
"start": "vinxi start",
"lint": "eslint .",
"format": "prettier --write .",
"format:check": "prettier --check .",
"db:generate": "drizzle-kit generate",
"db:migrate": "drizzle-kit migrate",
"db:push": "drizzle-kit push",
"db:studio": "drizzle-kit studio",
"prepare": "husky"
}
}
```
## Python/FastAPI Configuration Files
### pyproject.toml (Ruff)
Complete Ruff configuration from cvi-backend-template:
```toml
[tool.ruff]
fix-only = true
show-fixes = true
indent-width = 4
line-length = 130 # NOT 80 or 88!
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # pyupgrade
]
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
line-ending = "lf"
[tool.ruff.lint.isort]
known-first-party = ["app"]
```
**Field Explanations:**
- `line-length = 130` - Wrap lines at 130 characters (CRITICAL: NOT 80 or 88!)
- `indent-width = 4` - Use 4 spaces for indentation
- `fix-only = true` - Auto-fix issues without showing unfixable errors
- `show-fixes = true` - Show what was fixed
- `select = [...]` - Enable specific linter rules:
- `E`, `W` - pycodestyle style enforcement
- `F` - pyflakes error detection
- `I` - isort import sorting
- `B` - flake8-bugbear bug detection
- `C4` - flake8-comprehensions list/dict comprehension improvements
- `UP` - pyupgrade automatic Python version upgrades
### pyproject.toml (MyPy)
Complete MyPy configuration from cvi-backend-template:
```toml
[tool.mypy]
python_version = "3.11"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
check_untyped_defs = true
ignore_missing_imports = false
strict_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
warn_unreachable = true
```
**Key Settings:**
- `disallow_untyped_defs: true` - **CRITICAL**: Require type hints on all function definitions
- `python_version = "3.11"` - Target Python 3.11+ (projects use 3.12+)
- `strict_optional: true` - Strict checking of Optional types
- `warn_return_any: true` - Warn when returning Any from typed functions
- `warn_unused_configs: true` - Warn about unused mypy config
**Philosophy:** Type hints are **required** in Grey Haven Python projects. Unlike TypeScript's relaxed rules, Python enforces strict typing.
### pyproject.toml (Pytest)
Complete pytest configuration from cvi-backend-template:
```toml
[tool.pytest.ini_options]
pythonpath = ["."]
asyncio_mode = "auto"
testpaths = ["tests"]
python_files = ["test_*.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
markers = [
"unit: Unit tests (fast, isolated, mocked)",
"integration: Integration tests (database, external services)",
"e2e: End-to-end tests (full system)",
"benchmark: Performance benchmark tests",
"slow: Tests that take > 1 second",
]
addopts = [
"-ra", # Show summary of all test outcomes
"--strict-markers", # Require markers to be registered
"--strict-config", # Raise on config warnings
"--tb=short", # Shorter traceback format
]
[tool.coverage.run]
source = ["app"]
omit = ["tests/*", "*/migrations/*"]
[tool.coverage.report]
precision = 2
show_missing = true
skip_covered = false
```
**Marker Explanations:**
- `@pytest.mark.unit` - Fast, isolated tests with mocked dependencies
- `@pytest.mark.integration` - Tests with database or external services
- `@pytest.mark.e2e` - Full system end-to-end tests
- `@pytest.mark.benchmark` - Performance measurement tests
- `@pytest.mark.slow` - Tests taking over 1 second
**Coverage:** Aim for >80% code coverage across the project.
## Project Structure Details
### TypeScript/React Structure (cvi-template)
```plaintext
cvi-template/
├── src/
│ ├── routes/ # TanStack Router file-based routing
│ │ ├── __root.tsx # Root layout
│ │ ├── index.tsx # Homepage (/)
│ │ ├── _authenticated/ # Protected routes (requires auth)
│ │ │ └── dashboard.tsx # /dashboard
│ │ └── settings/
│ │ ├── index.tsx # /settings
│ │ └── profile.tsx # /settings/profile
│ │
│ ├── lib/
│ │ ├── components/ # React components
│ │ │ ├── ui/ # Shadcn UI components (button, card, etc.)
│ │ │ ├── auth/ # Authentication components
│ │ │ └── layout/ # Layout components (header, sidebar)
│ │ │
│ │ ├── server/ # Server-side code
│ │ │ ├── schema/ # Drizzle database schemas (snake_case!)
│ │ │ ├── functions/ # TanStack Start server functions
│ │ │ ├── auth.ts # Better-auth configuration
│ │ │ └── db.ts # Database connection with RLS
│ │ │
│ │ ├── config/ # Configuration files
│ │ │ └── env.ts # Environment validation (@t3-oss/env-core)
│ │ │
│ │ ├── hooks/ # Custom React hooks (use-* naming)
│ │ ├── utils/ # Utility functions
│ │ └── types/ # TypeScript type definitions
│ │
│ ├── clients/ # API client code
│ ├── data/ # Zod schemas for data validation
│ ├── middleware/ # Route middleware and guards
│ ├── services/ # Business logic services
│ ├── workers/ # Cloudflare Workers code
│ ├── index.css # Global styles (Tailwind)
│ └── router.tsx # Router configuration
├── public/ # Static assets
├── tests/ # Test files
├── .prettierrc # Prettier config
├── .eslintrc # ESLint config
├── tsconfig.json # TypeScript config
├── drizzle.config.ts # Drizzle ORM config
├── vite.config.ts # Vite bundler config
├── wrangler.jsonc # Cloudflare Workers config
└── package.json # Dependencies and scripts
```
### Python/FastAPI Structure (cvi-backend-template)
```plaintext
cvi-backend-template/
├── app/
│ ├── config/ # Application configuration
│ │ └── settings.py # Pydantic settings with env vars
│ │
│ ├── db/ # Database layer
│ │ ├── models/ # SQLModel database models (snake_case!)
│ │ │ ├── account.py # Account model
│ │ │ ├── tenant.py # Tenant model (multi-tenant)
│ │ │ └── user.py # User model
│ │ │
│ │ ├── repositories/ # Repository pattern (data access)
│ │ │ ├── base.py # Base repository
│ │ │ ├── account_repository.py
│ │ │ ├── tenant_repository.py
│ │ │ └── user_repository.py
│ │ │
│ │ ├── db_types.py # Custom database types (UTCDateTime)
│ │ └── session.py # Database session management
│ │
│ ├── routers/ # FastAPI routers (endpoints)
│ │ ├── accounts.py # /accounts endpoints
│ │ ├── tenants.py # /tenants endpoints
│ │ └── users.py # /users endpoints
│ │
│ ├── services/ # Business logic layer
│ │ ├── auth_service.py # Authentication service
│ │ └── billing_service.py # Billing service
│ │
│ ├── schemas/ # Pydantic schemas (API contracts)
│ │ ├── accounts.py # Account request/response schemas
│ │ ├── tenants.py # Tenant request/response schemas
│ │ └── users.py # User request/response schemas
│ │
│ ├── utils/ # Utility functions
│ │ ├── logging.py # Logging configuration
│ │ └── security.py # Security utilities
│ │
│ ├── dependencies.py # FastAPI dependencies
│ └── main.py # FastAPI app entry point
├── tests/ # Test files
│ ├── unit/ # Unit tests (@pytest.mark.unit)
│ ├── integration/ # Integration tests (@pytest.mark.integration)
│ ├── e2e/ # E2E tests (@pytest.mark.e2e)
│ ├── conftest.py # Pytest fixtures
│ └── __init__.py
├── alembic/ # Database migrations (if using Alembic)
├── pyproject.toml # Python project config (Ruff, MyPy, pytest)
├── requirements.txt # Python dependencies
└── .env.example # Example environment variables
```
## Database Naming Standards
### Field Naming Rules
**ALWAYS use snake_case for database columns:**
```text
✅ CORRECT ❌ WRONG
created_at createdAt
tenant_id tenantId
email_address emailAddress
is_active isActive
first_name firstName
last_name lastName
phone_number phoneNumber
billing_tier billingTier
max_retries maxRetries
api_key_hash apiKeyHash
```
### Table Naming Rules
**Use lowercase plural names:**
```text
✅ CORRECT ❌ WRONG
users User, Users, user
accounts Account, ACCOUNTS
tenants Tenant, Tenants
organizations Organization
subscriptions Subscription
```
### Index Naming Rules
**Use descriptive index names:**
```text
Format: {table}_{column}_idx
✅ CORRECT ❌ WRONG
user_email_idx idx_1, email_index
user_tenant_id_idx tenant_idx
organization_slug_idx slug
```
### Foreign Key Naming Rules
**Reference the parent table:**
```text
Format: {parent_table}_{singular}_id
✅ CORRECT ❌ WRONG
tenant_id tenant
account_id acc_id, accountId
organization_id org_id, orgId
user_id userId, uid
```
## Multi-Tenant Architecture
### Tenant Isolation Levels
Grey Haven projects use **row-level** tenant isolation:
1. **Every table** includes a `tenant_id` or `account_id` field
2. **Every query** filters by tenant ID
3. **Row Level Security (RLS)** policies enforce tenant boundaries
4. **Repository pattern** centralizes tenant filtering
### RLS Policy Pattern
Standard RLS policy structure:
```typescript
// TypeScript/Drizzle RLS helper
export const inSameTenant = (tenantIdCol: AnyPgColumn, query: SQL): SQL =>
sql`${isSameTenant(tenantIdCol)} and (${query})`;
// Apply to table
pgPolicy("table_name_select", {
for: "select",
to: "public",
using: inSameTenant(table.tenantId, sql`true`),
});
```
```sql
-- SQL RLS Policy
CREATE POLICY tenant_isolation_policy ON users
USING (tenant_id = current_setting('app.tenant_id')::text);
```
### Repository Tenant Filtering
Every repository method filters by tenant:
```python
# Python repository pattern
async def get_by_id(self, id: UUID, tenant_id: UUID) -> Optional[Model]:
"""Get record by ID with tenant isolation."""
result = await self.session.execute(
select(self.model)
.where(self.model.id == id)
.where(self.model.tenant_id == tenant_id) # Tenant filter!
)
return result.scalar_one_or_none()
```
## Import Organization
### TypeScript Import Order
Auto-organized by `prettier-plugin-organize-imports`:
```typescript
// 1. External libraries
import { useState, useEffect } from "react";
import { useQuery } from "@tanstack/react-query";
// 2. Internal modules (path alias)
import { Button } from "~/lib/components/ui/button";
import { useAuth } from "~/lib/hooks/use-auth";
import { env } from "~/lib/config/env";
// 3. Relative imports
import { helpers } from "./helpers";
```
### Python Import Order
Auto-organized by Ruff `isort`:
```python
# 1. Standard library imports
import os
from datetime import datetime
from typing import Optional
# 2. Third-party imports
from fastapi import APIRouter, Depends, HTTPException
from sqlmodel import select
from pydantic import BaseModel
# 3. Local imports (app.*)
from app.db.models.user import User
from app.db.repositories.user_repository import UserRepository
from app.schemas.user import UserCreate, UserResponse
```
## Line Length Reasoning
### TypeScript: 90 Characters
**Why 90?**
- Comfortable reading width on modern displays
- Allows two editor panes side-by-side
- Balances readability with code density
- TailwindCSS classes can be long - 90 gives room
- Standard 80 is too restrictive for modern development
### Python: 130 Characters
**Why 130?**
- Type hints can be verbose: `Annotated[AccountRepository, Depends(get_account_repository)]`
- Pydantic field definitions: `Field(default=None, description="Long description here")`
- Allows descriptive variable names without constant wrapping
- FastAPI decorators are long: `@router.post("/endpoint", response_model=ResponseSchema)`
- PEP 8's 79 is outdated for modern development
## Pre-commit Hooks
Both templates use pre-commit hooks for code quality:
### TypeScript Pre-commit
```bash
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# Run linting
npm run lint
# Run formatting check
npm run format:check
# Run type checking
npx tsc --noEmit
```
### Python Pre-commit
```bash
#!/usr/bin/env sh
# Activate virtual environment
source .venv/bin/activate
# Run Ruff formatter
ruff format .
# Run Ruff linter
ruff check --fix .
# Run MyPy type checking
mypy app/
# Run tests
pytest -m "not slow"
```
## Additional Resources
- **Frontend Template**: [cvi-template](https://github.com/greyhaven-ai/cvi-template) - TanStack Start + React 19 + Drizzle
- **Backend Template**: [cvi-backend-template](https://github.com/greyhaven-ai/cvi-backend-template) - FastAPI + SQLModel + PostgreSQL
- **Prettier Docs**: https://prettier.io/docs/en/configuration.html
- **ESLint Docs**: https://eslint.org/docs/latest/use/configure/
- **Ruff Docs**: https://docs.astral.sh/ruff/
- **Drizzle ORM**: https://orm.drizzle.team/docs/overview
- **TanStack Start**: https://tanstack.com/router/latest/docs/framework/react/start/overview

199
skills/code-style/SKILL.md Normal file
View File

@@ -0,0 +1,199 @@
---
name: grey-haven-code-style
description: "Apply Grey Haven Studio's TypeScript/React and Python/FastAPI coding standards from production templates. Use when writing code, reviewing PRs, fixing linting errors, formatting files, or when the user mentions 'code standards', 'Grey Haven style', 'linting', 'Prettier', 'ESLint', 'Ruff', 'formatting rules', or 'coding conventions'. Includes exact Prettier/ESLint/Ruff configs, naming conventions, project structure, and multi-tenant database patterns."
---
# Grey Haven Code Style Standards
**Actual coding standards from Grey Haven Studio production templates.**
Follow these exactly when working on Grey Haven codebases. This skill provides navigation to detailed examples, reference configs, and templates.
## Supporting Documentation
- **[EXAMPLES.md](EXAMPLES.md)** - Copy-paste code examples for TypeScript and Python
- **[REFERENCE.md](REFERENCE.md)** - Complete config files and detailed rule explanations
- **[templates/](templates/)** - Ready-to-use starter files
- **[checklists/](checklists/)** - Code review checklists
## Quick Reference
### TypeScript/React (Frontend)
Based on `cvi-template` - TanStack Start + React 19
**Key Settings:**
- **Line width:** 90 characters
- **Tab width:** 2 spaces
- **Quotes:** Double quotes
- **Semicolons:** Required
- **Trailing commas:** Always
- **ESLint:** Pragmatic (allows `any`, unused vars)
- **Path alias:** `~/` maps to `./src/*`
**Naming Conventions:**
- Variables/Functions: `camelCase` (`getUserData`, `isAuthenticated`)
- Components: `PascalCase` (`UserProfile`, `AuthProvider`)
- Constants: `UPPER_SNAKE_CASE` (`API_BASE_URL`, `MAX_RETRIES`)
- Types/Interfaces: `PascalCase` (`User`, `AuthConfig`)
- **Database fields:** `snake_case` (`user_id`, `created_at`, `tenant_id`) ⚠️ CRITICAL
**Project Structure:**
```plaintext
src/
├── routes/ # File-based routing (TanStack Router)
├── lib/
│ ├── components/ # UI components (grouped by feature)
│ ├── server/ # Server functions and DB schema
│ ├── config/ # Environment validation
│ ├── hooks/ # Custom React hooks (use-* naming)
│ ├── utils/ # Utility functions
│ └── types/ # TypeScript definitions
└── public/ # Static assets
```
### Python/FastAPI (Backend)
Based on `cvi-backend-template` - FastAPI + SQLModel
**Key Settings:**
- **Line length:** 130 characters
- **Indent:** 4 spaces
- **Type hints:** Required on all functions
- **Auto-fix:** Ruff fixes issues automatically
**Naming Conventions:**
- Functions/Variables: `snake_case` (`get_user_data`, `is_authenticated`)
- Classes: `PascalCase` (`UserRepository`, `AuthService`)
- Constants: `UPPER_SNAKE_CASE` (`API_BASE_URL`, `MAX_RETRIES`)
- **Database fields:** `snake_case` (`user_id`, `created_at`, `tenant_id`) ⚠️ CRITICAL
- Boolean fields: Prefix with `is_` or `has_` (`is_active`, `has_access`)
**Project Structure:**
```plaintext
app/
├── config/ # Application settings
├── db/
│ ├── models/ # SQLModel entities
│ └── repositories/ # Repository pattern (tenant isolation)
├── routers/ # FastAPI endpoints
├── services/ # Business logic
├── schemas/ # Pydantic models (API contracts)
└── utils/ # Utilities
```
## Database Field Convention (CRITICAL)
**ALWAYS use `snake_case` for database column names** - this is non-negotiable in Grey Haven projects.
**Correct:**
```typescript
// TypeScript - Drizzle schema
export const users = pgTable("users", {
id: uuid("id").primaryKey(),
created_at: timestamp("created_at").defaultNow(),
tenant_id: uuid("tenant_id").notNull(),
email_address: text("email_address").notNull(),
is_active: boolean("is_active").default(true),
});
```
```python
# Python - SQLModel
class User(SQLModel, table=True):
id: UUID = Field(default_factory=uuid4, primary_key=True)
created_at: datetime = Field(default_factory=datetime.utcnow)
tenant_id: UUID = Field(foreign_key="tenants.id", index=True)
email_address: str = Field(unique=True, index=True)
is_active: bool = Field(default=True)
```
**Wrong:**
```typescript
// DON'T use camelCase in database schemas
export const users = pgTable("users", {
id: uuid("id"),
createdAt: timestamp("createdAt"), // WRONG!
tenantId: uuid("tenantId"), // WRONG!
emailAddress: text("emailAddress"), // WRONG!
});
```
**See [EXAMPLES.md](EXAMPLES.md#database-schemas) for complete examples.**
## Multi-Tenant Architecture
**Every database table must include tenant isolation:**
- **Field name:** `tenant_id` (snake_case in DB) or `tenantId` (camelCase in TypeScript code)
- **Type:** UUID foreign key to tenants table
- **Index:** Always indexed for query performance
- **RLS:** Use Row Level Security policies for tenant isolation
- **Repository pattern:** All queries filter by `tenant_id`
**See [EXAMPLES.md](EXAMPLES.md#multi-tenant-patterns) for implementation patterns.**
## Virtual Environment (Python Projects)
**⚠️ ALWAYS activate virtual environment before running Python commands:**
```bash
source .venv/bin/activate
```
Required for:
- Running tests (`pytest`)
- Running pre-commit hooks
- Using task commands (`task test`, `task format`)
- Any Python script execution
## When to Apply This Skill
Use this skill when:
- ✅ Writing new TypeScript/React or Python/FastAPI code
- ✅ Reviewing code in pull requests
- ✅ Fixing linting or formatting errors
- ✅ Setting up new projects from templates
- ✅ Configuring Prettier, ESLint, or Ruff
- ✅ Creating database schemas
- ✅ Implementing multi-tenant features
- ✅ User mentions: "code standards", "linting rules", "Grey Haven style", "formatting"
## Template References
These standards come from actual Grey Haven production templates:
- **Frontend:** `cvi-template` (TanStack Start + React 19 + Drizzle)
- **Backend:** `cvi-backend-template` (FastAPI + SQLModel + PostgreSQL)
When in doubt, reference these templates for patterns and configurations.
## Critical Reminders
1. **Line lengths:** TypeScript=90, Python=130 (NOT 80/88)
2. **Database fields:** ALWAYS `snake_case` (both TypeScript and Python schemas)
3. **`any` type:** ALLOWED in Grey Haven TypeScript (pragmatic approach)
4. **Double quotes:** TypeScript uses double quotes (`singleQuote: false`)
5. **Type hints:** REQUIRED in Python (`disallow_untyped_defs: true`)
6. **Virtual env:** MUST activate before Python commands
7. **Multi-tenant:** Every table has `tenant_id`/`tenantId`
8. **Path aliases:** Use `~/` for TypeScript imports from `src/`
9. **Trailing commas:** ALWAYS in TypeScript (`trailingComma: "all"`)
10. **Pre-commit hooks:** Run before every commit (both projects)
## Next Steps
- **Need examples?** See [EXAMPLES.md](EXAMPLES.md) for copy-paste code
- **Need configs?** See [REFERENCE.md](REFERENCE.md) for complete config files
- **Need templates?** See [templates/](templates/) for starter files
- **Reviewing code?** Use [checklists/](checklists/) for systematic reviews

View File

@@ -0,0 +1,141 @@
# Python/FastAPI Code Review Checklist
Use this checklist when reviewing Python/FastAPI code or creating pull requests for Grey Haven projects.
## Formatting & Style
- [ ] **Line length**: Code lines do not exceed 130 characters (CRITICAL!)
- [ ] **Indentation**: Uses 4 spaces (not tabs or 2 spaces)
- [ ] **Quotes**: Uses double quotes for strings (Ruff default)
- [ ] **Line endings**: Uses Unix-style line endings (\\n)
- [ ] **Ruff formatted**: Code is formatted with Ruff (`ruff format .`)
- [ ] **Ruff linting**: No Ruff linting errors (`ruff check .`)
## Type Hints
- [ ] **Function signatures**: ALL functions have type hints (CRITICAL!)
- Parameters: `def get_user(user_id: str) -> Optional[User]:`
- Return types: Always include return type annotation
- [ ] **MyPy passing**: `mypy app/` has no type errors
- [ ] **Optional types**: Uses `Optional[T]` or `T | None` for nullable values
- [ ] **Generic types**: Uses proper generic types (`list[str]`, `dict[str, Any]`)
- [ ] **Type imports**: Imports types from `typing` module
## Database Models (SQLModel)
- [ ] **snake_case fields**: ALL database column names use snake_case (CRITICAL!)
-`created_at`, `tenant_id`, `email_address`, `is_active`
-`createdAt`, `tenantId`, `emailAddress`, `isActive`
- [ ] **Multi-tenant**: Models include `tenant_id` field
- [ ] **Field descriptions**: All fields have `description` parameter
- [ ] **Indexes**: Frequently queried fields have `index=True`
- [ ] **Constraints**: Foreign keys, unique constraints properly defined
- [ ] **Timestamps**: Uses UTC datetime (`UTCDateTime` type if available)
- [ ] **Table names**: Uses `__tablename__` with lowercase plural names
## Pydantic Schemas
- [ ] **Schema hierarchy**: Follows Base/Create/Update/Response pattern
- [ ] **Validators**: Uses `@field_validator` for custom validation
- [ ] **ConfigDict**: Response schemas have `model_config = ConfigDict(from_attributes=True)`
- [ ] **Field constraints**: Uses appropriate constraints (`ge`, `le`, `max_length`, etc.)
- [ ] **Optional fields**: Update schemas use `| None` for optional fields
- [ ] **Descriptions**: All fields have descriptions in `Field(..., description="...")`
## FastAPI Endpoints
- [ ] **Type hints**: ALL endpoint functions fully typed with `Annotated`
- [ ] **Docstrings**: Endpoints have comprehensive docstrings (Args, Returns, Raises)
- [ ] **Status codes**: Uses appropriate HTTP status codes from `status` module
- [ ] **Response models**: Endpoints specify `response_model`
- [ ] **Dependencies**: Uses Depends() for repository and auth dependencies
- [ ] **Error handling**: Raises HTTPException with proper status codes and messages
- [ ] **Router prefix**: Router has appropriate prefix and tags
## Repository Pattern
- [ ] **Tenant isolation**: ALL queries filter by `tenant_id` (CRITICAL!)
- [ ] **Type hints**: Repository methods fully typed
- [ ] **Async/await**: Uses async/await for database operations
- [ ] **Session management**: Properly commits and refreshes after changes
- [ ] **Error handling**: Handles database errors appropriately
- [ ] **CRUD methods**: Implements standard create, read, update, delete methods
## Multi-Tenant Architecture
- [ ] **Tenant filtering**: All queries include tenant_id filter
- [ ] **Repository methods**: Accept `tenant_id` parameter
- [ ] **Validation**: Validates user has access to requested tenant
- [ ] **Isolation**: No cross-tenant data leakage possible
- [ ] **Foreign keys**: Multi-tenant relationships properly enforced
## Imports Organization
- [ ] **Import order**: Follows Ruff isort rules:
1. Standard library imports
2. Third-party imports
3. Local imports (app.*)
- [ ] **Absolute imports**: Uses absolute imports (not relative)
- [ ] **Grouped imports**: Related imports grouped together
- [ ] **No unused imports**: All imports are used
## Testing (Pytest)
- [ ] **Tests exist**: Endpoints/functions have corresponding tests
- [ ] **Test markers**: Uses pytest markers (@pytest.mark.unit, @pytest.mark.integration)
- [ ] **Fixtures**: Uses pytest fixtures for setup
- [ ] **Async tests**: Async tests decorated with `@pytest.mark.asyncio`
- [ ] **Mocking**: Uses AsyncMock/MagicMock for external dependencies
- [ ] **Coverage**: Maintains or improves test coverage (aim for >80%)
- [ ] **Assertions**: Tests have clear, specific assertions
## Security
- [ ] **Input validation**: Uses Pydantic schemas for input validation
- [ ] **SQL injection**: Uses parameterized queries (SQLModel handles this)
- [ ] **Authentication**: Endpoints require authentication via dependencies
- [ ] **Authorization**: Validates user has permission for actions
- [ ] **Secrets**: Uses environment variables for secrets (never hardcode)
- [ ] **Rate limiting**: Critical endpoints have rate limiting
## Error Handling
- [ ] **HTTPException**: Raises HTTPException with proper status codes
- [ ] **Error messages**: Error messages are descriptive and user-friendly
- [ ] **Logging**: Errors are logged appropriately
- [ ] **Validation errors**: Pydantic validation errors return 422
- [ ] **Not found**: Returns 404 for missing resources
## Performance
- [ ] **Database queries**: Queries are efficient (no N+1 problems)
- [ ] **Indexes**: Frequently filtered columns have indexes
- [ ] **Pagination**: List endpoints implement pagination (limit/offset)
- [ ] **Async operations**: Uses async/await for I/O operations
- [ ] **Connection pooling**: Database uses connection pooling
## Documentation
- [ ] **Docstrings**: All functions have comprehensive docstrings
- [ ] **OpenAPI docs**: FastAPI auto-docs are accurate and complete
- [ ] **Type annotations**: Type hints serve as documentation
- [ ] **README updated**: README reflects any new features/changes
- [ ] **API examples**: Complex endpoints have usage examples
## Pre-commit Checks
- [ ] **Virtual env active**: Ran commands with `source .venv/bin/activate`
- [ ] **Ruff formatting**: `ruff format .` applied
- [ ] **Ruff linting**: `ruff check --fix .` passing
- [ ] **MyPy**: `mypy app/` passing with no type errors
- [ ] **Tests passing**: `pytest` passes all tests
- [ ] **Coverage**: Test coverage meets threshold (>80%)
- [ ] **Pre-commit hooks**: All pre-commit hooks pass
## API Design
- [ ] **RESTful**: Endpoints follow REST principles
- [ ] **Naming**: Endpoints use clear, descriptive names
- [ ] **Versioning**: API versioned appropriately (`/v1/`)
- [ ] **Consistency**: Similar endpoints have consistent patterns
- [ ] **CRUD complete**: Resource has full CRUD operations if needed

View File

@@ -0,0 +1,113 @@
# TypeScript/React Code Review Checklist
Use this checklist when reviewing TypeScript/React code or creating pull requests for Grey Haven projects.
## Formatting & Style
- [ ] **Line width**: Code lines do not exceed 90 characters
- [ ] **Indentation**: Uses 2 spaces (not tabs or 4 spaces)
- [ ] **Semicolons**: All statements end with semicolons
- [ ] **Quotes**: Uses double quotes for strings (not single quotes)
- [ ] **Trailing commas**: Has trailing commas in objects, arrays, function parameters
- [ ] **Prettier formatted**: Code is formatted with Prettier (`npm run format`)
- [ ] **ESLint passing**: No ESLint errors (`npm run lint`)
## TypeScript
- [ ] **Type safety**: No `any` types used unnecessarily (but allowed when appropriate)
- [ ] **Type annotations**: Complex types have proper interfaces/types defined
- [ ] **Imports organized**: Imports are auto-sorted (external → internal → relative)
- [ ] **Path aliases**: Uses `~/` path alias for src imports (not `../..`)
- [ ] **tsconfig compliance**: Follows strict TypeScript configuration
## Database Schema (Drizzle)
- [ ] **snake_case fields**: ALL database column names use snake_case (CRITICAL!)
-`created_at`, `tenant_id`, `email_address`
-`createdAt`, `tenantId`, `emailAddress`
- [ ] **Multi-tenant**: Tables include `tenant_id` or `tenantId` field
- [ ] **Indexes**: Frequently queried fields have indexes
- [ ] **RLS policies**: Row Level Security policies defined for multi-tenant isolation
- [ ] **Foreign keys**: Relationships use proper foreign key constraints
## React Components
- [ ] **Component structure**: Follows Grey Haven component pattern:
1. Imports (auto-sorted)
2. Types/Interfaces
3. Component definition
4. State management (hooks first)
5. Queries/Mutations
6. Effects
7. Event handlers
8. Conditional renders
9. Main render
- [ ] **Naming**: Components use PascalCase (`UserProfile.tsx`)
- [ ] **Props typed**: Component props have TypeScript interfaces
- [ ] **Hooks named**: Custom hooks start with `use-` prefix
- [ ] **Default export**: Route components export default
## TanStack Query
- [ ] **Query keys**: Uses descriptive, unique query keys
- [ ] **staleTime**: Sets appropriate staleTime (default: 60000ms / 1 minute)
- [ ] **Error handling**: Handles loading and error states
- [ ] **Mutations**: Uses useMutation for data updates
- [ ] **Invalidation**: Invalidates queries after mutations
## Environment Variables
- [ ] **Validation**: Environment variables validated with @t3-oss/env-core and Zod
- [ ] **VITE_ prefix**: Client variables prefixed with `VITE_`
- [ ] **Types**: All env variables have proper Zod schemas
- [ ] **Documentation**: Env variables have JSDoc comments
## Multi-Tenant Architecture
- [ ] **Tenant isolation**: All queries filter by `tenant_id` / `tenantId`
- [ ] **RLS enabled**: Row Level Security policies enforce tenant boundaries
- [ ] **Context usage**: Uses tenant context from auth provider
- [ ] **API calls**: Includes tenant ID in API requests
## Testing
- [ ] **Tests exist**: Components/functions have corresponding tests
- [ ] **Coverage**: Maintains or improves test coverage (aim for >80%)
- [ ] **Test structure**: Tests follow Arrange-Act-Assert pattern
- [ ] **Mocking**: External dependencies are properly mocked
## Security
- [ ] **Input validation**: User inputs are validated (Zod schemas)
- [ ] **XSS prevention**: No dangerouslySetInnerHTML without sanitization
- [ ] **API security**: API endpoints require authentication
- [ ] **Secrets**: No secrets or API keys in code (use env variables)
## Accessibility
- [ ] **Semantic HTML**: Uses appropriate HTML elements
- [ ] **ARIA labels**: Interactive elements have accessible labels
- [ ] **Keyboard nav**: Interactive elements are keyboard accessible
- [ ] **Color contrast**: Text has sufficient color contrast
## Performance
- [ ] **Code splitting**: Large components use lazy loading if appropriate
- [ ] **Memoization**: Expensive calculations use useMemo/useCallback
- [ ] **Query optimization**: Database queries are efficient (no N+1)
- [ ] **Bundle size**: No unnecessary dependencies added
## Documentation
- [ ] **JSDoc comments**: Complex functions have JSDoc comments
- [ ] **README updated**: README reflects any new features/changes
- [ ] **Type exports**: Exported types are documented
- [ ] **Examples**: Complex patterns have usage examples
## Pre-commit Checks
- [ ] **Build passes**: `npm run build` completes without errors
- [ ] **Linting passes**: `npm run lint` has no errors
- [ ] **Type checking**: `npx tsc --noEmit` has no errors
- [ ] **Tests passing**: `npm test` passes all tests
- [ ] **Pre-commit hooks**: Husky pre-commit hooks all pass

View File

@@ -0,0 +1,18 @@
{
"root": true,
"env": { "browser": true, "es2020": true },
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react-hooks/recommended"
],
"parser": "@typescript-eslint/parser",
"plugins": ["react-refresh"],
"rules": {
"react-hooks/exhaustive-deps": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": "off",
"no-unused-vars": "off",
"react-refresh/only-export-components": "off"
}
}

View File

@@ -0,0 +1,9 @@
{
"tabWidth": 2,
"semi": true,
"printWidth": 90,
"singleQuote": false,
"endOfLine": "lf",
"trailingComma": "all",
"plugins": ["prettier-plugin-organize-imports", "prettier-plugin-tailwindcss"]
}

View File

@@ -0,0 +1,186 @@
"""Example FastAPI Router Template.
Copy and adapt this for new Grey Haven API endpoints.
"""
from datetime import datetime
from typing import Annotated
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, Query, status
from pydantic import BaseModel, Field
# Replace with your actual imports
from app.db.models.example import ExampleDB
from app.db.repositories.example_repository import ExampleRepository
from app.dependencies import get_current_user, get_example_repository
from app.schemas.example import ExampleCreate, ExampleResponse, ExampleUpdate
# 1. Create router with tags and dependencies
router = APIRouter(
prefix="/examples",
tags=["examples"],
dependencies=[Depends(get_current_user)], # Require authentication
)
# 2. POST endpoint - Create resource
@router.post("/", response_model=ExampleResponse, status_code=status.HTTP_201_CREATED)
async def create_example(
data: ExampleCreate,
repo: Annotated[ExampleRepository, Depends(get_example_repository)],
current_user: Annotated[dict, Depends(get_current_user)],
) -> ExampleResponse:
"""
Create a new example resource.
Args:
data: Example creation data
repo: Example repository dependency
current_user: Currently authenticated user
Returns:
ExampleResponse: Created example
Raises:
HTTPException: If creation fails
"""
# Create resource with tenant isolation
example = await repo.create(data, tenant_id=current_user["tenant_id"])
return ExampleResponse.model_validate(example)
# 3. GET endpoint - Retrieve single resource
@router.get("/{example_id}", response_model=ExampleResponse)
async def get_example(
example_id: UUID,
repo: Annotated[ExampleRepository, Depends(get_example_repository)],
current_user: Annotated[dict, Depends(get_current_user)],
) -> ExampleResponse:
"""
Get example by ID with tenant isolation.
Args:
example_id: Example UUID
repo: Example repository dependency
current_user: Currently authenticated user
Returns:
ExampleResponse: Example data
Raises:
HTTPException: If not found
"""
# Get with tenant isolation
example = await repo.get_by_id(example_id, tenant_id=current_user["tenant_id"])
if not example:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Example not found"
)
return ExampleResponse.model_validate(example)
# 4. GET endpoint - List resources with pagination
@router.get("/", response_model=list[ExampleResponse])
async def list_examples(
repo: Annotated[ExampleRepository, Depends(get_example_repository)],
current_user: Annotated[dict, Depends(get_current_user)],
limit: int = Query(100, ge=1, le=1000, description="Max items to return"),
offset: int = Query(0, ge=0, description="Number of items to skip"),
is_active: bool | None = Query(None, description="Filter by active status"),
) -> list[ExampleResponse]:
"""
List examples with pagination and filtering.
Args:
repo: Example repository dependency
current_user: Currently authenticated user
limit: Maximum number of items to return
offset: Number of items to skip
is_active: Optional filter by active status
Returns:
list[ExampleResponse]: List of examples
"""
# List with tenant isolation
examples = await repo.list_by_tenant(
tenant_id=current_user["tenant_id"],
limit=limit,
offset=offset,
is_active=is_active,
)
return [ExampleResponse.model_validate(e) for e in examples]
# 5. PATCH endpoint - Update resource
@router.patch("/{example_id}", response_model=ExampleResponse)
async def update_example(
example_id: UUID,
data: ExampleUpdate,
repo: Annotated[ExampleRepository, Depends(get_example_repository)],
current_user: Annotated[dict, Depends(get_current_user)],
) -> ExampleResponse:
"""
Update example by ID with tenant isolation.
Args:
example_id: Example UUID
data: Update data (partial fields)
repo: Example repository dependency
current_user: Currently authenticated user
Returns:
ExampleResponse: Updated example
Raises:
HTTPException: If not found
"""
# Get existing example with tenant isolation
example = await repo.get_by_id(example_id, tenant_id=current_user["tenant_id"])
if not example:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Example not found"
)
# Update fields (exclude_unset to only update provided fields)
update_dict = data.model_dump(exclude_unset=True)
for field, value in update_dict.items():
setattr(example, field, value)
# Save updates
updated = await repo.update(example)
return ExampleResponse.model_validate(updated)
# 6. DELETE endpoint - Delete resource
@router.delete("/{example_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_example(
example_id: UUID,
repo: Annotated[ExampleRepository, Depends(get_example_repository)],
current_user: Annotated[dict, Depends(get_current_user)],
) -> None:
"""
Delete example by ID with tenant isolation.
Args:
example_id: Example UUID
repo: Example repository dependency
current_user: Currently authenticated user
Raises:
HTTPException: If not found
"""
# Get existing example with tenant isolation
example = await repo.get_by_id(example_id, tenant_id=current_user["tenant_id"])
if not example:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Example not found"
)
# Delete
await repo.delete(example_id, tenant_id=current_user["tenant_id"])

View File

@@ -0,0 +1,126 @@
"""Example SQLModel Database Model Template.
Copy and adapt this for new Grey Haven database models.
"""
from __future__ import annotations
from datetime import datetime
from uuid import UUID, uuid4
from sqlalchemy import Column as SAColumn
from sqlmodel import JSON, Column, Field, SQLModel
def utc_now() -> datetime:
"""Return current UTC datetime."""
from datetime import UTC
return datetime.now(UTC)
class ExampleDB(SQLModel, table=True): # type: ignore[call-arg]
"""
Example database model with multi-tenant support.
This model demonstrates Grey Haven's database conventions:
- snake_case field names
- Multi-tenant isolation with tenant_id
- UTC timestamps
- Proper indexes
- Comprehensive docstrings
"""
__tablename__ = "examples"
# Primary identification
id: UUID = Field(
default_factory=uuid4, primary_key=True, description="Unique example identifier"
)
# Multi-tenant field (CRITICAL - always include!)
tenant_id: UUID = Field(
foreign_key="tenants.id", index=True, description="Owning tenant identifier"
)
# Example fields - all snake_case!
name: str = Field(index=True, max_length=255, description="Example name")
description: str | None = Field(
default=None, max_length=1000, description="Optional description"
)
# Relationships (foreign keys)
owner_id: UUID | None = Field(
default=None, foreign_key="users.id", index=True, description="Owner user ID"
)
# Status flags
is_active: bool = Field(default=True, description="Whether example is active")
is_archived: bool = Field(default=False, description="Whether example is archived")
# JSON metadata field
metadata: dict | None = Field(
default=None,
sa_column=Column(JSON),
description="Flexible JSON metadata storage",
)
# Numerical fields
priority: int = Field(
default=0, ge=0, le=10, description="Priority level (0-10)"
)
max_retries: int = Field(
default=3, ge=0, description="Maximum number of retry attempts"
)
# Timestamps (UTC)
created_at: datetime = Field(
default_factory=utc_now, description="Creation timestamp (UTC)"
)
updated_at: datetime = Field(
default_factory=utc_now, description="Last update timestamp (UTC)"
)
archived_at: datetime | None = Field(
default=None, description="Archive timestamp (UTC)"
)
# Uncomment if using custom UTCDateTime type
# from app.db.db_types import UTCDateTime
# created_at: datetime = Field(
# default_factory=utc_now,
# sa_column=SAColumn(UTCDateTime, nullable=False)
# )
# updated_at: datetime = Field(
# default_factory=utc_now,
# sa_column=SAColumn(UTCDateTime, nullable=False, onupdate=utc_now)
# )
# Pydantic schemas for API (in separate schemas file)
# class ExampleBase(BaseModel):
# """Base example schema with shared fields."""
# name: str = Field(..., max_length=255)
# description: str | None = None
# is_active: bool = True
# priority: int = Field(default=0, ge=0, le=10)
#
# class ExampleCreate(ExampleBase):
# """Schema for creating an example."""
# tenant_id: UUID
#
# class ExampleUpdate(BaseModel):
# """Schema for updating an example (all fields optional)."""
# name: str | None = None
# description: str | None = None
# is_active: bool | None = None
# priority: int | None = Field(None, ge=0, le=10)
#
# class ExampleResponse(ExampleBase):
# """Example response schema."""
# id: UUID
# tenant_id: UUID
# owner_id: UUID | None
# created_at: datetime
# updated_at: datetime
#
# model_config = ConfigDict(from_attributes=True)

View File

@@ -0,0 +1,73 @@
# Grey Haven Studio - Ruff Configuration Template
# Copy this to your project root as pyproject.toml or ruff.toml
[tool.ruff]
# CRITICAL: Line length is 130, not 80 or 88!
line-length = 130
indent-width = 4
# Auto-fix issues without showing unfixable errors
fix-only = true
show-fixes = true
# Python version
target-version = "py312"
[tool.ruff.lint]
# Enable specific linter rules
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort (import sorting)
"B", # flake8-bugbear (bug detection)
"C4", # flake8-comprehensions
"UP", # pyupgrade (automatic upgrades)
]
# Ignore specific rules if needed
ignore = []
[tool.ruff.format]
# Use double quotes for strings
quote-style = "double"
# Use spaces for indentation
indent-style = "space"
# Use Unix-style line endings
line-ending = "lf"
[tool.ruff.lint.isort]
# Configure import sorting
known-first-party = ["app"]
section-order = [
"future",
"standard-library",
"third-party",
"first-party",
"local-folder",
]
# MyPy Configuration (add to pyproject.toml)
# [tool.mypy]
# python_version = "3.12"
# warn_return_any = true
# warn_unused_configs = true
# disallow_untyped_defs = true # REQUIRED: Type hints on all functions!
# check_untyped_defs = true
# ignore_missing_imports = false
# strict_optional = true
# warn_redundant_casts = true
# warn_unused_ignores = true
# Pytest Configuration (add to pyproject.toml)
# [tool.pytest.ini_options]
# pythonpath = ["."]
# asyncio_mode = "auto"
# testpaths = ["tests"]
# markers = [
# "unit: Unit tests",
# "integration: Integration tests",
# "e2e: End-to-end tests",
# ]

View File

@@ -0,0 +1,85 @@
// Example React Component Template
// Copy and adapt this for new Grey Haven components
import { useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { Button } from "~/lib/components/ui/button";
import { Card } from "~/lib/components/ui/card";
import { queryClient } from "~/lib/query-client";
// 1. Define your types/interfaces
interface MyComponentProps {
id: string;
onUpdate?: (data: MyData) => void;
}
interface MyData {
id: string;
name: string;
created_at: Date; // snake_case for database fields
is_active: boolean;
}
// 2. Component (default export for routes)
export default function MyComponent({ id, onUpdate }: MyComponentProps) {
// 3. State management
const [isEditing, setIsEditing] = useState(false);
// 4. Queries with TanStack Query
const { data, isLoading, error } = useQuery(
{
queryKey: ["myData", id],
queryFn: async () => {
// Replace with your API call
const response = await fetch(`/api/data/${id}`);
return response.json();
},
staleTime: 60000, // 1 minute - Grey Haven default
},
queryClient,
);
// 5. Event handlers
const handleSave = async () => {
// Replace with your save logic
console.log("Saving...");
setIsEditing(false);
onUpdate?.(data);
};
// 6. Conditional renders
if (isLoading) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error loading data</div>;
}
if (!data) {
return <div>No data found</div>;
}
// 7. Main render
return (
<Card className="p-6">
<h2 className="mb-4 text-2xl font-bold">{data.name}</h2>
{isEditing ? (
<div className="space-y-4">
{/* Edit mode UI */}
<Button onClick={handleSave}>Save</Button>
<Button variant="outline" onClick={() => setIsEditing(false)}>
Cancel
</Button>
</div>
) : (
<div className="space-y-2">
{/* View mode UI */}
<p>Status: {data.is_active ? "Active" : "Inactive"}</p>
<Button onClick={() => setIsEditing(true)}>Edit</Button>
</div>
)}
</Card>
);
}

View File

@@ -0,0 +1,92 @@
// Example TanStack Start Server Function Template
// Copy and adapt this for new Grey Haven server functions
import { createServerFn } from "@tanstack/start";
import { db } from "~/lib/server/db";
import { users } from "~/lib/server/schema/users";
import { eq } from "drizzle-orm";
import { z } from "zod";
// 1. Define input schema with Zod
const getUserInputSchema = z.object({
userId: z.string().uuid(),
tenantId: z.string(), // Always include tenant_id for multi-tenant isolation
});
// 2. Define output type
interface UserOutput {
id: string;
name: string;
email: string;
created_at: Date;
tenant_id: string;
}
// 3. Create server function
export const getUser = createServerFn("GET", async (input: unknown): Promise<UserOutput> => {
// Validate input
const { userId, tenantId } = getUserInputSchema.parse(input);
// Query database with tenant isolation
const user = await db.query.users.findFirst({
where: eq(users.id, userId) && eq(users.tenant_id, tenantId), // Tenant filtering!
});
if (!user) {
throw new Error("User not found");
}
// Return typed result
return {
id: user.id,
name: user.name,
email: user.email,
created_at: user.created_at,
tenant_id: user.tenant_id,
};
});
// 4. Mutation example
const updateUserInputSchema = z.object({
userId: z.string().uuid(),
tenantId: z.string(),
name: z.string().min(1),
email: z.string().email(),
});
export const updateUser = createServerFn(
"POST",
async (input: unknown): Promise<UserOutput> => {
// Validate input
const { userId, tenantId, name, email } = updateUserInputSchema.parse(input);
// Update with tenant isolation
const [updatedUser] = await db
.update(users)
.set({ name, email, updated_at: new Date() })
.where(eq(users.id, userId) && eq(users.tenant_id, tenantId)) // Tenant filtering!
.returning();
if (!updatedUser) {
throw new Error("User not found or update failed");
}
return {
id: updatedUser.id,
name: updatedUser.name,
email: updatedUser.email,
created_at: updatedUser.created_at,
tenant_id: updatedUser.tenant_id,
};
},
);
// 5. Usage in client components
// import { useQuery } from "@tanstack/react-query";
// import { getUser } from "~/lib/server/functions/users";
//
// const { data: user } = useQuery({
// queryKey: ["user", userId],
// queryFn: () => getUser({ userId, tenantId }),
// staleTime: 60000,
// });

View 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

View File

@@ -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

View 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)

View 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)

View File

@@ -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)

View 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)

View 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)

View File

@@ -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)

View 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)

View 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)

View 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)

View 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)

View 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)

View 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

View File

@@ -0,0 +1,25 @@
# Onboarding Coordination Skill
Automate developer onboarding with personalized plans, Linear integration, knowledge base setup, and milestone tracking.
## Description
Streamlined onboarding workflows with pre-boarding, Day 1 setup, weekly milestones, and 30/60/90 day tracking.
## What's Included
- **Examples**: Onboarding plans, Linear automation workflows
- **Reference**: Onboarding best practices, milestone templates
- **Templates**: Onboarding checklists, setup scripts
## Use When
- New developer onboarding
- Team expansion
- Role transitions
## Related Agents
- `onboarding-coordinator`
**Skill Version**: 1.0

View File

@@ -0,0 +1,67 @@
# Onboarding Automation Examples
Real-world examples of automated developer onboarding with personalized plans, Linear integration, and milestone tracking.
## Available Examples
### [Junior Engineer Onboarding](junior-engineer-onboarding.md)
Complete onboarding workflow for a junior frontend engineer from day 1 to 90 days.
**Scenario**: First full-time engineering hire needs comprehensive onboarding with extra mentorship
**Solution**: Structured learning path, buddy system, good-first-issues, daily check-ins
**Results**: First PR in 2 days (target: 3), 90-day satisfaction 4.8/5, promoted to mid-level at 18 months
**Key Techniques**: Graduated complexity, buddy pairing, structured milestones, feedback loops
---
### [Senior Engineer Onboarding](senior-engineer-onboarding.md)
Fast-track onboarding for experienced engineer focused on architecture and technical leadership.
**Scenario**: Senior hire needs to understand architecture quickly and start contributing to technical decisions
**Solution**: Architecture deep-dives, ADR reviews, design doc creation, early leadership opportunities
**Results**: First architectural proposal in week 2, leading design review in week 3, mentoring in week 4
**Key Techniques**: Architecture-first, design doc workflow, early technical leadership, stakeholder mapping
---
### [Linear Integration Automation](linear-automation-workflow.md)
Complete Linear automation for tracking onboarding progress from pre-boarding through 90 days.
**Scenario**: Manual onboarding tracking in spreadsheets, inconsistent milestone completion, no visibility
**Solution**: Automated Linear issue creation, milestone tracking, dashboard views, notification automation
**Results**: 100% milestone completion visibility, 0 missed check-ins, manager time saved 5hrs/new hire
**Key Techniques**: Linear API automation, milestone issues, custom views, webhook notifications
---
## Common Patterns
1. **Personalization**: Adapt onboarding to role (junior vs senior) and specialty (frontend vs backend vs fullstack)
2. **Automation**: Environment setup, account provisioning, Linear issue creation all automated
3. **Human Touch**: Reserve mentorship, code review, and team integration for humans
4. **Milestone Tracking**: 30/60/90 day check-ins with manager feedback loops
5. **Feedback Integration**: Continuous improvement from new hire retrospectives
## Quick Reference
| Need | Example | Key Focus |
|------|---------|-----------|
| Junior onboarding | [junior-engineer-onboarding.md](junior-engineer-onboarding.md) | Learning path, mentorship |
| Senior onboarding | [senior-engineer-onboarding.md](senior-engineer-onboarding.md) | Architecture, leadership |
| Linear automation | [linear-automation-workflow.md](linear-automation-workflow.md) | Task tracking, visibility |
---
Related: [Reference Guides](../reference/INDEX.md) | [Templates](../templates/) | [Return to Agent](../onboarding-coordinator.md)

View File

@@ -0,0 +1,59 @@
# Onboarding Coordinator Reference Guide
Quick-lookup reference for onboarding best practices, Linear API patterns, buddy system guidelines, and milestone tracking.
## Files in This Directory
### [onboarding-best-practices.md](onboarding-best-practices.md)
Research-backed best practices for developer onboarding - what works, what doesn't, and why. Covers psychological safety, graduated complexity, buddy systems, and feedback loops.
**When to use**: Designing new onboarding programs, improving existing processes, training managers/buddies
**Key topics**:
- First 90 days framework (pre-boarding, Day 1, Week 1, milestones)
- Junior vs mid vs senior onboarding differences
- Buddy system best practices
- Common onboarding mistakes and how to avoid them
### [linear-api-patterns.md](linear-api-patterns.md)
Complete Linear API reference for onboarding automation - issue creation, custom views, webhooks, and integrations.
**When to use**: Building onboarding automation, creating custom Linear integrations, troubleshooting API issues
**Key topics**:
- Linear CLI commands for issue management
- GraphQL API examples
- Webhook configuration for milestone notifications
- Custom dashboard views for managers and buddies
### [buddy-system-guide.md](buddy-system-guide.md)
Comprehensive guide to effective buddy systems - selection, training, responsibilities, and success metrics.
**When to use**: Launching buddy program, training buddies, improving buddy effectiveness
**Key topics**:
- Buddy selection criteria
- Week-by-week buddy responsibilities
- Check-in templates and conversation guides
- Measuring buddy program effectiveness
### [milestone-tracking.md](milestone-tracking.md)
Framework for 30/60/90 day milestones - what to measure, how to assess, and when to intervene.
**When to use**: Preparing for milestone check-ins, assessing onboarding progress, identifying at-risk new hires
**Key topics**:
- Success criteria for each milestone
- Red flags and intervention strategies
- Performance rating frameworks
- Feedback templates for managers
## Navigation
**Parent**: [Onboarding Coordinator Agent](../onboarding-coordinator.md)
**Examples**: [Examples Index](../examples/INDEX.md)
**Templates**: [Templates Index](../templates/INDEX.md)
---
Return to [agent documentation](../onboarding-coordinator.md)

View File

@@ -0,0 +1,41 @@
# Onboarding Coordinator Templates
Copy-paste ready templates for onboarding plans, buddy checklists, and milestone check-ins.
## Files in This Directory
### [onboarding-plan-template.md](onboarding-plan-template.md)
Complete onboarding plan template adaptable for junior, mid-level, and senior engineers. Copy, customize with new hire details, and assign Linear issues.
**When to use**: Creating onboarding plan for new hire
**Customization**: Replace [placeholders] with actual details
### [buddy-checklist-template.md](buddy-checklist-template.md)
Week-by-week checklist for buddies showing responsibilities from Day 1 through Week 12. Print and follow throughout onboarding period.
**When to use**: Assigning buddy to new hire
**Customization**: Adjust check-in frequencies based on experience level
### [milestone-check-in-templates.md](milestone-check-in-templates.md)
Meeting agendas and assessment templates for 30/60/90 day milestone check-ins with rating frameworks and feedback prompts.
**When to use**: Preparing for formal milestone reviews
**Customization**: Add role-specific success criteria
## Usage
All templates are markdown files designed for:
- Copy-paste into Linear issues
- Email to new hires or buddies
- Manager preparation documents
- Print and follow checklists
## Navigation
**Parent**: [Onboarding Coordinator Agent](../onboarding-coordinator.md)
**Examples**: [Examples Index](../examples/INDEX.md)
**Reference**: [Reference Index](../reference/INDEX.md)
---
Return to [agent documentation](../onboarding-coordinator.md)

View File

@@ -0,0 +1,68 @@
# Ontological Documentation Skill
This skill provides comprehensive tools and templates for creating ontological documentation of software systems.
## Directory Structure
```
ontological-documentation/
├── SKILL.md # Main skill definition
├── README.md # This file
├── references/ # Reference guides
│ ├── concept_extraction_guide.md
│ ├── documentation_templates.md
│ └── ontology_patterns.md
├── scripts/ # Utility scripts
│ ├── extract_concepts.py
│ └── generate_ontology_diagram.py
└── assets/ # Examples and templates
├── examples/
│ └── ecommerce-ontology.md
└── ontology-templates/
└── domain-ontology.md
```
## What's Included
### Reference Guides
- **concept_extraction_guide.md**: Methodologies for extracting domain concepts from codebases
- **documentation_templates.md**: Standardized templates for documenting concepts and relationships
- **ontology_patterns.md**: Common patterns and best practices for ontological documentation
### Scripts
- **extract_concepts.py**: Automated concept extraction from Python and JavaScript/TypeScript code
- **generate_ontology_diagram.py**: Generate Mermaid, PlantUML, GraphViz, and JSON-LD diagrams
### Examples & Templates
- **ecommerce-ontology.md**: Complete example of e-commerce domain ontology
- **domain-ontology.md**: Template for documenting new domain ontologies
## Usage
This skill activates automatically when working on:
- Domain modeling and architecture documentation
- Creating conceptual frameworks
- Extracting and documenting business concepts from code
- Building knowledge graphs and semantic models
## Quick Start
1. Read [SKILL.md](SKILL.md) for the full skill definition
2. Review the [concept extraction guide](references/concept_extraction_guide.md)
3. Use the [templates](references/documentation_templates.md) for your documentation
4. Check the [e-commerce example](assets/examples/ecommerce-ontology.md) for inspiration
## Scripts Usage
### Extract Concepts
```bash
python scripts/extract_concepts.py /path/to/codebase
```
### Generate Diagrams
```bash
python scripts/generate_ontology_diagram.py ontology.json --format mermaid
```

View File

@@ -0,0 +1,399 @@
---
name: grey-haven-ontological-documentation
description: Create comprehensive ontological documentation for Grey Haven systems - extract domain concepts from TanStack Start and FastAPI codebases, model semantic relationships, generate visual representations of system architecture, and document business domains. Use when onboarding, documenting architecture, or analyzing legacy systems.
---
# Grey Haven Ontological Documentation
Create comprehensive ontological documentation that captures fundamental concepts, relationships, and classification systems within Grey Haven codebases and systems.
## When to Use This Skill
Use this skill when you need to:
- Document the conceptual structure and domain model of Grey Haven applications
- Extract and organize business concepts from TanStack Start or FastAPI codebases
- Create visual representations of multi-tenant system architectures
- Build semantic maps of entities, services, and their tenant-isolated interactions
- Design or document domain models for new Grey Haven features
- Analyze and communicate complex architectures to stakeholders
- Create knowledge graphs for Grey Haven development teams
- Onboard new developers to Grey Haven project structure
## Core Capabilities
### 1. Concept Extraction from Grey Haven Codebases
**TanStack Start (Frontend) Extraction:**
- Drizzle schema tables and relationships
- React components and their hierarchies
- TanStack Router route structure
- Better-auth session and user models
- Server functions and their dependencies
- Multi-tenant data patterns (tenant_id isolation)
**FastAPI (Backend) Extraction:**
- SQLModel entities and relationships
- Repository pattern implementations
- Service layer business logic
- API endpoint hierarchies
- Multi-tenant repository filters
- Pydantic schemas and validation models
### 2. Grey Haven Architecture Patterns
**Identify and Document:**
- **Multi-Tenant Patterns**: tenant_id isolation, RLS roles (admin/authenticated/anon)
- **Repository Pattern**: BaseRepository with automatic tenant filtering
- **Service Layer**: Business logic separation from endpoints
- **Database Conventions**: snake_case fields, UUID primary keys, timestamps
- **Authentication**: Better-auth integration with session management
- **Deployment**: Cloudflare Workers architecture
### 3. Visual Documentation Formats
**Mermaid Diagrams** (for README files):
```mermaid
erDiagram
USER ||--o{ ORGANIZATION : belongs_to
USER {
uuid id PK
string email_address UK
uuid tenant_id FK
timestamp created_at
}
ORGANIZATION ||--o{ TEAM : contains
ORGANIZATION {
uuid id PK
string name
uuid tenant_id FK
timestamp created_at
}
```
**System Architecture**:
```mermaid
graph TB
Client[TanStack Start Client]
Server[Server Functions]
Auth[Better-auth]
DB[(PostgreSQL + RLS)]
Client -->|Authenticated Requests| Server
Client -->|Auth Flow| Auth
Server -->|Query with tenant_id| DB
Auth -->|Session Validation| DB
```
### 4. Domain Model Documentation Template
```markdown
## Entity: User
### Definition
Represents an authenticated user in the Grey Haven system with multi-tenant isolation.
### Database Schema
- **Table**: users (snake_case)
- **Primary Key**: id (UUID)
- **Tenant Isolation**: tenant_id (UUID, indexed)
- **Unique Constraints**: email_address per tenant
- **Timestamps**: created_at, updated_at (automatic)
### Relationships
- **Belongs To**: Organization (via tenant_id)
- **Has Many**: Sessions (Better-auth)
- **Has Many**: TeamMemberships
### Business Rules
- Email must be unique within tenant
- Cannot access data from other tenants
- Session expires after 30 days of inactivity
- RLS enforces tenant_id filtering at database level
### TypeScript Type
```typescript
interface User {
id: string;
emailAddress: string;
tenantId: string;
createdAt: Date;
updatedAt: Date;
}
```
### Python Model
```python
class User(SQLModel, table=True):
__tablename__ = "users"
id: UUID = Field(default_factory=uuid4, primary_key=True)
email_address: str = Field(unique=True, index=True)
tenant_id: UUID = Field(foreign_key="organizations.id", index=True)
created_at: datetime = Field(default_factory=datetime.utcnow)
updated_at: datetime = Field(default_factory=datetime.utcnow)
```
```
## Workflow
### Step 1: Discovery and Extraction
**For TanStack Start Projects:**
1. Analyze Drizzle schema files in `src/lib/server/schema/`
2. Map React component structure in `src/lib/components/`
3. Document TanStack Router routes in `src/routes/`
4. Extract server functions from `src/lib/server/functions/`
5. Identify tenant isolation patterns
**For FastAPI Projects:**
1. Analyze SQLModel models in `app/db/models/`
2. Map repository pattern in `app/db/repositories/`
3. Document service layer in `app/services/`
4. Extract API routes from `app/routers/`
5. Identify BaseRepository tenant filtering
### Step 2: Ontology Construction
**Categorize by Grey Haven Patterns:**
1. **Core Entities** (tables with tenant_id)
- User, Organization, Team, etc.
- Always include tenant_id
- UUID primary keys
- snake_case field names
2. **Service Boundaries**
- Repository layer (data access)
- Service layer (business logic)
- Router layer (API endpoints)
- Clear separation of concerns
3. **Relationships and Dependencies**
- Foreign key relationships
- Repository dependencies
- Service composition
- API endpoint groupings
4. **Multi-Tenant Patterns**
- RLS role usage (admin/authenticated/anon)
- tenant_id filtering in repositories
- Session-based tenant resolution
- Cross-tenant access prevention
### Step 3: Documentation Creation
**Use Grey Haven Documentation Standards:**
1. **Entity Documentation**
- Definition and purpose
- Database schema with exact field names
- Relationships to other entities
- Business rules and constraints
- TypeScript and Python representations
2. **Service Documentation**
- Service responsibilities
- Repository dependencies
- Business logic patterns
- Multi-tenant considerations
3. **API Documentation**
- Endpoint hierarchies
- Request/response schemas
- Authentication requirements
- Tenant isolation verification
### Step 4: Visualization
**Create Diagrams For:**
1. **Database ERD** - All tables with relationships and tenant_id fields
2. **Service Dependencies** - Repository → Service → Router layers
3. **Authentication Flow** - Better-auth integration with multi-tenant context
4. **Deployment Architecture** - Cloudflare Workers, Neon PostgreSQL, Redis
5. **Data Flow** - Client → Server Functions → Repository → Database (with RLS)
## Common Use Cases
### Use Case 1: New Developer Onboarding
*"I need to understand how Grey Haven's multi-tenant architecture works."*
**Approach:**
1. Extract all entities with tenant_id fields
2. Document BaseRepository tenant filtering pattern
3. Create ERD showing tenant_id relationships
4. Explain RLS roles and session-based tenant resolution
5. Show data flow with tenant isolation
### Use Case 2: Feature Design Documentation
*"Document the domain model for the new billing feature before implementation."*
**Approach:**
1. Design entity schema following Grey Haven conventions
2. Plan repository and service layer structure
3. Document API endpoints with tenant isolation
4. Create Mermaid diagrams for the feature
5. Validate multi-tenant patterns
### Use Case 3: Architecture Review
*"Analyze the current codebase to identify inconsistencies in multi-tenant patterns."*
**Approach:**
1. Extract all repositories and check tenant_id filtering
2. Review entities for proper tenant_id indexing
3. Audit RLS role usage across the application
4. Identify missing tenant isolation
5. Generate compliance report
### Use Case 4: Legacy Code Analysis
*"Understand the original domain model before refactoring the user management system."*
**Approach:**
1. Extract current User entity and relationships
2. Map all services depending on User
3. Document authentication flow with Better-auth
4. Identify refactoring boundaries
5. Create before/after architecture diagrams
## Grey Haven Specific Patterns
### Multi-Tenant Entity Pattern
```typescript
// Drizzle Schema (TanStack Start)
export const usersTable = pgTable("users", {
id: uuid("id").primaryKey().defaultRandom(),
emailAddress: text("email_address").unique().notNull(),
tenantId: uuid("tenant_id").references(() => organizationsTable.id).notNull(),
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
});
```
```python
# SQLModel (FastAPI)
class User(SQLModel, table=True):
__tablename__ = "users"
id: UUID = Field(default_factory=uuid4, primary_key=True)
email_address: str = Field(unique=True, index=True)
tenant_id: UUID = Field(foreign_key="organizations.id", index=True)
created_at: datetime = Field(default_factory=datetime.utcnow)
updated_at: datetime = Field(default_factory=datetime.utcnow)
```
### Repository Pattern with Tenant Isolation
```python
# BaseRepository with automatic tenant filtering
class BaseRepository(Generic[T]):
def __init__(self, session: AsyncSession, model: type[T]):
self.session = session
self.model = model
async def get_by_id(self, id: UUID, tenant_id: UUID) -> Optional[T]:
"""Automatic tenant isolation."""
result = await self.session.execute(
select(self.model)
.where(self.model.id == id)
.where(self.model.tenant_id == tenant_id) # Always filter
)
return result.scalar_one_or_none()
```
### RLS Role Pattern
```typescript
// Database connections with RLS roles
const adminDb = drizzle(process.env.DATABASE_URL_ADMIN); // Full access
const authenticatedDb = drizzle(process.env.DATABASE_URL_AUTHENTICATED); // Tenant-scoped
const anonDb = drizzle(process.env.DATABASE_URL_ANON); // Public only
```
## Documentation Output Structure
### Directory Organization
```
documentation/
├── architecture/
│ ├── system-overview.md
│ ├── multi-tenant-architecture.md
│ └── deployment-architecture.md
├── domain-model/
│ ├── entities/
│ │ ├── user.md
│ │ ├── organization.md
│ │ └── team.md
│ ├── relationships.md
│ └── business-rules.md
├── diagrams/
│ ├── database-erd.mmd
│ ├── service-dependencies.mmd
│ ├── auth-flow.mmd
│ └── deployment.mmd
└── ontology.json
```
### Ontology JSON Structure
```json
{
"version": "1.0.0",
"system": "Grey Haven Application",
"architecture": "Multi-tenant TanStack Start + FastAPI",
"entities": [
{
"name": "User",
"table": "users",
"primaryKey": "id",
"tenantKey": "tenant_id",
"fields": [...],
"relationships": [...],
"businessRules": [...]
}
],
"services": [...],
"patterns": {
"multiTenant": true,
"rls": true,
"repositoryPattern": true
}
}
```
## When to Apply This Skill
Use ontological documentation when:
- Onboarding new developers to Grey Haven projects
- Designing new features with domain modeling
- Documenting multi-tenant architecture
- Analyzing legacy code before refactoring
- Creating architecture presentations for stakeholders
- Building knowledge bases for Grey Haven teams
- Ensuring consistency across TanStack Start and FastAPI implementations
- Auditing multi-tenant isolation patterns
- Planning database migrations or schema changes
## Integration with Other Grey Haven Skills
**Works Best With:**
- `grey-haven-database-conventions` - Ensure proper schema design
- `grey-haven-project-structure` - Understand codebase organization
- `grey-haven-authentication-patterns` - Document Better-auth integration
- `grey-haven-data-modeling` - Design Drizzle and SQLModel schemas
- `grey-haven-api-design-standards` - Document API hierarchies
## Critical Reminders
1. **Always document tenant_id** - Every entity must show tenant isolation
2. **Follow naming conventions** - snake_case for database, camelCase for TypeScript
3. **Include both TypeScript and Python** - Grey Haven uses both stacks
4. **Show RLS roles** - Document admin/authenticated/anon usage
5. **Repository pattern is required** - All data access goes through repositories
6. **UUID primary keys** - Never use auto-increment integers
7. **Timestamps are automatic** - created_at and updated_at
8. **Multi-tenant first** - Every design considers tenant isolation
9. **Visual diagrams required** - Mermaid for all architecture documentation
10. **Cross-reference skills** - Link to relevant Grey Haven skills
## Template References
These patterns are from Grey Haven's actual templates:
- **Frontend**: `cvi-template` (TanStack Start + React 19 + Drizzle)
- **Backend**: `cvi-backend-template` (FastAPI + SQLModel + Repository Pattern)
- **Multi-tenant**: Neon PostgreSQL with RLS

View File

@@ -0,0 +1,236 @@
# Ontological Documentation Checklist
Systematic checklist for creating comprehensive ontological documentation.
## Pre-Documentation
- [ ] **Identify codebase scope** (frontend, backend, or full-stack)
- [ ] **Understand domain** (business concepts, terminology)
- [ ] **Set up documentation tools** (Mermaid, diagramming tools)
- [ ] **Review existing documentation** (READMEs, architecture docs)
- [ ] **Identify stakeholders** (who will use this documentation)
## Concept Extraction
### Frontend (TanStack Start)
- [ ] **Database schema extracted** (Drizzle tables, relationships)
- [ ] **Component hierarchy mapped** (React component tree)
- [ ] **Routes documented** (TanStack Router structure)
- [ ] **State management identified** (Context, queries, mutations)
- [ ] **Server functions cataloged** (API surface)
### Backend (FastAPI)
- [ ] **SQLModel entities documented** (all models)
- [ ] **Relationships mapped** (foreign keys, associations)
- [ ] **Repository pattern documented** (all repositories)
- [ ] **Service layer mapped** (business logic)
- [ ] **API endpoints cataloged** (all routes)
- [ ] **Pydantic schemas listed** (request/response models)
### Multi-Tenant Patterns
- [ ] **tenant_id fields identified** on all tables
- [ ] **RLS policies documented** (row level security)
- [ ] **Tenant isolation verified** in queries
- [ ] **Repository filters documented** (automatic tenant filtering)
- [ ] **Admin vs user access documented**
## Entity Documentation
### For Each Entity
- [ ] **Name and purpose** clearly stated
- [ ] **Attributes documented** (all fields with types)
- [ ] **Relationships documented** (to other entities)
- [ ] **Constraints documented** (unique, required, validation)
- [ ] **Business rules noted** (validation, lifecycle)
### Database Entities
- [ ] **Table name** documented
- [ ] **Primary key** identified
- [ ] **Foreign keys** documented
- [ ] **Indexes** listed
- [ ] **Timestamps** (created_at, updated_at)
- [ ] **Tenant isolation** (tenant_id field)
## Relationship Mapping
### Types of Relationships
- [ ] **One-to-One** relationships documented
- [ ] **One-to-Many** relationships documented
- [ ] **Many-to-Many** relationships documented
- [ ] **Join tables** identified (for many-to-many)
- [ ] **Cascade behavior** documented (delete, update)
### Relationship Documentation
- [ ] **Source entity** identified
- [ ] **Target entity** identified
- [ ] **Relationship name** clear and descriptive
- [ ] **Cardinality** specified
- [ ] **Business meaning** explained
## Architecture Documentation
### System Components
- [ ] **Frontend components** listed and categorized
- [ ] **Backend services** documented
- [ ] **Database** structure documented
- [ ] **External services** identified (Stripe, Resend, etc.)
- [ ] **Authentication system** documented (Better-auth)
### Data Flow
- [ ] **User actions****Frontend** flow documented
- [ ] **Frontend****Backend** API calls documented
- [ ] **Backend****Database** queries documented
- [ ] **Backend****External services** documented
- [ ] **Response flow** back to user documented
## Visualization
### Diagrams Created
- [ ] **Entity-Relationship Diagram** (ERD) for database
- [ ] **Component Hierarchy** for React components
- [ ] **Architecture Overview** showing all systems
- [ ] **Data Flow Diagrams** for critical paths
- [ ] **Multi-Tenant Isolation** diagram
### Diagram Quality
- [ ] **Clear labels** on all elements
- [ ] **Legend provided** (symbols explained)
- [ ] **Color coding** used effectively
- [ ] **Readable font size** and layout
- [ ] **Diagrams source-controlled** (Mermaid or PlantUML)
## Domain Model
### Business Concepts
- [ ] **Core domain entities** identified
- [ ] **Business processes** documented
- [ ] **Business rules** captured
- [ ] **Domain terminology** defined
- [ ] **Invariants** documented
### Semantic Relationships
- [ ] **"Is-a" relationships** (inheritance)
- [ ] **"Has-a" relationships** (composition)
- [ ] **"Uses" relationships** (dependencies)
- [ ] **Aggregation** relationships
- [ ] **Association** relationships
## Grey Haven Specific
### Multi-Tenant Architecture
- [ ] **Tenant model** documented
- [ ] **Organization model** documented
- [ ] **User-Tenant relationship** explained
- [ ] **Team structure** documented (if applicable)
- [ ] **RLS roles** explained (admin, authenticated, anon)
### Authentication & Authorization
- [ ] **Better-auth integration** documented
- [ ] **Session management** explained
- [ ] **User roles** documented
- [ ] **Permission model** explained
- [ ] **OAuth providers** listed
### Database Conventions
- [ ] **Naming conventions** documented (snake_case)
- [ ] **UUID usage** explained (primary keys)
- [ ] **Timestamp fields** standardized
- [ ] **Soft deletes** documented (if used)
- [ ] **Audit fields** documented (if used)
## Documentation Quality
### Completeness
- [ ] **All entities** documented
- [ ] **All relationships** documented
- [ ] **All business rules** captured
- [ ] **All external integrations** noted
- [ ] **All deployment architecture** documented
### Clarity
- [ ] **Technical jargon** explained
- [ ] **Domain terminology** consistent
- [ ] **Examples provided** where helpful
- [ ] **Diagrams clear** and readable
- [ ] **Navigation easy** (links, TOC)
### Maintainability
- [ ] **Documentation source-controlled** (with code)
- [ ] **Update process** defined
- [ ] **Ownership** assigned (who maintains)
- [ ] **Review schedule** established
- [ ] **Feedback mechanism** in place
## Automation
### Scripts Used
- [ ] **extract_concepts.py** run successfully
- [ ] **generate_ontology_diagram.py** produced diagrams
- [ ] **Output reviewed** and verified
- [ ] **Customizations documented**
- [ ] **Scripts committed** to repository
### Continuous Documentation
- [ ] **Documentation updates** in PR checklist
- [ ] **Schema changes** trigger doc updates
- [ ] **API changes** trigger doc updates
- [ ] **CI checks** for documentation completeness
## Stakeholder Review
### Technical Review
- [ ] **Developers reviewed** documentation
- [ ] **Technical accuracy** verified
- [ ] **Missing information** identified
- [ ] **Feedback incorporated**
### Business Review
- [ ] **Domain experts reviewed** business concepts
- [ ] **Business terminology** verified
- [ ] **Business rules** confirmed
- [ ] **Use cases validated**
## Deployment
### Documentation Delivery
- [ ] **Documentation committed** to repository
- [ ] **README updated** with links
- [ ] **Wiki/Confluence** updated (if used)
- [ ] **Team notified** of new documentation
- [ ] **Onboarding materials** updated
### Accessibility
- [ ] **Documentation discoverable** (easy to find)
- [ ] **Navigation clear** (links, search)
- [ ] **Formats appropriate** (markdown, diagrams)
- [ ] **Mobile-friendly** (if applicable)
## Scoring
- **90+ items checked**: Excellent - Comprehensive documentation ✅
- **75-89 items**: Good - Most areas covered ⚠️
- **60-74 items**: Fair - Significant gaps exist 🔴
- **<60 items**: Poor - Inadequate documentation ❌
## Priority Items
Address these first:
1. **Entity documentation** - Core to understanding
2. **Relationship mapping** - Critical for navigation
3. **Multi-tenant patterns** - Security-critical
4. **Data flow diagrams** - Helps debugging
5. **Automation setup** - Saves time
## Related Resources
- [Concept Extraction Guide](../reference/concept_extraction_guide.md)
- [Ontology Patterns](../reference/ontology_patterns.md)
- [Examples](../examples/INDEX.md)
- [Templates](../templates/)
- [Scripts](../scripts/)
---
**Total Items**: 100+ documentation checks
**Critical Items**: Entity docs, Relationships, Multi-tenant, Data flow
**Last Updated**: 2025-11-09

View File

@@ -0,0 +1,69 @@
# Ontological Documentation Examples
Real-world examples of creating ontological documentation for Grey Haven systems.
## Available Examples
1. **[TanStack Start Ontology](tanstack-start-example.md)** - Frontend codebase analysis
- Extracting concepts from Drizzle schemas
- Mapping React component hierarchies
- Documenting multi-tenant patterns
- Visualizing route structure
2. **[FastAPI Ontology](fastapi-example.md)** - Backend codebase analysis
- SQLModel entity relationships
- Repository pattern documentation
- Service layer mapping
- API endpoint hierarchy
3. **[Multi-Tenant System Architecture](multi-tenant-ontology.md)** - Complete system documentation
- Tenant isolation patterns
- RLS policies visualization
- Database schema relationships
- Authentication flow
4. **[Domain Model Extraction](domain-model-extraction.md)** - Business concept mapping
- Identifying domain entities
- Relationship mapping
- Business rule documentation
- Semantic relationships
## Recommended Path
**For new projects:**
1. Start with [domain-model-extraction.md](domain-model-extraction.md)
2. Document frontend with [tanstack-start-example.md](tanstack-start-example.md)
3. Document backend with [fastapi-example.md](fastapi-example.md)
4. Complete system view with [multi-tenant-ontology.md](multi-tenant-ontology.md)
**For existing systems:**
1. Run extraction scripts on codebase
2. Follow [domain-model-extraction.md](domain-model-extraction.md) to identify concepts
3. Use templates to document findings
## Quick Reference
### Frontend Ontology
- See [tanstack-start-example.md](tanstack-start-example.md)
- Use `scripts/extract_concepts.py` for automation
### Backend Ontology
- See [fastapi-example.md](fastapi-example.md)
- Focus on repository and service patterns
### Visualization
- See [multi-tenant-ontology.md](multi-tenant-ontology.md)
- Use `scripts/generate_ontology_diagram.py`
## Related Materials
- **[Concept Extraction Guide](../reference/concept_extraction_guide.md)** - How to extract concepts
- **[Ontology Patterns](../reference/ontology_patterns.md)** - Common patterns
- **[Templates](../templates/)** - Ready-to-use ontology templates
- **[Scripts](../scripts/)** - Automation scripts
---
**Total Examples**: 4 comprehensive guides
**Coverage**: TanStack Start, FastAPI, Multi-tenant, Domain modeling
**Last Updated**: 2025-11-09

View File

@@ -0,0 +1,98 @@
# E-Commerce Domain Ontology Example
## Overview
This example demonstrates an ontological documentation approach for a typical e-commerce system.
## Core Concepts
### Primary Entities
```
E-Commerce Domain
├── Customer Management
│ ├── Customer
│ ├── CustomerProfile
│ └── Address
├── Product Management
│ ├── Product
│ ├── Category
│ └── ProductVariant
├── Order Management
│ ├── Order
│ ├── OrderLine
│ └── OrderStatus
└── Payment Management
├── Payment
├── PaymentMethod
└── PaymentStatus
```
### Key Relationships
#### Customer Relationships
- **Customer** has-a **CustomerProfile**
- **Customer** has-many **Address**
- **Customer** places-many **Order**
- **Customer** has-many **Payment**
#### Product Relationships
- **Product** belongs-to **Category**
- **Product** has-many **ProductVariant**
- **ProductVariant** appears-in **OrderLine**
#### Order Relationships
- **Order** contains-many **OrderLine**
- **Order** has-a **OrderStatus**
- **Order** has-a **Payment**
- **OrderLine** references-a **ProductVariant**
## Business Rules
### Customer Rules
- Customer must have at least one address
- Customer profile must include valid email
- Customer can have multiple shipping addresses
### Order Rules
- Order must have at least one order line
- Order total must equal sum of order line totals
- Order status progression is immutable
### Payment Rules
- Payment amount must match order total
- Payment method must be valid for customer
- Payment status affects order fulfillment
## Implementation Examples
### Order Entity Example
```python
class Order:
def __init__(self, customer: Customer):
self.customer = customer
self.order_lines: List[OrderLine] = []
self.status = OrderStatus.PENDING
self.created_at = datetime.now()
def add_product(self, product: ProductVariant, quantity: int):
# Add business logic for adding products
pass
def calculate_total(self) -> Money:
# Calculate order total
pass
```
### Relationship Example
```python
# Order -> Customer relationship
class Order:
def __init__(self, customer: Customer):
self.customer_id = customer.id # Reference relationship
self.customer = customer # Object relationship
```
## Documentation Links
- [Customer Documentation](customer-concept.md)
- [Product Documentation](product-concept.md)
- [Order Documentation](order-concept.md)
- [Payment Documentation](payment-concept.md)

View File

@@ -0,0 +1,43 @@
# Ontological Documentation Reference
Technical reference for creating ontological documentation of Grey Haven systems.
## Reference Materials
1. **[Concept Extraction Guide](concept_extraction_guide.md)** - How to extract concepts from code
- TanStack Start extraction patterns
- FastAPI extraction patterns
- Identifying entities and relationships
- Semantic analysis techniques
2. **[Ontology Patterns](ontology_patterns.md)** - Common Grey Haven patterns
- Multi-tenant patterns
- Repository pattern
- Service layer patterns
- Authentication patterns
- Database conventions
3. **[Documentation Templates](documentation_templates.md)** - Template formats
- Entity documentation
- Relationship diagrams
- Architecture overviews
- Domain model templates
4. **[Visualization Techniques](visualization-techniques.md)** - Diagram creation
- Mermaid diagrams
- Entity-relationship diagrams
- Component hierarchies
- Data flow diagrams
## Quick Links
- For examples: See [examples/](../examples/INDEX.md)
- For templates: See [templates/](../templates/)
- For scripts: See [scripts/](../scripts/)
- For checklists: See [checklists/](../checklists/)
---
**Coverage**: Concept extraction, Patterns, Templates, Visualization
**Platforms**: TanStack Start, FastAPI
**Last Updated**: 2025-11-09

View File

@@ -0,0 +1,55 @@
# Reference Guides
This directory contains comprehensive reference guides for ontological documentation.
## Files
### concept_extraction_guide.md
Methodologies and techniques for identifying and extracting domain concepts, entities, and relationships from software codebases.
**Topics covered:**
- Static code analysis techniques
- Naming convention analysis
- Data structure analysis
- Configuration and metadata analysis
- Language-specific extraction patterns (Python, JavaScript/TypeScript, Java)
- Concept categorization framework
- Relationship identification
- Extraction workflow
- Quality assurance
### documentation_templates.md
Standardized templates for creating comprehensive ontological documentation.
**Templates included:**
- Concept Definition Template
- Relationship Documentation Template
- Domain Model Overview Template
- Ontology Change Log Template
- API Ontology Template
- Database Schema Ontology Template
- Event-Driven Architecture Ontology Template
### ontology_patterns.md
Common ontological patterns and taxonomies found in software systems.
**Patterns covered:**
- Fundamental relationship types (Is-A, Part-Of, Instance-Of, Depends-On, Associates-With)
- Layered Architecture Pattern
- Domain-Driven Design Pattern
- MVC Pattern Ontology
- Microservices Pattern Ontology
- Taxonomy classification systems
- Ontology validation rules
## Usage
These guides are designed to be used together:
1. Start with **ontology_patterns.md** to understand common patterns
2. Use **concept_extraction_guide.md** to extract concepts from your codebase
3. Apply **documentation_templates.md** to document your findings
## Integration with Main Skill
These references support the main [SKILL.md](../SKILL.md) and are automatically available when the ontological documentation skill is activated.

View File

@@ -0,0 +1,271 @@
# Concept Extraction Guide for Software Systems
This guide provides methodologies and techniques for identifying and extracting domain concepts, entities, and relationships from software codebases to build ontological documentation.
## Extraction Methodologies
### 1. Static Code Analysis
#### Class and Interface Analysis
- **Objective**: Identify conceptual entities and their hierarchies
- **Sources**: Class definitions, interface declarations, type annotations
- **Techniques**:
- Parse AST (Abstract Syntax Trees) to find type definitions
- Extract inheritance relationships (extends, implements)
- Identify composition patterns through member variables
- Analyze method signatures for behavioral concepts
#### Function and Method Analysis
- **Objective**: Discover actions, processes, and behavioral concepts
- **Sources**: Function definitions, method declarations
- **Techniques**:
- Group related functions into conceptual categories
- Identify command/query patterns (CQRS)
- Extract business process flows from method call chains
- Map function parameters to conceptual relationships
#### Import and Dependency Analysis
- **Objective**: Understand system boundaries and external dependencies
- **Sources**: Import statements, package dependencies, service calls
- **Techniques**:
- Map module dependencies to conceptual relationships
- Identify external system boundaries
- Categorize dependencies (internal, external, third-party)
- Analyze dependency graphs for architectural insights
### 2. Naming Convention Analysis
#### Semantic Naming Patterns
- **Entity Nouns**: User, Order, Product, Account (domain objects)
- **Process Verbs**: ProcessPayment, ValidateInput, SendEmail (actions)
- **State Adjectives**: Active, Pending, Completed, Expired (states)
- **Role-based Names**: AdminService, UserGateway, PaymentProcessor (roles)
#### Naming Pattern Recognition
```
Entity + Pattern = Concept Type
- User + Repository = Data Access Concept
- Order + Service = Business Logic Concept
- Payment + Gateway = Integration Concept
- Notification + Event = Event Concept
```
### 3. Data Structure Analysis
#### Database Schema Analysis
- **Tables as Entities**: Each table represents a domain concept
- **Foreign Keys as Relationships**: FKs define relationships between concepts
- **Indexes as Properties**: Important attributes for concept identification
- **Constraints as Rules**: Business rules and validation logic
#### API Contract Analysis
- **REST Resources**: URL paths often map to domain concepts
- **GraphQL Types**: Schema types define conceptual models
- **Message Schemas**: Event/message structures reveal concepts
- **OpenAPI Specifications**: Complete conceptual model of external interface
### 4. Configuration and Metadata Analysis
#### Configuration Files
- **Application Settings**: System behavior concepts
- **Feature Flags**: Feature-based concept organization
- **Environment Variables**: Deployment and environment concepts
- **Routing Tables**: Navigation and flow concepts
#### Documentation and Comments
- **README Files**: High-level conceptual overview
- **Code Comments**: Designer intent and conceptual explanations
- **API Documentation**: External conceptual contracts
- **Architecture Diagrams**: Visual conceptual relationships
## Extraction Techniques by Language
### Python
```python
# Key patterns to identify:
class UserService: # Service concept
def __init__(self, user_repo): # Dependency relationship
self.user_repo = user_repo
def create_user(self, user_dto): # Action concept
# Domain logic here
pass
# Look for:
# - Class definitions (entities, services, repositories)
# - Method names (actions, processes)
# - Parameter types (relationships)
# - Decorators (cross-cutting concerns)
```
### JavaScript/TypeScript
```typescript
// Key patterns to identify:
interface User { # Entity concept
id: string;
name: string;
}
class UserService { # Service concept
constructor(private userRepo: UserRepository) {} # Dependency
async createUser(userData: CreateUserDto): Promise<User> { # Action + types
// Implementation
}
}
// Look for:
# - Interface definitions (contracts, entities)
# - Class definitions (services, controllers)
# - Type annotations (concept properties)
# - Decorators (metadata, concerns)
```
### Java
```java
// Key patterns to identify:
@Entity # Entity annotation
public class User { # Entity concept
@Id
private Long id;
@OneToMany # Relationship annotation
private List<Order> orders;
}
@Service # Service annotation
public class UserService { # Service concept
@Autowired # Dependency injection
private UserRepository userRepo;
public User createUser(UserDto userDto) { // Action + type
// Implementation
}
}
// Look for:
# - Annotations (component types, relationships)
# - Class definitions (entities, services)
# - Interface definitions (contracts)
# - Method signatures (actions, processes)
```
## Concept Categorization Framework
### Primary Categories
1. **Domain Entities** (Nouns)
- Core business objects: User, Order, Product, Account
- Usually persistent, have identity
- Contain business logic and state
2. **Value Objects** (Nouns)
- Immutable concepts without identity: Address, Money, DateRange
- Defined by their attributes
- Often embedded in entities
3. **Services** (Verb + Noun)
- Business logic coordinators: UserService, PaymentService
- Stateless operations
- Orchestrate domain objects
4. **Repositories** (Noun + Repository/Store)
- Data access abstractions: UserRepository, OrderRepository
- Collection-like interfaces
- Hide storage details
5. **Controllers/Handlers** (Noun + Controller/Handler)
- Request/response coordination: UserController, OrderController
- Interface between external world and domain
- Thin layer, delegate to services
### Secondary Categories
6. **Events/Notifications** (Past Tense Verbs + Noun)
- State changes: OrderCreated, PaymentProcessed, UserRegistered
- Asynchronous communication
- Decouple system components
7. **DTOs/Models** (Noun + Dto/Model)
- Data transfer objects: UserDto, OrderModel
- External contract representations
- No business logic
8. **Utilities/Helpers** (Adjective/Noun + Utility/Helper)
- Cross-cutting functionality: ValidationHelper, EmailUtility
- Reusable operations
- No domain concepts
## Relationship Identification
### Direct Relationships
- **Inheritance**: `class Admin extends User` (Is-A)
- **Composition**: `class Order { private List<OrderLine> lines; }` (Part-Of)
- **Dependency**: `UserService(UserRepository repo)` (Depends-On)
### Indirect Relationships
- **Shared Interfaces**: Implement same interface (Associates-With)
- **Common Patterns**: Similar naming or structure (Similar-To)
- **Event Connections**: Producer-consumer patterns (Communicates-With)
### Semantic Relationships
- **Temporal**: CreatedBefore, UpdatedAfter
- **Spatial**: Contains, LocatedWithin
- **Causal**: Triggers, Enables, Prevents
- **Logical**: Implies, Contradicts, Equivalent
## Extraction Workflow
### Phase 1: Automated Extraction
1. Run static analysis tools to identify:
- Class/interface definitions
- Inheritance hierarchies
- Import dependencies
- Method signatures
### Phase 2: Manual Analysis
1. Review automated results for semantic accuracy
2. Identify implicit concepts not captured by code
3. Map business terminology to technical concepts
4. Validate relationships with domain experts
### Phase 3: Ontology Construction
1. Organize concepts into hierarchies
2. Define relationships between concepts
3. Add semantic metadata and descriptions
4. Validate completeness and consistency
### Phase 4: Documentation Generation
1. Create visual representations
2. Generate textual documentation
3. Create interactive navigation
4. Establish maintenance processes
## Quality Assurance
### Validation Checks
- [ ] All identified concepts have clear definitions
- [ ] Relationships are correctly classified
- [ ] No circular inheritance exists
- [ ] Domain terminology is consistent
- [ ] Technical and business concepts are aligned
### Review Process
1. **Developer Review**: Technical accuracy and completeness
2. **Domain Expert Review**: Business concept validation
3. **Architecture Review**: Consistency with system design
4. **Documentation Review**: Clarity and usability
## Maintenance Strategies
### Continuous Updates
- Monitor code changes for new concepts
- Update ontology when requirements evolve
- Regular reviews with stakeholders
- Automated validation checks
### Version Management
- Tag ontology versions with releases
- Track concept evolution over time
- Maintain change logs
- Backward compatibility considerations

View File

@@ -0,0 +1,447 @@
# Ontological Documentation Templates
This document provides standardized templates for creating comprehensive ontological documentation for software systems.
## Core Documentation Templates
### 1. Concept Definition Template
```markdown
# [Concept Name]
## Quick Reference
- **Type**: [Entity/Value Object/Service/Repository/etc.]
- **Category**: [Domain/Business/Infrastructure/etc.]
- **Status**: [Active/Deprecated/Experimental]
- **Owner**: [Team/Person responsible]
## Definition
[Clear, concise definition of the concept. What is it? What purpose does it serve?]
## Purpose and Scope
**Why this concept exists:**
- [Problem it solves]
- [Business requirement it addresses]
- [Technical necessity]
**Scope and Boundaries:**
- [What's included]
- [What's excluded]
- [Related but separate concepts]
## Characteristics
### Essential Properties
- **Property 1**: [Description] - [Type] - [Constraints]
- **Property 2**: [Description] - [Type] - [Constraints]
### Behavioral Aspects
- **Action 1**: [Description] - [Preconditions] - [Postconditions]
- **Action 2**: [Description] - [Preconditions] - [Postconditions]
### Constraints and Rules
- [Business rule 1]
- [Validation rule 2]
- [Integrity constraint 3]
## Relationships
### Hierarchical Relationships
- **Is-A**: [Parent Concept] - [Rationale]
- **Has-A**: [Child Components] - [Composition details]
### Dependency Relationships
- **Depends-On**: [Required Concept] - [Dependency type]
- **Required-By**: [Dependent Concept] - [Usage context]
### Association Relationships
- **Associates-With**: [Related Concept] - [Nature of association]
- **Similar-To**: [Analogous Concept] - [Comparison points]
## Implementation
### Code Representation
```python
# Example implementation
class [ConceptName]:
def __init__(self):
self.property1 = None
self.property2 = None
```
### Data Structure
- **Storage Format**: [Database table, JSON, etc.]
- **Serialization**: [How it's represented in API/transport]
- **Persistence**: [Where and how it's stored]
### Lifecycle
- **Creation**: [How instances are created]
- **Evolution**: [How instances change over time]
- **Deletion**: [How instances are removed]
## Examples
### Concrete Examples
1. **Example 1**: [Specific instance with explanation]
- [Context]
- [Properties]
- [Behavior]
2. **Example 2**: [Another specific instance]
- [Context]
- [Properties]
- [Behavior]
### Usage Patterns
- **Pattern 1**: [Common usage scenario]
- **Pattern 2**: [Another usage scenario]
## Evolution and History
- **Created**: [Date] - [Initial reason]
- **Major Changes**: [Change history]
- **Future Roadmap**: [Planned modifications]
## Related Documentation
- [Link to related concepts]
- [Link to implementation details]
- [Link to API documentation]
- [Link to user documentation]
```
### 2. Relationship Documentation Template
```markdown
# [Relationship Type]: [Source Concept] → [Target Concept]
## Relationship Overview
- **Type**: [Is-A/Part-Of/Depends-On/Associates-With/etc.]
- **Source**: [Source Concept Name]
- **Target**: [Target Concept Name]
- **Strength**: [Strong/Medium/Weak]
- **Direction**: [Unidirectional/Bidirectional]
## Definition
[Clear explanation of what this relationship means in the domain context]
## Rationale
**Why this relationship exists:**
- [Business reason]
- [Technical necessity]
- [Domain modeling decision]
## Characteristics
### Cardinality
- **Source → Target**: [One-to-One/One-to-Many/Many-to-Many]
- **Minimum**: [Required/Optional - specify minimum]
- **Maximum**: [Unbounded/Specific limit]
### Constraints
- **Existence Constraint**: [Rules about when relationship can exist]
- **Deletion Constraint**: [What happens when one end is deleted]
- **Update Constraint**: [How relationship changes are handled]
### Semantic Properties
- **Transitivity**: [Whether relationship is transitive]
- **Symmetry**: [Whether relationship is symmetric]
- **Reflexivity**: [Whether relationship is reflexive]
## Implementation
### Code Representation
```python
# Example implementation
class SourceConcept:
def __init__(self):
self.target_concepts = [] # Relationship implementation
```
### Data Modeling
- **Foreign Keys**: [How relationship is stored in database]
- **Join Tables**: [If applicable, for many-to-many relationships]
- **Indexing**: [Performance considerations]
### API Representation
- **REST Endpoints**: [How relationship is exposed in API]
- **GraphQL Schema**: [How relationship appears in GraphQL]
- **Serialization**: [How relationship is represented in JSON/XML]
## Examples
### Example Instances
1. **Example 1**: [Specific relationship instance]
- **Source Instance**: [Details]
- **Target Instance**: [Details]
- **Context**: [When and why this exists]
2. **Example 2**: [Another specific instance]
- **Source Instance**: [Details]
- **Target Instance**: [Details]
- **Context**: [When and why this exists]
### Usage Patterns
- **Creation Pattern**: [How relationships are established]
- **Query Pattern**: [How relationships are accessed]
- **Modification Pattern**: [How relationships are changed]
## Validation Rules
### Business Rules
- [Rule 1]: [Description and validation logic]
- [Rule 2]: [Description and validation logic]
### Technical Constraints
- [Constraint 1]: [Technical limitation or requirement]
- [Constraint 2]: [Performance or scalability consideration]
## Related Documentation
- [Source Concept Documentation]
- [Target Concept Documentation]
- [Related Relationships]
- [Implementation Details]
```
### 3. Domain Model Overview Template
```markdown
# [Domain Name] Domain Model
## Executive Summary
[Brief overview of the domain and its core concepts]
## Core Concepts Map
[Visual representation or hierarchical list of main concepts]
### Primary Entities
- **[Entity 1]**: [Brief description]
- **[Entity 2]**: [Brief description]
- **[Entity 3]**: [Brief description]
### Supporting Concepts
- **[Value Object 1]**: [Brief description]
- **[Service 1]**: [Brief description]
- **[Repository 1]**: [Brief description]
## Concept Hierarchy
```
[Top-level concepts]
├── [Category 1]
│ ├── [Sub-concept 1.1]
│ ├── [Sub-concept 1.2]
│ └── [Sub-concept 1.3]
├── [Category 2]
│ ├── [Sub-concept 2.1]
│ └── [Sub-concept 2.2]
└── [Category 3]
├── [Sub-concept 3.1]
└── [Sub-concept 3.2]
```
## Key Relationships
### Critical Relationships
1. **[Relationship 1]**: [Source] → [Target]
- [Importance and impact]
- [Business significance]
2. **[Relationship 2]**: [Source] → [Target]
- [Importance and impact]
- [Business significance]
### Relationship Patterns
- **Composition Pattern**: [Description]
- **Dependency Pattern**: [Description]
- **Association Pattern**: [Description]
## Business Rules and Constraints
### Domain Rules
1. **[Rule 1]**: [Description] - [Impact]
2. **[Rule 2]**: [Description] - [Impact]
### Invariants
- **Invariant 1**: [What must always be true]
- **Invariant 2**: [What must always be true]
## Processes and Workflows
### Core Business Processes
1. **[Process 1]**
- **Trigger**: [What starts the process]
- **Steps**: [Sequence of actions]
- **Actors**: [Who/what participates]
- **Outcomes**: [Results and side effects]
2. **[Process 2]**
- **Trigger**: [What starts the process]
- **Steps**: [Sequence of actions]
- **Actors**: [Who/what participates]
- **Outcomes**: [Results and side effects]
### State Machines
- **[Entity 1] States**: [State transitions and conditions]
- **[Entity 2] States**: [State transitions and conditions]
## Integration Points
### External Systems
- **[System 1]**: [Integration type and purpose]
- **[System 2]**: [Integration type and purpose]
### Data Flows
- **Inbound Data**: [What data comes from where]
- **Outbound Data**: [What data goes to where]
## Evolution Strategy
### Current State
- [Description of current domain model state]
### Planned Changes
- **[Change 1]**: [Description and timeline]
- **[Change 2]**: [Description and timeline]
### Migration Strategy
- [How to transition from current to future state]
## Quality Metrics
### Model Health
- **Complexity**: [Assessment of model complexity]
- **Consistency**: [How consistent the model is]
- **Completeness**: [Gaps and coverage]
### Usage Metrics
- **Most Used Concepts**: [Statistics on concept usage]
- **Relationship Density**: [How interconnected concepts are]
- **Change Frequency**: [How often concepts change]
## Related Documentation
- [Link to detailed concept documentation]
- [Link to API documentation]
- [Link to business requirements]
- [Link to technical architecture]
```
### 4. Ontology Change Log Template
```markdown
# Ontology Change Log
## Version [Version Number] - [Date]
### Summary
[Brief overview of changes in this version]
### Added Concepts
- **[Concept Name]**: [Reason for addition] - [Impact]
- **[Concept Name]**: [Reason for addition] - [Impact]
### Modified Concepts
- **[Concept Name]**: [Changes made] - [Reason for change] - [Impact]
- **[Concept Name]**: [Changes made] - [Reason for change] - [Impact]
### Removed Concepts
- **[Concept Name]**: [Reason for removal] - [Migration strategy]
### Added Relationships
- **[Relationship]**: [Source] → [Target] - [Reason]
### Modified Relationships
- **[Relationship]**: [Source] → [Target] - [Changes] - [Reason]
### Removed Relationships
- **[Relationship]**: [Source] → [Target] - [Reason] - [Impact]
### Breaking Changes
- **[Change Description]**: [Impact on dependent systems] - [Migration required]
### Migration Guide
[Step-by-step guide for adapting to these changes]
## Previous Versions
[Link to previous change logs]
```
## Specialized Templates
### API Ontology Template
```markdown
# [API Name] Ontology
## Resource Model
[List of all resources and their relationships]
## Semantic Operations
[CRUD operations and their domain meanings]
## Media Types
[Content types and their semantic significance]
## Hypermedia Controls
[HATEOAS relationships and link semantics]
```
### Database Schema Ontology Template
```markdown
# [Database Name] Schema Ontology
## Table Concepts
[Tables as domain concepts]
## Column Semantics
[Columns as concept properties]
## Constraint Logic
[Constraints as business rules]
## Trigger Semantics
[Triggers as automated processes]
```
### Event-Driven Architecture Ontology Template
```markdown
# [System Name] Event Ontology
## Event Taxonomy
[Categorization of all events]
## Event Relationships
[Causal and temporal relationships]
## Event Semantics
[Meaning and significance of events]
## Process Integration
[How events drive business processes]
```
## Template Usage Guidelines
### When to Use Each Template
1. **Concept Definition**: Use for every significant domain concept
2. **Relationship Documentation**: Use for critical or complex relationships
3. **Domain Model Overview**: Use for bounded contexts or major domains
4. **Change Log**: Use for every ontology modification
5. **Specialized Templates**: Use for specific architectural patterns
### Quality Checklist
For each documentation entry:
- [ ] Definition is clear and unambiguous
- [ ] Purpose and scope are well-defined
- [ ] Relationships are accurately described
- [ ] Examples are relevant and illustrative
- [ ] Implementation details are correct
- [ ] Related documentation is linked
- [ ] Review date is recorded
- [ ] Owner is identified
### Review Process
1. **Self-Review**: Check completeness and accuracy
2. **Peer Review**: Get feedback from other developers
3. **Domain Expert Review**: Validate with domain experts
4. **Architecture Review**: Ensure alignment with system architecture
5. **Documentation Review**: Check for clarity and usability

View File

@@ -0,0 +1,230 @@
# Ontological Patterns in Software Documentation
This document describes common ontological patterns and taxonomies found in software systems for creating effective conceptual documentation.
## Core Ontological Concepts
### Fundamental Relationship Types
**Is-A (Inheritance/Hyponymy)**
- Description: A concept is a subtype or specialization of another concept
- Example: `User` is-a `Person`, `Manager` is-a `Employee`
- Code pattern: Class inheritance, interface implementation
- Documentation: Use "extends," "inherits from," "is a type of"
**Part-Of (Mereology/Composition)**
- Description: A concept is a component or constituent of another concept
- Example: `Wheel` is-part-of `Car`, `Method` is-part-of `Class`
- Code pattern: Object composition, nested classes, containment relationships
- Documentation: Use "contains," "comprises," "consists of"
**Instance-Of (Instantiation)**
- Description: An object is an instance of a concept/class
- Example: `john_doe` is-instance-of `User`, `order_123` is-instance-of `Order`
- Code pattern: Object creation, variable assignment
- Documentation: Use "instance of," "example of," "specific case of"
**Depends-On (Dependency)**
- Description: A concept requires or relies on another concept
- Example: `OrderService` depends-on `PaymentGateway`, `Controller` depends-on `Service`
- Code pattern: Import statements, dependency injection, method calls
- Documentation: Use "requires," "uses," "relies on"
**Associates-With (Association)**
- Description: A concept has a loose semantic connection to another concept
- Example: `User` associates-with `Order`, `Product` associates-with `Category`
- Code pattern: Foreign keys, bidirectional references, event subscriptions
- Documentation: Use "related to," "connected with," "associated with"
## Common Software Ontology Patterns
### Layered Architecture Pattern
```
Presentation Layer
├── Controllers
├── Views
└── ViewModels
Business Logic Layer
├── Services
├── Domain Models
└── Business Rules
Data Access Layer
├── Repositories
├── Data Mappers
└── Database Models
Infrastructure Layer
├── External APIs
├── Message Queues
└── File Storage
```
**Relationships:**
- Controllers depend-on Services
- Services depend-on Repositories
- Repositories depend-on Database Models
- ViewModels part-of Presentation Layer
### Domain-Driven Design Pattern
**Entities**: Objects with distinct identity
- `Customer`, `Order`, `Product`
**Value Objects**: Objects defined by their attributes
- `Address`, `Money`, `DateRange`
**Aggregates**: Clusters of domain objects
- `OrderAggregate` contains `Order`, `OrderLine`, `OrderStatus`
**Repositories**: Collections of aggregate roots
- `CustomerRepository`, `OrderRepository`
**Domain Services**: Business logic that doesn't fit in entities
- `PaymentService`, `ShippingService`
### MVC Pattern Ontology
```
Model
├── Entity Models
├── View Models
└── Data Transfer Objects
View
├── Templates
├── Components
└── Layouts
Controller
├── Action Methods
├── Route Handlers
└── API Endpoints
```
**Relationships:**
- Controllers manipulate Models
- Controllers select Views
- Views display Models
- Models notify Views of changes
### Microservices Pattern Ontology
**Service Categories:**
- **API Gateway**: Entry point for external requests
- **Core Services**: Business logic services
- **Supporting Services**: Shared functionality (auth, logging)
- **Data Services**: Database operations
**Service Relationships:**
- `API Gateway` routes-to `Core Services`
- `Core Services` call `Supporting Services`
- `Services` publish-to `Message Broker`
- `Services` read-from `Configuration Service`
## Taxonomy Classification Systems
### Functional Classification
**By Purpose:**
- Business Logic Components
- Data Management Components
- Presentation Components
- Integration Components
- Infrastructure Components
**By Lifecycle:**
- Singleton Components
- Scoped Components
- Transient Components
- Request-scoped Components
### Structural Classification
**By Abstraction Level:**
- Interface Layer (highest abstraction)
- Service Layer
- Repository Layer
- Data Layer (lowest abstraction)
**By Coupling:**
- Tightly Coupled Components
- Loosely Coupled Components
- Decoupled Components
## Documentation Templates
### Concept Documentation Template
```markdown
# [Concept Name]
## Definition
Brief, clear definition of the concept
## Purpose
Why this concept exists and what problem it solves
## Characteristics
Key attributes and properties of the concept
## Relationships
- **Is-A**: [Parent concepts]
- **Part-Of**: [Containing concepts]
- **Depends-On**: [Required concepts]
- **Associates-With**: [Related concepts]
## Examples
Concrete examples of the concept in use
## Implementation Notes
Technical implementation details and considerations
```
### Relationship Documentation Template
```markdown
# [Relationship Type]: [Source] → [Target]
## Relationship Description
Description of the semantic relationship
## Cardinality
- One-to-One, One-to-Many, Many-to-Many
- Required vs Optional
## Constraints
Rules and limitations on the relationship
## Implementation
How the relationship is implemented in code
## Examples
Specific examples of the relationship
```
## Ontology Validation Rules
### Consistency Rules
1. **No Circular Inheritance**: A class cannot inherit from itself (directly or indirectly)
2. **Complete Relationships**: All referenced concepts must be defined
3. **Consistent Naming**: Use consistent terminology throughout the ontology
4. **Proper Abstraction Levels**: Related concepts should be at similar abstraction levels
### Completeness Rules
1. **Defined Concepts**: All concepts must have clear definitions
2. **Documented Relationships**: All relationships should be explicitly documented
3. **Coverage**: Important domain concepts should be represented
4. **Hierarchy**: Concepts should be organized in logical hierarchies
### Best Practices
1. **Use Standard Terminology**: Prefer established domain vocabulary
2. **Avoid Ambiguity**: Define terms clearly and consistently
3. **Maintain Separation**: Separate conceptual models from implementation details
4. **Document Rationale**: Explain why certain relationships exist
5. **Regular Review**: Update ontology as system evolves

View File

@@ -0,0 +1,114 @@
# Ontological Documentation Scripts
This directory contains utility scripts for automated concept extraction and diagram generation.
## Scripts
### extract_concepts.py
Analyzes codebases to extract domain concepts, entities, and relationships for building ontological documentation.
**Features:**
- Supports Python and JavaScript/TypeScript
- Extracts classes, functions, inheritance relationships, and imports
- Builds ontological structure with relationships (is_a, part_of, depends_on, associates_with)
- Generates JSON ontology representation
- Creates Mermaid diagrams
**Usage:**
```bash
# Analyze a single file
python extract_concepts.py /path/to/file.py
# Analyze a directory
python extract_concepts.py /path/to/codebase
# Save output to file
python extract_concepts.py /path/to/codebase > ontology.json
```
**Output:**
- JSON ontology structure
- Mermaid diagram representation
### generate_ontology_diagram.py
Generates visual representations of ontologies in various formats.
**Features:**
- Supports multiple diagram formats (Mermaid, PlantUML, GraphViz DOT, JSON-LD)
- Customizable relationship symbols
- Semantic web compatibility (JSON-LD output)
- Styled diagrams with concept type differentiation
**Usage:**
```bash
# Generate all formats
python generate_ontology_diagram.py ontology.json
# Generate specific format
python generate_ontology_diagram.py ontology.json --format mermaid
# Specify output directory
python generate_ontology_diagram.py ontology.json --output ./diagrams
# Available formats: mermaid, plantuml, dot, json-ld, all
```
**Output Examples:**
Mermaid:
```bash
python generate_ontology_diagram.py ontology.json --format mermaid
# Creates: ontology_mermaid.md
```
PlantUML:
```bash
python generate_ontology_diagram.py ontology.json --format plantuml
# Creates: ontology_plantuml.puml
```
GraphViz DOT:
```bash
python generate_ontology_diagram.py ontology.json --format dot
# Creates: ontology.dot
```
JSON-LD:
```bash
python generate_ontology_diagram.py ontology.json --format json-ld
# Creates: ontology_jsonld.json
```
## Requirements
Both scripts use only Python standard library modules:
- `ast` - Python AST parsing
- `re` - Regular expressions
- `json` - JSON processing
- `pathlib` - Path handling
- `argparse` - Command-line argument parsing
No additional dependencies required!
## Example Workflow
```bash
# 1. Extract concepts from codebase
python extract_concepts.py /path/to/codebase > ontology.json
# 2. Generate diagrams
python generate_ontology_diagram.py ontology.json --output ./docs/diagrams
# 3. Review generated documentation
ls ./docs/diagrams/
# ontology_mermaid.md
# ontology_plantuml.puml
# ontology.dot
# ontology_jsonld.json
```
## Integration with Skill
These scripts support the main [SKILL.md](../SKILL.md) by providing automated tools for concept extraction and visualization. Use them to bootstrap your ontological documentation process.

View File

@@ -0,0 +1,259 @@
#!/usr/bin/env python3
"""
Concept Extraction Script for Ontological Documentation
This script analyzes codebases to extract domain concepts, entities, and relationships
for building ontological documentation. It supports multiple programming languages
and can identify inheritance hierarchies, composition patterns, and semantic relationships.
"""
import ast
import re
import json
import sys
from pathlib import Path
from typing import Dict, List, Set, Tuple, Any
from collections import defaultdict
class ConceptExtractor:
"""Extracts ontological concepts from source code."""
def __init__(self):
self.concepts = defaultdict(dict)
self.relationships = defaultdict(list)
self.taxonomies = defaultdict(list)
def extract_from_python(self, file_path: Path) -> Dict[str, Any]:
"""Extract concepts from Python source code."""
try:
with open(file_path, 'r', encoding='utf-8') as f:
tree = ast.parse(f.read())
visitor = ClassVisitor()
visitor.visit(tree)
return {
'classes': visitor.classes,
'inheritance': visitor.inheritance,
'imports': visitor.imports,
'functions': visitor.functions
}
except Exception as e:
return {'error': str(e)}
def extract_from_javascript(self, file_path: Path) -> Dict[str, Any]:
"""Extract concepts from JavaScript/TypeScript source code."""
concepts = {
'classes': [],
'interfaces': [],
'functions': [],
'imports': []
}
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
# Extract class declarations
class_pattern = r'(?:class|interface)\s+(\w+)(?:\s+extends\s+(\w+))?'
for match in re.finditer(class_pattern, content):
class_name = match.group(1)
parent_class = match.group(2)
concepts['classes'].append({
'name': class_name,
'parent': parent_class,
'type': 'class' if 'class' in match.group(0) else 'interface'
})
# Extract function declarations
func_pattern = r'(?:function\s+(\w+)|const\s+(\w+)\s*=\s*(?:\([^)]*\)\s*)?=>|(\w+)\s*:\s*\([^)]*\)\s*=>)'
for match in re.finditer(func_pattern, content):
func_name = match.group(1) or match.group(2) or match.group(3)
if func_name:
concepts['functions'].append({'name': func_name})
# Extract imports
import_pattern = r'import\s+.*?from\s+["\']([^"\']+)["\']'
for match in re.finditer(import_pattern, content):
concepts['imports'].append({'source': match.group(1)})
except Exception as e:
concepts['error'] = str(e)
return concepts
def build_ontology(self, extracted_data: List[Dict[str, Any]]) -> Dict[str, Any]:
"""Build ontological structure from extracted data."""
ontology = {
'concepts': {},
'relationships': {
'is_a': [], # inheritance
'part_of': [], # composition
'depends_on': [], # dependencies
'associates_with': [] # loose associations
},
'taxonomies': {}
}
all_classes = []
all_functions = []
all_imports = []
# Collect all entities
for data in extracted_data:
if 'classes' in data:
all_classes.extend(data['classes'])
if 'functions' in data:
all_functions.extend(data['functions'])
if 'imports' in data:
all_imports.extend(data['imports'])
# Build concepts
for cls in all_classes:
if isinstance(cls, dict):
concept_name = cls.get('name', str(cls))
ontology['concepts'][concept_name] = {
'type': 'class',
'properties': cls
}
# Build inheritance relationships
parent = cls.get('parent')
if parent:
ontology['relationships']['is_a'].append({
'subject': concept_name,
'object': parent
})
for func in all_functions:
if isinstance(func, dict):
func_name = func.get('name', str(func))
ontology['concepts'][func_name] = {
'type': 'function',
'properties': func
}
return ontology
def generate_mermaid_diagram(self, ontology: Dict[str, Any]) -> str:
"""Generate Mermaid diagram from ontology."""
lines = ["graph TD"]
# Add concepts as nodes
for concept_name, concept_data in ontology['concepts'].items():
concept_type = concept_data.get('type', 'concept')
if concept_type == 'class':
lines.append(f" {concept_name}[({concept_name})]")
else:
lines.append(f" {concept_name}[{concept_name}]")
# Add relationships
for rel_type, relationships in ontology['relationships'].items():
for rel in relationships:
subject = rel['subject']
obj = rel['object']
if rel_type == 'is_a':
lines.append(f" {subject} --|> {obj}")
elif rel_type == 'part_of':
lines.append(f" {subject} --* {obj}")
elif rel_type == 'depends_on':
lines.append(f" {subject} -.-> {obj}")
else:
lines.append(f" {subject} --- {obj}")
return "\n".join(lines)
class ClassVisitor(ast.NodeVisitor):
"""AST visitor for Python class analysis."""
def __init__(self):
self.classes = []
self.inheritance = []
self.imports = []
self.functions = []
def visit_ClassDef(self, node):
class_info = {
'name': node.name,
'bases': [base.id for base in node.bases if hasattr(base, 'id')],
'methods': [],
'line_number': node.lineno
}
for item in node.body:
if isinstance(item, ast.FunctionDef):
class_info['methods'].append({
'name': item.name,
'args': [arg.arg for arg in item.args.args],
'line_number': item.lineno
})
self.classes.append(class_info)
# Track inheritance
for base in node.bases:
if hasattr(base, 'id'):
self.inheritance.append({
'child': node.name,
'parent': base.id
})
self.generic_visit(node)
def visit_Import(self, node):
for alias in node.names:
self.imports.append({
'module': alias.name,
'alias': alias.asname
})
self.generic_visit(node)
def visit_FunctionDef(self, node):
func_info = {
'name': node.name,
'args': [arg.arg for arg in node.args.args],
'line_number': node.lineno
}
self.functions.append(func_info)
self.generic_visit(node)
def main():
"""Main function to run concept extraction."""
if len(sys.argv) < 2:
print("Usage: python extract_concepts.py <file_or_directory_path>")
sys.exit(1)
path = Path(sys.argv[1])
extractor = ConceptExtractor()
extracted_data = []
if path.is_file():
if path.suffix == '.py':
data = extractor.extract_from_python(path)
extracted_data.append(data)
elif path.suffix in ['.js', '.ts', '.jsx', '.tsx']:
data = extractor.extract_from_javascript(path)
extracted_data.append(data)
elif path.is_dir():
for file_path in path.rglob('*'):
if file_path.is_file():
if file_path.suffix == '.py':
data = extractor.extract_from_python(file_path)
extracted_data.append(data)
elif file_path.suffix in ['.js', '.ts', '.jsx', '.tsx']:
data = extractor.extract_from_javascript(file_path)
extracted_data.append(data)
ontology = extractor.build_ontology(extracted_data)
# Output as JSON
print(json.dumps(ontology, indent=2))
# Also generate Mermaid diagram
diagram = extractor.generate_mermaid_diagram(ontology)
print("\n--- Mermaid Diagram ---")
print(diagram)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,288 @@
#!/usr/bin/env python3
"""
Ontology Diagram Generator
This script generates visual representations of ontologies in various formats
including Mermaid, PlantUML, GraphViz DOT, and JSON-LD for semantic web applications.
"""
import json
import sys
import argparse
import re
from pathlib import Path
from typing import Dict, List, Any, Optional
class OntologyDiagramGenerator:
"""Generates diagrams for ontological documentation."""
def __init__(self):
self.relationship_symbols = {
'is_a': '--|>', # Inheritance
'part_of': '--*', # Composition
'depends_on': '-.->', # Dependency
'associates_with': '---', # Association
'instance_of': '..>' # Instantiation
}
def generate_mermaid(self, ontology: Dict[str, Any]) -> str:
"""Generate Mermaid diagram from ontology."""
lines = ["graph TD"]
lines.append(" %% Ontology Diagram")
lines.append(" %% Generated from ontological documentation")
# Add styling
lines.extend([
" classDef concept fill:#e1f5fe,stroke:#01579b,stroke-width:2px",
" classDef class fill:#f3e5f5,stroke:#4a148c,stroke-width:2px",
" classDef interface fill:#e8f5e8,stroke:#1b5e20,stroke-width:2px",
" classDef function fill:#fff3e0,stroke:#e65100,stroke-width:2px"
])
# Add concepts as nodes
concept_classes = {}
for concept_name, concept_data in ontology['concepts'].items():
concept_type = concept_data.get('type', 'concept')
if concept_type == 'class':
lines.append(f" {self._safe_name(concept_name)}[({concept_name})]")
concept_classes[concept_name] = 'class'
elif concept_type == 'interface':
lines.append(f" {self._safe_name(concept_name)}[{{interface}}{concept_name}]")
concept_classes[concept_name] = 'interface'
elif concept_type == 'function':
lines.append(f" {self._safe_name(concept_name)}[{concept_name}()]")
concept_classes[concept_name] = 'function'
else:
lines.append(f" {self._safe_name(concept_name)}[{concept_name}]")
concept_classes[concept_name] = 'concept'
# Add relationships
for rel_type, relationships in ontology['relationships'].items():
symbol = self.relationship_symbols.get(rel_type, '---')
for rel in relationships:
subject = self._safe_name(rel['subject'])
obj = self._safe_name(rel['object'])
label = rel.get('label', rel_type.replace('_', ' ').title())
lines.append(f" {subject} {symbol} {obj}")
# Apply classes
for concept_name, css_class in concept_classes.items():
lines.append(f" class {self._safe_name(concept_name)} {css_class}")
return "\n".join(lines)
def generate_plantuml(self, ontology: Dict[str, Any]) -> str:
"""Generate PlantUML diagram from ontology."""
lines = ["@startuml Ontology"]
lines.append("!theme plain")
lines.append("skinparam classAttributeIconSize 0")
# Add concepts as classes
for concept_name, concept_data in ontology['concepts'].items():
concept_type = concept_data.get('type', 'concept')
if concept_type == 'class':
lines.append(f"class {concept_name} {{}}")
elif concept_type == 'interface':
lines.append(f"interface {concept_name} {{}}")
elif concept_type == 'function':
lines.append(f"object {concept_name} {{}}")
else:
lines.append(f"abstract {concept_name} {{}}")
lines.append("") # Empty line for separation
# Add relationships
for rel_type, relationships in ontology['relationships'].items():
for rel in relationships:
subject = rel['subject']
obj = rel['object']
if rel_type == 'is_a':
lines.append(f"{subject} <|-- {obj}")
elif rel_type == 'part_of':
lines.append(f"{subject} *-- {obj}")
elif rel_type == 'depends_on':
lines.append(f"{subject} ..> {obj}")
else:
lines.append(f"{subject} -- {obj}")
lines.append("@enduml")
return "\n".join(lines)
def generate_dot(self, ontology: Dict[str, Any]) -> str:
"""Generate GraphViz DOT diagram from ontology."""
lines = ["digraph Ontology {"]
lines.append(' rankdir=TB;')
lines.append(' node [shape=box, style=filled];')
lines.append(' edge [fontsize=10];')
# Add concepts as nodes
for concept_name, concept_data in ontology['concepts'].items():
concept_type = concept_data.get('type', 'concept')
# Set colors based on type
if concept_type == 'class':
color = "lightpurple"
elif concept_type == 'interface':
color = "lightgreen"
elif concept_type == 'function':
color = "lightorange"
else:
color = "lightblue"
lines.append(f' "{concept_name}" [label="{concept_name}", fillcolor="{color}"];')
lines.append("") # Empty line for separation
# Add relationships
for rel_type, relationships in ontology['relationships'].items():
for rel in relationships:
subject = rel['subject']
obj = rel['object']
label = rel.get('label', rel_type.replace('_', ' ').title())
# Set arrow styles based on relationship type
if rel_type == 'is_a':
arrow = 'empty'
elif rel_type == 'part_of':
arrow = 'diamond'
elif rel_type == 'depends_on':
arrow = 'dashed'
else:
arrow = 'normal'
lines.append(f' "{subject}" -> "{obj}" [label="{label}", arrowhead={arrow}];')
lines.append("}")
return "\n".join(lines)
def generate_json_ld(self, ontology: Dict[str, Any]) -> Dict[str, Any]:
"""Generate JSON-LD representation of ontology."""
context = {
"@context": {
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
"owl": "http://www.w3.org/2002/07/owl#",
"Concept": "rdfs:Class",
"subClassOf": {
"@id": "rdfs:subClassOf",
"@type": "@id"
},
"partOf": {
"@id": "http://example.org/ontology#partOf",
"@type": "@id"
},
"dependsOn": {
"@id": "http://example.org/ontology#dependsOn",
"@type": "@id"
}
},
"@graph": []
}
# Add concepts
for concept_name, concept_data in ontology['concepts'].items():
concept_entry = {
"@id": f"http://example.org/ontology#{concept_name}",
"@type": ["Concept"]
}
concept_type = concept_data.get('type', 'concept')
if concept_type == 'class':
concept_entry["@type"].append("owl:Class")
elif concept_type == 'interface':
concept_entry["@type"].append("owl:Class")
context["@graph"].append(concept_entry)
# Add relationships
for rel_type, relationships in ontology['relationships'].items():
for rel in relationships:
subject = rel['subject']
obj = rel['object']
if rel_type == 'is_a':
context["@graph"].append({
"@id": f"http://example.org/ontology#{subject}",
"subClassOf": f"http://example.org/ontology#{obj}"
})
elif rel_type == 'part_of':
context["@graph"].append({
"@id": f"http://example.org/ontology#{subject}",
"partOf": f"http://example.org/ontology#{obj}"
})
elif rel_type == 'depends_on':
context["@graph"].append({
"@id": f"http://example.org/ontology#{subject}",
"dependsOn": f"http://example.org/ontology#{obj}"
})
return context
def _safe_name(self, name: str) -> str:
"""Convert name to safe identifier for diagram formats."""
# Replace special characters and spaces with underscores
return re.sub(r'[^a-zA-Z0-9_]', '_', name)
def load_ontology(file_path: Path) -> Dict[str, Any]:
"""Load ontology from JSON file."""
with open(file_path, 'r', encoding='utf-8') as f:
return json.load(f)
def main():
"""Main function to generate diagrams."""
parser = argparse.ArgumentParser(description='Generate ontology diagrams')
parser.add_argument('ontology_file', help='Path to ontology JSON file')
parser.add_argument('--format', choices=['mermaid', 'plantuml', 'dot', 'json-ld', 'all'],
default='all', help='Diagram format to generate')
parser.add_argument('--output', help='Output directory (default: current directory)')
args = parser.parse_args()
ontology_path = Path(args.ontology_file)
if not ontology_path.exists():
print(f"Error: Ontology file '{ontology_path}' not found")
sys.exit(1)
ontology = load_ontology(ontology_path)
generator = OntologyDiagramGenerator()
output_dir = Path(args.output) if args.output else Path('.')
output_dir.mkdir(exist_ok=True)
formats_to_generate = ['mermaid', 'plantuml', 'dot', 'json-ld'] if args.format == 'all' else [args.format]
for format_type in formats_to_generate:
if format_type == 'mermaid':
diagram = generator.generate_mermaid(ontology)
output_file = output_dir / f"{ontology_path.stem}_mermaid.md"
with open(output_file, 'w', encoding='utf-8') as f:
f.write(f"# {ontology_path.stem} Ontology Diagram\n\n")
f.write("```mermaid\n")
f.write(diagram)
f.write("\n```")
print(f"Generated Mermaid diagram: {output_file}")
elif format_type == 'plantuml':
diagram = generator.generate_plantuml(ontology)
output_file = output_dir / f"{ontology_path.stem}_plantuml.puml"
with open(output_file, 'w', encoding='utf-8') as f:
f.write(diagram)
print(f"Generated PlantUML diagram: {output_file}")
elif format_type == 'dot':
diagram = generator.generate_dot(ontology)
output_file = output_dir / f"{ontology_path.stem}.dot"
with open(output_file, 'w', encoding='utf-8') as f:
f.write(diagram)
print(f"Generated GraphViz DOT diagram: {output_file}")
elif format_type == 'json-ld':
json_ld = generator.generate_json_ld(ontology)
output_file = output_dir / f"{ontology_path.stem}_jsonld.json"
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(json_ld, f, indent=2)
print(f"Generated JSON-LD: {output_file}")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,79 @@
# Assets
This directory contains examples and templates for ontological documentation.
## Directory Structure
```
assets/
├── examples/ # Real-world examples
│ └── ecommerce-ontology.md
└── ontology-templates/ # Reusable templates
└── domain-ontology.md
```
## Examples
### ecommerce-ontology.md
A complete example demonstrating ontological documentation for an e-commerce system.
**Includes:**
- Core concept hierarchy
- Entity relationships
- Business rules
- Implementation examples
- Documentation structure
**Use this example to:**
- Understand how to structure domain ontologies
- Learn relationship documentation patterns
- See practical implementation examples
- Get inspiration for your own domain models
## Templates
### domain-ontology.md
A ready-to-use template for documenting domain ontologies.
**Features:**
- Pre-structured sections
- Placeholder content
- Usage instructions
- Hierarchical concept organization
**How to use:**
1. Copy the template to your project
2. Replace placeholders with your domain information
3. Fill in the concept hierarchy
4. Document relationships
5. Add implementation details
## Creating Your Own Ontology
1. **Start with the template**: Copy `ontology-templates/domain-ontology.md`
2. **Review the example**: Study `examples/ecommerce-ontology.md` for structure
3. **Extract concepts**: Use `scripts/extract_concepts.py` on your codebase
4. **Document relationships**: Apply patterns from `references/ontology_patterns.md`
5. **Use standard templates**: Reference `references/documentation_templates.md`
6. **Generate diagrams**: Use `scripts/generate_ontology_diagram.py`
## Adding New Examples
When adding new examples:
1. Follow the structure shown in `ecommerce-ontology.md`
2. Include concept hierarchies
3. Document key relationships
4. Provide business rules
5. Add implementation examples
6. Link to related documentation
## Adding New Templates
When creating new templates:
1. Use placeholder syntax: `[Placeholder Name]`
2. Include usage instructions
3. Provide inline comments
4. Keep structure clear and minimal
5. Add to this README with description

View File

@@ -0,0 +1,35 @@
# Domain Ontology Template
## Overview
This template provides a structured approach to documenting domain ontologies for software systems.
## Domain: [Domain Name]
### Core Concepts
<!-- List the main domain concepts -->
```
[Domain Name]
├── Primary Entities
│ ├── Entity 1
│ ├── Entity 2
│ └── Entity 3
├── Value Objects
│ ├── Value Object 1
│ └── Value Object 2
├── Services
│ ├── Service 1
│ └── Service 2
└── Repositories
├── Repository 1
└── Repository 2
```
### Relationships
<!-- Document key relationships between concepts -->
## Usage Instructions
1. Replace [Domain Name] with your actual domain
2. Fill in the core concepts hierarchy
3. Document the relationships
4. Add specific concept details using the concept template

242
skills/pr-template/SKILL.md Normal file
View File

@@ -0,0 +1,242 @@
---
name: grey-haven-pr-template
description: Generate pull request descriptions following Grey Haven Studio standards with clear summary, motivation, implementation details, testing strategy, and comprehensive checklist. Use when creating or reviewing pull requests.
---
# Grey Haven Pull Request Template
Create comprehensive, informative pull request descriptions that help reviewers understand the changes, context, and testing approach.
## PR Structure (Standard Template)
Every pull request should follow this structure:
```markdown
## Summary
[Concise 2-4 sentence description of changes]
## Motivation
[Why these changes are needed - business value, user impact, problem solved]
## Implementation Details
[Technical approach, key decisions, trade-offs considered]
## Testing
[Test strategy: unit/integration/e2e/benchmark, manual testing steps]
## Checklist
- [ ] Code follows Grey Haven style guidelines (90 char TS, 130 char Python)
- [ ] Type hints added (Python) or types maintained (TypeScript)
- [ ] Tests added/updated (unit, integration, e2e, benchmark)
- [ ] Database migrations tested (up and down)
- [ ] Multi-tenant isolation verified (tenant_id/RLS)
- [ ] Pre-commit hooks passing
- [ ] Documentation updated
- [ ] No breaking changes (or documented with migration guide)
```
## Section Guidelines
### Summary
**Purpose**: Provide a brief, clear overview of what changed.
**Guidelines**:
- 2-4 sentences maximum
- Focus on **what** changed from user/system perspective
- Reference Linear issues: `GREY-123`
- Mention multi-tenant or RLS changes
- Use present tense
**Example**:
```markdown
## Summary
This PR adds magic link authentication using better-auth with email verification.
Users can now sign in via emailed links instead of passwords. Addresses Linear
issue GREY-234 and integrates with multi-tenant RLS policies.
```
### Motivation
**Purpose**: Explain **why** these changes are necessary.
**Guidelines**:
- Describe the problem being solved
- Explain business value or user impact
- Reference Linear issues: `GREY-123`
- Include context not obvious from code
- Mention technical debt or performance concerns
**Example**:
```markdown
## Motivation
Users reported frustration with password-based auth (GREY-234). Analytics show
35% abandon signup at password creation. Magic links offer passwordless auth,
better security, reduced support burden, and built-in email verification.
Aligns with Q1 goal of improving onboarding conversion by 20%.
```
### Implementation Details
**Purpose**: Explain **how** the changes work at technical level.
**Guidelines**:
- Mention Grey Haven tech stack: TanStack Start/Router/Query, FastAPI, Drizzle, SQLModel
- Reference Grey Haven patterns: repository pattern, multi-tenant RLS, server functions
- Note database schema changes (snake_case fields, tenant_id, indexes)
- Explain testing markers: unit, integration, e2e, benchmark
- Include code references with [file:line](file#Lline) format
**Example**:
```markdown
## Implementation Details
### Authentication Flow
1. Added magic link server function in [lib/server/functions/auth.ts:45](lib/server/functions/auth.ts#L45)
2. Created email template with Resend integration
3. Implemented token verification route at `/auth/verify`
### Key Changes
- **Server Functions**: New `sendMagicLink` and `verifyMagicLink` with tenant context
- **Database Schema**: Added `magic_link_tokens` table (snake_case, tenant_id, RLS)
- **Routes**: Magic link verification page with TanStack Router navigation
### Design Decisions
- Token expiry: 15 minutes (security vs UX balance)
- Single-use tokens with unique constraint
- Tenant isolation via RLS policies
- Email via Resend (better deliverability)
```
### Testing
**Purpose**: Describe testing strategy and manual testing steps.
**Guidelines**:
- List testing markers used: unit, integration, e2e, benchmark
- Include manual testing steps
- Mention test coverage
- Note any edge cases tested
**Example**:
```markdown
## Testing
### Automated Tests
- **Unit tests** (18 new): Token generation, validation, expiry logic
- **Integration tests** (6 new): Email sending, database operations
- **E2e tests** (3 new): Full magic link flow with Playwright
### Manual Testing
1. Request magic link from login page
2. Verify email received within 30 seconds
3. Click link in email
4. Verify successful auth and redirect
5. Test expired token (wait 16 minutes)
6. Test single-use token (use link twice)
### Coverage
- New code: 94% coverage
- Critical paths: 100% coverage
```
## Checklist
Use this checklist before requesting review:
- [ ] Code follows Grey Haven style guidelines (90 char TS, 130 char Python)
- [ ] Type hints added (Python) or types maintained (TypeScript)
- [ ] Tests added/updated (unit, integration, e2e, benchmark)
- [ ] Test coverage meets 80% threshold
- [ ] Database migrations tested (up and down)
- [ ] Multi-tenant isolation verified (tenant_id/RLS)
- [ ] Pre-commit hooks passing (Prettier, Ruff, mypy)
- [ ] Documentation updated (README, API docs)
- [ ] No breaking changes (or documented with migration guide)
- [ ] Linear issue referenced in description
- [ ] Commit messages follow commitlint format
- [ ] Virtual environment activated (Python projects)
## Supporting Documentation
All supporting files are under 500 lines per Anthropic best practices:
- **[examples/](examples/)** - Complete PR examples
- [feature-pr.md](examples/feature-pr.md) - Feature PR example
- [bugfix-pr.md](examples/bugfix-pr.md) - Bug fix PR example
- [refactor-pr.md](examples/refactor-pr.md) - Refactoring PR example
- [INDEX.md](examples/INDEX.md) - Examples navigation
- **[templates/](templates/)** - Copy-paste ready templates
- [feature-template.md](templates/feature-template.md) - Feature PR template
- [bugfix-template.md](templates/bugfix-template.md) - Bug fix PR template
- [database-template.md](templates/database-template.md) - Database PR template
- **[checklists/](checklists/)** - Pre-PR validation
- [pr-checklist.md](checklists/pr-checklist.md) - Comprehensive PR checklist
## Special Cases
### Breaking Changes
Always include migration guide:
```markdown
## Breaking Changes
**BREAKING:** User IDs are now UUIDs instead of sequential integers.
### Migration Guide
1. Update API clients to handle UUID format
2. Run database migration: `bun run db:migrate`
3. Update any hardcoded user IDs in tests
4. Verify multi-tenant isolation still works
### Timeline
- Migration available: 2025-01-15
- Required by: 2025-02-01
```
### Database Migrations
Include up and down testing:
```markdown
## Database Migration
### Changes
- Add `tenant_id` column to `organizations` table
- Create RLS policies for tenant isolation
- Add index on `tenant_id`
### Testing
- ✅ Migration up: Successful
- ✅ Migration down: Successful
- ✅ Data backfill: Verified for 1000+ records
- ✅ RLS policies: Tested with different tenants
```
## When to Apply This Skill
Use this skill when:
- Creating pull requests in Grey Haven projects
- Reviewing pull requests for completeness
- Onboarding new developers to PR standards
- Creating PR templates for new repos
- Documenting complex features or refactorings
## Template Reference
These standards come from Grey Haven's actual templates:
- **cvi-template**: TanStack Start + React 19
- **cvi-backend-template**: FastAPI + SQLModel
## Critical Reminders
1. **Summary: 2-4 sentences** - concise overview
2. **Motivation: explain why** - business value, user impact
3. **Implementation: explain how** - technical approach with file references
4. **Testing: comprehensive** - automated + manual steps
5. **Checklist: complete** - all items checked before review
6. **Linear issues: reference** - GREY-123 format
7. **Multi-tenant: verify** - tenant_id and RLS mentioned
8. **Breaking changes: document** - migration guide required
9. **Database: test migrations** - up and down
10. **Code references: clickable** - use [file:line](file#Lline) format

View File

@@ -0,0 +1,73 @@
# Pull Request Checklist
**Use before requesting PR review.**
## Code Quality
- [ ] Code follows Grey Haven style guidelines (90 char TS, 130 char Python)
- [ ] Type hints added (Python) or types maintained (TypeScript)
- [ ] No console.log or print statements (except intentional logging)
- [ ] Variable and function names are descriptive
- [ ] Comments explain **why**, not **what**
## Testing
- [ ] Unit tests added/updated
- [ ] Integration tests added/updated (if applicable)
- [ ] E2e tests added/updated (if applicable)
- [ ] Test coverage meets 80% threshold
- [ ] Manual testing completed
- [ ] Edge cases tested
## Database (if applicable)
- [ ] Migrations tested (up and down)
- [ ] snake_case field names used
- [ ] tenant_id included with RLS policies
- [ ] Indexes added for foreign keys
- [ ] Migration includes rollback strategy
## Multi-Tenant (if applicable)
- [ ] tenant_id filtering in all queries
- [ ] RLS policies created/updated
- [ ] Tenant isolation verified with tests
- [ ] JWT claims include tenant_id
## Documentation
- [ ] README updated (if needed)
- [ ] API documentation updated (if applicable)
- [ ] Inline code comments added for complex logic
- [ ] Migration guide provided (if breaking changes)
## Pre-Commit
- [ ] Pre-commit hooks passing
- [ ] Prettier/Ruff formatting applied
- [ ] ESLint/mypy checks passing
- [ ] Virtual environment activated (Python projects)
## Pull Request Description
- [ ] Summary: 2-4 sentences describing changes
- [ ] Motivation: Why changes are needed
- [ ] Implementation: Technical approach with file references
- [ ] Testing: Automated and manual testing steps
- [ ] Linear issue referenced (GREY-123)
- [ ] Breaking changes documented (if any)
## Security
- [ ] No sensitive data in code (passwords, keys, tokens)
- [ ] Input validation implemented
- [ ] SQL injection prevented (using ORM)
- [ ] XSS prevented (proper escaping)
- [ ] Rate limiting considered (if API changes)
## Final Checks
- [ ] Commit messages follow commitlint format
- [ ] No merge conflicts
- [ ] Branch is up to date with main
- [ ] All checklist items completed

View File

@@ -0,0 +1,53 @@
## Summary
[2-4 sentences describing what was added and why]
## Motivation
[Explain the problem being solved and business value]
- **Problem**: [Describe user pain point or business need]
- **Impact**: [Expected user/business benefit]
- **Linear Issue**: GREY-XXX
## Implementation Details
### Key Changes
- **[Component/Module]**: [What changed]
- **[Database/Schema]**: [Schema changes with snake_case, tenant_id]
- **[Routes/API]**: [New endpoints or routes]
### Design Decisions
- **Decision 1**: [Rationale]
- **Decision 2**: [Rationale]
### Multi-Tenant Considerations
- tenant_id filtering in [location]
- RLS policies on [tables]
- Tested with multiple tenants
## Testing
### Automated Tests
- **Unit tests** (X new): [What's tested]
- **Integration tests** (X new): [What's tested]
- **E2e tests** (X new): [What's tested]
### Manual Testing
1. [Step 1]
2. [Step 2]
3. [Step 3]
### Coverage
- New code: X% coverage
- Critical paths: 100% coverage
## Checklist
- [ ] Code follows Grey Haven style guidelines
- [ ] Type hints added/maintained
- [ ] Tests added/updated (80%+ coverage)
- [ ] Database migrations tested
- [ ] Multi-tenant isolation verified
- [ ] Pre-commit hooks passing
- [ ] Documentation updated
- [ ] No breaking changes

View File

@@ -0,0 +1,327 @@
---
name: grey-haven-project-structure
description: Organize Grey Haven projects following standard structures for TanStack Start (frontend) and FastAPI (backend). Use when creating new projects, organizing files, or refactoring project layout.
---
# Grey Haven Project Structure
Follow Grey Haven Studio's standardized project structures for **TypeScript/React** (TanStack Start) and **Python/FastAPI** projects.
## Frontend Structure (TanStack Start + React 19)
Based on `cvi-template` - TanStack Start, React 19, Drizzle, Better-auth.
### Directory Layout
```
project-root/
├── .claude/ # Claude Code configuration
├── .github/workflows/ # GitHub Actions (CI/CD)
├── public/ # Static assets
├── src/
│ ├── routes/ # TanStack Router file-based routes
│ │ ├── __root.tsx # Root layout
│ │ ├── index.tsx # Homepage
│ │ ├── _authenticated/ # Protected routes group
│ │ │ ├── _layout.tsx # Auth layout wrapper
│ │ │ ├── dashboard.tsx # /dashboard
│ │ │ └── profile.tsx # /profile
│ │ └── auth/ # Auth routes
│ │ ├── login.tsx # /auth/login
│ │ └── signup.tsx # /auth/signup
│ ├── lib/
│ │ ├── components/ # React components
│ │ │ ├── ui/ # Shadcn UI (PascalCase)
│ │ │ ├── auth/ # Auth components
│ │ │ ├── layout/ # Layout components
│ │ │ └── shared/ # Shared components
│ │ ├── server/ # Server-side code
│ │ │ ├── schema/ # Drizzle schema (snake_case)
│ │ │ ├── functions/ # Server functions
│ │ │ ├── auth.ts # Better-auth config
│ │ │ └── db.ts # Database connections
│ │ ├── config/ # Configuration
│ │ │ ├── env.ts # Environment validation
│ │ │ └── auth.ts # Auth configuration
│ │ ├── middleware/ # Route middleware
│ │ ├── hooks/ # Custom React hooks (use-*)
│ │ ├── utils/ # Utility functions
│ │ └── types/ # TypeScript types
│ └── tests/
│ ├── unit/ # Vitest unit tests
│ ├── integration/ # Vitest integration tests
│ └── e2e/ # Playwright E2E tests
├── migrations/ # Drizzle migrations
├── .env.example # Example environment variables
├── .prettierrc # Prettier (90 chars, double quotes)
├── .eslintrc # ESLint (any allowed, strict off)
├── tsconfig.json # TypeScript (~/* path alias)
├── commitlint.config.cjs # Commitlint (100 char header)
├── drizzle.config.ts # Drizzle ORM config
├── vite.config.ts # Vite configuration
├── vitest.config.ts # Vitest test configuration
├── package.json # Dependencies (use bun!)
└── README.md # Project documentation
```
### Key Frontend Patterns
#### Path Imports - Always Use ~/* Alias
```typescript
// ✅ Correct - Use ~/* path alias
import { Button } from "~/lib/components/ui/button";
import { getUserById } from "~/lib/server/functions/users";
import { env } from "~/lib/config/env";
import { useAuth } from "~/lib/hooks/use-auth";
// ❌ Wrong - Relative paths
import { Button } from "../../lib/components/ui/button";
```
#### File Naming Conventions
- **Components**: PascalCase (`UserProfile.tsx`, `LoginForm.tsx`)
- **Routes**: lowercase with hyphens (`user-profile.tsx`, `auth/login.tsx`)
- **Utilities**: camelCase or kebab-case (`formatDate.ts`, `use-auth.ts`)
- **Server functions**: camelCase (`auth.ts`, `users.ts`)
- **Schema files**: plural lowercase (`users.ts`, `organizations.ts`)
#### Component Structure Order
```typescript
import { useState } from "react"; // 1. External imports
import { useQuery } from "@tanstack/react-query";
import { Button } from "~/lib/components/ui/button"; // 2. Internal imports
import { getUserById } from "~/lib/server/functions/users";
interface UserProfileProps { // 3. Types/Interfaces
userId: string;
}
export default function UserProfile({ userId }: UserProfileProps) { // 4. Component
const [editing, setEditing] = useState(false); // 5. State hooks
const { data: user } = useQuery({ // 6. Queries/Mutations
queryKey: ["user", userId],
queryFn: () => getUserById(userId),
staleTime: 60000,
});
const handleSave = () => { // 7. Event handlers
// ...
};
return ( // 8. JSX
<div>
<h1>{user?.full_name}</h1>
<Button onClick={handleSave}>Save</Button>
</div>
);
}
```
## Backend Structure (FastAPI + Python)
Based on `cvi-backend-template` - FastAPI, SQLModel, Alembic.
### Directory Layout
```
project-root/
├── .github/workflows/ # GitHub Actions
├── app/
│ ├── __init__.py
│ ├── main.py # FastAPI app entry point
│ ├── routers/ # API routers (endpoints)
│ │ ├── __init__.py
│ │ ├── auth.py # /auth routes
│ │ ├── users.py # /users routes
│ │ └── health.py # /health routes
│ ├── services/ # Business logic layer
│ │ ├── __init__.py
│ │ ├── user_service.py
│ │ ├── auth_service.py
│ │ └── billing_service.py
│ ├── db/ # Database layer
│ │ ├── __init__.py
│ │ ├── models/ # SQLModel models (snake_case)
│ │ │ ├── __init__.py
│ │ │ ├── user.py
│ │ │ ├── tenant.py
│ │ │ └── organization.py
│ │ ├── repositories/ # Data access layer
│ │ │ ├── __init__.py
│ │ │ ├── base.py # Base repository
│ │ │ └── user_repository.py
│ │ └── session.py # Database sessions
│ ├── schemas/ # Pydantic schemas
│ │ ├── __init__.py
│ │ ├── user.py # UserCreate, UserResponse
│ │ ├── auth.py # AuthRequest, AuthResponse
│ │ └── common.py # Shared schemas
│ ├── middleware/ # FastAPI middleware
│ │ ├── __init__.py
│ │ ├── auth.py # JWT verification
│ │ └── tenant.py # Tenant context
│ ├── core/ # Core configuration
│ │ ├── __init__.py
│ │ ├── config.py # Settings (Doppler)
│ │ ├── security.py # Password hashing, JWT
│ │ └── deps.py # FastAPI dependencies
│ └── utils/ # Utility functions
│ ├── __init__.py
│ └── format.py
├── tests/ # Pytest tests
│ ├── __init__.py
│ ├── unit/ # @pytest.mark.unit
│ ├── integration/ # @pytest.mark.integration
│ └── e2e/ # @pytest.mark.e2e
├── alembic/ # Alembic migrations
│ ├── versions/
│ └── env.py
├── .env.example # Example environment variables
├── .env # Local environment (gitignored)
├── pyproject.toml # Ruff, mypy, pytest config
├── alembic.ini # Alembic configuration
├── Taskfile.yml # Task runner commands
├── requirements.txt # Production dependencies
├── requirements-dev.txt # Development dependencies
└── README.md # Project documentation
```
### Key Backend Patterns
#### Import Organization (Automatic with Ruff)
```python
"""Module docstring describing purpose."""
# 1. Standard library imports
import os
from datetime import datetime
from typing import Optional
from uuid import UUID
# 2. Third-party imports
from fastapi import APIRouter, Depends, HTTPException
from sqlmodel import select
# 3. Local imports
from app.db.models.user import User
from app.db.repositories.user_repository import UserRepository
from app.schemas.user import UserCreate, UserResponse
```
#### File Naming Conventions
- **Modules**: snake_case (`user_service.py`, `auth_middleware.py`)
- **Models**: PascalCase class, snake_case file (`User` in `user.py`)
- **Tests**: `test_` prefix (`test_user_service.py`)
#### Repository Pattern (with Tenant Isolation)
```python
# app/db/repositories/base.py
from typing import Generic, TypeVar, Optional
from uuid import UUID
from sqlmodel import select
from sqlalchemy.ext.asyncio import AsyncSession
T = TypeVar("T")
class BaseRepository(Generic[T]):
"""Base repository with CRUD and tenant isolation."""
def __init__(self, session: AsyncSession, model: type[T]):
self.session = session
self.model = model
async def get_by_id(self, id: UUID, tenant_id: UUID) -> Optional[T]:
"""Get by ID with automatic tenant filtering."""
result = await self.session.execute(
select(self.model)
.where(self.model.id == id)
.where(self.model.tenant_id == tenant_id)
)
return result.scalar_one_or_none()
```
#### Service Layer Pattern
```python
# app/services/user_service.py
from uuid import UUID
from app.db.repositories.user_repository import UserRepository
from app.schemas.user import UserCreate, UserResponse
class UserService:
"""User business logic."""
def __init__(self, user_repo: UserRepository):
self.user_repo = user_repo
async def create_user(self, data: UserCreate, tenant_id: UUID) -> UserResponse:
"""Create new user with validation."""
existing = await self.user_repo.get_by_email(data.email_address, tenant_id)
if existing:
raise ValueError("Email already registered")
user = await self.user_repo.create(data, tenant_id)
return UserResponse.model_validate(user)
```
## Supporting Documentation
All supporting files are under 500 lines per Anthropic best practices:
- **[examples/](examples/)** - Complete project examples
- [frontend-directory-structure.md](examples/frontend-directory-structure.md) - Full TanStack Start structure
- [backend-directory-structure.md](examples/backend-directory-structure.md) - Full FastAPI structure
- [component-structure.md](examples/component-structure.md) - React component patterns
- [repository-pattern.md](examples/repository-pattern.md) - Repository with tenant isolation
- [service-pattern.md](examples/service-pattern.md) - Service layer examples
- [INDEX.md](examples/INDEX.md) - Examples navigation
- **[reference/](reference/)** - Structure references
- [file-naming.md](reference/file-naming.md) - Naming conventions
- [import-organization.md](reference/import-organization.md) - Import ordering rules
- [path-aliases.md](reference/path-aliases.md) - Path alias configuration
- [INDEX.md](reference/INDEX.md) - Reference navigation
- **[templates/](templates/)** - Copy-paste ready templates
- [tanstack-start-project/](templates/tanstack-start-project/) - Frontend scaffold
- [fastapi-project/](templates/fastapi-project/) - Backend scaffold
- **[checklists/](checklists/)** - Structure checklists
- [project-setup-checklist.md](checklists/project-setup-checklist.md) - New project setup
- [refactoring-checklist.md](checklists/refactoring-checklist.md) - Structure refactoring
## When to Apply This Skill
Use this skill when:
- Creating new Grey Haven projects
- Organizing files in existing projects
- Refactoring project layout
- Setting up directory structure
- Deciding where to place new files
- Onboarding new team members to project structure
## Template Reference
These patterns are from Grey Haven's production templates:
- **Frontend**: cvi-template (TanStack Start + React 19)
- **Backend**: cvi-backend-template (FastAPI + Python)
## Critical Reminders
1. **Path aliases**: Always use ~/* for TypeScript imports
2. **File naming**: Components PascalCase, modules snake_case
3. **Import order**: External → Internal → Local
4. **Component structure**: Imports → Types → Component → Hooks → Handlers → JSX
5. **Tenant isolation**: Repository pattern includes tenant_id filtering
6. **Database fields**: snake_case in schema files (NOT camelCase)
7. **Test organization**: unit/, integration/, e2e/ directories
8. **Configuration**: Doppler for all environment variables
9. **Routes**: TanStack file-based routing in src/routes/
10. **Backend layers**: Routers → Services → Repositories → Models

View File

@@ -0,0 +1,165 @@
# Project Setup Checklist
**Use when creating new Grey Haven projects.**
## Initial Setup
### Choose Template
- [ ] Frontend: Use cvi-template (TanStack Start + React 19)
- [ ] Backend: Use cvi-backend-template (FastAPI + Python)
- [ ] Clone from Grey Haven GitHub organization
- [ ] Remove .git directory and re-initialize
### Environment Configuration
- [ ] Copy .env.example to .env
- [ ] Set up Doppler project (dev, test, staging, production)
- [ ] Add required secrets to Doppler
- [ ] Test Doppler access: `doppler run --config dev -- echo "Working"`
- [ ] Add .env to .gitignore (verify)
## Frontend Setup (TanStack Start)
### Directory Structure
- [ ] Verify src/routes/ structure (file-based routing)
- [ ] Verify src/lib/ organization (components, server, config, etc.)
- [ ] Verify public/ for static assets
- [ ] Verify migrations/ for Drizzle migrations
### Configuration Files
- [ ] Update tsconfig.json (verify ~/* path alias)
- [ ] Update package.json (project name, description)
- [ ] Verify .prettierrc (90 char line length, double quotes)
- [ ] Verify .eslintrc (any allowed, strict off)
- [ ] Update commitlint.config.cjs (100 char header)
- [ ] Update vite.config.ts (project-specific settings)
- [ ] Update vitest.config.ts (coverage thresholds >80%)
### Dependencies
- [ ] Run `bun install` (NOT npm!)
- [ ] Verify Drizzle ORM installed
- [ ] Verify better-auth installed
- [ ] Verify TanStack Start/Query/Router installed
- [ ] Verify Shadcn UI components
### Database Setup
- [ ] Create PostgreSQL database (PlanetScale)
- [ ] Add DATABASE_URL to Doppler
- [ ] Add DATABASE_URL_ADMIN to Doppler
- [ ] Generate initial migration: `bun run db:generate`
- [ ] Apply migration: `doppler run --config dev -- bun run db:migrate`
### Authentication
- [ ] Configure better-auth in src/lib/server/auth.ts
- [ ] Add BETTER_AUTH_SECRET to Doppler
- [ ] Add BETTER_AUTH_URL to Doppler
- [ ] Set up OAuth providers (if needed)
- [ ] Test auth flow locally
## Backend Setup (FastAPI)
### Directory Structure
- [ ] Verify app/ structure (routers, services, db, etc.)
- [ ] Verify tests/ organization (unit, integration, e2e)
- [ ] Verify alembic/ for migrations
### Configuration Files
- [ ] Update pyproject.toml (project name, dependencies)
- [ ] Verify Ruff configuration (130 char line length)
- [ ] Verify mypy configuration (strict type checking)
- [ ] Verify pytest configuration (markers, coverage >80%)
- [ ] Update alembic.ini (database URL from Doppler)
- [ ] Create Taskfile.yml (common commands)
### Dependencies
- [ ] Create virtual environment: `python -m venv venv`
- [ ] Activate venv: `source venv/bin/activate`
- [ ] Install deps: `pip install -r requirements.txt`
- [ ] Install dev deps: `pip install -r requirements-dev.txt`
- [ ] Verify SQLModel installed
- [ ] Verify FastAPI installed
- [ ] Verify Alembic installed
### Database Setup
- [ ] Create PostgreSQL database (PlanetScale)
- [ ] Add DATABASE_URL to Doppler
- [ ] Add DATABASE_URL_ADMIN to Doppler
- [ ] Generate initial migration: `alembic revision --autogenerate -m "Initial"`
- [ ] Apply migration: `doppler run --config dev -- alembic upgrade head`
## GitHub Setup
### Repository
- [ ] Create GitHub repository
- [ ] Push initial commit
- [ ] Set up branch protection rules (main branch)
- [ ] Require PR before merging
- [ ] Require 1 approval
- [ ] Require status checks to pass
### GitHub Actions
- [ ] Add DOPPLER_TOKEN to repository secrets
- [ ] Add CLOUDFLARE_API_TOKEN to repository secrets (if deploying)
- [ ] Verify .github/workflows/ci.yml
- [ ] Verify .github/workflows/deploy.yml
- [ ] Test CI/CD pipeline
## Testing
### Frontend Testing
- [ ] Run unit tests: `bun test`
- [ ] Run integration tests: `bun test:integration`
- [ ] Run E2E tests: `bun test:e2e`
- [ ] Verify coverage >80%
### Backend Testing
- [ ] Run unit tests: `pytest -m unit`
- [ ] Run integration tests: `pytest -m integration`
- [ ] Run E2E tests: `pytest -m e2e`
- [ ] Verify coverage >80%
## Documentation
### README.md
- [ ] Update project name and description
- [ ] Document getting started steps
- [ ] Document Doppler setup
- [ ] Document database setup
- [ ] Document testing commands
- [ ] Document deployment process
### Additional Docs
- [ ] Create API documentation (if applicable)
- [ ] Document architecture decisions
- [ ] Document multi-tenant setup
- [ ] Create onboarding guide
## Deployment
### Cloudflare Workers (Frontend)
- [ ] Create wrangler.toml files (dev, staging, production)
- [ ] Create KV namespaces
- [ ] Create R2 buckets (if needed)
- [ ] Configure custom domains
- [ ] Test deployment to staging
### Production Readiness
- [ ] Set up monitoring (Sentry, Axiom)
- [ ] Configure error tracking
- [ ] Set up performance monitoring
- [ ] Configure rate limiting
- [ ] Set up backup strategy
- [ ] Document rollback procedure
## Post-Setup
### Team Onboarding
- [ ] Share Doppler access with team
- [ ] Share repository access
- [ ] Document local setup process
- [ ] Schedule team walkthrough
### Maintenance
- [ ] Set up dependency update schedule
- [ ] Set up security scanning
- [ ] Schedule regular code reviews
- [ ] Document support procedures

View File

@@ -0,0 +1,48 @@
# Project Structure Examples
Complete project structure examples for Grey Haven applications.
## Available Examples
### [frontend-directory-structure.md](frontend-directory-structure.md)
Full TanStack Start project structure.
- Complete directory tree with annotations
- File-based routing examples
- Component organization patterns
- Server functions structure
### [backend-directory-structure.md](backend-directory-structure.md)
Full FastAPI project structure.
- Complete directory tree with annotations
- Routers, services, repositories layers
- Database models and migrations
- Testing organization
### [component-structure.md](component-structure.md)
React component organization patterns.
- Import ordering
- Hook usage patterns
- Event handler organization
- JSX structure
### [repository-pattern.md](repository-pattern.md)
Repository pattern with tenant isolation.
- Base repository implementation
- Specific repository examples
- Tenant filtering patterns
- Async/await patterns
### [service-pattern.md](service-pattern.md)
Service layer examples.
- Business logic organization
- Service dependencies
- Error handling
- Validation patterns
## Quick Reference
**Need frontend structure?** → [frontend-directory-structure.md](frontend-directory-structure.md)
**Need backend structure?** → [backend-directory-structure.md](backend-directory-structure.md)
**Need component patterns?** → [component-structure.md](component-structure.md)
**Need repository patterns?** → [repository-pattern.md](repository-pattern.md)
**Need service patterns?** → [service-pattern.md](service-pattern.md)

View File

@@ -0,0 +1,32 @@
# Project Structure Reference
Configuration references and naming conventions for Grey Haven projects.
## Available References
### [file-naming.md](file-naming.md)
File naming conventions for both stacks.
- TypeScript/React conventions
- Python/FastAPI conventions
- Test file naming
- Configuration file naming
### [import-organization.md](import-organization.md)
Import ordering and organization rules.
- TypeScript import order
- Python import order (PEP 8)
- Ruff automatic sorting
- ESLint import rules
### [path-aliases.md](path-aliases.md)
Path alias configuration and usage.
- tsconfig.json setup (~/* alias)
- Vite configuration
- Import examples
- Common pitfalls
## Quick Reference
**Need naming rules?** → [file-naming.md](file-naming.md)
**Need import order?** → [import-organization.md](import-organization.md)
**Need path aliases?** → [path-aliases.md](path-aliases.md)