[AZ-189] [AZ-190] [AZ-191] [AZ-192] [AZ-193] [AZ-194] [AZ-195] Add e2e blackbox test suite

Made-with: Cursor
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-04-16 06:25:36 +03:00
parent 1b38e888e1
commit d320d6dd59
98 changed files with 6883 additions and 1 deletions
@@ -0,0 +1,127 @@
# User Management
## 1. High-Level Overview
**Purpose**: Full user lifecycle management — registration, credential validation, hardware binding, role changes, account enable/disable, and deletion.
**Architectural Pattern**: Service layer — stateless business logic operating on the Data Layer through `IDbFactory`.
**Upstream dependencies**: Data Layer (IDbFactory, ICache, User entity), Security & Cryptography (hashing).
**Downstream consumers**: Admin API (endpoint handlers), Authentication (GetByEmail).
## 2. Internal Interfaces
### Interface: IUserService
| Method | Input | Output | Async | Error Types |
|--------|-------|--------|-------|-------------|
| `RegisterUser` | `RegisterUserRequest, CancellationToken` | void | Yes | `BusinessException(EmailExists)` |
| `ValidateUser` | `LoginRequest, CancellationToken` | `User` | Yes | `BusinessException(NoEmailFound, WrongPassword)` |
| `GetByEmail` | `string? email, CancellationToken` | `User?` | Yes | `ArgumentNullException` |
| `UpdateHardware` | `string email, string? hardware, CancellationToken` | void | Yes | None |
| `UpdateQueueOffsets` | `string email, UserQueueOffsets, CancellationToken` | void | Yes | None |
| `GetUsers` | `string? searchEmail, RoleEnum? searchRole, CancellationToken` | `IEnumerable<User>` | Yes | None |
| `CheckHardwareHash` | `User, string hardware, CancellationToken` | `string` (hash) | Yes | `BusinessException(HardwareIdMismatch)` |
| `ChangeRole` | `string email, RoleEnum, CancellationToken` | void | Yes | None |
| `SetEnableStatus` | `string email, bool, CancellationToken` | void | Yes | None |
| `RemoveUser` | `string email, CancellationToken` | void | Yes | None |
**Input DTOs**:
```
RegisterUserRequest:
Email: string (required) — validated: min 8 chars, valid email format
Password: string (required) — validated: min 8 chars
Role: RoleEnum (required)
LoginRequest:
Email: string (required)
Password: string (required)
SetHWRequest:
Email: string (required, validated: not empty)
Hardware: string? (optional — null clears hardware)
SetUserQueueOffsetsRequest:
Email: string (required)
Offsets: UserQueueOffsets (required)
```
## 3. External API Specification
N/A — exposed through Admin API component.
## 4. Data Access Patterns
### Queries
| Query | Frequency | Hot Path | Index Needed |
|-------|-----------|----------|--------------|
| User by email (cached) | High | Yes | Yes |
| User list with filters | Medium | No | No |
| User insert (registration) | Low | No | No |
| User update (hardware, role, config, status) | Medium | No | No |
| User delete | Low | No | No |
### Caching Strategy
| Data | Cache Type | TTL | Invalidation |
|------|-----------|-----|-------------|
| User by email | In-memory (via ICache) | 4 hours | After UpdateHardware, UpdateQueueOffsets, CheckHardwareHash (first login) |
## 5. Implementation Details
**State Management**: Stateless — all state in PostgreSQL + in-memory cache.
**Key Dependencies**:
| Library | Version | Purpose |
|---------|---------|---------|
| FluentValidation | 11.10.0 | Request validation (auto-discovered) |
**Error Handling Strategy**:
- Domain errors thrown as `BusinessException` with specific `ExceptionEnum` codes.
- `GetByEmail` throws `ArgumentNullException` for null/whitespace email.
- Database errors propagate from `IDbFactory`.
- Write operations use `RunAdmin` (admin connection); reads use `Run` (reader connection).
## 6. Extensions and Helpers
| Helper | Purpose | Used By |
|--------|---------|---------|
| `Security.ToHash` | Password hashing (SHA-384) | RegisterUser, ValidateUser |
| `Security.GetHWHash` | Hardware fingerprint hashing | CheckHardwareHash |
| `QueryableExtensions.WhereIf` | Conditional LINQ filters | GetUsers |
## 7. Caveats & Edge Cases
**Known limitations**:
- No pagination on `GetUsers` — returns all matching users.
- `CheckHardwareHash` auto-stores hardware on first access (no explicit admin approval step).
- `RemoveUser` is a hard delete, not soft delete.
**Potential race conditions**:
- Concurrent `RegisterUser` calls with the same email: both could pass the existence check before insert. Mitigated by database unique constraint on email (if one exists).
- `CheckHardwareHash` first-login path: concurrent requests could trigger multiple hardware updates.
**Performance bottlenecks**:
- `GetUsers` loads full user objects including `UserConfig` JSON; for large user bases, projection would be more efficient.
## 8. Dependency Graph
**Must be implemented after**: Data Layer, Security & Cryptography.
**Can be implemented in parallel with**: Resource Management.
**Blocks**: Authentication (uses `GetByEmail`), Admin API.
## 9. Logging Strategy
No explicit logging in UserService.
## Modules Covered
- `Services/UserService`
- `Common/Requests/LoginRequest`
- `Common/Requests/RegisterUserRequest`
- `Common/Requests/SetHWRequest`
- `Common/Requests/SetUserQueueOffsetsRequest`