oh-my-customcode 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +287 -0
- package/dist/cli/index.js +13299 -0
- package/dist/index.js +927 -0
- package/package.json +74 -0
- package/templates/.claude/contexts/dev.md +20 -0
- package/templates/.claude/contexts/ecomode.md +63 -0
- package/templates/.claude/contexts/index.yaml +41 -0
- package/templates/.claude/contexts/research.md +28 -0
- package/templates/.claude/contexts/review.md +23 -0
- package/templates/.claude/hooks/hooks.json +185 -0
- package/templates/.claude/hooks/hud/index.yaml +27 -0
- package/templates/.claude/hooks/hud/update-status.sh +32 -0
- package/templates/.claude/hooks/index.yaml +46 -0
- package/templates/.claude/hooks/memory-persistence/pre-compact.sh +37 -0
- package/templates/.claude/hooks/memory-persistence/session-end.sh +64 -0
- package/templates/.claude/hooks/memory-persistence/session-start.sh +41 -0
- package/templates/.claude/hooks/strategic-compact/suggest-compact.sh +50 -0
- package/templates/.claude/install-hooks.sh +100 -0
- package/templates/.claude/rules/MAY-optimization.md +93 -0
- package/templates/.claude/rules/MUST-agent-design.md +107 -0
- package/templates/.claude/rules/MUST-agent-identification.md +108 -0
- package/templates/.claude/rules/MUST-continuous-improvement.md +132 -0
- package/templates/.claude/rules/MUST-intent-transparency.md +199 -0
- package/templates/.claude/rules/MUST-language-policy.md +62 -0
- package/templates/.claude/rules/MUST-orchestrator-coordination.md +266 -0
- package/templates/.claude/rules/MUST-parallel-execution.md +341 -0
- package/templates/.claude/rules/MUST-permissions.md +84 -0
- package/templates/.claude/rules/MUST-safety.md +69 -0
- package/templates/.claude/rules/MUST-sync-verification.md +219 -0
- package/templates/.claude/rules/MUST-tool-identification.md +112 -0
- package/templates/.claude/rules/SHOULD-ecomode.md +145 -0
- package/templates/.claude/rules/SHOULD-error-handling.md +102 -0
- package/templates/.claude/rules/SHOULD-hud-statusline.md +89 -0
- package/templates/.claude/rules/SHOULD-interaction.md +103 -0
- package/templates/.claude/rules/SHOULD-memory-integration.md +114 -0
- package/templates/.claude/rules/SHOULD-pipeline-mode.md +165 -0
- package/templates/.claude/rules/index.yaml +125 -0
- package/templates/.claude/uninstall-hooks.sh +52 -0
- package/templates/CLAUDE.md.en +259 -0
- package/templates/CLAUDE.md.ko +259 -0
- package/templates/agents/index.yaml +237 -0
- package/templates/agents/infra-engineer/aws-expert/AGENT.md +47 -0
- package/templates/agents/infra-engineer/aws-expert/index.yaml +27 -0
- package/templates/agents/infra-engineer/docker-expert/AGENT.md +47 -0
- package/templates/agents/infra-engineer/docker-expert/index.yaml +27 -0
- package/templates/agents/manager/creator/AGENT.md +274 -0
- package/templates/agents/manager/creator/index.yaml +66 -0
- package/templates/agents/manager/gitnerd/AGENT.md +91 -0
- package/templates/agents/manager/gitnerd/index.yaml +55 -0
- package/templates/agents/manager/sauron/AGENT.md +153 -0
- package/templates/agents/manager/sauron/index.yaml +52 -0
- package/templates/agents/manager/supplier/AGENT.md +142 -0
- package/templates/agents/manager/supplier/index.yaml +31 -0
- package/templates/agents/manager/sync-checker/AGENT.md +34 -0
- package/templates/agents/manager/sync-checker/index.yaml +32 -0
- package/templates/agents/manager/updater/AGENT.md +125 -0
- package/templates/agents/manager/updater/index.yaml +31 -0
- package/templates/agents/orchestrator/dev-lead/AGENT.md +116 -0
- package/templates/agents/orchestrator/dev-lead/index.yaml +73 -0
- package/templates/agents/orchestrator/planner/AGENT.md +102 -0
- package/templates/agents/orchestrator/planner/index.yaml +38 -0
- package/templates/agents/orchestrator/qa-lead/AGENT.md +92 -0
- package/templates/agents/orchestrator/qa-lead/index.yaml +40 -0
- package/templates/agents/orchestrator/secretary/AGENT.md +132 -0
- package/templates/agents/orchestrator/secretary/index.yaml +55 -0
- package/templates/agents/qa-team/qa-engineer/AGENT.md +98 -0
- package/templates/agents/qa-team/qa-engineer/index.yaml +59 -0
- package/templates/agents/qa-team/qa-planner/AGENT.md +75 -0
- package/templates/agents/qa-team/qa-planner/index.yaml +47 -0
- package/templates/agents/qa-team/qa-writer/AGENT.md +98 -0
- package/templates/agents/qa-team/qa-writer/index.yaml +44 -0
- package/templates/agents/sw-architect/documenter/AGENT.md +120 -0
- package/templates/agents/sw-architect/documenter/index.yaml +39 -0
- package/templates/agents/sw-architect/speckit-agent/AGENT.md +127 -0
- package/templates/agents/sw-architect/speckit-agent/index.yaml +78 -0
- package/templates/agents/sw-engineer/backend/express-expert/AGENT.md +132 -0
- package/templates/agents/sw-engineer/backend/express-expert/index.yaml +36 -0
- package/templates/agents/sw-engineer/backend/fastapi-expert/AGENT.md +47 -0
- package/templates/agents/sw-engineer/backend/fastapi-expert/index.yaml +27 -0
- package/templates/agents/sw-engineer/backend/go-backend-expert/AGENT.md +47 -0
- package/templates/agents/sw-engineer/backend/go-backend-expert/index.yaml +27 -0
- package/templates/agents/sw-engineer/backend/nestjs-expert/AGENT.md +107 -0
- package/templates/agents/sw-engineer/backend/nestjs-expert/index.yaml +43 -0
- package/templates/agents/sw-engineer/backend/springboot-expert/AGENT.md +103 -0
- package/templates/agents/sw-engineer/backend/springboot-expert/index.yaml +69 -0
- package/templates/agents/sw-engineer/frontend/svelte-agent/AGENT.md +71 -0
- package/templates/agents/sw-engineer/frontend/svelte-agent/index.yaml +41 -0
- package/templates/agents/sw-engineer/frontend/vercel-agent/AGENT.md +67 -0
- package/templates/agents/sw-engineer/frontend/vercel-agent/index.yaml +43 -0
- package/templates/agents/sw-engineer/frontend/vuejs-agent/AGENT.md +71 -0
- package/templates/agents/sw-engineer/frontend/vuejs-agent/index.yaml +48 -0
- package/templates/agents/sw-engineer/language/golang-expert/AGENT.md +47 -0
- package/templates/agents/sw-engineer/language/golang-expert/index.yaml +27 -0
- package/templates/agents/sw-engineer/language/java21-expert/AGENT.md +122 -0
- package/templates/agents/sw-engineer/language/java21-expert/index.yaml +51 -0
- package/templates/agents/sw-engineer/language/kotlin-expert/AGENT.md +47 -0
- package/templates/agents/sw-engineer/language/kotlin-expert/index.yaml +27 -0
- package/templates/agents/sw-engineer/language/python-expert/AGENT.md +47 -0
- package/templates/agents/sw-engineer/language/python-expert/index.yaml +27 -0
- package/templates/agents/sw-engineer/language/rust-expert/AGENT.md +47 -0
- package/templates/agents/sw-engineer/language/rust-expert/index.yaml +27 -0
- package/templates/agents/sw-engineer/language/typescript-expert/AGENT.md +47 -0
- package/templates/agents/sw-engineer/language/typescript-expert/index.yaml +27 -0
- package/templates/agents/sw-engineer/tooling/bun-expert/AGENT.md +73 -0
- package/templates/agents/sw-engineer/tooling/bun-expert/index.yaml +46 -0
- package/templates/agents/sw-engineer/tooling/npm-expert/AGENT.md +160 -0
- package/templates/agents/sw-engineer/tooling/npm-expert/index.yaml +45 -0
- package/templates/agents/sw-engineer/tooling/optimizer/AGENT.md +170 -0
- package/templates/agents/sw-engineer/tooling/optimizer/index.yaml +45 -0
- package/templates/agents/system/memory-keeper/AGENT.md +126 -0
- package/templates/agents/system/memory-keeper/index.yaml +45 -0
- package/templates/agents/system/naggy/AGENT.md +72 -0
- package/templates/agents/system/naggy/index.yaml +35 -0
- package/templates/commands/COMMANDS.md +136 -0
- package/templates/commands/creator/agent.md +121 -0
- package/templates/commands/dev/refactor.md +126 -0
- package/templates/commands/dev/review.md +82 -0
- package/templates/commands/git/branch.yaml +8 -0
- package/templates/commands/git/commit.yaml +4 -0
- package/templates/commands/git/pr.yaml +4 -0
- package/templates/commands/git/status.yaml +4 -0
- package/templates/commands/git/sync.yaml +4 -0
- package/templates/commands/index.yaml +225 -0
- package/templates/commands/intent/explain.md +144 -0
- package/templates/commands/memory/recall.md +164 -0
- package/templates/commands/memory/save.md +128 -0
- package/templates/commands/naggy/add.yaml +8 -0
- package/templates/commands/naggy/done.yaml +8 -0
- package/templates/commands/naggy/list.yaml +4 -0
- package/templates/commands/naggy/priority.yaml +11 -0
- package/templates/commands/naggy/remind.yaml +4 -0
- package/templates/commands/npm/audit.yaml +62 -0
- package/templates/commands/npm/publish.yaml +52 -0
- package/templates/commands/npm/version.yaml +62 -0
- package/templates/commands/optimize/analyze.yaml +34 -0
- package/templates/commands/optimize/bundle.yaml +50 -0
- package/templates/commands/optimize/report.yaml +56 -0
- package/templates/commands/pipeline/list.md +81 -0
- package/templates/commands/pipeline/run.md +127 -0
- package/templates/commands/sauron/quick.yaml +4 -0
- package/templates/commands/sauron/report.yaml +4 -0
- package/templates/commands/sauron/watch.yaml +4 -0
- package/templates/commands/supplier/audit.md +133 -0
- package/templates/commands/supplier/fix.md +121 -0
- package/templates/commands/sync/agents.yaml +4 -0
- package/templates/commands/sync/check.yaml +4 -0
- package/templates/commands/sync/commands.yaml +4 -0
- package/templates/commands/sync/docs.yaml +4 -0
- package/templates/commands/sync/fix.yaml +4 -0
- package/templates/commands/system/help.md +137 -0
- package/templates/commands/system/lists.md +86 -0
- package/templates/commands/system/status.md +163 -0
- package/templates/commands/updater/docs.md +165 -0
- package/templates/commands/updater/external.md +214 -0
- package/templates/guides/aws/common-patterns.md +169 -0
- package/templates/guides/aws/index.yaml +26 -0
- package/templates/guides/aws/well-architected.md +143 -0
- package/templates/guides/claude-code/01-overview.md +42 -0
- package/templates/guides/claude-code/03-tools.md +107 -0
- package/templates/guides/claude-code/04-agent-skills.md +90 -0
- package/templates/guides/claude-code/05-agent-sdk.md +129 -0
- package/templates/guides/claude-code/06-mcp.md +165 -0
- package/templates/guides/claude-code/07-prompt-engineering.md +100 -0
- package/templates/guides/claude-code/08-testing.md +58 -0
- package/templates/guides/claude-code/09-guardrails.md +80 -0
- package/templates/guides/claude-code/10-monitoring.md +89 -0
- package/templates/guides/claude-code/index.yaml +51 -0
- package/templates/guides/docker/compose-best-practices.md +284 -0
- package/templates/guides/docker/dockerfile-best-practices.md +262 -0
- package/templates/guides/docker/index.yaml +26 -0
- package/templates/guides/fastapi/best-practices.md +232 -0
- package/templates/guides/fastapi/index.yaml +21 -0
- package/templates/guides/go-backend/index.yaml +26 -0
- package/templates/guides/go-backend/project-layout.md +243 -0
- package/templates/guides/go-backend/uber-style.md +212 -0
- package/templates/guides/golang/concurrency.md +282 -0
- package/templates/guides/golang/effective-go.md +309 -0
- package/templates/guides/golang/error-handling.md +250 -0
- package/templates/guides/golang/index.yaml +27 -0
- package/templates/guides/index.yaml +101 -0
- package/templates/guides/kotlin/coding-conventions.md +247 -0
- package/templates/guides/kotlin/idioms.md +234 -0
- package/templates/guides/kotlin/index.yaml +26 -0
- package/templates/guides/python/index.yaml +26 -0
- package/templates/guides/python/pep8-style-guide.md +202 -0
- package/templates/guides/python/zen-of-python.md +79 -0
- package/templates/guides/rust/error-handling.md +262 -0
- package/templates/guides/rust/index.yaml +26 -0
- package/templates/guides/rust/ownership.md +180 -0
- package/templates/guides/springboot/best-practices.md +361 -0
- package/templates/guides/springboot/index.yaml +22 -0
- package/templates/guides/typescript/advanced-types.md +225 -0
- package/templates/guides/typescript/index.yaml +26 -0
- package/templates/guides/typescript/type-system.md +219 -0
- package/templates/guides/web-design/accessibility.md +66 -0
- package/templates/guides/web-design/index.yaml +20 -0
- package/templates/guides/web-design/performance.md +102 -0
- package/templates/pipelines/examples/code-review.yaml +66 -0
- package/templates/pipelines/index.yaml +18 -0
- package/templates/pipelines/templates/pipeline-template.yaml +50 -0
- package/templates/skills/backend/fastapi-best-practices/SKILL.md +269 -0
- package/templates/skills/backend/fastapi-best-practices/index.yaml +25 -0
- package/templates/skills/backend/go-backend-best-practices/SKILL.md +337 -0
- package/templates/skills/backend/go-backend-best-practices/index.yaml +26 -0
- package/templates/skills/backend/springboot-best-practices/SKILL.md +356 -0
- package/templates/skills/backend/springboot-best-practices/index.yaml +27 -0
- package/templates/skills/development/go-best-practices/SKILL.md +202 -0
- package/templates/skills/development/go-best-practices/index.yaml +25 -0
- package/templates/skills/development/kotlin-best-practices/SKILL.md +255 -0
- package/templates/skills/development/kotlin-best-practices/index.yaml +27 -0
- package/templates/skills/development/python-best-practices/SKILL.md +221 -0
- package/templates/skills/development/python-best-practices/index.yaml +25 -0
- package/templates/skills/development/react-best-practices/SKILL.md +100 -0
- package/templates/skills/development/react-best-practices/index.yaml +39 -0
- package/templates/skills/development/rust-best-practices/SKILL.md +266 -0
- package/templates/skills/development/rust-best-practices/index.yaml +26 -0
- package/templates/skills/development/typescript-best-practices/SKILL.md +320 -0
- package/templates/skills/development/typescript-best-practices/index.yaml +28 -0
- package/templates/skills/development/vercel-deploy/SKILL.md +73 -0
- package/templates/skills/development/vercel-deploy/index.yaml +30 -0
- package/templates/skills/development/web-design-guidelines/SKILL.md +117 -0
- package/templates/skills/development/web-design-guidelines/index.yaml +34 -0
- package/templates/skills/index.yaml +129 -0
- package/templates/skills/infrastructure/aws-best-practices/SKILL.md +279 -0
- package/templates/skills/infrastructure/aws-best-practices/index.yaml +27 -0
- package/templates/skills/infrastructure/docker-best-practices/SKILL.md +274 -0
- package/templates/skills/infrastructure/docker-best-practices/index.yaml +26 -0
- package/templates/skills/orchestration/intent-detection/SKILL.md +214 -0
- package/templates/skills/orchestration/intent-detection/index.yaml +30 -0
- package/templates/skills/orchestration/intent-detection/patterns/agent-triggers.yaml +333 -0
- package/templates/skills/orchestration/pipeline-execution/SKILL.md +188 -0
- package/templates/skills/orchestration/pipeline-execution/index.yaml +27 -0
- package/templates/skills/system/memory-management/SKILL.md +194 -0
- package/templates/skills/system/memory-management/index.yaml +30 -0
- package/templates/skills/system/result-aggregation/SKILL.md +163 -0
- package/templates/skills/system/result-aggregation/index.yaml +36 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# FastAPI Best Practices Skill
|
|
2
|
+
|
|
3
|
+
> **Category**: Backend
|
|
4
|
+
> **Source**: Internal (based on FastAPI docs and community patterns)
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
Apply FastAPI patterns for building high-performance async APIs.
|
|
9
|
+
|
|
10
|
+
## Rules
|
|
11
|
+
|
|
12
|
+
### 1. Project Structure
|
|
13
|
+
|
|
14
|
+
```yaml
|
|
15
|
+
structure:
|
|
16
|
+
domain_based: true
|
|
17
|
+
module_contents:
|
|
18
|
+
- router.py: API endpoints
|
|
19
|
+
- schemas.py: Pydantic models
|
|
20
|
+
- models.py: Database models
|
|
21
|
+
- service.py: Business logic
|
|
22
|
+
- dependencies.py: Route validators
|
|
23
|
+
- constants.py: Module constants
|
|
24
|
+
- config.py: Module configuration
|
|
25
|
+
- exceptions.py: Custom exceptions
|
|
26
|
+
- utils.py: Helper functions
|
|
27
|
+
|
|
28
|
+
imports:
|
|
29
|
+
style: explicit
|
|
30
|
+
example: "from src.auth import constants as auth_constants"
|
|
31
|
+
|
|
32
|
+
layout: |
|
|
33
|
+
src/
|
|
34
|
+
├── auth/
|
|
35
|
+
│ ├── router.py
|
|
36
|
+
│ ├── schemas.py
|
|
37
|
+
│ ├── models.py
|
|
38
|
+
│ ├── service.py
|
|
39
|
+
│ └── dependencies.py
|
|
40
|
+
├── users/
|
|
41
|
+
│ └── ...
|
|
42
|
+
├── config.py
|
|
43
|
+
└── main.py
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. Async Patterns
|
|
47
|
+
|
|
48
|
+
```yaml
|
|
49
|
+
io_intensive:
|
|
50
|
+
use: "async def"
|
|
51
|
+
await: "asyncio.sleep(), httpx, asyncpg, etc."
|
|
52
|
+
example: |
|
|
53
|
+
async def fetch_data():
|
|
54
|
+
async with httpx.AsyncClient() as client:
|
|
55
|
+
response = await client.get(url)
|
|
56
|
+
return response.json()
|
|
57
|
+
|
|
58
|
+
sync_io:
|
|
59
|
+
use: "def (regular function)"
|
|
60
|
+
reason: FastAPI offloads to threadpool automatically
|
|
61
|
+
example: |
|
|
62
|
+
def read_file():
|
|
63
|
+
with open('file.txt') as f:
|
|
64
|
+
return f.read()
|
|
65
|
+
|
|
66
|
+
cpu_intensive:
|
|
67
|
+
avoid: async and threadpool
|
|
68
|
+
use: separate worker processes
|
|
69
|
+
example: "Use Celery or multiprocessing"
|
|
70
|
+
|
|
71
|
+
never:
|
|
72
|
+
- "time.sleep() in async functions"
|
|
73
|
+
- "Blocking I/O in async functions"
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 3. Pydantic Models
|
|
77
|
+
|
|
78
|
+
```yaml
|
|
79
|
+
validation:
|
|
80
|
+
use_builtin: regex, enums, email, URL validators
|
|
81
|
+
custom_validators: for complex logic
|
|
82
|
+
|
|
83
|
+
base_model:
|
|
84
|
+
create_custom: true
|
|
85
|
+
purpose: enforce application-wide standards
|
|
86
|
+
example: |
|
|
87
|
+
from pydantic import BaseModel
|
|
88
|
+
from datetime import datetime
|
|
89
|
+
|
|
90
|
+
class AppBaseModel(BaseModel):
|
|
91
|
+
class Config:
|
|
92
|
+
from_attributes = True
|
|
93
|
+
json_encoders = {
|
|
94
|
+
datetime: lambda v: v.isoformat()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
settings:
|
|
98
|
+
split: across modules
|
|
99
|
+
avoid: single global configuration
|
|
100
|
+
example: |
|
|
101
|
+
# auth/config.py
|
|
102
|
+
class AuthSettings(BaseSettings):
|
|
103
|
+
jwt_secret: str
|
|
104
|
+
jwt_algorithm: str = "HS256"
|
|
105
|
+
|
|
106
|
+
# database/config.py
|
|
107
|
+
class DatabaseSettings(BaseSettings):
|
|
108
|
+
url: str
|
|
109
|
+
pool_size: int = 5
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### 4. Dependencies
|
|
113
|
+
|
|
114
|
+
```yaml
|
|
115
|
+
usage:
|
|
116
|
+
- Dependency injection
|
|
117
|
+
- Validation against database
|
|
118
|
+
- Authentication/authorization
|
|
119
|
+
- Request scoped caching
|
|
120
|
+
|
|
121
|
+
patterns:
|
|
122
|
+
chain: avoid code repetition
|
|
123
|
+
cache: FastAPI caches within request scope
|
|
124
|
+
decouple: small, reusable functions
|
|
125
|
+
|
|
126
|
+
example: |
|
|
127
|
+
async def get_current_user(
|
|
128
|
+
token: str = Depends(oauth2_scheme),
|
|
129
|
+
db: Session = Depends(get_db)
|
|
130
|
+
) -> User:
|
|
131
|
+
user = await db.get_user_by_token(token)
|
|
132
|
+
if not user:
|
|
133
|
+
raise HTTPException(status_code=401)
|
|
134
|
+
return user
|
|
135
|
+
|
|
136
|
+
async def get_active_user(
|
|
137
|
+
user: User = Depends(get_current_user)
|
|
138
|
+
) -> User:
|
|
139
|
+
if not user.is_active:
|
|
140
|
+
raise HTTPException(status_code=403)
|
|
141
|
+
return user
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 5. Error Handling
|
|
145
|
+
|
|
146
|
+
```yaml
|
|
147
|
+
custom_exceptions:
|
|
148
|
+
scope: module-specific
|
|
149
|
+
purpose: clarity and consistency
|
|
150
|
+
|
|
151
|
+
pattern: |
|
|
152
|
+
# auth/exceptions.py
|
|
153
|
+
class AuthException(Exception):
|
|
154
|
+
pass
|
|
155
|
+
|
|
156
|
+
class InvalidCredentials(AuthException):
|
|
157
|
+
pass
|
|
158
|
+
|
|
159
|
+
class TokenExpired(AuthException):
|
|
160
|
+
pass
|
|
161
|
+
|
|
162
|
+
# auth/router.py
|
|
163
|
+
@router.post("/login")
|
|
164
|
+
async def login(credentials: LoginSchema):
|
|
165
|
+
try:
|
|
166
|
+
return await auth_service.login(credentials)
|
|
167
|
+
except InvalidCredentials:
|
|
168
|
+
raise HTTPException(
|
|
169
|
+
status_code=401,
|
|
170
|
+
detail="Invalid credentials"
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
exception_handlers: |
|
|
174
|
+
@app.exception_handler(AuthException)
|
|
175
|
+
async def auth_exception_handler(request, exc):
|
|
176
|
+
return JSONResponse(
|
|
177
|
+
status_code=401,
|
|
178
|
+
content={"detail": str(exc)}
|
|
179
|
+
)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### 6. Database
|
|
183
|
+
|
|
184
|
+
```yaml
|
|
185
|
+
naming:
|
|
186
|
+
establish: upfront conventions
|
|
187
|
+
consistency: across all models
|
|
188
|
+
|
|
189
|
+
migrations:
|
|
190
|
+
tool: Alembic
|
|
191
|
+
naming: explicit naming rules
|
|
192
|
+
|
|
193
|
+
design:
|
|
194
|
+
approach: SQL-first
|
|
195
|
+
then: add Pydantic models
|
|
196
|
+
|
|
197
|
+
patterns: |
|
|
198
|
+
# Use async database drivers
|
|
199
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
200
|
+
|
|
201
|
+
async def get_user(db: AsyncSession, user_id: int):
|
|
202
|
+
result = await db.execute(
|
|
203
|
+
select(User).where(User.id == user_id)
|
|
204
|
+
)
|
|
205
|
+
return result.scalar_one_or_none()
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### 7. API Design
|
|
209
|
+
|
|
210
|
+
```yaml
|
|
211
|
+
routing:
|
|
212
|
+
prefix: meaningful module prefix
|
|
213
|
+
tags: for documentation grouping
|
|
214
|
+
|
|
215
|
+
responses:
|
|
216
|
+
schema: always define response models
|
|
217
|
+
status_codes: document all possible codes
|
|
218
|
+
|
|
219
|
+
example: |
|
|
220
|
+
router = APIRouter(
|
|
221
|
+
prefix="/users",
|
|
222
|
+
tags=["users"]
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
@router.get(
|
|
226
|
+
"/{user_id}",
|
|
227
|
+
response_model=UserResponse,
|
|
228
|
+
responses={
|
|
229
|
+
404: {"model": ErrorResponse}
|
|
230
|
+
}
|
|
231
|
+
)
|
|
232
|
+
async def get_user(user_id: int):
|
|
233
|
+
...
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### 8. Testing
|
|
237
|
+
|
|
238
|
+
```yaml
|
|
239
|
+
setup:
|
|
240
|
+
async_client: from day one
|
|
241
|
+
structure: mirror module layout
|
|
242
|
+
|
|
243
|
+
patterns: |
|
|
244
|
+
import pytest
|
|
245
|
+
from httpx import AsyncClient
|
|
246
|
+
|
|
247
|
+
@pytest.fixture
|
|
248
|
+
async def client():
|
|
249
|
+
async with AsyncClient(app=app, base_url="http://test") as ac:
|
|
250
|
+
yield ac
|
|
251
|
+
|
|
252
|
+
@pytest.mark.asyncio
|
|
253
|
+
async def test_get_user(client):
|
|
254
|
+
response = await client.get("/users/1")
|
|
255
|
+
assert response.status_code == 200
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Application
|
|
259
|
+
|
|
260
|
+
When writing FastAPI code:
|
|
261
|
+
|
|
262
|
+
1. **Always** use domain-based project structure
|
|
263
|
+
2. **Always** use `async def` for I/O operations
|
|
264
|
+
3. **Prefer** Pydantic for all validation
|
|
265
|
+
4. **Use** dependencies for reusable logic
|
|
266
|
+
5. **Define** module-specific exceptions
|
|
267
|
+
6. **Document** API with response models
|
|
268
|
+
7. **Test** with async client
|
|
269
|
+
8. **Use** Ruff for code quality
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# FastAPI Best Practices Skill
|
|
2
|
+
|
|
3
|
+
metadata:
|
|
4
|
+
name: fastapi-best-practices
|
|
5
|
+
category: backend
|
|
6
|
+
description: FastAPI patterns for high-performance async APIs
|
|
7
|
+
|
|
8
|
+
source:
|
|
9
|
+
type: internal
|
|
10
|
+
reference:
|
|
11
|
+
- https://fastapi.tiangolo.com/
|
|
12
|
+
- https://github.com/zhanymkanov/fastapi-best-practices
|
|
13
|
+
|
|
14
|
+
provides:
|
|
15
|
+
- Project structure patterns
|
|
16
|
+
- Async/await best practices
|
|
17
|
+
- Pydantic validation patterns
|
|
18
|
+
- Dependency injection design
|
|
19
|
+
- Error handling patterns
|
|
20
|
+
- Database integration
|
|
21
|
+
- API design guidelines
|
|
22
|
+
- Testing patterns
|
|
23
|
+
|
|
24
|
+
used_by:
|
|
25
|
+
- fastapi-expert
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
# Go Backend Best Practices Skill
|
|
2
|
+
|
|
3
|
+
> **Category**: Backend
|
|
4
|
+
> **Source**: Internal (based on Uber Go Style Guide and Standard Layout)
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
Apply Go backend patterns for building production-ready services.
|
|
9
|
+
|
|
10
|
+
## Rules
|
|
11
|
+
|
|
12
|
+
### 1. Project Structure (Standard Layout)
|
|
13
|
+
|
|
14
|
+
```yaml
|
|
15
|
+
layout: |
|
|
16
|
+
project/
|
|
17
|
+
├── cmd/
|
|
18
|
+
│ └── server/
|
|
19
|
+
│ └── main.go
|
|
20
|
+
├── internal/
|
|
21
|
+
│ ├── handler/
|
|
22
|
+
│ ├── service/
|
|
23
|
+
│ ├── repository/
|
|
24
|
+
│ └── model/
|
|
25
|
+
├── pkg/
|
|
26
|
+
│ └── shared/
|
|
27
|
+
├── api/
|
|
28
|
+
│ └── openapi.yaml
|
|
29
|
+
├── configs/
|
|
30
|
+
├── scripts/
|
|
31
|
+
├── Dockerfile
|
|
32
|
+
├── Makefile
|
|
33
|
+
└── go.mod
|
|
34
|
+
|
|
35
|
+
directories:
|
|
36
|
+
cmd: Main applications (one per binary)
|
|
37
|
+
internal: Private application code
|
|
38
|
+
pkg: Library code safe for external use
|
|
39
|
+
api: API definitions (OpenAPI, protobuf)
|
|
40
|
+
configs: Configuration files
|
|
41
|
+
scripts: Build and CI scripts
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2. Error Handling (Uber Style)
|
|
45
|
+
|
|
46
|
+
```yaml
|
|
47
|
+
principles:
|
|
48
|
+
- Wrap errors with context using %w
|
|
49
|
+
- Handle errors once (don't log AND return)
|
|
50
|
+
- Use sentinel errors for specific conditions
|
|
51
|
+
- Name error variables with Err prefix
|
|
52
|
+
|
|
53
|
+
patterns: |
|
|
54
|
+
// Sentinel errors
|
|
55
|
+
var (
|
|
56
|
+
ErrNotFound = errors.New("not found")
|
|
57
|
+
ErrInvalidInput = errors.New("invalid input")
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
// Wrap with context
|
|
61
|
+
func getUser(id string) (*User, error) {
|
|
62
|
+
user, err := db.FindUser(id)
|
|
63
|
+
if err != nil {
|
|
64
|
+
return nil, fmt.Errorf("getUser %s: %w", id, err)
|
|
65
|
+
}
|
|
66
|
+
return user, nil
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Check specific errors
|
|
70
|
+
if errors.Is(err, ErrNotFound) {
|
|
71
|
+
return http.StatusNotFound
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 3. Concurrency (Uber Style)
|
|
76
|
+
|
|
77
|
+
```yaml
|
|
78
|
+
channels:
|
|
79
|
+
size: "Use 0 (unbuffered) or 1 only"
|
|
80
|
+
larger: "Requires careful review"
|
|
81
|
+
|
|
82
|
+
goroutines:
|
|
83
|
+
never: fire-and-forget
|
|
84
|
+
always: wait for completion or manage lifecycle
|
|
85
|
+
|
|
86
|
+
patterns: |
|
|
87
|
+
// Wait group for goroutines
|
|
88
|
+
func process(items []Item) error {
|
|
89
|
+
var wg sync.WaitGroup
|
|
90
|
+
errCh := make(chan error, 1)
|
|
91
|
+
|
|
92
|
+
for _, item := range items {
|
|
93
|
+
wg.Add(1)
|
|
94
|
+
go func(item Item) {
|
|
95
|
+
defer wg.Done()
|
|
96
|
+
if err := processItem(item); err != nil {
|
|
97
|
+
select {
|
|
98
|
+
case errCh <- err:
|
|
99
|
+
default:
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}(item)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
wg.Wait()
|
|
106
|
+
close(errCh)
|
|
107
|
+
return <-errCh
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Context for cancellation
|
|
111
|
+
func longRunningTask(ctx context.Context) error {
|
|
112
|
+
for {
|
|
113
|
+
select {
|
|
114
|
+
case <-ctx.Done():
|
|
115
|
+
return ctx.Err()
|
|
116
|
+
default:
|
|
117
|
+
// do work
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 4. HTTP Server
|
|
124
|
+
|
|
125
|
+
```yaml
|
|
126
|
+
structure:
|
|
127
|
+
handler: HTTP layer (request/response)
|
|
128
|
+
service: Business logic
|
|
129
|
+
repository: Data access
|
|
130
|
+
|
|
131
|
+
patterns: |
|
|
132
|
+
// Handler with dependency injection
|
|
133
|
+
type UserHandler struct {
|
|
134
|
+
service UserService
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
func NewUserHandler(s UserService) *UserHandler {
|
|
138
|
+
return &UserHandler{service: s}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
|
|
142
|
+
id := chi.URLParam(r, "id")
|
|
143
|
+
|
|
144
|
+
user, err := h.service.GetUser(r.Context(), id)
|
|
145
|
+
if err != nil {
|
|
146
|
+
if errors.Is(err, ErrNotFound) {
|
|
147
|
+
http.Error(w, "user not found", http.StatusNotFound)
|
|
148
|
+
return
|
|
149
|
+
}
|
|
150
|
+
http.Error(w, "internal error", http.StatusInternalServerError)
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
json.NewEncoder(w).Encode(user)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Router setup
|
|
158
|
+
func NewRouter(h *UserHandler) *chi.Mux {
|
|
159
|
+
r := chi.NewRouter()
|
|
160
|
+
r.Use(middleware.Logger)
|
|
161
|
+
r.Use(middleware.Recoverer)
|
|
162
|
+
|
|
163
|
+
r.Route("/api/v1", func(r chi.Router) {
|
|
164
|
+
r.Get("/users/{id}", h.GetUser)
|
|
165
|
+
r.Post("/users", h.CreateUser)
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
return r
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### 5. Dependency Injection
|
|
173
|
+
|
|
174
|
+
```yaml
|
|
175
|
+
approach: constructor injection
|
|
176
|
+
avoid: global variables
|
|
177
|
+
|
|
178
|
+
patterns: |
|
|
179
|
+
// Service with dependencies
|
|
180
|
+
type UserService struct {
|
|
181
|
+
repo UserRepository
|
|
182
|
+
cache Cache
|
|
183
|
+
logger *slog.Logger
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
func NewUserService(
|
|
187
|
+
repo UserRepository,
|
|
188
|
+
cache Cache,
|
|
189
|
+
logger *slog.Logger,
|
|
190
|
+
) *UserService {
|
|
191
|
+
return &UserService{
|
|
192
|
+
repo: repo,
|
|
193
|
+
cache: cache,
|
|
194
|
+
logger: logger,
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Wire up in main
|
|
199
|
+
func main() {
|
|
200
|
+
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
|
|
201
|
+
db := database.New(cfg.DatabaseURL)
|
|
202
|
+
cache := redis.New(cfg.RedisURL)
|
|
203
|
+
|
|
204
|
+
repo := repository.NewUserRepository(db)
|
|
205
|
+
service := service.NewUserService(repo, cache, logger)
|
|
206
|
+
handler := handler.NewUserHandler(service)
|
|
207
|
+
|
|
208
|
+
router := handler.NewRouter(handler)
|
|
209
|
+
http.ListenAndServe(":8080", router)
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### 6. Configuration
|
|
214
|
+
|
|
215
|
+
```yaml
|
|
216
|
+
approach:
|
|
217
|
+
- Use environment variables
|
|
218
|
+
- Validate at startup
|
|
219
|
+
- Group related settings
|
|
220
|
+
|
|
221
|
+
patterns: |
|
|
222
|
+
type Config struct {
|
|
223
|
+
Server ServerConfig
|
|
224
|
+
Database DatabaseConfig
|
|
225
|
+
Redis RedisConfig
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
type ServerConfig struct {
|
|
229
|
+
Host string `env:"SERVER_HOST" envDefault:"0.0.0.0"`
|
|
230
|
+
Port int `env:"SERVER_PORT" envDefault:"8080"`
|
|
231
|
+
ReadTimeout time.Duration `env:"SERVER_READ_TIMEOUT" envDefault:"5s"`
|
|
232
|
+
WriteTimeout time.Duration `env:"SERVER_WRITE_TIMEOUT" envDefault:"10s"`
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
func LoadConfig() (*Config, error) {
|
|
236
|
+
var cfg Config
|
|
237
|
+
if err := env.Parse(&cfg); err != nil {
|
|
238
|
+
return nil, fmt.Errorf("parse config: %w", err)
|
|
239
|
+
}
|
|
240
|
+
return &cfg, nil
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### 7. Testing
|
|
245
|
+
|
|
246
|
+
```yaml
|
|
247
|
+
patterns:
|
|
248
|
+
table_driven: for comprehensive coverage
|
|
249
|
+
interfaces: for mocking
|
|
250
|
+
parallel: for speed
|
|
251
|
+
|
|
252
|
+
example: |
|
|
253
|
+
func TestUserService_GetUser(t *testing.T) {
|
|
254
|
+
tests := []struct {
|
|
255
|
+
name string
|
|
256
|
+
userID string
|
|
257
|
+
mock func(*MockRepository)
|
|
258
|
+
want *User
|
|
259
|
+
wantErr error
|
|
260
|
+
}{
|
|
261
|
+
{
|
|
262
|
+
name: "success",
|
|
263
|
+
userID: "123",
|
|
264
|
+
mock: func(m *MockRepository) {
|
|
265
|
+
m.EXPECT().FindByID("123").Return(&User{ID: "123"}, nil)
|
|
266
|
+
},
|
|
267
|
+
want: &User{ID: "123"},
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
name: "not found",
|
|
271
|
+
userID: "999",
|
|
272
|
+
mock: func(m *MockRepository) {
|
|
273
|
+
m.EXPECT().FindByID("999").Return(nil, ErrNotFound)
|
|
274
|
+
},
|
|
275
|
+
wantErr: ErrNotFound,
|
|
276
|
+
},
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
for _, tt := range tests {
|
|
280
|
+
t.Run(tt.name, func(t *testing.T) {
|
|
281
|
+
t.Parallel()
|
|
282
|
+
ctrl := gomock.NewController(t)
|
|
283
|
+
repo := NewMockRepository(ctrl)
|
|
284
|
+
tt.mock(repo)
|
|
285
|
+
|
|
286
|
+
svc := NewUserService(repo, nil, slog.Default())
|
|
287
|
+
got, err := svc.GetUser(context.Background(), tt.userID)
|
|
288
|
+
|
|
289
|
+
if !errors.Is(err, tt.wantErr) {
|
|
290
|
+
t.Errorf("got error %v, want %v", err, tt.wantErr)
|
|
291
|
+
}
|
|
292
|
+
if diff := cmp.Diff(tt.want, got); diff != "" {
|
|
293
|
+
t.Errorf("mismatch (-want +got):\n%s", diff)
|
|
294
|
+
}
|
|
295
|
+
})
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### 8. Performance (Uber Style)
|
|
301
|
+
|
|
302
|
+
```yaml
|
|
303
|
+
guidelines:
|
|
304
|
+
- Use strconv over fmt for conversions
|
|
305
|
+
- Pre-allocate slices with known capacity
|
|
306
|
+
- Avoid repeated string-to-byte conversions
|
|
307
|
+
- Copy slices/maps at boundaries
|
|
308
|
+
|
|
309
|
+
patterns: |
|
|
310
|
+
// Pre-allocate
|
|
311
|
+
items := make([]Item, 0, len(input))
|
|
312
|
+
|
|
313
|
+
// strconv for conversions
|
|
314
|
+
s := strconv.Itoa(n) // not fmt.Sprintf("%d", n)
|
|
315
|
+
|
|
316
|
+
// Copy at boundaries
|
|
317
|
+
func (s *Store) GetItems() []Item {
|
|
318
|
+
s.mu.RLock()
|
|
319
|
+
defer s.mu.RUnlock()
|
|
320
|
+
items := make([]Item, len(s.items))
|
|
321
|
+
copy(items, s.items)
|
|
322
|
+
return items
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
## Application
|
|
327
|
+
|
|
328
|
+
When writing Go backend code:
|
|
329
|
+
|
|
330
|
+
1. **Always** use standard project layout
|
|
331
|
+
2. **Always** wrap errors with context
|
|
332
|
+
3. **Never** fire-and-forget goroutines
|
|
333
|
+
4. **Use** constructor injection
|
|
334
|
+
5. **Use** table-driven tests
|
|
335
|
+
6. **Handle** errors once
|
|
336
|
+
7. **Copy** data at boundaries
|
|
337
|
+
8. **Validate** config at startup
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Go Backend Best Practices Skill
|
|
2
|
+
|
|
3
|
+
metadata:
|
|
4
|
+
name: go-backend-best-practices
|
|
5
|
+
category: backend
|
|
6
|
+
description: Go backend patterns from Uber style and standard layout
|
|
7
|
+
|
|
8
|
+
source:
|
|
9
|
+
type: internal
|
|
10
|
+
reference:
|
|
11
|
+
- https://go.dev/doc/effective_go
|
|
12
|
+
- https://github.com/golang-standards/project-layout
|
|
13
|
+
- https://github.com/uber-go/guide/blob/master/style.md
|
|
14
|
+
|
|
15
|
+
provides:
|
|
16
|
+
- Project structure (standard layout)
|
|
17
|
+
- Error handling patterns
|
|
18
|
+
- Concurrency patterns
|
|
19
|
+
- HTTP server design
|
|
20
|
+
- Dependency injection
|
|
21
|
+
- Configuration management
|
|
22
|
+
- Testing patterns
|
|
23
|
+
- Performance guidelines
|
|
24
|
+
|
|
25
|
+
used_by:
|
|
26
|
+
- go-backend-expert
|