Token导航 LogoToken导航TokenDH.com
研究检索需要联网github未标认证来源可访问许可证需确认审计通过

architecture-decision-records架构决策记录

Agent Skill

architecture-decision-records 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

242

周安装

10

GitHub Stars

公开资料未说明

下载量

79
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:architecture-decision-records(架构决策记录)
来源仓库:https://github.com/tejovanthn/rasikalife
仓库路径:skills/architecture-decision-records
安装命令:
npx skills add https://github.com/tejovanthn/rasikalife --skill architecture-decision-records
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/tejovanthn/rasikalife --skill architecture-decision-records

简介

architecture-decision-records 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词快速定位候选结果时使用。

  • 适用于架构决策记录查找、历史方案回顾和技术债务分析等研究检索场景。
  • 通过关键词或任务场景输入,返回匹配的候选信息列表供进一步处理。
  • 安装命令:npx skills add https://github.com/tejovanthn/rasikalife --skill architecture-decision-records。
  • 使用前请确认仓库维护状态及是否涉及文件读写或网络请求权限。

SKILL.md

Architecture Decision Records (ADR) - Writing Guide

This skill provides comprehensive guidance for writing high-quality Architecture Decision Records (ADRs) for the VedaGhosham project, based on the existing 13 ADRs in docs/architecture-decisions/.

What is an ADR?

An Architecture Decision Record documents a significant technical decision made during the project's development. ADRs capture:

  • What decision was made
  • Why it was made (problem context)
  • How it's implemented (with code examples)
  • Trade-offs (what was gained/lost)
  • Alternatives considered

When to Write an ADR

Write an ADR when making decisions that:

  1. Impact the entire system (database choice, framework selection, deployment strategy)
  2. Are difficult to reverse (DynamoDB single-table design, monorepo structure)
  3. Involve significant trade-offs (tRPC vs REST, Remix vs Next.js)
  4. Set architectural patterns (entity structure, error handling, authentication)
  5. Require future context (why we chose this approach over alternatives)

Examples of ADR-Worthy Decisions

  • ✅ Choosing DynamoDB single-table design (ADR-004)
  • ✅ Selecting tRPC over REST (ADR-005)
  • ✅ Email blacklist management strategy (ADR-015)
  • ✅ Fresh user data from database vs JWT (ADR-001)
  • ✅ Monorepo with pnpm workspaces (ADR-009)

Examples of Non-ADR Decisions

  • ❌ Adding a new field to an entity (routine change)
  • ❌ Refactoring a component (implementation detail)
  • ❌ Fixing a bug (not an architectural decision)
  • ❌ Updating dependencies (maintenance task)

ADR Format and Structure

File Naming Convention

docs/architecture-decisions/adr-NNN-kebab-case-title.md
  • NNN: Zero-padded 3-digit number (001, 002, 015, etc.)
  • kebab-case-title: Descriptive, lowercase, hyphen-separated
  • Find the next number by checking existing ADRs

Examples:

  • adr-001-fresh-user-data.md
  • adr-005-trpc-over-rest.md
  • adr-015-email-blacklist-bounce-management.md

Document Structure

Every ADR follows this structure:

# ADR-NNN: Title (Clear, Concise Description)

**Date:** YYYY-MM-DD
**Status:** Accepted | Proposed | Deprecated | Superseded
**Context:** One-line summary of when/why this decision was needed

---

## Problem

[Detailed problem description with 3-5 paragraphs]

### Option 1: [First Alternative]
[Code example or description]

**Problems:**
- List specific issues
- Technical limitations
- Business concerns

### Option 2: [Second Alternative]
[Code example or description]

**Problems:**
- List specific issues

### Option 3: [Chosen Approach]
[Code example or description]

**Benefits:**
- Why this is better
- Advantages over alternatives

---

## Decision

**Use [Chosen Approach] for [Purpose].**

[1-2 paragraph explanation of the decision]

**Why [Chosen Approach]:**
1. Reason 1
2. Reason 2
3. Reason 3

---

## Implementation

[Detailed implementation with code examples]

### 1. [First Implementation Aspect]
[Code examples with comments]

### 2. [Second Implementation Aspect]
[Code examples with comments]

[Continue for all major implementation aspects]

---

## Benefits

### 1. **[Benefit Name]**
[Explanation with code/metrics examples]

### 2. **[Benefit Name]**
[Explanation with code/metrics examples]

