Skip to content

Doctor administration ​

All paths use /api/v1. These routes are implemented and use the same explicit request DTO, response DTO, mapper and use-case structure as organization creation. Success responses contain message, data, and status_code; collection responses also contain pagination.

MethodPathRequired admin permission
GET/admin/doctorsadmin.doctor.list
GET/admin/doctors/{doctorId}admin.doctor.read
GET/admin/doctors/{doctorId}/organizationsadmin.doctor.read + admin.organization.read
POST/admin/doctors/{doctorId}/suspendadmin.doctor.suspend
POST/admin/doctors/{doctorId}/activateadmin.doctor.activate
GET/admin/organizations/{organizationId}/doctorsadmin.organization.read + admin.doctor.list
GET/admin/organizations/{organizationId}/doctors/{doctorId}admin.organization.read + admin.doctor.read
PATCH/admin/organizations/{organizationId}/doctors/{doctorId}admin.organization.read + admin.doctor.affiliation.update
POST/admin/organizations/{organizationId}/doctorsadmin.doctor.assign
GET/admin/verifications/pendingadmin.doctor_verification.list
GET/admin/verifications/{verificationId}admin.doctor_verification.read
POST/admin/verifications/{verificationId}/approveadmin.doctor_verification.approve
POST/admin/verifications/{verificationId}/rejectadmin.doctor_verification.reject

Every admin operation requires an active Identity account, an active persisted admin membership, and the matching explicit permission. Admin membership alone does not grant access. Missing/invalid credentials return 401; insufficient access returns 403; unavailable capabilities return 503. Unknown body and query fields are rejected.

Directory and details ​

doctorId is the professional profile ID, independent from user_id. Both list and details expose current name/email/account status from Identity, professional fields (including one speciality, specialization selections, qualification and chambers) from Doctor, the latest verification, and Organization-owned affiliations. verification_status is not_submitted, pending, verified, or rejected. If the current license differs from the latest submission's license, the effective status is not_submitted. The nested verification retains its historical submitted license and review outcome; a changed license needs a new review.

Directory filters are search, account_status=active|inactive|suspended, verification_status, and organization_id. Organization filtering matches active affiliations. Results use created_at DESC, id DESC, default limit=20, maximum 100, and an opaque cursor bound to the filters. Pagination contains next_cursor, current_page, per_page, total_pages, and total_items. The initial implementation composes provider directories and filters in memory, following the existing organization list convention.

Account lifecycle ​

Suspend and activate have no request body. Suspension changes the global Identity account to suspended and revokes every session in the same transaction. It affects all account access, including other memberships. Activation changes the account to active; revoked sessions remain invalid and a new login is required. These actions preserve professional records, affiliations and review history.

Organization doctor roster ​

GET /admin/organizations/{organizationId}/doctors lists persisted affiliations for the target organization. Query parameters are search, status=active|inactive, limit (default 20, maximum 100), and cursor. Omit status to include both relationship states. Search matches current Identity name, license, speciality name, and specialization names. Results order by assigned_at DESC, id DESC, with cursors bound to organization, normalized search, status, and page size. Invalid/mismatched continuation returns 400; schema validation errors return 422.

Each item includes affiliation IDs, organization display/lifecycle fields, relationship status, assignment provenance, join/creation/update times, and a nested doctor with professional ID, live name, license, one speciality object, a specialization array, verification status, and account status. Empty lists return data: [] and zero totals. Missing enrichment fails with 503.

GET /admin/organizations/{organizationId}/doctors/{doctorId} returns the same item shape for the exact organization/professional profile pair. A missing organization or affiliation returns 404, even if the doctor exists elsewhere. Authorized platform admins can inspect suspended/deleted organizations; ordinary portal permissions do not grant access to these Admin routes.

PATCH /admin/organizations/{organizationId}/doctors/{doctorId} accepts:

json
{"status":"inactive"}

Use active to reactivate the existing affiliation. The response contains the committed affiliation. Deactivation retains history, assignment provenance, and original joined_at; reactivation refreshes assignment time, trusted admin actor, and super_admin_portal source. Repeated valid states preserve timestamps and produce no extra change audit event. Activation requires an active organization and doctor account, with account/lifecycle checks serialized with the write; ineligible activation returns 409. Deactivation remains available for inactive accounts and suspended/deleted organizations. PATCH requires an existing relationship; POST handles initial assignment. These operations preserve global account status, ordinary memberships, and affiliations with other organizations. Audit failure rolls back the transition. Verification and mocked capacity are display-only, matching the existing assignment policy.

Apply Authorization migration 00005_doctor_affiliation_permission.sql and grant admin.doctor.affiliation.update explicitly to administrators managing affiliation status. The development full-access role receives it through the permission catalog when seeded; read-only roles do not.

Organization assignment ​

json
{"doctor_ids":["00000000-0000-4000-8000-000000000001","00000000-0000-4000-8000-000000000002"]}

Supply 1–100 unique professional profile UUIDs. Every profile must exist, every account must be active, and the target organization must be active. Admin checks profiles/accounts through their public capabilities before the Organization-owned transaction. An invalid profile fails the batch before writing. Assignment creates or reactivates separate professional affiliations; existing active assignments are idempotent, and affiliations with other organizations remain in place. No ordinary membership is created. Subscription capacity enforcement is outside this initial implementation.

Credential review ​

POST /admin/verifications is a doctor-authenticated submission endpoint despite its historical path. It derives the account/profile and credential snapshot from the authenticated doctor. The body contains 1–20 absolute HTTP(S) documents URLs and optional notes. URLs are validated without fetching their contents. Document upload/storage remains outside this API.

Only one pending submission per doctor is allowed (409 on duplicates). Rejected doctors may submit again; previous submissions remain stored. The pending queue uses cursor pagination with the same 20/100 limits and returns pagination.next_cursor.

Approval accepts {} or optional notes. Rejection requires a nonblank reason and accepts optional notes. Only a pending submission can be reviewed. The transaction locks the submission, stamps the reviewing Identity user ID and time, and retains the submitted evidence. Repeated or competing decisions return 409. The directory reports the latest submission's status. Review does not implement prescription eligibility enforcement or change login requirements.

All authoritative mutations commit their audit records in the same transaction; audit failure rolls back the business change. Apply the Admin verification, Organization affiliation and Authorization permission migrations before serving these routes. Existing admins need explicit grants for the new permission keys.

Organization management extension ​

See Organization management API for target-aware directory eligibility, scoped affiliation reads, assignment provenance and mock billing. Assignment requires active accounts only, regardless of verification state. Account locks serialize concurrent suspension with affiliation commit.

Documentation follows the source. Planned contracts are marked explicitly.