4.1 KiB
4.1 KiB
Coding Conventions
AI 에이전트는 코드를 작성하기 전 이 컨벤션을 확인합니다.
네이밍
Python (서버)
| 대상 | 규칙 | 예시 |
|---|---|---|
| 변수/함수 | snake_case | write_pending_approval() |
| 클래스 | PascalCase | GravityBot, WSHub, TokenManager |
| 상수 | UPPER_SNAKE_CASE | MAX_MSG_SIZE, HEARTBEAT_INTERVAL |
| 파일명 | snake_case | hub.py, ws_client.py |
| 로거명 | 모듈명 | logging.getLogger("hub") |
TypeScript (Extension)
| 대상 | 규칙 | 예시 |
|---|---|---|
| 변수/함수 | camelCase | writePendingApproval(), setupMonitor() |
| 클래스 | PascalCase | WSBridgeClient |
| 인터페이스 | PascalCase | BridgeContext, WSPendingData |
| 상수 | UPPER_SNAKE_CASE | MAX_QUEUE_SIZE, AUTH_TIMEOUT |
| 파일명 | kebab-case | ws-client.ts, step-probe.ts |
| export 함수 | camelCase | initStepProbe(), generateApprovalObserverScript() |
코드 스타일
| 항목 | Python | TypeScript |
|---|---|---|
| 들여쓰기 | 4 spaces | 4 spaces |
| 따옴표 | 쌍따옴표 " (f-string 포함) |
작은따옴표 ' |
| 세미콜론 | N/A | 사용 |
| 줄바꿈 | LF (Unix) | CRLF (Windows, git 자동 변환) |
| 최대 줄 길이 | 120자 권장 | 120자 권장 |
| 타입 힌트 | 적극 사용 (-> list[str]) |
strict (BridgeContext 인터페이스) |
커밋 메시지
<type>(<scope>): <description>
type: feat|fix|refactor|test|docs|chore|ci|infra
scope: server|extension|hub|bot|gateway|bridge (선택)
예시:
feat(hub): WebSocket Hub 구현 + JWT 인증refactor(extension): 모듈 분리 (step-probe, observer-script)fix(bot): auto-approve 세션 간 초기화docs: architecture.md 전면 재작성
관련 Vikunja 태스크가 있으면: feat(hub): WS Hub 구현 #task-395
주석
- 한국어/영어 혼용 가능
- TODO 주석:
// TODO: 설명형식 - 섹션 구분:
// ─── Section Name ───(TypeScript),# ─── Section ───(Python) - 복잡한 로직에는 반드시 WHY(왜) 주석 추가
- 함수 docstring: Python은
"""...""", TypeScript는/** ... */
모듈 분리 패턴
Extension 모듈 분리 시 사용하는 패턴:
| 패턴 | 용도 | 예시 |
|---|---|---|
| 순수 함수 추출 | 외부 상태 참조 없는 함수 | step-utils.ts |
| 독립 스크립트 | 문자열 반환 함수 | observer-script.ts |
| Context 패턴 | 공유 상태가 많은 함수 그룹 | step-probe.ts (BridgeContext) |
| 클래스 추출 | 자체 상태 + 메서드 | ws-client.ts (WSBridgeClient) |
테스트
| 항목 | 위치 | 도구 |
|---|---|---|
| Python 구문 검사 | tests/test_syntax.py |
ast.parse |
| WS Hub 연결 | tests/test_ws_hub.py |
websockets |
| TypeScript 컴파일 | npx tsc --noEmit |
TypeScript compiler |
| E2E | 수동 (Discord 버튼 클릭) | — |
로깅
| 측 | 방식 | 포맷 |
|---|---|---|
| Python | logging.getLogger(name) |
YYYY-MM-DD HH:MM:SS [name] LEVEL: message |
| Extension | logToFile(msg) → bridge/log/ |
[HH:MM:SS] message + [WS] prefix |
| Hub | [HUB] prefix |
[HUB] Auth OK: {conn_id} project={project} |
| Gateway | [GATEWAY] prefix |
[GATEWAY] HTTP API started on {host}:{port} |
WS / File Bridge 상호 배타 패턴
Important
WS Hub과 파일 bridge는 항상 상호 배타적이어야 합니다. 양쪽에 동시에 쓰면 이중 전달 버그가 발생합니다. (known-issues-archive 참조)
Extension (TypeScript):
// ✅ 올바른 패턴
if (ctx.wsBridge?.isConnected()) {
ctx.wsBridge.sendPending(data);
return; // ← 반드시 return으로 파일 쓰기 건너뛰기
}
// File fallback
fs.writeFileSync(pendingPath, JSON.stringify(data));
Bot (Python):
# ✅ 올바른 패턴
if self.hub:
await self.hub.send_response(...)
else:
bridge.write_response(...)
금지 패턴:
# ❌ 이중 쓰기 — 절대 금지
if self.hub:
await self.hub.send_response(...)
bridge.write_response(...) # ← Hub 성공해도 파일에도 씀 → 이중 처리