[Continue for all major benefits]

---

## Trade-offs

### What We Gained
- ✅ Benefit 1
- ✅ Benefit 2
- ✅ Benefit 3

### What We Lost
- ❌ Limitation 1
- ❌ Limitation 2
- ❌ Limitation 3

### Why Trade-offs Are Acceptable
1. **Limitation 1**: Explanation of why it's acceptable
2. **Limitation 2**: Explanation
3. **Limitation 3**: Explanation

---

## Comparison

| Feature | Alternative 1 | Alternative 2 | Chosen Approach |
|---------|--------------|---------------|-----------------|
| **Metric 1** | Value | Value | Value |
| **Metric 2** | Value | Value | Value |

---

## Real-World Example

### Scenario: [Concrete Use Case]

**With [Alternative Approach]:**

[Step-by-step flow showing problems]

**With [Chosen Approach]:**

[Step-by-step flow showing benefits]

**Winner:** [Chosen Approach] ([quantified benefit])

---

## Future Considerations

### [Future Topic 1]
[Discussion of how this decision might evolve]

### [Future Topic 2]
[Potential extensions or modifications]

**Current Status:** [Current state and future plans]

---

## Related Files

### [Category 1]
- `path/to/file1.ts` - Description
- `path/to/file2.ts` - Description

### [Category 2]
- `path/to/file3.ts` - Description

---

## References

- **[Resource Name]**: [URL]
- **[Documentation]**: [URL]
- Related: [Cross-reference to other ADRs]

Writing Guidelines

1. Title and Header

Title Format:

# ADR-NNN: Clear, Concise Description

Examples:

  • ADR-001: Load Fresh User Data from Database (Not Stale JWT)
  • ADR-005: tRPC Over REST API
  • ADR-015: Email Blacklist and Bounce Management
  • ADR-001: User Data (too vague)
  • ADR-005: API Decision (not descriptive)

Header Fields:

**Date:** 2025-12-17 (ISO format)
**Status:** Accepted (current state)
**Context:** Brief one-liner about when/why this decision was needed

Status Values:

  • Proposed - Under consideration
  • Accepted - Active and implemented
  • Deprecated - No longer recommended
  • Superseded - Replaced by another ADR (reference ADR-XXX)

2. Problem Section

The Problem section should:

  • Explain the context (3-5 paragraphs minimum)
  • Show code examples of the problem or alternatives
  • List 2-4 alternatives considered
  • Explain trade-offs for each alternative

Good Problem Description Example:

## Problem

VedaGhosham sends authentication OTP emails via AWS SES. Without proper bounce
and complaint handling, we risk:

1. **Sender Reputation Damage**: Repeated bounces to invalid emails harm sender reputation
2. **Service Suspension**: AWS SES may suspend service if bounce rate exceeds 5%
3. **Wasted Resources**: Sending emails to blacklisted addresses wastes API calls and costs
4. **Poor User Experience**: Users with invalid emails get stuck in auth flow
5. **No Visibility**: No tracking of email delivery issues or spam complaints

### Without Blacklist Management

// ❌ Sends to all emails without checking export async function sendOTPEmail(email: string, code: string) { // Always sends, even if email previously bounced await sesClient.send(new SendEmailCommand({ ... })); }


**Problems:**

- Hard bounces (permanent failures) get retried every login
- Spam complaints not tracked (user marked email as spam)
- No way to prevent sending to known-bad addresses
- AWS SES reputation degrades over time

Key Points:

  • Start with business impact (reputation, cost, UX)
  • Show concrete code examples
  • List specific, actionable problems

3. Decision Section

Format:

## Decision

**Use [Technology/Pattern] for [Purpose].**

[1-2 paragraph justification]

**Why [Chosen Approach]:**
1. Reason 1 (with evidence)
2. Reason 2 (with evidence)
3. Reason 3 (with evidence)

Example:

## Decision

**Use tRPC (TypeScript Remote Procedure Call) instead of REST or GraphQL.**

tRPC provides end-to-end type safety without codegen, perfect for our TypeScript monorepo.

**Why tRPC:**
1. **Full type safety with zero codegen**: Types flow automatically through AppRouter export
2. **Automatic validation**: Zod schemas validate input before handler runs
3. **Middleware composition**: Reusable auth/permission middleware
4. **Request batching**: Reduces Lambda invocations and latency

