2.2 KiB
2.2 KiB
Coding Style (Extended)
Extends the style guidelines in CLAUDE.md with patterns from ECC.
Immutability
Create new objects — never mutate existing ones:
// WRONG: mutation
user.name = newName;
items.push(newItem);
// RIGHT: immutable update
const updated = { ...user, name: newName };
const updatedItems = [...items, newItem];
# WRONG: mutation
user["name"] = new_name
items.append(new_item)
# RIGHT: immutable (when it matters)
updated = {**user, "name": new_name}
updated_items = [*items, new_item]
Exception: Pydantic models and SQLAlchemy ORM objects are designed for mutation — use them as intended.
File Organization
- 200-400 lines typical, 800 max per file
- High cohesion, low coupling — one concept per file
- Backend: module structure is fixed (models, schemas, repository, service, router) — don't add extra files
- Frontend: FSD layers are fixed — don't add files outside the layer structure
Error Handling
Frontend
- API errors: handle in TanStack Query
onErrorcallbacks or error boundaries - Form validation:
react-hook-formwith inlineregister()validation rules andControllerfor controlled components. Error messages in Russian. - Never show raw error strings to users — map to user-friendly Russian messages
Backend
- Raise
HTTPExceptionwith appropriate status codes in routers - Service layer returns data or raises domain exceptions
- Repository layer lets SQLAlchemy exceptions propagate (service handles them)
- Store error messages as named constants with
ERROR_prefix
Input Validation
- Frontend: TypeScript interfaces +
react-hook-forminline rules for form data, OpenAPI-generated types for API responses - Backend: Pydantic schemas validate all request bodies — never trust raw input
- File uploads: validate extension + MIME type in files module
- Never construct SQL from user input — SQLAlchemy handles parameterization
Named Constants
# WRONG
if status == "completed":
...
# RIGHT
JOB_STATUS_COMPLETED = "completed"
if status == JOB_STATUS_COMPLETED:
...
// WRONG
if (job.status === "completed") { ... }
// RIGHT
const JOB_STATUS_COMPLETED = "completed" as const;
if (job.status === JOB_STATUS_COMPLETED) { ... }