Initial commit
This commit is contained in:
55
skills/documentation-architecture/reference/INDEX.md
Normal file
55
skills/documentation-architecture/reference/INDEX.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Documentation Reference
|
||||
|
||||
Quick-lookup guides for OpenAPI patterns, Mermaid diagrams, and documentation quality standards.
|
||||
|
||||
## Available References
|
||||
|
||||
### [OpenAPI 3.1 Patterns](openapi-patterns.md)
|
||||
|
||||
Comprehensive OpenAPI 3.1 specification patterns for Grey Haven stack.
|
||||
|
||||
**Covers**: Complete schemas, authentication (JWT/OAuth2/API Key), error responses, pagination, multi-language examples, webhooks, FastAPI integration
|
||||
|
||||
**Use for**: API documentation generation, OpenAPI schema creation, endpoint documentation standards
|
||||
|
||||
---
|
||||
|
||||
### [Mermaid Diagram Templates](mermaid-diagrams.md)
|
||||
|
||||
Complete templates for all Mermaid diagram types with Grey Haven examples.
|
||||
|
||||
**Covers**: System architecture, sequence diagrams, data flow, ER diagrams, state machines, deployment diagrams, class diagrams
|
||||
|
||||
**Use for**: Architecture documentation, visualizing data flows, documenting state transitions, database schemas
|
||||
|
||||
---
|
||||
|
||||
### [Documentation Standards](documentation-standards.md)
|
||||
|
||||
Quality standards and best practices for technical documentation.
|
||||
|
||||
**Covers**: Writing style, code examples, API documentation templates, function documentation (JSDoc/docstrings), README structure, quality checklist
|
||||
|
||||
**Use for**: Ensuring consistency, setting quality thresholds, creating maintainable documentation
|
||||
|
||||
---
|
||||
|
||||
## Common Patterns
|
||||
|
||||
1. **API Documentation**: Use OpenAPI patterns + documentation standards
|
||||
2. **Architecture Docs**: Use Mermaid diagrams + ADR template from standards
|
||||
3. **Coverage Validation**: Use standards checklist + automated tools
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Need | Reference | Key Section |
|
||||
|------|-----------|-------------|
|
||||
| API endpoint docs | [openapi-patterns.md](openapi-patterns.md) | Endpoint Documentation Template |
|
||||
| System diagrams | [mermaid-diagrams.md](mermaid-diagrams.md) | Architecture Diagrams |
|
||||
| Quality checklist | [documentation-standards.md](documentation-standards.md) | Quality Checklist |
|
||||
| Code examples | [documentation-standards.md](documentation-standards.md) | Code Examples |
|
||||
| Error responses | [openapi-patterns.md](openapi-patterns.md) | Error Response Schema |
|
||||
|
||||
---
|
||||
|
||||
Related: [Examples](../examples/INDEX.md) | [Templates](../templates/) | [Return to Agent](../docs-architect.md)
|
||||
@@ -0,0 +1,496 @@
|
||||
# Documentation Standards and Quality Guidelines
|
||||
|
||||
Comprehensive standards for creating high-quality technical documentation for Grey Haven projects.
|
||||
|
||||
## Documentation Principles
|
||||
|
||||
### 1. Progressive Disclosure
|
||||
Start with overview, provide details on demand.
|
||||
|
||||
**Good**:
|
||||
```markdown
|
||||
# User Authentication
|
||||
|
||||
Quick overview: Our authentication uses JWT tokens with refresh rotation.
|
||||
|
||||
## Getting Started
|
||||
[Simple example]
|
||||
|
||||
## Advanced Usage
|
||||
[Detailed configuration options]
|
||||
|
||||
## Security Considerations
|
||||
[Deep dive into security]
|
||||
```
|
||||
|
||||
### 2. Show, Don't Tell
|
||||
Use code examples instead of lengthy explanations.
|
||||
|
||||
**Bad**: "To create a user, you need to instantiate a User class with email and password, then call the save method."
|
||||
|
||||
**Good**:
|
||||
```python
|
||||
user = User(email="user@example.com", password="secure123")
|
||||
user.save()
|
||||
```
|
||||
|
||||
### 3. Keep It Current
|
||||
Documentation that's out of date is worse than no documentation.
|
||||
|
||||
Use automation:
|
||||
- Auto-generate API docs from code
|
||||
- CI/CD validation (fail if docs outdated)
|
||||
- Link to code for truth source
|
||||
|
||||
## Writing Style
|
||||
|
||||
### Voice and Tone
|
||||
|
||||
**Use Active Voice**:
|
||||
- ❌ "The order will be processed by the system"
|
||||
- ✅ "The system processes the order"
|
||||
|
||||
**Be Direct**:
|
||||
- ❌ "It might be a good idea to consider using..."
|
||||
- ✅ "Use X when Y"
|
||||
|
||||
**Avoid Jargon**:
|
||||
- ❌ "Leverage our enterprise-grade synergistic platform"
|
||||
- ✅ "Use our API to manage users"
|
||||
|
||||
### Structure
|
||||
|
||||
**Every Page Should Have**:
|
||||
1. **Title**: Clear, descriptive
|
||||
2. **Summary**: 1-2 sentence overview
|
||||
3. **Prerequisites**: What user needs to know/have
|
||||
4. **Step-by-Step**: Numbered instructions
|
||||
5. **Code Examples**: Working, copy-paste ready
|
||||
6. **Troubleshooting**: Common errors and solutions
|
||||
7. **Next Steps**: Where to go next
|
||||
|
||||
### Code Examples
|
||||
|
||||
**Always Include**:
|
||||
- ✅ Complete, working examples
|
||||
- ✅ Expected output/result
|
||||
- ✅ Error handling
|
||||
- ✅ Comments explaining why, not what
|
||||
|
||||
**Example Template**:
|
||||
```python
|
||||
# Create a new user
|
||||
# Requires: Admin authentication
|
||||
# Returns: User object or raises ValidationError
|
||||
|
||||
try:
|
||||
user = User.objects.create(
|
||||
email="user@example.com",
|
||||
password="secure123",
|
||||
role="member" # Default role for new users
|
||||
)
|
||||
print(f"User created: {user.id}")
|
||||
except ValidationError as e:
|
||||
print(f"Validation failed: {e.message}")
|
||||
```
|
||||
|
||||
## API Documentation Standards
|
||||
|
||||
### Endpoint Documentation Template
|
||||
|
||||
```markdown
|
||||
## POST /api/v1/users
|
||||
|
||||
Create a new user account.
|
||||
|
||||
### Authentication
|
||||
Requires: Admin JWT token in Authorization header
|
||||
|
||||
### Request
|
||||
|
||||
**Headers**:
|
||||
- `Authorization: Bearer <token>` (required)
|
||||
- `Content-Type: application/json` (required)
|
||||
|
||||
**Body**:
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| email | string | Yes | Valid email address |
|
||||
| password | string | Yes | Min 8 characters |
|
||||
| role | string | No | Default: "member" |
|
||||
|
||||
**Example**:
|
||||
```json
|
||||
{
|
||||
"email": "user@example.com",
|
||||
"password": "secure123",
|
||||
"role": "member"
|
||||
}
|
||||
```
|
||||
|
||||
### Response
|
||||
|
||||
**Success (201 Created)**:
|
||||
```json
|
||||
{
|
||||
"id": "usr_123abc",
|
||||
"email": "user@example.com",
|
||||
"role": "member",
|
||||
"created_at": "2024-01-15T10:30:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
**Errors**:
|
||||
- `400 Bad Request`: Validation failed (email invalid, password too short)
|
||||
- `401 Unauthorized`: Missing or invalid auth token
|
||||
- `403 Forbidden`: User lacks admin role
|
||||
- `409 Conflict`: Email already exists
|
||||
- `429 Too Many Requests`: Rate limit exceeded
|
||||
|
||||
**Error Response**:
|
||||
```json
|
||||
{
|
||||
"error": "VALIDATION_ERROR",
|
||||
"message": "Email address is invalid",
|
||||
"details": {
|
||||
"field": "email",
|
||||
"value": "invalid-email"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Rate Limiting
|
||||
- Authenticated: 1000 requests/hour
|
||||
- Unauthenticated: 100 requests/hour
|
||||
|
||||
### Code Examples
|
||||
|
||||
**TypeScript**:
|
||||
```typescript
|
||||
const response = await fetch("https://api.greyhaven.com/users", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Authorization": `Bearer ${token}`,
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email: "user@example.com",
|
||||
password: "secure123"
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.message);
|
||||
}
|
||||
|
||||
const user = await response.json();
|
||||
console.log(`User created: ${user.id}`);
|
||||
```
|
||||
|
||||
**Python**:
|
||||
```python
|
||||
import httpx
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.post(
|
||||
"https://api.greyhaven.com/users",
|
||||
headers={"Authorization": f"Bearer {token}"},
|
||||
json={"email": "user@example.com", "password": "secure123"}
|
||||
)
|
||||
response.raise_for_status()
|
||||
user = response.json()
|
||||
print(f"User created: {user['id']}")
|
||||
```
|
||||
```
|
||||
|
||||
## Function Documentation Standards
|
||||
|
||||
### JSDoc (TypeScript)
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Calculate order total including tax and shipping.
|
||||
*
|
||||
* @param items - Array of order items with quantity and price
|
||||
* @param shippingAddress - Address for tax calculation
|
||||
* @returns Total amount in USD cents
|
||||
* @throws {ValidationError} If items array is empty
|
||||
* @throws {TaxCalculationError} If tax lookup fails
|
||||
*
|
||||
* @example
|
||||
* const total = calculateTotal(
|
||||
* [{ quantity: 2, price: 2999 }],
|
||||
* { zip: "94105", country: "US" }
|
||||
* );
|
||||
* // Returns: 6398 (5998 + 400 tax + 0 shipping)
|
||||
*/
|
||||
export function calculateTotal(
|
||||
items: OrderItem[],
|
||||
shippingAddress: Address
|
||||
): number {
|
||||
if (items.length === 0) {
|
||||
throw new ValidationError("Items array cannot be empty");
|
||||
}
|
||||
|
||||
const subtotal = items.reduce((sum, item) =>
|
||||
sum + (item.quantity * item.price), 0
|
||||
);
|
||||
|
||||
const tax = calculateTax(subtotal, shippingAddress);
|
||||
const shipping = calculateShipping(items, shippingAddress);
|
||||
|
||||
return subtotal + tax + shipping;
|
||||
}
|
||||
```
|
||||
|
||||
### Python Docstrings (Google Style)
|
||||
|
||||
```python
|
||||
def calculate_total(items: List[OrderItem], shipping_address: Address) -> int:
|
||||
"""Calculate order total including tax and shipping.
|
||||
|
||||
Args:
|
||||
items: Array of order items with quantity and price.
|
||||
shipping_address: Address for tax calculation.
|
||||
|
||||
Returns:
|
||||
Total amount in USD cents.
|
||||
|
||||
Raises:
|
||||
ValidationError: If items array is empty.
|
||||
TaxCalculationError: If tax lookup fails.
|
||||
|
||||
Example:
|
||||
>>> items = [OrderItem(quantity=2, price=2999)]
|
||||
>>> address = Address(zip="94105", country="US")
|
||||
>>> total = calculate_total(items, address)
|
||||
>>> print(total)
|
||||
6398 # 5998 + 400 tax + 0 shipping
|
||||
"""
|
||||
if not items:
|
||||
raise ValidationError("Items array cannot be empty")
|
||||
|
||||
subtotal = sum(item.quantity * item.price for item in items)
|
||||
tax = calculate_tax(subtotal, shipping_address)
|
||||
shipping = calculate_shipping(items, shipping_address)
|
||||
|
||||
return subtotal + tax + shipping
|
||||
```
|
||||
|
||||
## README Structure
|
||||
|
||||
Every project should have a comprehensive README:
|
||||
|
||||
```markdown
|
||||
# Project Name
|
||||
|
||||
One-line description of what this project does.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Visit http://localhost:3000
|
||||
|
||||
## Features
|
||||
|
||||
- Feature 1: Brief description
|
||||
- Feature 2: Brief description
|
||||
- Feature 3: Brief description
|
||||
|
||||
## Installation
|
||||
|
||||
### Prerequisites
|
||||
- Node.js 20+
|
||||
- PostgreSQL 14+
|
||||
- Redis (optional)
|
||||
|
||||
### Steps
|
||||
|
||||
1. Clone repository
|
||||
```bash
|
||||
git clone https://github.com/greyhaven/project.git
|
||||
cd project
|
||||
```
|
||||
|
||||
2. Install dependencies
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
3. Configure environment
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# Edit .env with your values
|
||||
```
|
||||
|
||||
4. Run migrations
|
||||
```bash
|
||||
npm run migrate
|
||||
```
|
||||
|
||||
5. Start development server
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|----------|----------|---------|-------------|
|
||||
| `DATABASE_URL` | Yes | - | PostgreSQL connection string |
|
||||
| `REDIS_URL` | No | - | Redis connection string |
|
||||
| `API_KEY` | Yes | - | API key for external service |
|
||||
|
||||
## Architecture
|
||||
|
||||
[Link to architecture docs or include Mermaid diagram]
|
||||
|
||||
## Development
|
||||
|
||||
### Running Tests
|
||||
```bash
|
||||
npm test
|
||||
```
|
||||
|
||||
### Code Quality
|
||||
```bash
|
||||
npm run lint
|
||||
npm run type-check
|
||||
```
|
||||
|
||||
### Building
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
[Link to deployment guide or include basic steps]
|
||||
|
||||
## Contributing
|
||||
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||
|
||||
## License
|
||||
|
||||
MIT License - see [LICENSE](LICENSE)
|
||||
```
|
||||
|
||||
## Documentation Coverage
|
||||
|
||||
### Minimum Requirements
|
||||
|
||||
**Code Coverage**:
|
||||
- Public functions: 100%
|
||||
- Exported types: 100%
|
||||
- API endpoints: 100%
|
||||
|
||||
**Content Coverage**:
|
||||
- Every function has description
|
||||
- Every parameter documented
|
||||
- Return value documented
|
||||
- Errors/exceptions documented
|
||||
- At least one example
|
||||
|
||||
### Validation
|
||||
|
||||
Use automated tools:
|
||||
- TypeScript: ts-morph for AST analysis
|
||||
- Python: AST module for docstring coverage
|
||||
- API: OpenAPI schema validation
|
||||
|
||||
```bash
|
||||
# Check coverage
|
||||
npm run docs:coverage
|
||||
|
||||
# Expected output
|
||||
TypeScript: 87% (124/142 documented)
|
||||
Python: 91% (98/108 documented)
|
||||
API Endpoints: 95% (42/44 documented)
|
||||
```
|
||||
|
||||
## Quality Checklist
|
||||
|
||||
Before publishing documentation:
|
||||
|
||||
- [ ] All code examples work (copy-paste tested)
|
||||
- [ ] Links are valid (no 404s)
|
||||
- [ ] Screenshots are current
|
||||
- [ ] Version numbers are correct
|
||||
- [ ] Prerequisite versions are accurate
|
||||
- [ ] Examples use realistic data
|
||||
- [ ] Error messages match actual errors
|
||||
- [ ] Spelling and grammar checked
|
||||
- [ ] Follows style guide
|
||||
- [ ] Reviewed by another person
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
### 1. Outdated Examples
|
||||
|
||||
❌ **Bad**: Uses deprecated API
|
||||
```typescript
|
||||
// This was removed in v2.0
|
||||
const user = User.create({ email, password });
|
||||
```
|
||||
|
||||
✅ **Good**: Current API with version note
|
||||
```typescript
|
||||
// As of v2.0, use createUser instead of User.create
|
||||
const user = await createUser({ email, password });
|
||||
```
|
||||
|
||||
### 2. Missing Error Handling
|
||||
|
||||
❌ **Bad**: Happy path only
|
||||
```typescript
|
||||
const user = await api.getUser(id);
|
||||
console.log(user.email);
|
||||
```
|
||||
|
||||
✅ **Good**: Error handling included
|
||||
```typescript
|
||||
try {
|
||||
const user = await api.getUser(id);
|
||||
console.log(user.email);
|
||||
} catch (error) {
|
||||
if (error.code === 'NOT_FOUND') {
|
||||
console.error(`User ${id} not found`);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Vague Instructions
|
||||
|
||||
❌ **Bad**: "Configure the database"
|
||||
|
||||
✅ **Good**: Specific steps
|
||||
```markdown
|
||||
1. Create database: `createdb myapp`
|
||||
2. Run migrations: `npm run migrate`
|
||||
3. Verify: `psql myapp -c "\dt"`
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Update docs with code**: Documentation changes in same PR as code changes
|
||||
2. **Link to code**: Reference specific files and line numbers
|
||||
3. **Version everything**: Document which version each feature was added
|
||||
4. **Test examples**: All code examples must be tested
|
||||
5. **Screenshots with captions**: Always explain what image shows
|
||||
6. **Consistent terminology**: Use same terms throughout
|
||||
7. **Mobile-friendly**: Documentation should work on phones
|
||||
8. **Search-optimized**: Use descriptive headings and keywords
|
||||
9. **Accessible**: Alt text for images, semantic HTML
|
||||
10. **Feedback loops**: Easy way for users to report doc issues
|
||||
|
||||
---
|
||||
|
||||
Related: [openapi-patterns.md](openapi-patterns.md) | [mermaid-diagrams.md](mermaid-diagrams.md) | [Return to INDEX](INDEX.md)
|
||||
500
skills/documentation-architecture/reference/mermaid-diagrams.md
Normal file
500
skills/documentation-architecture/reference/mermaid-diagrams.md
Normal file
@@ -0,0 +1,500 @@
|
||||
# Mermaid Diagram Templates for Architecture Documentation
|
||||
|
||||
Comprehensive guide to Mermaid diagram types for visualizing system architecture, data flows, and interactions.
|
||||
|
||||
## Why Mermaid?
|
||||
|
||||
- **Version Controlled**: Diagrams in code, reviewable in PRs
|
||||
- **Always Up-to-Date**: Easy to update alongside code changes
|
||||
- **No Image Files**: Rendered dynamically in documentation
|
||||
- **GitHub Native**: Renders in README.md and issues
|
||||
- **Interactive**: Clickable links, zooming
|
||||
|
||||
## System Architecture Diagrams
|
||||
|
||||
### Basic Architecture
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Frontend"
|
||||
UI[React UI]
|
||||
end
|
||||
|
||||
subgraph "Backend"
|
||||
API[FastAPI]
|
||||
DB[(PostgreSQL)]
|
||||
end
|
||||
|
||||
UI --> API
|
||||
API --> DB
|
||||
```
|
||||
|
||||
### Multi-Tier Architecture
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Client"
|
||||
Browser[Web Browser]
|
||||
Mobile[Mobile App]
|
||||
end
|
||||
|
||||
subgraph "Edge (Cloudflare)"
|
||||
Gateway[API Gateway]
|
||||
Cache[KV Cache]
|
||||
end
|
||||
|
||||
subgraph "Application"
|
||||
Frontend[TanStack Start]
|
||||
Backend[FastAPI]
|
||||
end
|
||||
|
||||
subgraph "Data"
|
||||
DB[(PostgreSQL)]
|
||||
Redis[(Redis)]
|
||||
R2[(Object Storage)]
|
||||
end
|
||||
|
||||
Browser --> Gateway
|
||||
Mobile --> Gateway
|
||||
Gateway --> Frontend
|
||||
Gateway --> Backend
|
||||
Gateway --> Cache
|
||||
Backend --> DB
|
||||
Backend --> Redis
|
||||
Backend --> R2
|
||||
```
|
||||
|
||||
### Microservices Architecture
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
Gateway[API Gateway]
|
||||
|
||||
subgraph "Services"
|
||||
Auth[Auth Service]
|
||||
Users[User Service]
|
||||
Orders[Order Service]
|
||||
Payments[Payment Service]
|
||||
end
|
||||
|
||||
subgraph "Data"
|
||||
AuthDB[(Auth DB)]
|
||||
UserDB[(User DB)]
|
||||
OrderDB[(Order DB)]
|
||||
end
|
||||
|
||||
Gateway --> Auth
|
||||
Gateway --> Users
|
||||
Gateway --> Orders
|
||||
Gateway --> Payments
|
||||
|
||||
Auth --> AuthDB
|
||||
Users --> UserDB
|
||||
Orders --> OrderDB
|
||||
Payments -.Stripe.-> External[External API]
|
||||
```
|
||||
|
||||
## Sequence Diagrams
|
||||
|
||||
### Authentication Flow
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
actor User
|
||||
participant Browser
|
||||
participant Gateway
|
||||
participant Auth
|
||||
participant DB
|
||||
|
||||
User->>Browser: Enter credentials
|
||||
Browser->>Gateway: POST /auth/login
|
||||
Gateway->>Auth: Validate credentials
|
||||
Auth->>DB: Query user
|
||||
DB-->>Auth: User record
|
||||
|
||||
alt Valid
|
||||
Auth->>Auth: Generate JWT
|
||||
Auth-->>Gateway: {token, user}
|
||||
Gateway-->>Browser: 200 OK
|
||||
Browser-->>User: Redirect
|
||||
else Invalid
|
||||
Auth-->>Gateway: 401
|
||||
Gateway-->>Browser: Error
|
||||
Browser-->>User: Show error
|
||||
end
|
||||
```
|
||||
|
||||
### API Request Flow
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client
|
||||
participant Gateway
|
||||
participant Backend
|
||||
participant DB
|
||||
participant Cache
|
||||
|
||||
Client->>Gateway: GET /users/123
|
||||
Gateway->>Gateway: Validate JWT
|
||||
Gateway->>Cache: Check cache
|
||||
|
||||
alt Cache Hit
|
||||
Cache-->>Gateway: User data
|
||||
Gateway-->>Client: 200 OK (cached)
|
||||
else Cache Miss
|
||||
Gateway->>Backend: Forward request
|
||||
Backend->>DB: Query user
|
||||
DB-->>Backend: User data
|
||||
Backend-->>Gateway: Response
|
||||
Gateway->>Cache: Store in cache
|
||||
Gateway-->>Client: 200 OK
|
||||
end
|
||||
```
|
||||
|
||||
### Payment Processing
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client
|
||||
participant API
|
||||
participant PaymentSvc
|
||||
participant Stripe
|
||||
participant DB
|
||||
|
||||
Client->>API: POST /orders
|
||||
API->>PaymentSvc: Process payment
|
||||
PaymentSvc->>Stripe: Create payment intent
|
||||
Stripe-->>PaymentSvc: Payment intent
|
||||
PaymentSvc-->>API: Intent created
|
||||
API-->>Client: {client_secret}
|
||||
|
||||
Client->>Stripe: Confirm payment
|
||||
Stripe->>PaymentSvc: Webhook: payment.succeeded
|
||||
PaymentSvc->>DB: Update order status
|
||||
PaymentSvc->>API: Notify completion
|
||||
API->>Client: Send confirmation email
|
||||
```
|
||||
|
||||
## Data Flow Diagrams
|
||||
|
||||
### Order Processing Flow
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Start[User Creates Order] --> Validate[Validate Data]
|
||||
Validate --> Stock{Check Stock}
|
||||
|
||||
Stock -->|Insufficient| Error[Return Error]
|
||||
Stock -->|Available| Reserve[Reserve Items]
|
||||
|
||||
Reserve --> Payment[Process Payment]
|
||||
Payment -->|Failed| Release[Release Items]
|
||||
Release --> Error
|
||||
|
||||
Payment -->|Success| Create[Create Order]
|
||||
Create --> Queue[Queue Email]
|
||||
Queue --> Cache[Invalidate Cache]
|
||||
Cache --> Success[Return Order]
|
||||
|
||||
Success --> Async[Async: Send Email]
|
||||
```
|
||||
|
||||
### Data Transformation Pipeline
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Raw[Raw Data] --> Extract[Extract]
|
||||
Extract --> Transform[Transform]
|
||||
Transform --> Validate{Validate}
|
||||
|
||||
Validate -->|Invalid| Log[Log Error]
|
||||
Validate -->|Valid| Enrich[Enrich Data]
|
||||
|
||||
Enrich --> Normalize[Normalize]
|
||||
Normalize --> Store[(Store in DB)]
|
||||
Store --> Index[Update Search Index]
|
||||
Index --> Cache[Update Cache]
|
||||
```
|
||||
|
||||
## Entity Relationship Diagrams
|
||||
|
||||
### Multi-Tenant E-Commerce
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
TENANT ||--o{ USER : has
|
||||
TENANT ||--o{ ORDER : has
|
||||
TENANT ||--o{ PRODUCT : has
|
||||
USER ||--o{ ORDER : places
|
||||
ORDER ||--|{ ORDER_ITEM : contains
|
||||
PRODUCT ||--o{ ORDER_ITEM : included_in
|
||||
|
||||
TENANT {
|
||||
uuid id PK
|
||||
string name
|
||||
string subdomain UK
|
||||
timestamp created_at
|
||||
}
|
||||
|
||||
USER {
|
||||
uuid id PK
|
||||
uuid tenant_id FK
|
||||
string email UK
|
||||
string role
|
||||
}
|
||||
|
||||
PRODUCT {
|
||||
uuid id PK
|
||||
uuid tenant_id FK
|
||||
string name
|
||||
decimal price
|
||||
int stock
|
||||
}
|
||||
|
||||
ORDER {
|
||||
uuid id PK
|
||||
uuid tenant_id FK
|
||||
uuid user_id FK
|
||||
decimal total
|
||||
string status
|
||||
}
|
||||
|
||||
ORDER_ITEM {
|
||||
uuid id PK
|
||||
uuid order_id FK
|
||||
uuid product_id FK
|
||||
int quantity
|
||||
decimal unit_price
|
||||
}
|
||||
```
|
||||
|
||||
### User Authentication Schema
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
USER ||--o{ SESSION : has
|
||||
USER ||--o{ API_KEY : has
|
||||
USER ||--o{ OAUTH_TOKEN : has
|
||||
USER }|--|| USER_PROFILE : has
|
||||
|
||||
USER {
|
||||
uuid id PK
|
||||
string email UK
|
||||
string hashed_password
|
||||
bool email_verified
|
||||
}
|
||||
|
||||
SESSION {
|
||||
uuid id PK
|
||||
uuid user_id FK
|
||||
string token UK
|
||||
timestamp expires_at
|
||||
}
|
||||
|
||||
API_KEY {
|
||||
uuid id PK
|
||||
uuid user_id FK
|
||||
string key_hash UK
|
||||
string name
|
||||
timestamp last_used
|
||||
}
|
||||
```
|
||||
|
||||
## State Diagrams
|
||||
|
||||
### Order State Machine
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Pending: Order Created
|
||||
Pending --> Processing: Payment Confirmed
|
||||
Pending --> Cancelled: Payment Failed
|
||||
|
||||
Processing --> Shipped: Fulfillment Complete
|
||||
Processing --> Cancelled: Out of Stock
|
||||
|
||||
Shipped --> Delivered: Tracking Confirmed
|
||||
Shipped --> Returned: Customer Return
|
||||
|
||||
Delivered --> Returned: Return Requested
|
||||
Returned --> Refunded: Return Approved
|
||||
|
||||
Cancelled --> [*]
|
||||
Delivered --> [*]
|
||||
Refunded --> [*]
|
||||
```
|
||||
|
||||
### User Lifecycle
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Invited: User Invited
|
||||
Invited --> Active: Accept Invitation
|
||||
Invited --> Expired: 7 Days Passed
|
||||
|
||||
Active --> Suspended: Policy Violation
|
||||
Active --> Inactive: 90 Days No Login
|
||||
|
||||
Suspended --> Active: Appeal Approved
|
||||
Inactive --> Active: User Logs In
|
||||
|
||||
Active --> Deleted: User Deletes Account
|
||||
Suspended --> Deleted: Admin Deletes
|
||||
|
||||
Expired --> [*]
|
||||
Deleted --> [*]
|
||||
```
|
||||
|
||||
## Deployment Diagrams
|
||||
|
||||
### CI/CD Pipeline
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
Dev[Feature Branch] -->|PR| CI[GitHub Actions]
|
||||
CI -->|Tests| Tests{Tests Pass?}
|
||||
|
||||
Tests -->|No| Fail[❌ Fail]
|
||||
Tests -->|Yes| Build[Build]
|
||||
|
||||
Build --> Stage[Deploy to Staging]
|
||||
Stage -->|Smoke Tests| SmokeTest{Pass?}
|
||||
|
||||
SmokeTest -->|No| Fail
|
||||
SmokeTest -->|Yes| Approve{Manual Approve?}
|
||||
|
||||
Approve -->|No| Wait[Wait]
|
||||
Approve -->|Yes| Canary[Canary Deploy 10%]
|
||||
|
||||
Canary -->|Monitor| Monitor{Healthy?}
|
||||
Monitor -->|No| Rollback[Rollback]
|
||||
Monitor -->|Yes| Prod[Deploy 100%]
|
||||
```
|
||||
|
||||
### Multi-Region Deployment
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Region: US-East"
|
||||
USWorker[Cloudflare Workers]
|
||||
USDB[(Primary DB)]
|
||||
end
|
||||
|
||||
subgraph "Region: Europe"
|
||||
EUWorker[Cloudflare Workers]
|
||||
EUDB[(Read Replica)]
|
||||
end
|
||||
|
||||
subgraph "Region: Asia"
|
||||
AsiaWorker[Cloudflare Workers]
|
||||
AsiaDB[(Read Replica)]
|
||||
end
|
||||
|
||||
subgraph "Global"
|
||||
DNS[Global DNS]
|
||||
CDN[Cloudflare CDN]
|
||||
end
|
||||
|
||||
DNS --> USWorker
|
||||
DNS --> EUWorker
|
||||
DNS --> AsiaWorker
|
||||
|
||||
CDN --> USWorker
|
||||
CDN --> EUWorker
|
||||
CDN --> AsiaWorker
|
||||
|
||||
USDB -.replication.-> EUDB
|
||||
USDB -.replication.-> AsiaDB
|
||||
```
|
||||
|
||||
## Class Diagrams (TypeScript/Python)
|
||||
|
||||
### Service Architecture
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class OrderService {
|
||||
-repository: OrderRepository
|
||||
-payment: PaymentService
|
||||
+createOrder(data) Order
|
||||
+getOrder(id) Order
|
||||
+cancelOrder(id) void
|
||||
}
|
||||
|
||||
class OrderRepository {
|
||||
-db: Database
|
||||
+save(order) Order
|
||||
+findById(id) Order
|
||||
+findByUser(userId) Order[]
|
||||
}
|
||||
|
||||
class PaymentService {
|
||||
-stripe: StripeClient
|
||||
+processPayment(amount) PaymentResult
|
||||
+refund(paymentId) void
|
||||
}
|
||||
|
||||
class Order {
|
||||
+id: string
|
||||
+userId: string
|
||||
+total: number
|
||||
+status: OrderStatus
|
||||
}
|
||||
|
||||
OrderService --> OrderRepository
|
||||
OrderService --> PaymentService
|
||||
OrderRepository --> Order
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Keep Diagrams Simple**: One concept per diagram
|
||||
2. **Use Subgraphs**: Group related components
|
||||
3. **Consistent Naming**: Use same names as code
|
||||
4. **Color Coding**: Use colors sparingly for emphasis
|
||||
5. **Labels**: Add descriptive labels to edges
|
||||
6. **Legend**: Include legend for complex diagrams
|
||||
7. **Direction**: LR (left-right) or TB (top-bottom) based on flow
|
||||
8. **Update Regularly**: Keep in sync with code changes
|
||||
|
||||
## Rendering in Documentation
|
||||
|
||||
### GitHub Markdown
|
||||
|
||||
````markdown
|
||||
```mermaid
|
||||
graph TB
|
||||
A[Start] --> B[Process]
|
||||
B --> C[End]
|
||||
```
|
||||
````
|
||||
|
||||
### Docusaurus
|
||||
|
||||
Install plugin:
|
||||
```bash
|
||||
npm install @docusaurus/theme-mermaid
|
||||
```
|
||||
|
||||
### MkDocs
|
||||
|
||||
Install plugin:
|
||||
```bash
|
||||
pip install mkdocs-mermaid2-plugin
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Request/Response Flow
|
||||
Use sequence diagrams with alt/opt for error handling
|
||||
|
||||
### Data Relationships
|
||||
Use ER diagrams with proper cardinality (||--o{)
|
||||
|
||||
### State Transitions
|
||||
Use state diagrams for order status, user lifecycle
|
||||
|
||||
### System Overview
|
||||
---
|
||||
|
||||
Related: [openapi-patterns.md](openapi-patterns.md) | [documentation-standards.md](documentation-standards.md) | [Return to INDEX](INDEX.md)
|
||||
491
skills/documentation-architecture/reference/openapi-patterns.md
Normal file
491
skills/documentation-architecture/reference/openapi-patterns.md
Normal file
@@ -0,0 +1,491 @@
|
||||
# OpenAPI 3.1 Patterns and Best Practices
|
||||
|
||||
Comprehensive guide to OpenAPI 3.1 specification patterns for Grey Haven stack (FastAPI + TanStack Start).
|
||||
|
||||
## OpenAPI 3.1 Overview
|
||||
|
||||
OpenAPI 3.1 is fully compatible with JSON Schema Draft 2020-12.
|
||||
|
||||
**Key Differences from 3.0**: Full JSON Schema compatibility, `examples` replaces `example`, `webhooks` support, better discriminator
|
||||
|
||||
## Basic Structure
|
||||
|
||||
```yaml
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
title: Grey Haven API
|
||||
version: 1.0.0
|
||||
|
||||
servers:
|
||||
- url: https://api.greyhaven.com
|
||||
|
||||
paths:
|
||||
/users:
|
||||
get:
|
||||
operationId: listUsers
|
||||
tags: [users]
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/User'
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
### JWT Bearer
|
||||
|
||||
```yaml
|
||||
components:
|
||||
securitySchemes:
|
||||
BearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
|
||||
security:
|
||||
- BearerAuth: []
|
||||
```
|
||||
|
||||
### OAuth2
|
||||
|
||||
```yaml
|
||||
components:
|
||||
securitySchemes:
|
||||
OAuth2:
|
||||
type: oauth2
|
||||
flows:
|
||||
authorizationCode:
|
||||
authorizationUrl: https://auth.greyhaven.com/oauth/authorize
|
||||
tokenUrl: https://auth.greyhaven.com/oauth/token
|
||||
scopes:
|
||||
read:users: Read user data
|
||||
```
|
||||
|
||||
### API Key
|
||||
|
||||
```yaml
|
||||
components:
|
||||
securitySchemes:
|
||||
ApiKey:
|
||||
type: apiKey
|
||||
in: header
|
||||
name: X-API-Key
|
||||
```
|
||||
|
||||
## Schema Patterns
|
||||
|
||||
### Pydantic v2 to OpenAPI
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Literal
|
||||
|
||||
class User(BaseModel):
|
||||
id: str = Field(..., pattern="^usr_[a-z0-9]{16}$")
|
||||
email: str = Field(..., examples=["user@example.com"])
|
||||
role: Literal["admin", "member", "guest"] = "member"
|
||||
```
|
||||
|
||||
Generates:
|
||||
|
||||
```yaml
|
||||
User:
|
||||
type: object
|
||||
required: [id, email]
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
pattern: ^usr_[a-z0-9]{16}$
|
||||
email:
|
||||
type: string
|
||||
examples: ["user@example.com"]
|
||||
role:
|
||||
type: string
|
||||
enum: [admin, member, guest]
|
||||
default: member
|
||||
```
|
||||
|
||||
### Nullable and Optional
|
||||
|
||||
```yaml
|
||||
# Optional (can be omitted)
|
||||
username:
|
||||
type: string
|
||||
|
||||
# Nullable (can be null)
|
||||
middle_name:
|
||||
type: [string, 'null']
|
||||
|
||||
# Both
|
||||
nickname:
|
||||
type: [string, 'null']
|
||||
```
|
||||
|
||||
### Discriminated Unions
|
||||
|
||||
```yaml
|
||||
PaymentMethod:
|
||||
type: object
|
||||
required: [type]
|
||||
discriminator:
|
||||
propertyName: type
|
||||
mapping:
|
||||
card: '#/components/schemas/CardPayment'
|
||||
bank: '#/components/schemas/BankPayment'
|
||||
|
||||
CardPayment:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/PaymentMethod'
|
||||
- type: object
|
||||
properties:
|
||||
card_number:
|
||||
type: string
|
||||
pattern: ^\d{16}$
|
||||
```
|
||||
|
||||
## Response Patterns
|
||||
|
||||
### Error Response
|
||||
|
||||
```yaml
|
||||
ErrorResponse:
|
||||
type: object
|
||||
required: [error, message]
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
examples: ["VALIDATION_ERROR"]
|
||||
message:
|
||||
type: string
|
||||
details:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
|
||||
# Use in responses
|
||||
responses:
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
```
|
||||
|
||||
### Paginated Response
|
||||
|
||||
```yaml
|
||||
PaginatedUsers:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/User'
|
||||
pagination:
|
||||
type: object
|
||||
properties:
|
||||
page:
|
||||
type: integer
|
||||
minimum: 1
|
||||
per_page:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 100
|
||||
total:
|
||||
type: integer
|
||||
total_pages:
|
||||
type: integer
|
||||
```
|
||||
|
||||
### Multiple Status Codes
|
||||
|
||||
```yaml
|
||||
responses:
|
||||
'201':
|
||||
description: Created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
'202':
|
||||
description: Accepted (async)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
job_id:
|
||||
type: string
|
||||
```
|
||||
|
||||
## Request Body
|
||||
|
||||
### Required vs Optional
|
||||
|
||||
```yaml
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [email, password] # Required
|
||||
properties:
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
password:
|
||||
type: string
|
||||
minLength: 8
|
||||
name:
|
||||
type: string # Optional
|
||||
```
|
||||
|
||||
### File Upload
|
||||
|
||||
```yaml
|
||||
requestBody:
|
||||
content:
|
||||
multipart/form-data:
|
||||
schema:
|
||||
properties:
|
||||
file:
|
||||
type: string
|
||||
format: binary
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
### Path
|
||||
|
||||
```yaml
|
||||
parameters:
|
||||
- name: user_id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
pattern: ^usr_[a-z0-9]{16}$
|
||||
```
|
||||
|
||||
### Query
|
||||
|
||||
```yaml
|
||||
parameters:
|
||||
- name: status
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
enum: [pending, processing, shipped]
|
||||
- name: created_after
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
format: date-time
|
||||
- name: sort
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
enum: [created_at:asc, created_at:desc]
|
||||
default: created_at:desc
|
||||
```
|
||||
|
||||
### Headers
|
||||
|
||||
```yaml
|
||||
components:
|
||||
parameters:
|
||||
TenantId:
|
||||
name: X-Tenant-ID
|
||||
in: header
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
|
||||
paths:
|
||||
/orders:
|
||||
post:
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/TenantId'
|
||||
```
|
||||
|
||||
## Response Headers
|
||||
|
||||
```yaml
|
||||
responses:
|
||||
'200':
|
||||
headers:
|
||||
X-RateLimit-Limit:
|
||||
schema:
|
||||
type: integer
|
||||
X-RateLimit-Remaining:
|
||||
schema:
|
||||
type: integer
|
||||
X-Request-ID:
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
```
|
||||
|
||||
## Multi-Language Examples
|
||||
|
||||
```yaml
|
||||
x-codeSamples:
|
||||
- lang: TypeScript
|
||||
source: |
|
||||
const response = await fetch("https://api.greyhaven.com/users", {
|
||||
method: "POST",
|
||||
headers: { "Authorization": `Bearer ${token}` },
|
||||
body: JSON.stringify({ email, password })
|
||||
});
|
||||
|
||||
- lang: Python
|
||||
source: |
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.post(
|
||||
"https://api.greyhaven.com/users",
|
||||
headers={"Authorization": f"Bearer {token}"},
|
||||
json={"email": email, "password": password}
|
||||
)
|
||||
|
||||
- lang: Shell
|
||||
source: |
|
||||
curl -X POST https://api.greyhaven.com/users \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-d '{"email": "user@example.com"}'
|
||||
```
|
||||
|
||||
## Webhooks (OpenAPI 3.1)
|
||||
|
||||
```yaml
|
||||
webhooks:
|
||||
orderCreated:
|
||||
post:
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [event, data]
|
||||
properties:
|
||||
event:
|
||||
type: string
|
||||
const: order.created
|
||||
data:
|
||||
$ref: '#/components/schemas/Order'
|
||||
responses:
|
||||
'200':
|
||||
description: Received
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use $ref**: Define schemas once, reference everywhere
|
||||
2. **Examples**: Realistic examples for all schemas
|
||||
3. **Error Schemas**: Consistent error format
|
||||
4. **Validation**: Use pattern, minLength, minimum
|
||||
5. **Descriptions**: Document every field
|
||||
6. **operationId**: Unique for SDK generation
|
||||
7. **Tags**: Group related endpoints
|
||||
8. **Deprecation**: Mark with `deprecated: true`
|
||||
9. **Security**: Define at global or operation level
|
||||
10. **Versioning**: Include in URL (/api/v1/)
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Multi-Tenant
|
||||
|
||||
```yaml
|
||||
components:
|
||||
parameters:
|
||||
TenantId:
|
||||
name: X-Tenant-ID
|
||||
in: header
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
```
|
||||
|
||||
### Idempotency
|
||||
|
||||
```yaml
|
||||
components:
|
||||
parameters:
|
||||
IdempotencyKey:
|
||||
name: Idempotency-Key
|
||||
in: header
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
```
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
```yaml
|
||||
responses:
|
||||
'429':
|
||||
description: Rate limit exceeded
|
||||
headers:
|
||||
X-RateLimit-Reset:
|
||||
schema:
|
||||
type: integer
|
||||
```
|
||||
|
||||
## FastAPI Integration
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI(
|
||||
title="Grey Haven API",
|
||||
version="1.0.0",
|
||||
openapi_version="3.1.0"
|
||||
)
|
||||
|
||||
# Customize OpenAPI
|
||||
def custom_openapi():
|
||||
if app.openapi_schema:
|
||||
return app.openapi_schema
|
||||
|
||||
openapi_schema = get_openapi(
|
||||
title=app.title,
|
||||
version=app.version,
|
||||
routes=app.routes
|
||||
)
|
||||
|
||||
# Add security schemes
|
||||
openapi_schema["components"]["securitySchemes"] = {
|
||||
"BearerAuth": {
|
||||
"type": "http",
|
||||
"scheme": "bearer",
|
||||
"bearerFormat": "JWT"
|
||||
}
|
||||
}
|
||||
|
||||
app.openapi_schema = openapi_schema
|
||||
return app.openapi_schema
|
||||
|
||||
app.openapi = custom_openapi
|
||||
```
|
||||
|
||||
## Validation
|
||||
|
||||
Use @redocly/cli for validation:
|
||||
|
||||
```bash
|
||||
npx @redocly/cli lint openapi.yaml
|
||||
```
|
||||
|
||||
Common issues:
|
||||
- Missing operationId
|
||||
- Missing response descriptions
|
||||
- Inconsistent naming
|
||||
- Missing examples
|
||||
- Invalid $ref paths
|
||||
|
||||
---
|
||||
|
||||
Related: [mermaid-diagrams.md](mermaid-diagrams.md) | [documentation-standards.md](documentation-standards.md) | [Return to INDEX](INDEX.md)
|
||||
Reference in New Issue
Block a user