4. Implementation Section

The Implementation section should:

  • Show working code examples (not pseudocode)
  • Include file paths in code comments
  • Explain key patterns with inline comments
  • Cover all major aspects of implementation

Structure:

## Implementation

### 1. [Infrastructure/Configuration]
[SST/config code with explanations]

### 2. [Core Business Logic]
[Entity/service code]

### 3. [API Layer]
[tRPC router/endpoint code]

### 4. [Frontend Integration]
[Remix route/component code]

### 5. [Testing/Monitoring]
[Test examples, CloudWatch alarms]

Code Example Standards:

// ✅ Good: Working code with comments
// packages/core/src/email/blacklist.ts
export async function checkEmailBlacklist(
  email: string,
): Promise<BlacklistCheckResult> {
  const normalizedEmail = normalizeEmail(email);

  try {
    const result = await User.query.byEmail({ email: normalizedEmail }).go();

    if (result.data.length > 0) {
      const user = result.data[0];

      if (user.emailBlacklisted) {
        return {
          isBlacklisted: true,
          reason: user.emailBlacklistReason || 'UNKNOWN',
          userId: user.userId,
          blacklistedAt: user.emailBlacklistedAt,
        };
      }
    }

    return { isBlacklisted: false };
  } catch (error) {
    // Database error - fail open to prevent auth system breakage
    console.error('Failed to check email blacklist, allowing send:', error);
    return { isBlacklisted: false };
  }
}

// ❌ Bad: Pseudocode without context
function checkBlacklist(email) {
  // Check if email is blacklisted
  return query(email);
}

5. Benefits Section

Format:

## Benefits

### 1. **[Concrete Benefit]**
[Explanation with evidence]

**Example/Metric:**
[Code example or quantified metric]

### 2. **[Concrete Benefit]**
[Explanation with evidence]

Good Benefits Example:

## Benefits

### 1. **Cost Efficiency**
Single table = one set of provisioned capacity. No cross-table query overhead.

**Example:**
- Multi-table: 7 tables × $5/month = **$35/month** (minimum)
- Single-table: 1 table × $5/month = **$5/month**
- **Savings: 85%** (at small scale)

### 2. **Consistent Performance**
All queries within one table (no cross-table latency). GSIs provide O(1) lookups
for all access patterns. Single-digit millisecond latency.

Key Points:

  • Use bold for benefit names
  • Provide concrete evidence (metrics, code examples)
  • Quantify when possible (percentages, time, cost)

6. Trade-offs Section

Format:

## Trade-offs

### What We Gained
- ✅ Benefit 1
- ✅ Benefit 2
- ✅ Benefit 3

### What We Lost
- ❌ Limitation 1
- ❌ Limitation 2
- ❌ Limitation 3

### Why Trade-offs Are Acceptable

1. **Limitation 1**: Detailed explanation of why this is acceptable
2. **Limitation 2**: Explanation with context
3. **Limitation 3**: Explanation

Good Trade-offs Example:

## Trade-offs

### What We Gained
- ✅ Full type safety with zero codegen
- ✅ Automatic validation (Zod schemas)
- ✅ Simplified error handling (TRPCError)
- ✅ Middleware composition for auth/permissions
- ✅ Request batching (reduces Lambda invocations)
- ✅ IntelliSense for all procedures

