pre-dev-api-design
About
This skill defines component contracts and interfaces after technical requirements are validated but before selecting implementation technologies. It focuses on specifying what data and operations components expose while avoiding protocol or implementation details. Use it when multiple components need clear integration specifications to prevent development blockers and inconsistent data structures.
Documentation
API/Contract Design - Defining Component Interfaces
Foundational Principle
Component contracts and interfaces must be defined before technology/protocol selection.
Jumping to implementation without contract definition creates:
- Integration failures discovered during development
- Inconsistent data structures across components
- Teams blocked waiting for interface clarity
- Rework when assumptions about contracts differ
- No clear integration test boundaries
The API Design answers: WHAT data/operations components expose and consume? The API Design never answers: HOW those are implemented (protocols, serialization, specific tech).
When to Use This Skill
Use this skill when:
- TRD has passed Gate 3 validation
- System has multiple components that need to integrate
- Building APIs (internal or external)
- Microservices, modular monoliths, or distributed systems
- Need clear contracts for parallel development
Mandatory Workflow
Phase 1: Contract Analysis (Inputs Required)
- Approved TRD (Gate 3 passed) - architecture patterns defined
- Approved Feature Map (Gate 2 passed) - feature interactions mapped
- Approved PRD (Gate 1 passed) - business requirements locked
- Identify integration points from TRD component diagram
- Extract data flows from Feature Map
Phase 2: Contract Definition
For each component interface:
- Define operations (what actions can be performed)
- Specify inputs (what data is required)
- Specify outputs (what data is returned)
- Define errors (what failure cases exist)
- Document events (what notifications are sent)
- Set constraints (validation rules, rate limits)
- Version contracts (how changes are managed)
Phase 3: Gate 4 Validation
MANDATORY CHECKPOINT - Must pass before proceeding to Data Modeling:
- All TRD component interactions have contracts
- Operations are clearly named and described
- Inputs/outputs are fully specified
- Error scenarios are documented
- Events are defined with schemas
- Constraints are explicit (validation, limits)
- Versioning strategy is defined
- No protocol specifics (REST/gRPC/GraphQL)
- No technology implementations
Explicit Rules
✅ DO Include in API Design
- Operation names and descriptions
- Input parameters (name, type, required/optional, constraints)
- Output structure (fields, types, nullable)
- Error codes and descriptions
- Event types and payloads
- Validation rules (format, ranges, patterns)
- Rate limits or quota policies
- Idempotency requirements
- Authentication/authorization needs (abstract)
- Contract versioning strategy
❌ NEVER Include in API Design
- HTTP verbs (GET/POST/PUT) or REST specifics
- gRPC/GraphQL/WebSocket protocol details
- URL paths or route definitions
- Serialization formats (JSON/Protobuf/Avro)
- Framework-specific code (middleware, decorators)
- Database queries or ORM code
- Infrastructure (load balancers, API gateways)
- Specific authentication libraries (JWT libraries, OAuth packages)
Abstraction Rules
- Operation: Say "CreateUser" not "POST /api/v1/users"
- Data Type: Say "EmailAddress (validated)" not "string with regex"
- Error: Say "UserAlreadyExists" not "HTTP 409 Conflict"
- Auth: Say "Requires authenticated user" not "JWT Bearer token"
- Format: Say "ISO8601 timestamp" not "time.RFC3339"
Rationalization Table
| Excuse | Reality |
|---|---|
| "REST is obvious, just document endpoints" | Protocol choice goes in Dependency Map. Define contracts abstractly. |
| "We need HTTP codes for errors" | Error semantics matter; HTTP codes are protocol. Abstract the errors. |
| "Teams need to see JSON examples" | JSON is serialization. Define structure; format comes later. |
| "The contract IS the OpenAPI spec" | OpenAPI is protocol-specific. Design contracts first, generate specs later. |
| "gRPC/GraphQL affects the contract" | Protocols deliver contracts. Design protocol-agnostic contracts first. |
| "We already know it's REST" | Knowing doesn't mean documenting prematurely. Stay abstract. |
| "Framework validates inputs" | Validation logic is universal. Document rules; implementation comes later. |
| "This feels redundant with TRD" | TRD = components exist. API = how they talk. Different concerns. |
| "URL structure matters for APIs" | URLs are HTTP-specific. Focus on operations and data. |
| "But API Design means REST API" | API = interface. Could be REST, gRPC, events, or in-process. Stay abstract. |
Red Flags - STOP
If you catch yourself writing any of these in API Design, STOP:
- HTTP methods (GET, POST, PUT, DELETE, PATCH)
- URL paths (/api/v1/users, /users/{id})
- Protocol names (REST, GraphQL, gRPC, WebSocket)
- Status codes (200, 404, 500)
- Serialization formats (JSON, XML, Protobuf)
- Authentication tokens (JWT, OAuth2 tokens, API keys)
- Framework code (Express routes, gRPC service definitions)
- Transport mechanisms (HTTP/2, TCP, UDP)
When you catch yourself: Replace protocol detail with abstract contract. "POST /users" → "CreateUser operation"
Gate 4 Validation Checklist
Before proceeding to Data Modeling, verify:
Contract Completeness:
- All component-to-component interactions have contracts
- All external system integrations have contracts
- All event/message contracts are defined
- Client-facing APIs are fully specified
Operation Clarity:
- Each operation has clear purpose and description
- Operation names follow consistent naming convention
- Idempotency requirements are documented
- Batch operations are identified where relevant
Data Specification:
- All input parameters are typed and documented
- Required vs. optional is explicit
- Output structures are complete
- Null/empty cases are handled
Error Handling:
- All error scenarios are identified
- Error codes/types are defined
- Error messages provide actionable guidance
- Retry/recovery strategies are documented
Event Contracts:
- All events are named and described
- Event payloads are fully specified
- Event ordering/delivery semantics documented
- Event versioning strategy defined
Constraints & Policies:
- Validation rules are explicit (format, range, pattern)
- Rate limits or quotas are defined
- Timeouts and deadlines are specified
- Backward compatibility strategy exists
Technology Agnostic:
- No protocol-specific details (REST/gRPC/etc)
- No serialization format specifics
- No framework or library names
- Can implement in any protocol
Gate Result:
- ✅ PASS: All checkboxes checked → Proceed to Data Modeling
- ⚠️ CONDITIONAL: Remove protocol details → Re-validate
- ❌ FAIL: Incomplete contracts → Add missing specifications
Contract Template
# API/Contract Design: [Project/Feature Name]
## Overview
- **TRD Reference**: [Link to approved TRD]
- **Feature Map Reference**: [Link to approved Feature Map]
- **Last Updated**: [Date]
- **Status**: Draft / Under Review / Approved
## Contract Versioning Strategy
- **Approach**: [e.g., Semantic versioning, Date-based, etc.]
- **Backward Compatibility**: [Policy for breaking changes]
- **Deprecation Process**: [How old contracts are sunset]
## Component Contracts
### Component: [Component Name]
**Purpose**: [What this component does - from TRD]
**Integration Points** (from TRD):
- Inbound: [Components that call this one]
- Outbound: [Components this one calls]
---
#### Operation: [OperationName]
**Purpose**: [What this operation does]
**Inputs**:
| Parameter | Type | Required | Constraints | Description |
|-----------|------|----------|-------------|-------------|
| userId | Identifier | Yes | Non-empty, UUID format | Unique user identifier |
| email | EmailAddress | Yes | Valid email format | User's email address |
| displayName | String | No | 3-50 chars, alphanumeric | Public display name |
| preferences | PreferenceSet | No | - | User preferences object |
**Input Validation Rules**:
- `email` must match pattern: `[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}`
- `displayName` must not contain profanity (filter list: [reference])
- `preferences.theme` must be one of: ["light", "dark", "auto"]
**Outputs** (Success):
| Field | Type | Nullable | Description |
|-------|------|----------|-------------|
| userId | Identifier | No | Created user's unique ID |
| createdAt | Timestamp | No | ISO8601 timestamp of creation |
| status | UserStatus | No | Account status: "active" | "pending_verification" |
**Output Structure Example** (abstract):
UserCreatedResponse { userId: Identifier createdAt: Timestamp status: UserStatus }
**Errors**:
| Error Code | Condition | Description | Retry? |
|------------|-----------|-------------|--------|
| InvalidEmail | Email format invalid | Provided email doesn't match format | No |
| EmailAlreadyExists | Email in use | Account with this email exists | No |
| RateLimitExceeded | Too many requests | Max 5 creates per hour per IP | Yes, after delay |
| ServiceUnavailable | Downstream failure | Dependency unavailable | Yes, with backoff |
**Idempotency**:
- Idempotent if called with same `email` within 5 minutes
- Returns existing user if already created
**Authorization**:
- Requires: Anonymous (public operation)
- Rate limited: 5 requests per hour per IP
**Related Operations**:
- Triggers Event: `UserCreated` (see Events section)
- May call: `SendVerificationEmail` (async)
---
#### Operation: [AnotherOperationName]
[Same structure as above]
---
## Event Contracts
### Event: UserCreated
**Purpose**: Notifies system that new user account was created
**When Emitted**: After successful user creation, before returning response
**Payload**:
| Field | Type | Nullable | Description |
|-------|------|----------|-------------|
| eventId | Identifier | No | Unique event identifier |
| timestamp | Timestamp | No | ISO8601 event timestamp |
| userId | Identifier | No | Created user's ID |
| email | EmailAddress | No | User's email (for notifications) |
| source | String | No | Registration source: "web" | "mobile" | "api" |
**Payload Structure Example** (abstract):
UserCreatedEvent { eventId: Identifier timestamp: Timestamp userId: Identifier email: EmailAddress source: String }
**Consumers**:
- Email Service (sends welcome email)
- Analytics Service (tracks signups)
- Audit Log Service (records event)
**Delivery Semantics**:
- At-least-once delivery
- Consumers must handle duplicates (idempotency required)
**Ordering**:
- No guaranteed ordering with other events
- Events for same `userId` are ordered
**Retention**:
- Events retained for 30 days in event store
---
### Event: [AnotherEvent]
[Same structure as above]
---
## Cross-Component Integration Contracts
### Integration: User Service → Email Service
**Purpose**: Send transactional emails to users
**Operations Used**:
- `SendEmail` (async, fire-and-forget)
- `GetEmailStatus` (query email delivery status)
**Contract Reference**: See Email Service component contracts
**Data Flow**:
UserService --[UserCreated event]--> EventBroker --[subscribe]--> EmailService EmailService --[SendEmail operation]--> EmailProvider
**Error Handling**:
- Email Service failures do NOT block User Service operations
- Retries handled by Email Service (3 attempts, exponential backoff)
- Dead-letter queue for permanent failures
---
### Integration: [Another Integration]
[Same structure as above]
---
## External System Contracts
### External System: Payment Gateway
**Purpose**: Process payments for user subscriptions
**Operations Exposed to Us**:
- `InitiatePayment`: Start payment transaction
- `CheckPaymentStatus`: Query transaction status
- `RefundPayment`: Reverse transaction
**Operations We Expose to Them**:
- `PaymentWebhook`: Receive payment status updates
**Contract Details**:
#### Operation: InitiatePayment (We call Them)
**Inputs**:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| transactionId | Identifier | Yes | Our internal transaction ID |
| amount | MonetaryAmount | Yes | Amount in smallest currency unit (cents) |
| currency | CurrencyCode | Yes | ISO 4217 code (USD, EUR, etc.) |
| customerEmail | EmailAddress | Yes | Customer's email for receipt |
**Outputs**:
| Field | Type | Description |
|-------|------|-------------|
| paymentId | Identifier | Gateway's payment ID (store for status checks) |
| redirectUrl | URL | URL to redirect user for payment |
| expiresAt | Timestamp | Payment link expiration |
**Errors**:
| Error Code | Description |
|------------|-------------|
| InvalidAmount | Amount out of acceptable range |
| UnsupportedCurrency | Currency not supported |
| GatewayUnavailable | External service down |
---
#### Operation: PaymentWebhook (They call Us)
**Purpose**: Receive async payment status updates
**Inputs**:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| paymentId | Identifier | Yes | Gateway's payment ID |
| status | PaymentStatus | Yes | "succeeded" | "failed" | "pending" |
| transactionId | Identifier | Yes | Our transaction ID (from InitiatePayment) |
| timestamp | Timestamp | Yes | Status update timestamp |
| signature | String | Yes | HMAC signature for verification |
**Outputs**:
| Field | Type | Description |
|-------|------|-------------|
| acknowledged | Boolean | Always true (confirms receipt) |
**Security**:
- Must verify HMAC signature before processing
- Signature algorithm: HMAC-SHA256
- Secret key: [stored in secrets management]
**Idempotency**:
- Must handle duplicate webhooks (same paymentId + status)
- Store processed webhook IDs for deduplication
---
## Data Type Definitions
### Custom Types
#### EmailAddress
- **Base Type**: String
- **Format**: Valid email format per RFC 5322
- **Constraints**: Max 254 characters, case-insensitive
- **Example**: "user@example.com"
#### Identifier
- **Base Type**: String
- **Format**: UUID v4
- **Constraints**: Non-empty, immutable
- **Example**: "550e8400-e29b-41d4-a716-446655440000"
#### Timestamp
- **Base Type**: String
- **Format**: ISO 8601 with timezone
- **Constraints**: UTC timezone, millisecond precision
- **Example**: "2025-10-23T16:45:00.123Z"
#### MonetaryAmount
- **Base Type**: Integer
- **Format**: Amount in smallest currency unit (cents, pence, etc.)
- **Constraints**: Non-negative, max value 9,223,372,036,854,775,807
- **Example**: 1999 (represents $19.99)
#### CurrencyCode
- **Base Type**: String
- **Format**: ISO 4217 three-letter code
- **Constraints**: Uppercase, exactly 3 characters
- **Example**: "USD", "EUR", "GBP"
#### UserStatus
- **Base Type**: Enum
- **Values**: "active", "suspended", "deleted", "pending_verification"
- **Description**: Current account status
---
## Naming Conventions
**Operations**:
- Use verb + noun format: `CreateUser`, `GetPayment`, `UpdateProfile`
- Be specific: `ArchiveUser` instead of `DeleteUser` if soft-delete
**Parameters**:
- Use camelCase: `userId`, `createdAt`, `displayName`
- Be descriptive: `subscriptionExpiresAt` not `expiry`
- Boolean parameters: prefix with `is`/`has`: `isActive`, `hasPermission`
**Events**:
- Use past tense: `UserCreated`, `PaymentProcessed`, `OrderShipped`
- Include entity: `OrderShipped` not just `Shipped`
**Errors**:
- Use noun + condition: `ResourceNotFound`, `InvalidInput`, `RateLimitExceeded`
- Be specific: `EmailAlreadyExists` not `DuplicateError`
---
## Rate Limiting & Quotas
### Per-Operation Limits
| Operation | Limit | Window | Scope |
|-----------|-------|--------|-------|
| CreateUser | 5 requests | 1 hour | Per IP address |
| GetUserProfile | 100 requests | 1 minute | Per user |
| UpdateProfile | 10 requests | 1 minute | Per user |
| SendPasswordReset | 3 requests | 1 hour | Per email |
### Quota Policies
- Free tier: 1,000 API calls per day
- Pro tier: 100,000 API calls per day
- Enterprise: Custom limits
### Exceeded Limit Behavior
- Return error: `RateLimitExceeded`
- Include retry info: `retryAfter` timestamp
- Do NOT process request
---
## Backward Compatibility Strategy
### Breaking Changes
**Definition**: Changes that require consumers to update
- Removing fields from outputs
- Adding required parameters to inputs
- Changing data types
- Renaming operations
**Process**:
1. Announce deprecation 90 days in advance
2. Support old + new contract in parallel
3. Monitor old contract usage
4. Remove old contract after 180 days
### Non-Breaking Changes
**Definition**: Changes consumers can ignore
- Adding optional parameters
- Adding new fields to outputs
- Adding new operations
- Adding new error codes
**Process**:
- Deploy immediately
- Document in changelog
- No consumer updates required
---
## Testing Contracts
### Contract Testing Strategy
- Use contract testing tools (language-agnostic)
- Provider tests verify contract implementation
- Consumer tests verify contract usage
- CI/CD validates contracts haven't broken
### Example Test Scenarios
**CreateUser Operation**:
- ✓ Valid input creates user successfully
- ✓ Duplicate email returns `EmailAlreadyExists`
- ✓ Invalid email returns `InvalidEmail`
- ✓ Missing required field returns `InvalidInput`
- ✓ Rate limit exceeded returns `RateLimitExceeded`
- ✓ Success emits `UserCreated` event
---
## Gate 4 Validation
**Validation Date**: [Date]
**Validated By**: [Person/team]
- [ ] All component contracts defined
- [ ] All operations have inputs/outputs
- [ ] Error scenarios documented
- [ ] Events fully specified
- [ ] External integrations covered
- [ ] No protocol specifics included
- [ ] Ready for Data Modeling (Gate 5)
**Approval**: ☐ Approved | ☐ Needs Revision | ☐ Rejected
**Next Step**: Proceed to Data Modeling (`pre-dev-data-model`)
Common Violations and Fixes
Violation 1: Protocol-Specific Details
❌ Wrong:
#### Operation: CreateUser
**Endpoint**: POST /api/v1/users
**Status Codes**:
- 201 Created
- 409 Conflict (email exists)
- 400 Bad Request
✅ Correct:
#### Operation: CreateUser
**Purpose**: Create new user account
**Inputs**: [userId, email, displayName]
**Outputs**: UserCreatedResponse
**Errors**:
- EmailAlreadyExists (email in use)
- InvalidInput (validation failure)
Violation 2: Implementation in Contract
❌ Wrong:
**Validation**:
```javascript
if (!/^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/.test(email)) {
throw new ValidationError("Invalid email");
}
✅ **Correct**:
```markdown
**Validation Rules**:
- `email` must match email format per RFC 5322
- Pattern: local@domain.tld
- Max length: 254 characters
Violation 3: Technology-Specific Types
❌ Wrong:
**Output**:
```json
{
"userId": "uuid",
"createdAt": "Date",
"profile": "Map<String, Any>"
}
✅ **Correct**:
```markdown
**Outputs**:
| Field | Type | Description |
|-------|------|-------------|
| userId | Identifier | UUID format |
| createdAt | Timestamp | ISO8601 timestamp |
| profile | ProfileObject | User profile data |
Confidence Scoring
Use this to adjust your interaction with the user:
Confidence Factors:
Contract Completeness: [0-30]
- All operations documented: 30
- Most operations covered: 20
- Significant gaps: 10
Interface Clarity: [0-25]
- Clear, unambiguous contracts: 25
- Some interpretation needed: 15
- Vague or conflicting: 5
Integration Complexity: [0-25]
- Simple point-to-point: 25
- Moderate dependencies: 15
- Complex orchestration: 5
Error Handling Coverage: [0-20]
- All scenarios documented: 20
- Common cases covered: 12
- Minimal coverage: 5
Total: [0-100]
Action:
80+: Generate complete contracts autonomously
50-79: Present options for user selection
<50: Ask clarifying questions about integration needs
Output Location
Always output to: docs/pre-development/api-design/api-contracts-[feature-name].md
After API Design Approval
- ✅ Lock the contracts - interfaces are now reference for implementation
- 🎯 Use contracts as input for Data Modeling (next phase:
pre-dev-data-model) - 🚫 Never add protocol specifics to contracts retroactively
- 📋 Keep contracts technology-agnostic until Dependency Map
Quality Self-Check
Before declaring API Design complete, verify:
- All TRD integration points have contracts
- Operations are clearly named and described
- Inputs are fully specified (type, required, constraints)
- Outputs are complete (all fields documented)
- Error scenarios are comprehensive
- Events have full payload specifications
- Validation rules are explicit
- Rate limits are defined
- Idempotency is documented where relevant
- Zero protocol specifics (REST/gRPC/etc)
- Zero implementation code
- Contracts are testable
- Backward compatibility strategy exists
- Gate 4 validation checklist 100% complete
The Bottom Line
If you wrote API contracts with HTTP endpoints or gRPC services, remove them.
Contracts are protocol-agnostic. Period. No REST. No GraphQL. No HTTP codes.
Protocol choices go in Dependency Map. That's a later phase. Wait for it.
Violating this separation means:
- You're locked into a protocol before evaluating alternatives
- Contracts can't be reused across different delivery mechanisms
- You can't objectively compare REST vs. gRPC vs. messaging
- Teams can't work in parallel with clear interface agreements
Define the contract. Stay abstract. Choose protocol later.
Quick Install
/plugin add https://github.com/LerianStudio/ring/tree/main/pre-dev-api-designCopy and paste this command in Claude Code to install this skill
GitHub 仓库
Related Skills
evaluating-llms-harness
TestingThis Claude Skill runs the lm-evaluation-harness to benchmark LLMs across 60+ standardized academic tasks like MMLU and GSM8K. It's designed for developers to compare model quality, track training progress, or report academic results. The tool supports various backends including HuggingFace and vLLM models.
langchain
MetaLangChain is a framework for building LLM applications using agents, chains, and RAG pipelines. It supports multiple LLM providers, offers 500+ integrations, and includes features like tool calling and memory management. Use it for rapid prototyping and deploying production systems like chatbots, autonomous agents, and question-answering services.
business-rule-documentation
MetaThis skill provides standardized templates for systematically documenting business logic and domain knowledge following Domain-Driven Design principles. It helps developers capture business rules, process flows, decision trees, and terminology glossaries to maintain consistency between requirements and implementation. Use it when documenting domain models, creating business rule repositories, or bridging communication between business and technical teams.
csv-data-summarizer
MetaThis skill automatically analyzes CSV files to generate comprehensive statistical summaries and visualizations using Python's pandas and matplotlib/seaborn. It should be triggered whenever a user uploads or references CSV data without prompting for analysis preferences. The tool provides immediate insights into data structure, quality, and patterns through automated analysis and visualization.
