diff --git a/docs/API.md b/docs/API.md index 95d2534..68fe07c 100644 --- a/docs/API.md +++ b/docs/API.md @@ -632,4 +632,73 @@ Validation errors (`400`): ## 7. Recent Changes — `feature/security-hardening` -_TODO_ +This section summarises API-visible changes introduced on the `feature/security-hardening` branch (commits `3d456f2` → `b1324e3` → `8b96433` → `f0de751`). A developer or agent reading this document should be aware of these differences compared to the `main` branch. + +--- + +### New: Centralised error handling (`GlobalExceptionHandler`) + +**File:** `src/main/java/.../controller/GlobalExceptionHandler.java` + +All error responses now follow the consistent JSON shape described in [Section 6](#6-error-handling). Previously, individual controllers returned ad-hoc responses, including HTTP 417 and raw stack trace output. Both have been removed. SLF4J logging has been added for server-side error visibility. + +--- + +### New: `AuthenticatedUserResolver` + +**File:** `src/main/java/.../security/AuthenticatedUserResolver.java` + +A new component that extracts the Google ID from the JWT `sub` claim and resolves the corresponding `AppUser`. Injected into all protected controller methods. Returns `403 Forbidden` if the token is valid but the user has never called `POST /api/users/createUser`. + +--- + +### New: `RateLimitFilter` — 60 req/min + +**File:** `src/main/java/.../security/RateLimitFilter.java` + +Rate limiting was not present on `main`. See [Section 3](#3-rate-limiting) for full details. + +--- + +### New: `CreateExpenseListRequest` DTO with validation + +**File:** `src/main/java/.../model/CreateExpenseListRequest.java` + +`POST /api/expenselist/create` previously accepted a raw `ExpenseList` body. It now requires a `CreateExpenseListRequest` with a single validated `name` field (`@NotBlank`, `@Size(max=100)`). Clients must update their request body shape. + +--- + +### Updated: Validation constraints tightened on existing DTOs + +| DTO | Field | Change | +|-----|-------|--------| +| `AppUserCreateRequest` | `username` | Added `@Pattern(regexp="^[a-zA-Z0-9_.\-]+$")` — special characters (other than `_`, `.`, `-`) now rejected | +| `InviteRequest` | `inviteCode` | Added `@Size(min=6, max=6)` — non-6-char codes now rejected at binding | +| `ExpenseInput` | `amount` | Added `@DecimalMin("0.01")` — zero and negative amounts now rejected | +| `ExpenseChangeRequest` | `amount` | Added `@DecimalMin("0.01")` — zero and negative amounts now rejected | + +--- + +### Updated: `SecurityConfig` — test-profile isolation + +**File:** `src/main/java/.../security/SecurityConfig.java` + +Two separate `SecurityFilterChain` beans now exist: +- `@Profile("test")` — all endpoints permitted, CSRF disabled (for automated tests only). +- `@Profile("!test")` — full JWT/OAuth2 enforcement (production behaviour). + +Previously a single config was used for both, which made tests fragile. + +--- + +### Fixed: `ExpenseListService` — JPQL and exception consistency + +- Single `@Param` used in all JPQL queries (multi-param variant was broken). +- `ResourceNotFoundException` is now thrown consistently instead of returning `null` or a generic `RuntimeException`. +- `addExpenseToList` delegates directly to `ExpenseList.addExpense()` rather than looping. + +--- + +### Fixed: `UserService` — null returns replaced with exceptions + +All not-found paths in `UserService` now throw `ResourceNotFoundException` instead of returning `null`. Callers that previously needed to null-check responses will now receive a `404` response.