### What We Lost
- ❌ No OpenAPI/Swagger documentation (tRPC-specific)
- ❌ Smaller ecosystem than REST (fewer tools/integrations)
- ❌ TypeScript-only (can't call from Python, Go, etc.)
- ❌ Less familiar to REST-only developers

### Why Trade-offs Are Acceptable

1. **No OpenAPI**: Internal API only (not public-facing); tRPC docs are code itself
2. **Smaller Ecosystem**: TypeScript ecosystem is sufficient for our needs
3. **TypeScript-Only**: Entire stack is TypeScript (no other languages planned)
4. **Learning Curve**: One-time cost; tRPC is simpler than REST + OpenAPI codegen

7. Comparison Section

Use tables to compare alternatives across multiple dimensions:

## Comparison

| Feature | Alternative 1 | Alternative 2 | Chosen Approach |
|---------|--------------|---------------|-----------------|
| **Feature 1** | ❌ No | ⚠️ Partial | ✅ Yes |
| **Feature 2** | Value | Value | Value |
| **Cost** | $X/month | $Y/month | $Z/month |
| **Performance** | Metric | Metric | Metric |

Symbols to Use:

  • ✅ = Advantage
  • ❌ = Disadvantage
  • ⚠️ = Partial/Conditional
  • Use actual values when possible (numbers, percentages)

8. Real-World Example

Provide a concrete scenario showing the decision in action:

## Real-World Example

### Scenario: Add "dateOfBirth" field to User

**With Polyrepo (Multi-Repository):**

1. Update core

cd vedaghosham-core

Edit User entity

git commit -m "Add dateOfBirth" npm version patch # 1.2.0 → 1.2.1 npm publish

2. Update API

cd ../vedaghosham-api npm install @vedaghosham/core@1.2.1 # Wait for npm registry propagation

Update API code

git commit -m "Support dateOfBirth"

3. Update Web

cd ../vedaghosham-web npm install @vedaghosham/core@1.2.1

Update web code

git commit -m "Show dateOfBirth in profile"

Total time: 30-60 minutes


**With Monorepo (Chosen Approach):**

1. Update core

cd packages/core/src/user

Edit entity.ts and types.ts

2. Update functions (TypeScript error guides you!)

cd packages/functions/src/user

Update router.ts

3. Update web (TypeScript error guides you!)

cd packages/web/app/routes

Update profile route

4. Commit everything

git commit -m "Add dateOfBirth field"

Total time: 5-10 minutes ✅


**Winner:** Monorepo (6× faster, no versioning hassle)

9. Future Considerations

Discuss how the decision might evolve:

## Future Considerations

### Adding Public API
If we need a public API (for mobile apps, third-party integrations):
- **Option A**: Keep tRPC for internal use; add separate REST API for public
- **Option B**: Use tRPC + tRPC-OpenAPI adapter (generates OpenAPI from tRPC)

**Current Status:** Internal API only; no public API needed yet.

### Non-TypeScript Clients
If we need Python/Go clients:
- **Option A**: Create thin REST wrapper around tRPC backend
- **Option B**: Use HTTP directly (tRPC is just JSON-RPC over HTTP)

**Current Status:** Full TypeScript stack; no other languages planned.

10. Related Files

List all files implementing the decision:

## Related Files

### Backend
- `packages/functions/src/shared/trpc.ts` - tRPC initialization
- `packages/functions/src/shared/middleware.ts` - Auth middleware
- `packages/functions/src/{entity}/router.ts` - Entity routers

### Frontend
- `packages/web/app/lib/trpc.ts` - tRPC client factory
- `packages/web/app/routes/_app.*.tsx` - Usage in Remix routes

### Schemas
- `packages/core/src/{entity}/schema.ts` - Zod schemas used by tRPC

11. References

Include all relevant resources:

## References

- **tRPC Documentation**: https://trpc.io/
- **tRPC vs REST**: https://trpc.io/docs/concepts
- **ElectricSQL tRPC Talk**: https://www.youtube.com/watch?v=2LYM8gf184U
- **Zod Validation**: https://zod.dev/
- Related: ADR-004 (Single-Table DynamoDB)
- Related: ADR-010 (Zod Shared Validation)

Code Example Standards

1. Use Real, Working Code

// ✅ Good: Actual code from codebase
export async function loader({ request }: LoaderFunctionArgs) {
  await requireAuth(request);
  const trpc = await createServerClient(request);
  const user = await trpc.user.me.query();
  return json({ user });
}

// ❌ Bad: Pseudocode
export function loader() {
  // Get user
  return user;
}

2. Include File Paths

// ✅ Good: Shows where code lives
// packages/web/app/routes/_app.tsx
export async function loader({ request }: LoaderFunctionArgs) {
  // ...
}

// ❌ Bad: No context
export async function loader() {
  // ...
}

3. Add Explanatory Comments

// ✅ Good: Explains why
try {
  const result = await User.query.byEmail({ email: normalizedEmail }).go();
  return { isBlacklisted: false };
} catch (error) {
  // Database error - fail open to prevent auth system breakage
  console.error('Failed to check email blacklist, allowing send:', error);
  return { isBlacklisted: false };
}

// ❌ Bad: No explanation for non-obvious behavior
} catch (error) {
  return { isBlacklisted: false };
}

4. Show Before/After

// ❌ WRONG: Checks stale JWT token
export async function loader({ request }: LoaderFunctionArgs) {
  const userData = await requireCompleteProfile(request);
  // userData.profileCompleted is STALE!
}

