# Coding Style (Extended)

Extends the style guidelines in CLAUDE.md with patterns from ECC.

## Immutability

Create new objects — never mutate existing ones:

```typescript
// WRONG: mutation
user.name = newName;
items.push(newItem);

// RIGHT: immutable update
const updated = { ...user, name: newName };
const updatedItems = [...items, newItem];
```

```python
# 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 `onError` callbacks or error boundaries
- Form validation: `react-hook-form` with inline `register()` validation rules and `Controller` for controlled components. Error messages in Russian.
- Never show raw error strings to users — map to user-friendly Russian messages

### Backend
- Raise `HTTPException` with 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-form` inline 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

```python
# WRONG
if status == "completed":
    ...

# RIGHT
JOB_STATUS_COMPLETED = "completed"
if status == JOB_STATUS_COMPLETED:
    ...
```

```typescript
// WRONG
if (job.status === "completed") { ... }

// RIGHT
const JOB_STATUS_COMPLETED = "completed" as const;
if (job.status === JOB_STATUS_COMPLETED) { ... }
```
