원클릭으로
add-endpoint
Add a complete REST endpoint from command to controller route. Use when building new API endpoints.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Add a complete REST endpoint from command to controller route. Use when building new API endpoints.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
Summarize the API interface changes made during THIS session for the frontend, then optionally spawn an agent to implement them in the frontend repo. Use after changing endpoints, request/response DTOs, or auth.
One-shot guided session — prunes unused code, scaffolds new entities/endpoints, updates project identity config, and replaces the init migration for a specific project.
Compress natural language memory files (CLAUDE.md, todos, preferences) into caveman format to save input tokens. Preserves all technical substance, code, URLs, and structure. Compressed version overwrites the original file. Human-readable backup saved as FILE.original.md. Trigger: /caveman-compress FILEPATH or "compress memory file"
Implement a change with a pipeline scaled to its complexity. Single entry point for all code changes — auto-detects effort or accepts small|mid|tuff override.
Run a Linear task end-to-end — creates an isolated tmux session + worktree, starts a Claude agent to implement it, opens a PR, and watches for review feedback automatically.
Add a new domain event with its publisher call and background event handler. Use for async side effects.
SOC 직업 분류 기준
| name | add-endpoint |
| description | Add a complete REST endpoint from command to controller route. Use when building new API endpoints. |
| argument-hint | <domain> <action> <http-method> |
Create a full endpoint pipeline: Command -> Handler -> DTO -> Controller route -> DI wiring.
$0 -- Domain name (e.g., users, auth, roles)$1 -- Action name (e.g., create, get, list, update, delete, login)$2 -- HTTP method (e.g., get, post, patch, delete)Existing handlers:
!find backend/app/rest/v1/handlers -name "*.py" -not -name "__init__.py" -not -name "__pycache__" -not -path "*/base/*" 2>/dev/null | sort
Existing controllers:
!find backend/entry/rest/v1 -maxdepth 1 -name "*.py" -not -name "__init__.py" -not -name "__pycache__" 2>/dev/null | sort
Is this a read or write operation?
├── Read (GET, no side effects) -> type_=HandlerType.READ
└── Write (POST/PATCH/DELETE, mutations) -> type_=HandlerType.WRITE
Is this a standard CRUD operation or a custom action?
├── CRUD (create/get/update/delete/list) -> use standard REST paths
└── Custom action (assign, revoke, markRead, signIn, etc.) -> use trailing /camelCaseVerb segment
├── Mutation: @post("/{id:str}/assignRole") with body DTO in entry/rest/v1/dtos.py
└── Custom read: @get("/listForUser") with query params
(NOT the Google colon /{id}:verb — Litestar can't route a param + literal in one segment; it 404s. See rules/controllers.md.)
Does the handler need path parameters?
├── Yes -> Controller converts str to UUID/enum before creating command
└── No -> Command fields come from request body
Does this return data?
├── Yes -> Define/reuse a response DTO in app/rest/v1/dtos/
└── No -> Handler returns None, controller returns None
Is this a list endpoint?
├── Yes -> Use offset: int = 0, limit: int = 50
└── No -> N/A
File: backend/app/rest/v1/handlers/{domain}/{action}.py
from dataclasses import dataclass
from uuid import UUID
from backend.app.errors import NotFoundError
from backend.app.rest.v1 import dtos
from backend.app.rest.v1.handlers.base import Command, Handler, HandlerType
from backend.app.shared.db.database import Database
class Get{Entity}Command(Command):
{entity}_id: UUID
@dataclass
class Get{Entity}Handler(Handler[Get{Entity}Command, dtos.{Entity}, None], type_=HandlerType.READ):
db: Database
async def __call__(self, cmd: Get{Entity}Command, _ctx: None = None) -> dtos.{Entity}:
async with self.db:
entity = (await self.db.gateway.{entity}.get_by_id(cmd.{entity}_id)).some(
NotFoundError(message="{Entity} not found")
)
return dtos.{Entity}.from_object(entity)
File: backend/app/rest/v1/handlers/{domain}/__init__.py
Add the new command and handler to __all__ and imports.
File: backend/app/rest/v1/dtos/{domain}.py
from backend.internal.dto import StructDTO
class {Entity}(StructDTO):
id: str
# ... fields matching what the entity exposes
created_at: str
updated_at: str
File: backend/entry/rest/v1/{domain}.py
Standard CRUD:
@{method}("/{entity_id:str}", exclude_from_auth=False)
@inject
@result
async def {action}_{entity}(
self,
entity_id: str,
handler: Depends[{domain}.Get{Entity}Handler],
) -> dtos.{Entity}:
return await handler({domain}.Get{Entity}Command({entity}_id=UUID(entity_id)))
Custom method (non-CRUD action):
@post("/{id:str}/assignRole")
@inject
@result
async def assign_role(
self,
id: str,
data: AssignRoleBody,
handler: Depends[users.AssignRoleHandler],
) -> None:
return await handler(users.AssignRoleCommand(user_id=UUID(id), role_id=data.role_id))
List endpoint:
@get("/{entities}/")
@inject
@result
async def list_{entities}(
self,
handler: Depends[{domain}.List{Entities}Handler],
offset: int = 0,
limit: int = 50,
) -> dtos.PaginatedResponse[dtos.{Entity}]:
return await handler({domain}.List{Entities}Command(offset=offset, limit=limit))
File: backend/entry/rest/v1/__init__.py
Add to create_v1_router() route_handlers list.
Run just check to ensure type checking and linting pass.