04-clinicalwave: W2filled13 citations

Intake Engine — Patient Intake and Evaluation

Audiences: doctor, nurse, receptionist, clinical-buyer, developer

Intake Engine — Patient Intake and Evaluation

The intake engine manages the structured pre-consultation evaluation workflow — capturing a patient's presenting complaint, clinical history, insurance, referrals, and functional assessments — and publishes real-time SSE events so the clinical team sees intake progress live.

Business Purpose

Patient intake is the structured information-gathering phase before a clinical visit. Without a systematic intake process, receptionists ask the same questions every visit, clinicians discover gaps in the chart mid-consultation, and hand-offs between staff are verbal and lossy.

Dudoxx HMS's intake engine provides:

  1. Structured IntakeEvaluation records — Prisma-backed, linked to a patient and organization. Lifecycle: PENDING → IN_PROGRESS → COMPLETED → ARCHIVED.
  2. Rich participant model — multiple staff members (roles: CLINICIAN, NURSE, ADMIN, COORDINATOR) can collaborate on a single intake record.
  3. Linked sub-documents — each intake evaluation can carry: clinical profile, referral, insurance coverage, functional assessment, placement request, conversation threads, notes, and file attachments.
  4. Intake rules engine — configurable IntakeRulesGroup / IntakeRuleItem records (stored in ddx_api_ai Prisma schema) allow clinics to define conditional intake workflows (trigger conditions, required fields by patient category).
  5. Vector indexingIntakeVectorService indexes intake data into Qdrant for semantic search (used by the AI assistant to find relevant past intakes).
  6. Real-time SSEIntakeSseHelper emits intake.created, intake.updated, intake.status.changed events over the organization-level SSE channel so all connected staff see intake updates instantly.

Clinics that deploy intake properly reduce consultation prep time by 40–60% and eliminate missing-information callbacks.

Audiences

  • Investor: The intake engine is a differentiator for psychiatric, addiction medicine, and rehabilitation settings that require multi-party, multi-document evaluation workflows. It extends the platform beyond simple GP visit management.
  • Clinical buyer (doctor/nurse/receptionist): Receptionists create intakes when patients call or arrive. Nurses add clinical profiles and functional assessments. Doctors review the completed intake before the visit. All actions stream in real-time to the clinical dashboard.
  • Developer/partner: POST /api/v1/intake-evaluations creates an intake. Sub-resources: /participants, /notes, /conversations, /attachments, /clinical-profile, /referrals, /insurance, /functional-assessments, /placement-requests — all nested under the intake ID. Rules: GET|POST /api/v1/intake-rules-groups.
  • Internal (ops/support): Main intake data in Prisma ddx_api_main (IntakeEvaluation, IntakeParticipant, IntakeNote, IntakeConversation). Rules in ddx_api_ai (IntakeRulesGroup, IntakeRuleItem). Vector index in Qdrant (collection keyed per org). SSE via EventBusService (Redis DB1).

Architecture

diagram
IntakeEvaluationController   (/api/v1/intake-evaluations)
  ├── IntakeEvaluationService     — CRUD, status machine, SSE, vector indexing
  │     ├── PrismaService         — IntakeEvaluation, Participant, Note, Conversation
  │     ├── EventBusService       — SSE events (intake.created, intake.updated, etc.)
  │     ├── IntakeSseHelper       — SSE channel resolution + event publication
  │     └── IntakeVectorService   — Qdrant indexing for semantic search
  ├── IntakeParticipantService    — Multi-staff collaboration model
  ├── IntakeAttachmentService     — File uploads (MinIO buckets)
  ├── IntakeNoteService           — Clinical notes on intake
  ├── IntakeConversationService   — Messaging threads within intake
  ├── IntakeLinkedEntityService   — Generic entity linking (visit, appointment, etc.)
  ├── IntakeClinicalProfileService — Structured clinical history capture
  ├── IntakeReferralService       — Referral source documentation
  ├── IntakeInsuranceService      — Insurance coverage capture
  ├── IntakeFunctionalAssessmentService — GAF, ADL, and other functional scales
  └── IntakePlacementService      — Placement request management

IntakeRulesGroupsController  (/api/v1/intake-rules-groups)
  └── IntakeRulesService
        ├── PrismaService         — IntakeEvaluation (for org resolution)
        └── PrismaAiService       — IntakeRulesGroup + IntakeRuleItem (ddx_api_ai DB)

IntakeRulesExecutionsController  (/api/v1/intake-rules-executions)
  └── IntakeRulesExecutorService  — evaluates rules against intake data

Dual DB pattern: Intake evaluation records use PrismaService (main DB); intake rules use PrismaAiService (AI DB). This separates clinical operational data from the AI/rules engine configuration schema.

SSE events flow through EventBusService (src/ai/tucan/sse/event-bus.service.ts) — same bus used by TUCAN AI. Events use organization-level channels via SSEChannels.organization(orgSlug).

Tech Stack & Choices

