# Admin Panel Service Context ## Roles - ADMIN: full CRUD + all dictionaries + SLA + users + quotes - LAWYER: - see assigned requests - see unassigned queue - can manually claim unassigned request ("Take in work") ## Core Features - Universal table with filters (`= != > < >= <= ~`) - Universal record modal (meta-driven) - Manual editing of available entities - AuditLog for any CREATE/UPDATE/DELETE and system assignment events - Atomic claim action to prevent race conditions between lawyers - User profile avatar (`avatar_url`) with fallback initials in UI - Lawyer profile includes default lawyer rate (editable by ADMIN) - Lawyer profile includes salary percent (editable by ADMIN) ## Assignment Logic - Request can be claimed manually by lawyer - Manual claim is allowed only when `assigned_lawyer_id` is null - Lawyer takeover is forbidden - Manual reassignment of assigned request is ADMIN-only action - If not claimed within 24h and still unassigned, auto-assign is applied - Lawyer profile includes: - one primary topic - additional topics - Additional topics are stored via separate link table (`admin_user_topics`) - Assignment priority: primary topic matches first, then additional topics, then lowest active load - Active load = count of assigned requests with non-terminal status (`is_terminal=false`) ## Status Logic - Status flow is configured per topic - Base model is linear, but with allowed flow variations (Jira-like) - On any status change: - all previous messages immutable - all previous attachments immutable - add `status_history` record ### Implemented Flow Configuration (`P14`) - New dictionary table: `topic_status_transitions` - Transition rule fields: - `topic_code` - `from_status` - `to_status` - `sla_hours` (SLA для перехода, в часах) - `enabled` - `sort_order` - ADMIN manages flow rules in "Справочники -> Переходы статусов" - Server-side validation: - if topic has configured enabled rules, transition is allowed only when rule exists - if topic has no rules yet, backward-compatible free transition is kept ### Planned Billing Status Extension - Add status type: `INVOICE` / "Выставление счета" - For this status type: - invoice is generated from admin-managed template - invoice is attached/sent to client through platform notification channel - billing status can be included in topic-specific flow as regular transition node ### Implemented Billing Status Flow (`P25`) - `statuses.kind` supports: - `DEFAULT` (regular status) - `INVOICE` (billing step: выставление счета) - `PAID` (business payment fact status) - `statuses.invoice_template` stores admin-managed invoice template with placeholders (`{track_number}`, `{client_name}`, `{topic_code}`, `{amount}` and others). - On request status transition to `INVOICE` kind: - system auto-creates waiting invoice (`WAITING_PAYMENT`) from template - invoice is linked to request and available in ADMIN/LAWYER + public cabinet - On request status transition to `PAID` kind: - only ADMIN can perform this transition - latest waiting invoice is marked as paid - request payment fields are fixed (`invoice_amount`, `paid_at`, `paid_by_admin_id`) - Multiple billing cycles in the same request are supported (sequential invoice->paid events). ### Implemented SLA Transition Config (`P18`) - SLA configuration is stored in `topic_status_transitions.sla_hours` - `sla_hours` is optional but if set must be integer > 0 - CRUD validation prevents: - unknown `topic_code` / status codes - `from_status == to_status` - non-positive `sla_hours` - Admin UI for "Переходы статусов" includes `SLA (часы)` in table, filters, and edit/create modal ### Implemented Status Immutability (`P15`) - On request status change: - all existing `messages` for request are marked `immutable=true` - all existing `attachments` for request are marked `immutable=true` - new row is written into `status_history` (`from_status`, `to_status`, `changed_by_admin_id`) - Immutable records protection: - `PATCH /api/admin/crud/messages/{id}` and `DELETE /api/admin/crud/messages/{id}` are blocked for immutable rows - `PATCH /api/admin/crud/attachments/{id}` and `DELETE /api/admin/crud/attachments/{id}` are blocked for immutable rows - upload complete rejects binding file to immutable message (`message_id`) ## Templates - ADMIN configures required client fields for request creation (by topic) - For in-progress work, lawyer can use topic template for requested docs/data - Lawyer can extend that template for a specific request only - No template versioning requirement ### Implemented Template Split (`P16`) - New dictionaries: - `topic_required_fields`: required request creation fields per topic (`topic_code`, `field_key`, `required`, `enabled`, `sort_order`) - `topic_data_templates`: topic-level data/doc request template (`topic_code`, `key`, `label`, `description`, `required`, `enabled`, `sort_order`) - Request-level table: - `request_data_requirements`: per-request expanded template items, including lawyer-added custom items - Validation: - create request (`/api/public/requests`, `/api/admin/requests`, `/api/admin/crud/requests`) validates `extra_fields` against active required keys from `topic_required_fields` - Request template API: - `GET /api/admin/requests/{request_id}/data-template` - `POST /api/admin/requests/{request_id}/data-template/sync` - `POST /api/admin/requests/{request_id}/data-template/items` - `PATCH /api/admin/requests/{request_id}/data-template/items/{item_id}` - `DELETE /api/admin/requests/{request_id}/data-template/items/{item_id}` - RBAC: - ADMIN has full access - LAWYER can work with template items only for assigned request ## Rates & Billing Rules (planned) - ADMIN sets default lawyer rate in user profile - ADMIN sets lawyer salary percent in user profile - ADMIN can override rate for a specific request - Effective request rate is stored in request and frozen for financial traceability - Request rate is not returned in public client endpoints and not shown in public UI - Effective request amount is stored in request and frozen for financial traceability - Fact of payment is recorded when ADMIN changes request status to "Оплачено" (business paid event) - Payment event stores who changed status and when (for salary/month reports) - A request may contain more than one payment event (multiple invoice-payment cycles) ### Implemented Rate Rules (`P24`) - On first assignment (`claim`, `reassign`, `auto-assign`, create/update request with assigned lawyer), `requests.effective_rate` is auto-filled from `admin_users.default_rate` if request rate is empty. - If request already has `effective_rate`, assignment/reassignment does not overwrite it. - LAWYER role cannot create/update request financial fields (`effective_rate`, `invoice_amount`, `paid_at`, `paid_by_admin_id`). - Public client API does not expose internal request financial fields. ### Implemented Baseline For Dashboard (`P21`) - Financial profile fields are persisted: - `admin_users.default_rate` - `admin_users.salary_percent` - Request financial fields are persisted: - `requests.effective_rate` - `requests.invoice_amount` - `requests.paid_at` - `requests.paid_by_admin_id` - Admin UI record forms/tables include these fields. - Public API still does not expose internal financial fields. ## Read / Unread UX - Unread state is tracked per request for both LAWYER and PUBLIC user - New message/file/status change marks request as updated - Opening request marks updates as read - UI can show one-time green indicator for what changed (message/file/status) ## Implemented Marker Model (`P13`) - `requests.client_has_unread_updates` / `requests.client_unread_event_type` - `requests.lawyer_has_unread_updates` / `requests.lawyer_unread_event_type` - Event types: `MESSAGE`, `ATTACHMENT`, `STATUS` - LAWYER opening request (`GET /api/admin/crud/requests/{id}` or `GET /api/admin/requests/{id}`) clears lawyer marker - Client opening request (`GET /api/public/requests/{track_number}`) clears client marker ## Admin Dashboard Financial Metrics (planned) - For each lawyer show: - active requests count (current load) - sum of active requests amounts (if amount exists) - monthly gross of paid requests - monthly gross of paid events - monthly salary amount - Salary calculation base: - paid event = ADMIN changes request status to "Оплачено" - salary = paid request amount * lawyer salary percent ## Implemented File Security Audit (`P26`) - Added dedicated immutable security log table: `security_audit_log`. - File operations in admin/public upload APIs now produce security events: - `UPLOAD_INIT`, `UPLOAD_COMPLETE`, `DOWNLOAD_OBJECT`. - Both successful and denied attempts are logged (including RBAC denials on download). - `security_audit_log` is exposed in admin dictionaries as read-only (query/read only, no update/delete via universal CRUD).