// ✅ CORRECT: Loads fresh data from database
export async function loader({ request }: LoaderFunctionArgs) {
  await requireAuth(request);
  const trpc = await createServerClient(request);
  const user = await trpc.user.me.query();
  // user.profileCompleted is always fresh! ✅
}

Writing Style Guidelines

1. Be Concrete, Not Abstract

  • ✅ "Single table costs $5/month vs multi-table $35/month (85% savings)"
  • ❌ "Single table is cheaper"

2. Use Numbers and Metrics

  • ✅ "3-6× faster initial load (300-500ms vs 2-3 seconds)"
  • ❌ "Much faster initial load"

3. Show, Don't Just Tell

  • ✅ Include code examples showing the problem and solution
  • ❌ "The old approach had issues"

4. Explain Trade-offs Honestly

  • ✅ "What we lost: No OpenAPI docs. Why acceptable: Internal API only"
  • ❌ "Perfect solution with no downsides"

5. Future-Proof with Considerations

  • ✅ "If we need public API: Option A vs Option B. Current status: Not needed"
  • ❌ "We'll never need a public API"

Common Pitfalls to Avoid

❌ Don't Write Vague ADRs

## Decision
We decided to use a database.

❌ Don't Skip Alternatives

## Problem
We need to store data.

## Decision
Use DynamoDB.

(Missing: Why not PostgreSQL? MongoDB? What were the trade-offs?)

❌ Don't Use Pseudocode

function doSomething() {
  // Do the thing
}

❌ Don't Ignore Trade-offs

## Benefits
- Fast
- Cheap
- Easy

(Missing: What did we lose? Every decision has trade-offs)

❌ Don't Skip Real Examples

## Implementation
We implemented the feature.

(Missing: How? Show code!)

Checklist for Reviewing ADRs

Before finalizing an ADR, ensure:

  • Title is clear and descriptive (ADR-NNN format)
  • Date is in YYYY-MM-DD format
  • Status is set (Proposed/Accepted/Deprecated/Superseded)
  • Problem section explains context with 3+ paragraphs
  • Alternatives section lists 2-4 options considered
  • Decision section has clear justification (3+ reasons)
  • Implementation has real code examples with file paths
  • Benefits section quantifies advantages (metrics/percentages)
  • Trade-offs section honestly discusses limitations
  • Comparison table compares alternatives across multiple dimensions
  • Real-World Example shows concrete scenario
  • Future Considerations discusses evolution/extensions
  • Related Files lists all implementation files
  • References includes external docs and cross-references
  • Code examples use ✅/❌ to show right/wrong patterns
  • Numbers and metrics used throughout (not just "better/faster")
  • All code examples include comments explaining why

ADR Template

Use this template when creating a new ADR:

# ADR-NNN: [Title]

**Date:** YYYY-MM-DD
**Status:** Proposed | Accepted | Deprecated | Superseded
**Context:** [One-line summary]

---

## Problem

[3-5 paragraph problem description]

### Option 1: [First Alternative]
[Code/description]

**Problems:**
- Issue 1
- Issue 2

### Option 2: [Second Alternative]
[Code/description]

**Problems:**
- Issue 1
- Issue 2

---

## Decision

**Use [Chosen Approach] for [Purpose].**

[1-2 paragraph justification]

**Why [Chosen Approach]:**
1. Reason 1
2. Reason 2
3. Reason 3

---

## Implementation

### 1. [Implementation Aspect 1]
[Code examples]

### 2. [Implementation Aspect 2]
[Code examples]

---

## Benefits

### 1. **[Benefit Name]**
[Explanation with evidence]

### 2. **[Benefit Name]**
[Explanation with evidence]

---

## Trade-offs

### What We Gained
- ✅ Benefit 1
- ✅ Benefit 2

### What We Lost
- ❌ Limitation 1
- ❌ Limitation 2

### Why Trade-offs Are Acceptable
1. **Limitation 1**: Explanation
2. **Limitation 2**: Explanation

---

## Comparison

| Feature | Alternative 1 | Alternative 2 | Chosen |
|---------|--------------|---------------|--------|
| **Feature 1** | Value | Value | Value |

---

## Real-World Example

### Scenario: [Use Case]

**With [Alternative]:**
[Step-by-step flow]