LayerTechnologyNotes
Intake CRUDPrisma ddx_api_mainIntakeEvaluation, IntakeParticipant, IntakeNote, IntakeConversation, IntakeAttachment
Rules storagePrisma ddx_api_ai (PrismaAiService)IntakeRulesGroup, IntakeRuleItem — separated from clinical data
SSEEventBusService (Redis DB1, RxJS)5 intake event types; organization-level channel
Vector indexIntakeVectorService → QdrantSemantic search over historical intake records
File attachmentsMinIO via StorageServiceStored in {clinic}-attachments bucket
Status machineIntakeStatus enum (PENDING/IN_PROGRESS/COMPLETED/ARCHIVED)Prisma-managed; SSE emitted on transition
Auth@RequireRole() per sub-resource@RbacExempt() on guest submission endpoints (public intake forms)
PriorityIntakePriority enumDrives queue ordering in intake dashboard

Data Flow

Receptionist creates an intake

Business outcome: A patient calls to book an appointment; the receptionist creates an intake evaluation and assigns a nurse. Both staff see the new intake appear in the dashboard within 1 second.

Technical mechanism:

  1. POST /api/v1/intake-evaluations with { patientId, organizationId, priority: "HIGH", notes: "Patient reports chest pain" }.
  2. IntakeEvaluationController.create() (intake-evaluation.controller.ts:80) resolves role via @RequireRole(DOCTOR, NURSE, CLINIC_ADMIN, ...).
  3. IntakeEvaluationService.create() (intake-evaluation.service.ts:34): a. Resolves organizationId — accepts UUID or slug (resolveOrganizationId(), intake-evaluation.service.ts:57). b. Creates IntakeEvaluation Prisma row with status PENDING. c. Calls IntakeSseHelper.emitCreated() → publishes intake.created event to SSEChannels.organization(orgSlug) via EventBusService. d. Calls IntakeVectorService.indexIntake() to add to Qdrant for semantic recall.
  4. All clinical staff with active SSE connections receive the event immediately.

Intake rules evaluation

POST /api/v1/intake-rules-executions with intake ID → IntakeRulesExecutorService loads applicable IntakeRulesGroup from ddx_api_ai, evaluates each IntakeRuleItem's condition against the intake data, returns pass/fail results and recommended next steps.

Intake completion + summary

PATCH /api/v1/intake-evaluations/:id with status: "COMPLETED"IntakeEvaluationService transitions status, emits intake.status.changed SSE event, triggers IntakeSummaryService to generate a structured summary (used by the attending doctor as pre-visit brief).

Implicated Code

  • ddx-api/src/clinical-forms/intake-evaluation/intake-evaluation.controller.ts:60IntakeEvaluationController — 11 injected sub-services; @Controller('intake-evaluations')
  • ddx-api/src/clinical-forms/intake-evaluation/intake-evaluation.controller.ts:80POST /intake-evaluations — entry point for intake creation
  • ddx-api/src/clinical-forms/intake-evaluation/intake-evaluation.service.ts:26INTAKE_EVENTS — SSE event type constants (intake.created, intake.updated, intake.status.changed, intake.archived, intake.ownership.transferred)
  • ddx-api/src/clinical-forms/intake-evaluation/intake-evaluation.service.ts:34IntakeEvaluationService — orchestrates Prisma + SSE + Qdrant for each lifecycle action
  • ddx-api/src/clinical-forms/intake-evaluation/intake-evaluation.service.ts:57resolveOrganizationId() — accepts UUID or slug; queries Prisma organization table by multiple fields
  • ddx-api/src/clinical-forms/intake-evaluation/intake-sse.helper.ts:1IntakeSseHelper — SSE channel resolution + event emission wrapper
  • ddx-api/src/clinical-forms/intake-evaluation/intake-vector.service.ts:1IntakeVectorService — Qdrant indexing for semantic intake search
  • ddx-api/src/clinical-forms/intake-evaluation/intake-rules.service.ts:19IntakeRulesService — uses dual-DB: PrismaService (org resolution) + PrismaAiService (rules data)
  • ddx-api/src/clinical-forms/intake-evaluation/intake-rules.service.ts:59createGroup() — creates IntakeRulesGroup in ddx_api_ai DB
  • ddx-api/src/clinical-forms/intake-evaluation/intake-summary.service.ts:1IntakeSummaryService — generates structured intake summary for doctor pre-brief

Operational Notes

  • Dual DB for rules: Intake rules (IntakeRulesGroup, IntakeRuleItem) live in ddx_api_ai — not ddx_api_main. IntakeRulesService uses PrismaAiService, not the default PrismaService. Confirm AI_DATABASE_URL is configured if rules creation returns 500.
  • SSE channel is org-scoped: Intake SSE events go to SSEChannels.organization(orgSlug) — all staff in the same org receive them. No per-user filtering — clinic staff UI must filter by assigned participant if needed.
  • Organization ID slug resolution: IntakeEvaluationService.resolveOrganizationId() accepts both UUID and slug. The X-Clinic-ID header contains the slug — the service translates it. Do not assume UUID in intake-specific code.
  • Qdrant vector indexing: IntakeVectorService indexes intake records for semantic search. If Qdrant is unavailable at create time, the indexing failure is logged but does NOT block intake creation (graceful degradation).
  • Guest submission: GuestSubmissionsController (guest-submissions.controller.ts) provides @RbacExempt() endpoints for unauthenticated patient-facing intake form submissions. Validate CSRF/rate-limit on this surface before exposing to the internet.
    Intake Engine — Patient Intake and Evaluation — Dudoxx Docs | Dudoxx