E1: User & Profile Management - Tasks¶
Epic: E1: User & Profile Management
E1-F1: User Registration API¶
Feature: E1-F1: User Registration API
| Status | Task | Verification |
|---|---|---|
| Create User database migration (id, email, password_hash, oib, status, created_at, updated_at) | Run migrations + check table exists in DB | |
| Implement POST /users/register endpoint with email/password/OIB fields | curl POST returns 201 with user_id | |
| Add email format validation using standard regex | Unit test with invalid emails returns 400 | |
| Add password strength validation (min 8 chars, 1 uppercase, 1 number) | Unit test with weak passwords returns 400 | |
| Integrate OIB checksum validation (call E1-F5 service) | Unit test with invalid OIB returns 400 | |
| Add duplicate email check before insert | Integration test creating same email twice returns 409 | |
| Hash password using bcrypt before storage | DB inspection shows hashed value, not plaintext |
E1-F2: User Authentication¶
Feature: E1-F2: User Authentication
| Status | Task | Verification |
|---|---|---|
| Create Session database migration (id, user_id, refresh_token_hash, expires_at) | Run migrations | |
| Implement POST /auth/login endpoint returning JWT access + refresh tokens | curl with valid credentials returns tokens | |
| Set JWT access token expiration to 15 minutes | Decode token shows correct exp claim | |
| Set refresh token expiration to 7 days, store hashed in DB | Session record created with correct expires_at | |
| Implement POST /auth/refresh endpoint to issue new tokens | Valid refresh token returns new access token | |
| Implement POST /auth/logout endpoint to invalidate refresh token | Subsequent refresh with old token fails | |
| Return 401 for invalid credentials with generic message | Wrong password returns 401 without revealing which field is wrong |
E1-F3: Default Ticketing Profile¶
Feature: E1-F3: Default Ticketing Profile
| Status | Task | Verification |
|---|---|---|
| Create UserProfile database migration (user_id FK, full_name, date_of_birth, nationality, oib, passport_number, phone, updated_at) | Run migrations | |
| Add UNIQUE constraint on OIB column in UserProfile table | Migration adds unique constraint | |
| Implement GET /users/me/profile endpoint returning 404 if profile doesn't exist | Returns 404 for user without profile, 200 with data for user with profile | |
| Implement POST /users/me/profile endpoint for initial profile creation | Creates profile, returns 201 with profile data | |
| Return 409 on POST if profile already exists | Authenticated user with existing profile gets 409 "Profile already exists" | |
| Implement PUT /users/me/profile endpoint for profile updates | Update saves correctly | |
| Return 404 on PUT if profile doesn't exist | User without profile gets 404 suggesting to use POST | |
| Add global OIB uniqueness check before setting OIB | OIB already used by another user returns 409 with message "This OIB is already registered with another account. If you think this is a mistake, please contact customer support." | |
| Add OIB checksum validation (ISO 7064 MOD 11-10) on POST/PUT | Invalid OIB checksum returns 422 | |
| Make OIB field immutable after first set (reject updates to non-null OIB) | Attempt to change OIB returns 400 | |
| Require OIB for Croatian nationality, passport_number for non-Croatian | Croatian without OIB returns 422, non-Croatian without passport returns 422 | |
| Add age validation (18+ required for default profile) | User under 18 returns 422 with age requirement message | |
| Add profile completeness check (all required fields filled) | API returns is_complete boolean in response |
E1-F4: Saved Profiles¶
Feature: E1-F4: Saved Profiles
| Status | Task | Verification |
|---|---|---|
| Create SavedProfile database migration (id, user_id, full_name, date_of_birth, nationality, oib_encrypted, passport_encrypted, email, phone, relationship, created_at) | Run migrations | |
| Implement POST /users/me/saved-profiles endpoint | Creates profile, returns id | |
| Implement GET /users/me/saved-profiles endpoint returning list with masked OIB | OIB shows only last 4 digits | |
| Implement PUT /users/me/saved-profiles/{id} endpoint | Update works | |
| Implement DELETE /users/me/saved-profiles/{id} endpoint | Soft or hard delete works | |
| Enforce max 10 profiles per user | 11th creation returns 400 with limit message | |
| Check for duplicate OIB within user's profiles before create/update | Duplicate OIB returns 409 | |
| Encrypt OIB and passport fields at rest | DB inspection shows encrypted values |
E1-F5: OIB Checksum Validation¶
Feature: E1-F5: OIB Checksum Validation
| Status | Task | Verification |
|---|---|---|
| Implement OIB validation utility function (11 digits, checksum algorithm) | Unit tests with known valid/invalid OIBs | |
| Document checksum algorithm (ISO 7064, MOD 11-10) | README in validation module | |
| Export as internal service callable from other modules | Can import and call from User and Profile modules |
Last Updated: January 2026