**With [Chosen Approach]:**
[Step-by-step flow]

**Winner:** [Chosen] ([quantified benefit])

---

## Future Considerations

### [Topic 1]
[Discussion]

**Current Status:** [State]

---

## Related Files

### [Category 1]
- `path/to/file.ts` - Description

---

## References

- **[Resource]**: [URL]
- Related: ADR-XXX

Example: Simplified ADR

Here's a simplified example showing the key elements:

# ADR-016: Rate Limiting for API Endpoints

**Date:** 2025-12-20
**Status:** Proposed
**Context:** Protecting API from abuse and ensuring fair usage

---

## Problem

VedaGhosham's tRPC API is publicly accessible (after authentication). Without
rate limiting, we risk:

1. **DoS Attacks**: Malicious users could overwhelm Lambda functions
2. **Cost Spikes**: Unlimited requests = unlimited AWS costs
3. **Poor UX**: One user's heavy usage slows down others
4. **No Abuse Protection**: No mechanism to block bad actors

### Option 1: No Rate Limiting

// No protection - anyone can spam requests export const userRouter = router({ list: protectedProcedure.query(async () => { return await User.scan.go(); // Expensive query, no limits }), });


**Problems:**

- No protection against abuse
- AWS costs unbounded
- Poor experience for legitimate users

### Option 2: Lambda Concurrency Limits

Set reserved concurrency on Lambda functions.

**Problems:**

- All-or-nothing (affects all users equally)
- No per-user fairness
- Hard to configure correctly

### Option 3: DynamoDB-Based Rate Limiting

Track request counts per user in DynamoDB with TTL.

**Benefits:**

- Per-user fairness
- Serverless (no Redis needed)
- Fine-grained control

---

## Decision

**Use DynamoDB-based rate limiting with per-user counters and TTL.**

We'll create a RateLimit entity tracking requests per user per time window.

**Why DynamoDB Rate Limiting:**

1. **Serverless**: No Redis/Memcached infrastructure needed
2. **Per-User Fairness**: Each user has independent limit
3. **Automatic Cleanup**: DynamoDB TTL removes old records
4. **Fine-Grained**: Can set limits per endpoint or globally

---

## Implementation

### 1. RateLimit Entity

// packages/core/src/rate-limit/entity.ts export const RateLimit = new Entity({ model: { entity: 'RateLimit', version: '1', service: 'vedaghosham', }, attributes: { userId: { type: 'string', required: true }, endpoint: { type: 'string', required: true }, windowStart: { type: 'number', required: true }, // Unix timestamp requestCount: { type: 'number', required: true, default: 0 }, ttl: { type: 'number' }, // DynamoDB TTL (auto-delete after 1 hour) }, indexes: { primary: { pk: { field: 'pk', composite: ['userId', 'endpoint'] }, sk: { field: 'sk', composite: ['windowStart'] }, }, }, }, configuration);


### 2. Rate Limiting Middleware

// packages/functions/src/shared/rate-limit.ts const RATE_LIMITS = { 'user.list': { requests: 100, windowMs: 60000 }, // 100 req/min 'course.create': { requests: 10, windowMs: 60000 }, // 10 req/min default: { requests: 1000, windowMs: 60000 }, // 1000 req/min };

export const rateLimitMiddleware = t.middleware(async ({ ctx, path, next }) => { const userId = ctx.user?.userId; if (!userId) return next(); // Skip for unauthenticated

const limit = RATE_LIMITS[path] || RATE_LIMITS.default; const windowStart = Math.floor(Date.now() / limit.windowMs) * limit.windowMs;

// Check current count const result = await RateLimit.get({ userId, endpoint: path, windowStart, }).go();

if (result.data && result.data.requestCount >= limit.requests) { throw new TRPCError({ code: 'TOO_MANY_REQUESTS', message: Rate limit exceeded. Try again in ${limit.windowMs / 1000}s, }); }

// Increment counter await RateLimit.upsert({ userId, endpoint: path, windowStart, requestCount: (result.data?.requestCount || 0) + 1, ttl: Math.floor(Date.now() / 1000) + 3600, // Expire after 1 hour }).go();

return next(); });


### 3. Apply to Procedures

// packages/functions/src/shared/procedures.ts export const protectedProcedure = t.procedure .use(isAuthenticated) .use(rateLimitMiddleware);


---

## Benefits

### 1. **Cost Protection**

