01 -- Architecture Overview: Admin Service
1. Task Restatement
Заголовок раздела «1. Task Restatement»The platform currently supports two user roles — Customer and Employee — each with dedicated JWT authentication infrastructure, Passport strategies, and guards. This task introduces a full Admin Service layer to enable platform operators to manage users and projects through a privileged administrative interface. The Admin Service implements passwordless authentication (corporate email plus 6-digit verification code), a separate admin JWT token infrastructure (access + refresh), project management CRUD (list all, edit any, soft delete), and user management (list, block/unblock). Prisma schema changes are required to add ADMIN to the RoleType enum, introduce isBlocked on the User model, add deletedAt to the Project model for soft deletes, and make passwordHash/passwordSalt nullable to support the passwordless admin flow.
2. Scope Table
Заголовок раздела «2. Scope Table»| # | Path | Type | Action | Purpose |
|---|---|---|---|---|
| 1 | apps/auth-api | App | Modified | Host admin auth endpoints (/admin/auth/*), extend app.module.ts to import admin-auth feature, add Swagger tag in main.ts |
| 2 | apps/core-api | App | Modified | Prisma schema changes (ADMIN enum, isBlocked, deletedAt, nullable password fields), new migration, seed ADMIN role record |
| 3 | apps/admin-api | App | Created | New NX app hosting admin CRUD endpoints (/admin/projects/*, /admin/users/*) |
| 4 | apps/user-api | App | Reference Only | Existing user microservice; no direct changes, consumed via shared Prisma client |
| 5 | apps/project-api | App | Reference Only | Existing project microservice; soft-delete filter applied through its provider lib |
| 6 | libs/apis/shared | Lib | Modified | Add AdminAccessTokenGuard, AdminRefreshTokenGuard, ADMIN to Role constants, token extraction helper for admin tokens |
| 7 | libs/apis/providers/auth-api/features/token | Lib | Modified | Add TokenAdminService for admin access/refresh token generation and validation |
| 8 | libs/apis/providers/auth-api/features/employee-auth | Lib | Modified | Add isBlocked check to EmployeeAccessTokenStrategy.validate() |
| 9 | libs/apis/providers/auth-api/features/customer-auth | Lib | Modified | Add isBlocked check to CustomerAccessTokenStrategy.validate() |
| 10 | libs/apis/providers/email-sender-api/features/sender | Lib | Modified | Add admin_email_verification HTML template and sendAdminVerificationCode() method |
| 11 | libs/apis/providers/project-api/features/project | Lib | Modified | Add deletedAt IS NULL filter to all existing project queries |
| 12 | libs/apis/providers/user-api/features/user | Lib | Modified | Add updateIsBlocked(userId, isBlocked) method to UserService |
| 13 | libs/apis/configs/auth-api/jwt-admin | Lib | Created | JWT admin configuration module: env vars JWT_ADMIN_ACCESS_SECRET, JWT_ADMIN_REFRESH_SECRET, expiration settings |
| 14 | libs/apis/providers/auth-api/features/admin-auth | Lib | Created | Passwordless auth flow: controller, service, AdminAccessTokenStrategy, AdminRefreshTokenStrategy, register/login/verify/refresh |
| 15 | libs/apis/providers/admin-api/features/admin-project | Lib | Created | Admin project CRUD: list all (with pagination + filters), get by ID, edit any project, soft delete |
| 16 | libs/apis/providers/admin-api/features/admin-user | Lib | Created | Admin user management: list (with pagination + filters), get by ID, block, unblock |
| 17 | libs/apis/providers/admin-api/data-access | Lib | Created | DTOs (AdminProjectDto, AdminUserDto, pagination DTOs) and constants for admin endpoints |
3. Architecture Decision Records
Заголовок раздела «3. Architecture Decision Records»ADR-1: Where to Host Admin CRUD Endpoints
Заголовок раздела «ADR-1: Where to Host Admin CRUD Endpoints»Context. The admin service requires 8 CRUD endpoints for project and user management. The existing auth-api app handles authentication, while user-api and project-api handle their respective domains. We need to decide where the admin CRUD controllers live.
Decision. Create a new admin-api NX application dedicated to admin CRUD operations. Admin authentication endpoints (/admin/auth/*) remain in auth-api since they are part of the auth domain. The admin-api app hosts project management (/admin/projects/*) and user management (/admin/users/*) controllers.
Alternatives considered.
- Add everything to
auth-apiunder/adminprefix. Simpler setup but conflates authentication concerns with resource management. Theauth-apiapp would grow into a monolith, violating the existing microservice boundary conventions. - Split across
user-apiandproject-apiwith admin guards. Follows domain boundaries but scatters admin logic across multiple apps, making it harder to reason about admin capabilities as a unit and to apply uniform admin middleware. - Single
admin-apifor both auth and CRUD. Clean separation but breaks the established pattern where all authentication flows live inauth-api.
Consequences.
- Positive: Clear separation of concerns; admin CRUD is isolated and independently deployable;
auth-apistays focused on authentication. - Positive: Follows the existing monorepo convention where each app maps to a bounded context.
- Negative: One additional app to build, configure (Swagger, env, Dockerfile), and deploy. Increases infrastructure surface slightly.
- Negative: Admin auth and admin CRUD are in different apps, requiring shared JWT validation infrastructure through the
sharedlib.
ADR-2: Passwordless Authentication Approach
Заголовок раздела «ADR-2: Passwordless Authentication Approach»Context. Admin users authenticate without passwords. The system must verify admin identity through a secondary channel. The existing codebase already has infrastructure for 6-digit code generation (random-code.helper.ts), Redis-based code storage with TTL, cooldown enforcement, and SMTP email delivery via @nestjs-modules/mailer.
Decision. Use email-based 6-digit verification codes for passwordless admin auth. Both registration and login follow a two-step flow: (1) submit email, receive code; (2) submit code, receive JWT tokens. Codes are stored in Redis with a 900-second TTL and a 120-second resend cooldown, reusing the existing verification infrastructure patterns.
Alternatives considered.
- Magic link (email with signed URL). Simpler UX (single click) but requires configuring a frontend callback URL, does not work well in API-only/Swagger testing scenarios, and introduces URL expiration management that differs from the existing code-based pattern.
- OAuth/SSO with corporate identity provider. Strongest security but adds external IdP dependency (Google Workspace, Okta, etc.), significant integration complexity, and is premature given the current scale and the absence of an existing SSO provider.
- Password-based auth identical to Customer/Employee. Simplest to implement (reuse existing flows) but the spec explicitly mandates passwordless, and admin accounts are managed differently — no self-service password reset, no password storage liability.
Consequences.
- Positive: Reuses existing code generation, Redis TTL, cooldown, and email sending infrastructure with minimal new code.
- Positive: No password storage for admin accounts, reducing credential-related attack surface.
- Negative: Every login requires email access, which may be slower than password-based auth for frequent admin sessions. Mitigated by long-lived refresh tokens.
- Negative: Dependency on SMTP availability for every auth attempt.
ADR-3: Soft Delete Strategy for Projects
Заголовок раздела «ADR-3: Soft Delete Strategy for Projects»Context. Admin users need the ability to remove projects from public visibility without permanently destroying data. The system must support potential future restoration and audit trails. The Project model currently has no deletion mechanism.
Decision. Add a nullable deletedAt (DateTime?) column to the Project model. A soft-deleted project has deletedAt set to the current timestamp. All existing project queries in ProjectService add a WHERE deletedAt IS NULL filter. The admin soft-delete endpoint sets deletedAt via a Prisma update, not a delete.
Alternatives considered.
- Separate archive table. Move deleted projects to a
ProjectArchivetable. Provides clean separation but requires duplicating the schema, managing data migration between tables, and updating all relations (e.g.,WalriderThread.projectIdforeign key). - Status flag (
status: DELETED). TheProjectStatusenum already exists; adding aDELETEDvalue is simple. However, this conflates lifecycle status (DRAFT, IN_PROGRESS, COMPLETED) with visibility/deletion semantics. A project could be COMPLETED and also soft-deleted; a single enum cannot represent both states. - Prisma middleware / global filter. Apply
deletedAt IS NULLautomatically via Prisma middleware or$extends. Convenient but implicit, making it easy to forget about soft deletes, harder to debug, and the existing codebase does not use Prisma middleware.
Consequences.
- Positive: Simple, well-understood pattern. Single new nullable column; no schema duplication.
- Positive: Supports future restoration by setting
deletedAtback tonull. - Positive: Compatible with the existing
ProjectStatusenum without semantic overloading. - Negative: Every existing query that returns projects must be updated to filter
deletedAt IS NULL. Missed filters could leak soft-deleted data. - Negative: Soft-deleted records accumulate in the same table, potentially affecting query performance at scale. Mitigated by indexing
deletedAt.
ADR-4: Separate JWT Secrets for Admin Tokens
Заголовок раздела «ADR-4: Separate JWT Secrets for Admin Tokens»Context. The system already uses separate JWT secret pairs for Customer (JWT_CUSTOMER_ACCESS_SECRET, JWT_CUSTOMER_REFRESH_SECRET) and Employee (JWT_EMPLOYEE_ACCESS_SECRET, JWT_EMPLOYEE_REFRESH_SECRET). Admin tokens need their own signing configuration.
Decision. Create a dedicated jwt-admin config library (libs/apis/configs/auth-api/jwt-admin) with its own secret pair (JWT_ADMIN_ACCESS_SECRET, JWT_ADMIN_REFRESH_SECRET) and separate expiration values. Admin Passport strategies validate exclusively against admin secrets.
Alternatives considered.
- Reuse Employee JWT secrets with a role claim. Fewer env vars but a compromised Employee secret would grant admin access. Role claims in the token payload could be tampered with if the same signing key is shared.
- Single shared secret with audience/issuer claims. Reduces secret management overhead but weakens the security boundary; all token types become interchangeable if claims validation is missed.
Consequences.
- Positive: Cryptographic isolation between admin and non-admin tokens. A compromised Customer or Employee secret cannot forge admin tokens.
- Positive: Consistent with the existing multi-secret pattern, reducing cognitive overhead for developers familiar with the codebase.
- Negative: Two additional secrets to generate, store, and rotate per environment.
ADR-5: Blocking Check Location — Auth Strategies vs. Guard
Заголовок раздела «ADR-5: Blocking Check Location — Auth Strategies vs. Guard»Context. The new isBlocked field on User must be enforced so that blocked users cannot access protected endpoints. This check needs to be applied to all three user types (Customer, Employee, Admin).
Decision. Add the isBlocked check inside each Passport strategy’s validate() method (CustomerAccessTokenStrategy, EmployeeAccessTokenStrategy, AdminAccessTokenStrategy). If isBlocked is true, the strategy throws UnauthorizedException, preventing token validation from succeeding.
Alternatives considered.
- Dedicated
IsBlockedGuardapplied globally or per-route. Separates concerns but adds another database query per request (the strategy already fetches the user). Also requires ensuring guard ordering relative to auth guards. - Redis-based blocklist checked in middleware. Fastest check but introduces cache invalidation complexity. Blocking/unblocking a user would require updating both the database and the Redis blocklist atomically.
Consequences.
- Positive: No additional database query; the strategy already loads the user, so the
isBlockedcheck is effectively free. - Positive: Blocked users are rejected at the earliest possible point in the request lifecycle (token validation).
- Negative: The check is duplicated across three strategies. Mitigated by the fact that each strategy is a separate class by design in this codebase, and the check is a single conditional.
4. Assumptions
Заголовок раздела «4. Assumptions»-
Admin domain restriction is sufficient for registration authorization. Only users with email addresses matching domains listed in
ADMIN_ALLOWED_DOMAINScan register as admins. There is no additional invitation flow, approval queue, or superadmin confirmation step required. -
All admins have equal privileges. There is no admin hierarchy, permission levels, or role-based access control within the admin tier. Every admin can perform all admin operations (manage any project, block/unblock any user).
-
Existing
TokenandSessionmodels are reused for admin tokens. Admin access/refresh tokens are stored in the sametokensandsessionstables used by Customer and Employee. TheuserIdforeign key is sufficient to associate tokens with the admin user, and theUserOnRolejoin table distinguishes the role. -
The
passwordHashandpasswordSaltfields can be made nullable without breaking existing auth flows. Existing Customer and Employee registration flows always populate these fields, so existing user records will not have null values. Prisma validation and application-level checks in Customer/Employee strategies will continue to work as before. -
Soft-deleted projects are excluded from all non-admin queries by default. The
project-apiservice’sProjectServicewill filter outdeletedAt IS NOT NULLrecords in all list and detail queries. Only the admin project endpoints will have the ability to query soft-deleted projects (for audit or restore purposes in future iterations). -
Admin verification codes use the same TTL (900s) and resend cooldown (120s) as existing email verification. These values are consistent with the established patterns in the codebase and are not configurable per-role.
-
The
admin-apiapp connects to the same PostgreSQL database (via Prisma) and the same Redis instance as the other apps. No separate data store is provisioned for admin operations. -
RabbitMQ is used for inter-service communication where needed (e.g., email sending), but admin CRUD operations are synchronous request-response over HTTP against the shared database. There is no event-driven saga for admin actions in this iteration.
5. Output File Reference Table
Заголовок раздела «5. Output File Reference Table»| # | File | Description |
|---|---|---|
| 1 | architecture/01_overview.md | This document. Task restatement, scope table, ADRs, assumptions, and file index. |
| 2 | architecture/02_api_endpoints.md | Full specification of all 13 admin API endpoints: routes, HTTP methods, request/response schemas, status codes, auth requirements. |
| 3 | architecture/03_prisma_schema.md | Prisma schema changes: ADMIN enum value, isBlocked on User, nullable password fields, deletedAt on Project, migration plan, seed data. |
| 4 | architecture/04_auth_flow.md | Detailed passwordless authentication flow for admin: registration sequence, login sequence, code verification, token issuance, refresh logic. |
| 5 | architecture/05_jwt_infrastructure.md | Admin JWT configuration: env variables, secret management, token payload structure, expiration policy, Passport strategy wiring. |
| 6 | architecture/06_guards_and_strategies.md | Admin guards (AdminAccessTokenGuard, AdminRefreshTokenGuard), strategy implementations, isBlocked enforcement across all user types. |
| 7 | architecture/07_project_management.md | Admin project CRUD: list all with pagination/filters, edit any project, soft delete/restore logic, deletedAt filtering in existing queries. |
| 8 | architecture/08_user_management.md | Admin user management: list with pagination/filters, block/unblock flow, isBlocked field behavior, cascade effects on active sessions. |
| 9 | architecture/09_libs_structure.md | NX library creation and modification plan: new lib generators, module wiring, barrel exports, dependency graph between libs. |
| 10 | architecture/10_email_templates.md | Admin email verification template specification: HTML structure, template variables, localization (en/ru), integration with EmailSenderService. |
| 11 | architecture/11_testing_strategy.md | Testing plan: unit tests for services/strategies, e2e tests for admin endpoints, test fixtures, mocking strategy for Redis/Prisma/SMTP. |