Files
admin/_docs/02_document/components/02_user_management/description.md
T
Oleksandr Bezdieniezhnykh c7b297de83
ci/woodpecker/push/01-test Pipeline failed
ci/woodpecker/push/02-build-push unknown status
refactor: remove deploy.cmd and update Dockerfile for health checks
- Deleted the deploy.cmd script as it was no longer needed.
- Updated Dockerfile to include curl for health checks and added a non-root user for improved security.
- Modified health check command to use curl for better reliability.
- Adjusted docker-compose.test.yml to reflect changes in health check configuration.
- Cleaned up appsettings.json and removed unused configuration properties.
- Removed Resource entity and related requests from the codebase as part of the architectural shift.
- Updated documentation to reflect the removal of hardware binding and related endpoints.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-13 08:47:21 +03:00

6.4 KiB

User Management

Cycle 1 (2026-05-13) note — hardware-binding methods (UpdateHardware, CheckHardwareHash) and SetHWRequest were removed by AZ-197; the ValidateUser error set now includes UserDisabled; RegisterDevice was added by AZ-196 to back the new POST /devices endpoint. Post-cycle-1 (security audit F-3): RegisterDevice now reuses RegisterUser for the row insert; the duplicate-row race was closed by adding a UNIQUE INDEX on users.email (env/db/06_users_email_unique.sql) and translating Npgsql.PostgresException(SqlState=23505) to BusinessException(EmailExists) inside RegisterUser.

1. High-Level Overview

Purpose: Full user lifecycle management — web-user registration, credential validation, role changes, account enable/disable, deletion, plus auto-provisioning of CompanionPC device users.

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), System.Security.Cryptography.RandomNumberGenerator (device password entropy).

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) — translated from PostgresException(23505) after the F-3 hardening
RegisterDevice CancellationToken RegisterDeviceResponse Yes BusinessException(EmailExists) (propagated from RegisterUser) — added by AZ-196, refactored post-audit to call RegisterUser end-to-end
ValidateUser LoginRequest, CancellationToken User Yes BusinessException(NoEmailFound, WrongPassword, UserDisabled)
GetByEmail string? email, CancellationToken User? Yes ArgumentNullException
UpdateQueueOffsets string email, UserQueueOffsets, CancellationToken void Yes None
GetUsers string? searchEmail, RoleEnum? searchRole, CancellationToken IEnumerable<User> Yes None
ChangeRole string email, RoleEnum, CancellationToken void Yes None
SetEnableStatus string email, bool, CancellationToken void Yes None
RemoveUser string email, CancellationToken void Yes None

Removed by AZ-197: UpdateHardware, CheckHardwareHash, and the private UpdateLastLoginDate helper.

Input / Output 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)

RegisterDeviceResponse (AZ-196):
  Serial: string ("azj-NNNN", zero-padded)
  Email: string ("azj-NNNN@azaion.com")
  Password: string (32-char hex, plaintext, exposed exactly once)

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 UpdateQueueOffsets (only — UpdateHardware / CheckHardwareHash invalidations are gone with AZ-197)

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, RegisterDevice, ValidateUser
RandomNumberGenerator.GetBytes(16) + Convert.ToHexString 32-char hex device password RegisterDevice
QueryableExtensions.WhereIf Conditional LINQ filters GetUsers

7. Caveats & Edge Cases

Known limitations:

  • No pagination on GetUsers — returns all matching users.
  • RemoveUser is a hard delete, not soft delete.
  • RegisterDevice returns the plaintext password to the caller exactly once; if the provisioning script loses it, the device must be re-registered.
  • The User.Hardware column is left in place but unused (AZ-197 chose to leave the column nullable rather than ship a migration).

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).
  • Concurrent RegisterDevice calls: both could read the same "most recent CompanionPC" row and try to claim the same azj-NNNN serial. Mitigated by the users.email unique constraint — the loser will fail the insert. (Out of cycle-1 scope: a sequence-based serial allocator would eliminate the retry.)

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/RegisterDeviceResponse (added cycle 1, AZ-196)
  • Common/Requests/SetUserQueueOffsetsRequest

Removed cycle 1 (AZ-197): Common/Requests/SetHWRequest