Rate limiting prevents runaway costs from abuse.

**Example:**

- Without limit: Malicious user makes 1M requests = $200+ Lambda cost
- With limit: Blocked at 1,000 requests = $0.20 maximum cost per user
- **Savings: 99.9%** in abuse scenario

### 2. **Fair Resource Allocation**

Each user has independent quota (one user can't starve others).

### 3. **No Additional Infrastructure**

Uses existing DynamoDB table (no Redis/Memcached needed).

---

## Trade-offs

### What We Gained

- ✅ Protection from abuse and DoS
- ✅ Cost predictability
- ✅ Per-user fairness
- ✅ Serverless (no Redis)

### What We Lost

- ❌ DynamoDB write costs (1 write per request)
- ❌ Slight latency increase (~10ms per request)
- ❌ Complexity (middleware + entity)

### Why Trade-offs Are Acceptable

1. **DynamoDB Writes**: ~$0.001 per 1,000 requests (negligible vs abuse cost)
2. **Latency**: 10ms overhead acceptable for cost/abuse protection
3. **Complexity**: Essential for production API

---

## Comparison

| Feature | No Limit | Lambda Limits | DynamoDB Limit |
| --- | --- | --- | --- |
| **Cost Protection** | ❌ No | ⚠️ Global | ✅ Per-user |
| **Fairness** | ❌ No | ❌ No | ✅ Yes |
| **Infrastructure** | ✅ None | ✅ None | ✅ Existing DB |
| **Granularity** | N/A | ❌ Coarse | ✅ Fine-grained |

---

## Real-World Example

### Scenario: User spams "list all courses" endpoint

**Without Rate Limiting:**

User makes 10,000 requests in 1 minute → 10,000 Lambda invocations × $0.0000002 = $2.00 → 10,000 DynamoDB scans × $0.00025 = $2.50 → Total cost: $4.50 per abuse incident → API slow for all users


**With Rate Limiting (100 req/min):**

User makes 10,000 requests in 1 minute → First 100 succeed → Next 9,900 blocked with 429 error → Cost: 100 requests = $0.045 → Other users unaffected


**Winner:** Rate limiting (99% cost reduction, better UX)

---

## Future Considerations

### Distributed Rate Limiting

If we need multi-region:

- Use DynamoDB Global Tables for consistent limits across regions

**Current Status:** Single region sufficient.

### Redis Alternative

If DynamoDB becomes too expensive:

- Switch to ElastiCache Redis (faster, lower per-request cost)

**Current Status:** DynamoDB cost acceptable (<$1/month).

---

## Related Files

### Core

- `packages/core/src/rate-limit/entity.ts` - RateLimit entity

### Functions

- `packages/functions/src/shared/rate-limit.ts` - Middleware
- `packages/functions/src/shared/procedures.ts` - Applied to procedures

### Infrastructure

- `infra/database.ts` - DynamoDB table (already has TTL enabled)

---

## References

- **DynamoDB TTL**: [https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html)
- **Rate Limiting Patterns**: [https://aws.amazon.com/blogs/architecture/rate-limiting-strategies-for-serverless-applications/](https://aws.amazon.com/blogs/architecture/rate-limiting-strategies-for-serverless-applications/)
- **tRPC Middleware**: [https://trpc.io/docs/server/middlewares](https://trpc.io/docs/server/middlewares)
- Related: ADR-004 (Single-Table DynamoDB)
- Related: ADR-005 (tRPC Over REST)

Summary

High-quality ADRs in VedaGhosham:

  1. Document significant decisions (not routine changes)
  2. Show alternatives considered (2-4 options with trade-offs)
  3. Provide working code examples (real code from codebase)
  4. Quantify benefits (metrics, percentages, cost savings)
  5. Explain trade-offs honestly (what we lost and why it's acceptable)
  6. Include comparison tables (features across alternatives)
  7. Show real-world scenarios (concrete before/after examples)
  8. Discuss future evolution (how decision might change)
  9. List all related files (where implementation lives)
  10. Reference external docs (AWS docs, library docs, related ADRs)

Use the ADR template and checklist to ensure comprehensive, maintainable architecture documentation that will serve the project for years to come.

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

34.16%
按下载量换算27

Claude

32.95%
按下载量换算26

Cursor

17.48%
按下载量换算14

Gemini CLI

8.83%
按下载量换算7

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills