Skip to content

Organization ​

Responsibility and models ​

Organization owns organizations, teams, ordinary memberships, active organization context, doctor affiliations, registration invitations, and join requests. It does not own account credentials, professional doctor profiles, subscriptions, or clinical documents. A doctor may affiliate with multiple organizations; ordinary member roles and doctor affiliations are independent.

Current implementation ​

The module has mixed implementation status. Curated organization creation/read/edit/lifecycle capabilities and member creation/lookups used by Admin are implemented, with pgx repositories when a database is supplied and in-memory fallback construction for tests/tools. Most organization portal contracts remain validated Huma operations returning 501; the scoped organization doctor list is implemented. See Organization management API for summary, type constants, counts, assignment provenance and mocked billing projections.

GET /api/v1/organizations/auth/verify validates the bearer token and persistent session and requires an active identity, active membership and active organization. No organization ID or slug query parameter is required. It infers the organization slug from a tenant subdomain such as acme.prescriptoobd.com or opsonin.prescriptoobd.com in the request Host. When the host has no tenant subdomain (for example, api.prescriptoobd.com), it checks the browser's Origin instead. Only a single tenant label under prescriptoobd.com is recognized; api and www are shared hosts, and forwarded headers are not used. If a tenant is inferred, the caller must be an active member of that active organization; an unknown tenant or missing membership returns 403 without falling back to another organization. If no tenant is available, organization ID and slug matching are skipped and any active membership in an active organization is accepted. The response contains a message, data, status_code envelope with identity, member, and organization in data. Missing or invalid credentials return 401, ineligible accounts/memberships/organizations return 403, and unavailable dependencies return 503. Identity always comes from the bearer token.

GET /api/v1/organizations/profile replaces /api/v1/organizations/{organizationId}/profile and uses the same optional request-subdomain check and any-membership fallback as verification. It returns identity account fields directly in data, membership details in profile, assigned role metadata in roles, effective own/any decisions in permissions, and the chosen organization. Role metadata omits permission grants; effective permissions include direct allow/deny overrides and are scoped to the returned organization. Empty role and permission lists are arrays. This requires a valid bearer session, active identity, active membership and active organization, without management permissions or an active context selection. Invalid credentials return 401, ineligible membership or organization returns 403, and unavailable dependencies return 503. Successful responses use Cache-Control: no-store.

POST /api/v1/organizations/auth/login accepts email and password and returns Identity's access_token, refresh_token, token_type, and expires_in fields. It uses Identity's public AuthenticationService and requires an active Identity account with an active membership in at least one active organization before issuing credentials or creating a session. No organization selector or active context is required. Incorrect credentials, disabled accounts, and missing or inactive memberships/organizations return 401. Login shares Identity's ten-attempt limit per normalized email per 15-minute window and returns 429 when exceeded. Responses use Cache-Control: no-store; unavailable dependencies return 503.

Selected legacy member removal, active-context, and team routes remain mounted in the API. organization_legacy.go restricts that mount so it cannot shadow portal operations. Do not treat every legacy handler retained in source as a currently mounted production route, or assume its legacy permissions match the planned portal contract.

Portal workflows and boundaries ​

Organization and doctor workflows describes independent/invited doctor onboarding, discovery, invitations, affiliation, join requests, ordinary members, billing views, and route inventories. The portal's planned organization-admin checks, affiliation isolation, subscription usage gates, and transactions are not implemented by the 501 contracts.

Management API contracts adds affiliation status PATCH, active-context lookup, team detail/edit/delete, and member team assignment. These six operations return 501; non-admin organization PATCH has been retired. The team-assignment contract distinguishes a required ID from explicit null clearing and adds optional team_id to member views.

Module.Administration() exposes a single public AdminOrganizationService for organization creation, reads, editing, lifecycle changes, member creation, and member lookup. Admin use cases receive this same service through Dependencies.AdminOrganizationService. Provider-owned DTOs and stable errors remain the cross-service boundary. Planned doctor and billing orchestration should use Doctor and Subscription public contracts rather than their internals.

Storage and events ​

Embedded migrations cover organizations, memberships, and teams. Configurable roles, permissions, and assignments live in Authorization's authz_* tables. Membership role remains organization-owned and identifies scope owners and member categories. The CLI applies migrations after Identity and Admin. Implemented facade changes publish organization/member events after the repository operation. Event failures are not backed by a transactional outbox. Doctor affiliations and invitation redemption are persisted; unimplemented invitation/join-request operations retain their documented 501 behavior.

Code reference ​

See public contracts, module facades, and use cases.

Audit history ​

This service owns its scoped list/detail audit HTTP endpoints and consumes internal Audit capabilities. Persistent working mutations append history in their authoritative PostgreSQL transactions. Admin-originated changes remain in admin history, including delegated organization writes. Audit has no direct HTTP API.

Documentation follows the source. Planned contracts are marked explicitly.