From workflow-skills
Design RESTful APIs, microservice boundaries, and database schemas. Use when designing API endpoints, planning service architecture, creating database schemas, implementing caching strategies, or setting up authentication patterns.
npx claudepluginhub arosenkranz/claude-code-config --plugin workflow-skillsThis skill uses the workspace's default tool permissions.
Guidelines for scalable API design and microservices architecture.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
Designs and optimizes AI agent action spaces, tool definitions, observation formats, error recovery, and context for higher task completion rates.
Designs, implements, and audits WCAG 2.2 AA accessible UIs for Web (ARIA/HTML5), iOS (SwiftUI traits), and Android (Compose semantics). Audits code for compliance gaps.
Guidelines for scalable API design and microservices architecture.
# Good - nouns, plural, hierarchical
GET /users
GET /users/{id}
GET /users/{id}/orders
POST /users/{id}/orders
GET /orders/{id}/items
# Bad - verbs, singular, flat
GET /getUser
POST /createOrder
GET /user-order-list
| Method | Purpose | Idempotent | Body |
|---|---|---|---|
| GET | Read resource | Yes | No |
| POST | Create resource | No | Yes |
| PUT | Replace resource | Yes | Yes |
| PATCH | Partial update | No | Yes |
| DELETE | Remove resource | Yes | No |
200 OK - Successful GET/PUT/PATCH
201 Created - Successful POST (include Location header)
204 No Content - Successful DELETE
400 Bad Request - Invalid input
401 Unauthorized - Missing/invalid auth
403 Forbidden - Valid auth, insufficient permissions
404 Not Found - Resource doesn't exist
409 Conflict - State conflict (duplicate, version mismatch)
422 Unprocessable - Valid syntax, invalid semantics
429 Too Many Reqs - Rate limited
500 Internal Error - Server error (log details, return generic msg)
// POST /users
{
"email": "user@example.com",
"name": "John Doe",
"role": "member"
}
// Response 201 Created
{
"id": "usr_abc123",
"email": "user@example.com",
"name": "John Doe",
"role": "member",
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}
// Error Response
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request parameters",
"details": [
{ "field": "email", "message": "Invalid email format" }
]
}
}
GET /users?page=2&limit=20
GET /users?cursor=eyJpZCI6MTAwfQ&limit=20
Response:
{
"data": [...],
"pagination": {
"total": 150,
"page": 2,
"limit": 20,
"hasMore": true,
"nextCursor": "eyJpZCI6MTIwfQ"
}
}
GET /orders?status=pending&createdAfter=2024-01-01
GET /orders?sort=-createdAt,+total
GET /users?fields=id,name,email
# URL path (recommended)
GET /v1/users
GET /v2/users
# Header
GET /users
Accept: application/vnd.api+json;version=2
# Query param
GET /users?version=2
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
email_verified_at TIMESTAMPTZ,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE sessions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
token_hash VARCHAR(255) UNIQUE NOT NULL,
expires_at TIMESTAMPTZ NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
INDEX idx_sessions_user (user_id),
INDEX idx_sessions_expires (expires_at)
);
ALTER TABLE users ADD COLUMN deleted_at TIMESTAMPTZ;
-- Query active users
SELECT * FROM users WHERE deleted_at IS NULL;
-- Create view for convenience
CREATE VIEW active_users AS
SELECT * FROM users WHERE deleted_at IS NULL;
ALTER TABLE orders ADD COLUMN version INTEGER DEFAULT 1;
-- Update with version check
UPDATE orders
SET status = 'shipped', version = version + 1
WHERE id = $1 AND version = $2;
-- If rows affected = 0, version conflict occurred
┌─────────────────┐ ┌─────────────────┐
│ User Service │ │ Order Service │
│ - Registration │ │ - Cart │
│ - Auth │ │ - Checkout │
│ - Profile │ │ - History │
│ [users DB] │ │ [orders DB] │
└────────┬────────┘ └────────┬────────┘
│ │
└───────────┬───────────┘
│
┌──────┴──────┐
│ API Gateway │
│ - Routing │
│ - Auth │
│ - Rate Lim │
└─────────────┘
Synchronous (HTTP/gRPC)
Asynchronous (Message Queue)
// Event structure
interface DomainEvent {
id: string;
type: string;
aggregateId: string;
timestamp: string;
data: unknown;
}
// OrderCreated event
{
"id": "evt_123",
"type": "order.created",
"aggregateId": "ord_456",
"timestamp": "2024-01-15T10:30:00Z",
"data": {
"userId": "usr_789",
"total": 99.99,
"items": [...]
}
}
async function getUser(id: string): Promise<User> {
// Check cache first
const cached = await cache.get(`user:${id}`);
if (cached) return JSON.parse(cached);
// Cache miss - fetch from DB
const user = await db.users.findById(id);
// Populate cache
await cache.set(`user:${id}`, JSON.stringify(user), 'EX', 3600);
return user;
}
// Invalidate on write
async function updateUser(id: string, data: Partial<User>) {
await db.users.update(id, data);
await cache.del(`user:${id}`);
}
// Use cache tags for related data
await cache.set(`user:${id}`, data, { tags: [`user:${id}`, 'users'] });
await cache.invalidateTag('users'); // Clear all user caches
// Access Token (short-lived, 15min)
{
"sub": "usr_123",
"email": "user@example.com",
"roles": ["user"],
"exp": 1705312200,
"iat": 1705311300
}
// Refresh Token (long-lived, stored in DB)
{
"sub": "usr_123",
"jti": "tok_abc", // Unique ID for revocation
"exp": 1707903300
}
1. POST /auth/login → { accessToken, refreshToken }
2. GET /api/users (Authorization: Bearer <accessToken>)
3. POST /auth/refresh → { accessToken } (when expired)
4. POST /auth/logout → Revoke refresh token
// Token bucket algorithm
interface RateLimiter {
identifier: string; // IP or user ID
maxRequests: number; // e.g., 100
windowMs: number; // e.g., 60000 (1 minute)
}
// Response headers
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 42
X-RateLimit-Reset: 1705312200
// GET /health
{
"status": "healthy",
"version": "1.2.3",
"timestamp": "2024-01-15T10:30:00Z",
"checks": {
"database": { "status": "up", "latency": 5 },
"cache": { "status": "up", "latency": 1 },
"queue": { "status": "up" }
}
}