Architecture, Security, and Implementation
IntakeIQ is an AI-powered dental intake automation platform designed to replace paper-and-clipboard patient onboarding with a secure, intelligent digital workflow. Built on Next.js 14, PostgreSQL, and AWS HIPAA-eligible infrastructure, IntakeIQ enables dental practices to collect patient demographics, medical history, insurance information, and consent signatures through a mobile-first web application — accessed via QR code — while maintaining rigorous compliance with the HIPAA Security Rule.
This document provides a comprehensive technical overview of IntakeIQ's architecture, security controls, data model, deployment infrastructure, and development practices. It is intended for chief technology officers, technical advisors, information security officers, and enterprise compliance reviewers evaluating IntakeIQ for deployment in healthcare environments.
Every layer of the IntakeIQ stack — from field-level AES-256-GCM encryption of Protected Health Information (PHI), to role-based access control, to append-only audit logging with 7-year retention — was engineered with HIPAA's Technical, Administrative, and Physical Safeguards as first-class requirements, not afterthoughts.
Dental patient intake is fundamentally broken. The majority of dental practices in the United States still rely on paper forms, clipboards, and manual data entry. This creates a cascade of operational failures:
IntakeIQ replaces the entire paper intake workflow with a digital, AI-assisted process. Patients scan a QR code, complete a guided 7-step intake form on their own device, photograph their insurance card for automatic OCR processing, and sign consent forms digitally. Staff receive completed, validated, pre-structured intake data in their dashboard — ready for review and import into their practice management system.
IntakeIQ integrates AI at two critical points. First, Anthropic's Claude API assists with intelligent intake processing — interpreting freeform patient responses, flagging potential clinical concerns, and structuring unstructured data. Second, AWS Textract performs optical character recognition (OCR) on insurance cards, extracting carrier name, member ID, group number, and coverage details without manual transcription. AI assists clinical workflows but never replaces clinical judgment — all AI-generated outputs require staff review before becoming part of the patient record.
IntakeIQ follows a monolithic-first architecture pattern using Next.js, which provides both the frontend rendering layer and the backend API layer in a single deployable unit. This design minimizes operational complexity, reduces inter-service latency, and simplifies HIPAA compliance auditing — all PHI processing occurs within a single trust boundary.
| Component | Technology | Purpose |
|---|---|---|
| Frontend | Next.js 14 + Tailwind CSS | Server-rendered React UI for patient intake and staff dashboard |
| API Layer | Next.js API Routes | RESTful endpoints for all data operations |
| ORM | Prisma | Type-safe database access with schema migrations |
| Database | PostgreSQL 16 (RDS) | Primary data store, KMS-encrypted at rest |
| Object Storage | AWS S3 | Insurance card image storage, KMS-encrypted |
| AI — Language | Claude API (Anthropic) | Intelligent intake processing and data structuring |
| AI — Vision | AWS Textract | Insurance card OCR |
| Container Runtime | ECS Fargate | Serverless container orchestration |
| Load Balancer | ALB | HTTPS termination, health checks, routing |
| Key Management | AWS KMS | PHI encryption key management |
| Logging | CloudWatch | Centralized logging with 7-year retention |
| Category | Technology | Rationale |
|---|---|---|
| Runtime | Node.js 20 (Alpine Linux) | Minimal container footprint (~120 MB). LTS support through April 2026. |
| Framework | Next.js 14+ | Full-stack React framework with server components, API routes, and built-in optimization. Single deployment artifact for frontend + backend. |
| Language | TypeScript (strict mode) | Compile-time type safety eliminates entire categories of runtime errors. Critical for PHI handling where data shape correctness matters. |
| UI | Tailwind CSS | Utility-first CSS framework. No unused CSS in production builds. Consistent design tokens across the application. |
| Database | PostgreSQL 16 | Battle-tested relational database with ACID compliance, advanced indexing, and JSON support. AWS RDS provides managed backups and encryption. |
| ORM | Prisma | Type-safe database client generated from schema. Prevents SQL injection by design. Declarative migrations. |
| Validation | Zod v4 | Runtime type validation library. Validates all API inputs before processing. TypeScript-native schema definitions. |
| Authentication | jose (JWT) | Standards-compliant JWT library for session management. HS256 signing with server-side secret. |
| Encryption | Node.js native crypto | AES-256-GCM for PHI field-level encryption. Zero external dependencies for the most critical security code. |
| AI — Language | Claude API (Anthropic) | State-of-the-art language model for medical intake data processing and structuring. |
| AI — OCR | AWS Textract | Purpose-built document OCR service. HIPAA-eligible. Native AWS integration for insurance card processing. |
| Integrations | Open Dental API, Vyne Dental, Stripe, Twilio | Practice management sync, insurance verification, payment processing, and SMS notifications. |
| Infrastructure | AWS (HIPAA-eligible) | CloudFormation IaC. VPC isolation, ECS Fargate, RDS, S3, KMS, CloudWatch. BAA-eligible services only. |
| Containerization | Docker (multi-stage) | Reproducible builds. Non-root user. Standalone Next.js output for minimal image size. |
IntakeIQ uses a multi-tenant relational data model where every record is scoped to a Practice. The schema is defined in Prisma and supports both SQLite (development) and PostgreSQL (production). All PHI fields are encrypted at the application layer before database storage.
The top-level tenant entity. Every user, patient, form, and intake session belongs to exactly one practice. Stores practice metadata (name, phone, email, address), timezone, subscription plan, and configurable settings as JSON.
Staff members who access the IntakeIQ dashboard. Each user belongs to one practice and has a role (OWNER, ADMIN, DENTIST, HYGIENIST, or FRONT_DESK) that determines their access permissions via RBAC. Passwords are stored as bcrypt hashes. The isActive flag allows soft-disabling accounts without deletion.
The core PHI entity. Fields including firstName, lastName, email, phone, dateOfBirth, and ssn are encrypted with AES-256-GCM before storage. Address and emergency contact information are stored as encrypted JSON. Each patient belongs to one practice.
PHI_ENCRYPTION_KEY managed via AWS KMS / SSM Parameter Store.
Customizable intake form templates. Each form has a name, description, version number, and a JSON array of field definitions. Forms are versioned so that completed sessions retain a reference to the exact form version the patient filled out.
The central workflow entity. Represents a single patient intake event, tracking the patient, form, current step, all responses (as JSON), flags for clinical review, and the complete lifecycle from PENDING through IN_PROGRESS, COMPLETED, and REVIEWED. Sessions can expire and are linked to the reviewing staff member.
Stores insurance card processing results. Linked 1:1 to an intake session. Contains carrier name, member ID, group number, subscriber name (all encrypted PHI), coverage type, copay, deductible, and annual maximum. Tracks verification status: PENDING, VERIFIED, FAILED, or MANUAL_REVIEW. Insurance card image URLs reference S3 objects.
An append-only table for HIPAA compliance. Every access to PHI — views, creates, updates, deletes, exports, and prints — is recorded with the acting user, their role, the resource accessed, the action taken, IP address, user agent, timestamp, and success/failure status. Audit logs must be retained for a minimum of 7 years per HIPAA requirements.
| Model | Records PHI | Encrypted Fields | Indexed On |
|---|---|---|---|
| Practice | No | — | id (PK) |
| User | No | — | id (PK), practiceId, email (unique) |
| Patient | Yes | firstName, lastName, email, phone, dateOfBirth, ssn, address, emergencyContact | id (PK), practiceId |
| Form | No | — | id (PK), practiceId |
| IntakeSession | Yes (responses) | Responses contain encrypted patient data | id (PK), practiceId, patientId, status |
| InsuranceVerification | Yes | memberId, groupNumber, subscriberName | id (PK), sessionId (unique), patientId |
| AuditLog | Never | — | id (PK), practiceId, userId, action, timestamp |
IntakeIQ's security architecture is designed to satisfy HIPAA's Technical Safeguards across all four categories: Access Controls, Audit Controls, Integrity Controls, and Transmission Security. Security is not a bolt-on feature; it is woven into every layer of the stack.
IntakeIQ implements field-level encryption for all PHI using AES-256-GCM (Galois/Counter Mode). Unlike whole-disk or whole-database encryption, field-level encryption ensures that individual PHI values are encrypted before they leave the application layer. Even a compromised database dump reveals only ciphertext.
import { randomBytes, createCipheriv, createDecipheriv } from "crypto"; const ALGORITHM = "aes-256-gcm"; const IV_LENGTH = 12; // GCM recommended IV length const AUTH_TAG_LENGTH = 16; export function encryptPHI(plaintext: string): string { const key = getEncryptionKey(); const iv = randomBytes(IV_LENGTH); const cipher = createCipheriv(ALGORITHM, key, iv, { authTagLength: AUTH_TAG_LENGTH, }); const encrypted = Buffer.concat([ cipher.update(plaintext, "utf8"), cipher.final(), ]); const authTag = cipher.getAuthTag(); // Pack: IV (12) + AuthTag (16) + Ciphertext const packed = Buffer.concat([iv, authTag, encrypted]); return packed.toString("base64"); }
| Property | Value |
|---|---|
| Algorithm | AES-256-GCM (authenticated encryption) |
| Key Size | 256 bits (32 bytes), base64-encoded |
| IV Size | 96 bits (12 bytes), randomly generated per encryption |
| Authentication Tag | 128 bits (16 bytes) — provides integrity verification |
| Output Format | Base64-encoded: IV || AuthTag || Ciphertext |
| Key Source | PHI_ENCRYPTION_KEY environment variable, managed via AWS SSM / KMS |
| Dependencies | Node.js native crypto module only (zero external deps) |
| Entity | Encrypted Fields |
|---|---|
| Patient | firstName, lastName, email, phone, dateOfBirth, ssn |
| InsuranceVerification | memberId, groupNumber, subscriberName |
Additionally, the RDS PostgreSQL instance uses AWS KMS-managed storage encryption, and the S3 bucket for insurance card images uses SSE-KMS with a dedicated PHI encryption key. This provides defense-in-depth: application-layer encryption plus infrastructure-layer encryption.
All data in transit is protected by TLS 1.3. The Application Load Balancer enforces the ELBSecurityPolicy-TLS13-1-2-2021-06 SSL policy, which requires TLS 1.2 minimum and prefers TLS 1.3. HTTP requests on port 80 receive a 301 redirect to HTTPS. HSTS headers with a 1-year max-age, includeSubDomains, and preload are set on every response.
IntakeIQ uses stateless JWT-based sessions with server-side verification. Sessions are created on login, stored in HTTP-only cookies, and verified on every authenticated request.
const SESSION_MAX_AGE = 60 * 15; // 15 minutes (HIPAA automatic logoff) const token = await new SignJWT({ sub: user.id, email: user.email, role: user.role, practiceId: user.practiceId, }) .setProtectedHeader({ alg: "HS256" }) .setIssuedAt() .setExpirationTime(`${SESSION_MAX_AGE}s`) .sign(getSecret());
| Property | Configuration |
|---|---|
| Algorithm | HS256 (HMAC-SHA256) |
| Session Duration | 15 minutes (HIPAA automatic logoff requirement) |
| Sliding Window | Yes — cookie refreshed on every authenticated request |
| Cookie Flags | httpOnly, secure (production), sameSite: lax |
| Secret Management | NEXTAUTH_SECRET via AWS SSM Parameter Store |
| Token Payload | User ID, email, name, role, practice ID (no PHI) |
NEXTAUTH_SECRET environment variable is required. The application refuses to start with a fallback secret. In development, a warning is logged when using the insecure fallback.
IntakeIQ implements a hierarchical RBAC system with five roles. Each role inherits the permissions of all roles below it in the hierarchy.
| Role | Level | Capabilities |
|---|---|---|
OWNER | 100 | Full system access. Practice settings, billing, user management, all clinical data. |
ADMIN | 80 | User management, practice settings, all clinical and intake data. |
DENTIST | 60 | Review intake sessions, view/update patients, access clinical data. |
HYGIENIST | 40 | View intake sessions, view patient records. |
FRONT_DESK | 20 | Create intake sessions, manage appointments, view patient list. |
const ROLE_HIERARCHY: Record<string, number> = { OWNER: 100, ADMIN: 80, DENTIST: 60, HYGIENIST: 40, FRONT_DESK: 20, }; export function hasRole(userRole: string, requiredRole: string): boolean { return (ROLE_HIERARCHY[userRole] ?? 0) >= (ROLE_HIERARCHY[requiredRole] ?? 0); }
Every API endpoint validates incoming data against Zod schemas before any processing occurs. This prevents injection attacks, malformed data from reaching the database, and provides clear error messages to API consumers.
export const createPatientSchema = z.object({ firstName: z.string().min(1).max(100), lastName: z.string().min(1).max(100), email: z.email().optional(), phone: z.string().max(20).optional(), dateOfBirth: z.string().optional(), gender: z.string().max(20).optional(), address: z.record(z.string(), z.any()).optional(), emergencyContact: z.record(z.string(), z.any()).optional(), }); export const loginSchema = z.object({ email: z.email(), password: z.string().min(1), });
IntakeIQ enforces per-endpoint rate limits to prevent brute force attacks and API abuse. The rate limiter runs in-process with an in-memory store (upgrading to Redis for multi-instance deployments).
| Endpoint Category | Limit | Window |
|---|---|---|
Login (/api/auth/login) | 5 requests | 60 seconds |
| General API | 60 requests | 60 seconds |
| File Upload (insurance cards) | 10 requests | 60 seconds |
Rate-limited responses return HTTP 429 with Retry-After and X-RateLimit-Reset headers, conforming to RFC 6585.
IntakeIQ maintains an append-only audit log of every PHI access event. The audit system captures who (user ID, role), what (resource type, resource ID, action), when (ISO 8601 timestamp), where (IP address, user agent), and outcome (success/failure). Audit logs are persisted to both the database and structured JSON output for CloudWatch ingestion.
| Category | Actions |
|---|---|
| PHI Access | view_patient, create_patient, update_patient, delete_patient, view_patient_list |
| Intake Sessions | start_intake, submit_intake, review_intake, view_session, create_session |
| Insurance | upload_insurance_card, view_insurance, verify_insurance |
| Authentication | login_success, login_failed, logout, password_change |
| Data Operations | export_data, print_record, download_record |
| Administration | user_created, role_changed, settings_changed |
| System | encryption_key_rotated, backup_created, breach_detected |
The Next.js middleware enforces security headers on every response and manages session lifecycle for authenticated routes.
| Header | Value | Purpose |
|---|---|---|
Strict-Transport-Security | max-age=31536000; includeSubDomains; preload | Force HTTPS for 1 year |
X-Content-Type-Options | nosniff | Prevent MIME type sniffing |
X-Frame-Options | DENY | Prevent clickjacking |
X-XSS-Protection | 1; mode=block | XSS protection (legacy browsers) |
Referrer-Policy | strict-origin-when-cross-origin | Prevent PHI leakage via referrer |
Permissions-Policy | camera=(self), microphone=(), geolocation=(), payment=() | Restrict browser feature access |
Content-Security-Policy | Strict CSP with self default | Prevent XSS and data exfiltration |
Cache-Control | no-store, no-cache, must-revalidate (on PHI routes) | Prevent browser caching of PHI |
For authenticated /app/* routes, the middleware implements a sliding window session: on every request, the session cookie is re-issued with a fresh 15-minute maxAge. If 15 minutes pass without activity, the cookie expires and the user is redirected to the login page — satisfying HIPAA's automatic logoff requirement.
The patient intake process is designed for zero-friction, mobile-first completion. The entire flow is accessible without app installation or account creation.
Patient scans a practice-specific QR code (displayed in the waiting room, sent via SMS, or included in appointment reminders). The QR code encodes a URL that creates a new intake session and redirects the patient to the intake form.
The server creates an IntakeSession record with status PENDING and returns a unique session URL. No authentication is required — the session ID serves as a capability token. Sessions expire after a configurable timeout.
Patient enters name, date of birth, contact information, gender, and address. All fields are validated client-side (Zod) and server-side before storage. PHI fields are encrypted before database writes.
Guided questionnaire covering medications, allergies, medical conditions, previous procedures, and relevant medical history. Responses are structured and stored as JSON within the session.
Patient photographs the front and back of their insurance card using their device camera. Images are uploaded to the KMS-encrypted S3 bucket. AWS Textract performs OCR to extract carrier, member ID, group number, and subscriber name automatically.
Patient reviews and signs consent forms (HIPAA notice of privacy practices, treatment consent, financial responsibility) using a digital signature pad. Signature timestamps and consent records are captured.
Patient reviews all entered information, makes any corrections, and submits. The session status changes to COMPLETED. An audit log entry records the submission. The intake appears in the staff dashboard for review.
A staff member (DENTIST, ADMIN, or FRONT_DESK) reviews the completed intake in the dashboard, verifies insurance information, resolves any flags, and marks the session as REVIEWED. The reviewing user and timestamp are recorded.
IntakeIQ integrates Anthropic's Claude API to add intelligence to the intake process. Claude is used for:
When a patient uploads an insurance card image, IntakeIQ sends it to AWS Textract for optical character recognition. The OCR pipeline:
/api/insurance/ocr endpoint (rate-limited to 10 requests/minute).InsuranceVerification record with encrypted PHI fields.Textract is a HIPAA-eligible AWS service, and all data is transmitted via TLS. Insurance card images are retained in S3 with lifecycle rules that transition them to Infrequent Access storage after 90 days for cost optimization.
IntakeIQ's production infrastructure runs entirely on HIPAA-eligible AWS services, provisioned via a single CloudFormation template for reproducible, auditable deployments.
| Service | Configuration | HIPAA Controls | Monthly Cost |
|---|---|---|---|
| VPC | 10.0.0.0/16, 2 public + 2 private subnets, no NAT Gateway | Network isolation. Private subnets for database. | Free |
| ALB | Internet-facing, HTTPS only, TLS 1.3 policy | SSL termination. HTTP-to-HTTPS redirect. Invalid header drop. | ~$16 |
| ECS Fargate | 0.25 vCPU, 512 MB, rolling deploy | No SSH access. Immutable infrastructure. Non-root container. | ~$9 |
| RDS PostgreSQL | 16.4, db.t4g.micro, 20-100 GB gp3, 35-day backups | KMS encryption. Private subnet. Deletion protection. Performance Insights. | Free (yr 1), ~$13 after |
| S3 | Versioned, KMS-SSE, no public access, lifecycle to IA at 90 days | TLS-only policy. Block all public access. KMS encryption. | ~$0.02/GB |
| KMS | Dedicated PHI encryption key | HSM-backed key management. IAM-controlled access. | ~$1 |
| CloudWatch | 7-year retention (2,557 days), KMS-encrypted | Immutable log storage. HIPAA audit trail. Encrypted with KMS. | ~$2-3 |
| ACM | DNS-validated TLS certificate | Free managed TLS certificate renewal. | Free |
| SSM Parameter Store | Database URL, auth secret, encryption key | Secrets never in code or environment files. | Free |
Security groups implement a strict least-privilege network policy:
0.0.0.0/0 (internet-facing).All secrets are stored in AWS Systems Manager Parameter Store and injected into ECS task definitions at runtime. Secrets never appear in source code, Docker images, or CloudFormation templates (the template stores placeholder values that must be updated post-deploy via the AWS Console).
| Parameter | Purpose |
|---|---|
/intakeiq/DATABASE_URL | PostgreSQL connection string |
/intakeiq/NEXTAUTH_SECRET | JWT signing secret |
/intakeiq/PHI_ENCRYPTION_KEY | AES-256 encryption key for PHI |
The following matrix maps HIPAA Security Rule requirements to their implementations within IntakeIQ.
| HIPAA Requirement | Section | IntakeIQ Implementation | Status |
|---|---|---|---|
| Access Control (164.312(a)(1)) | Technical | Hierarchical RBAC with 5 roles. JWT session tokens. requireAuth() and requireRole() guards on every protected endpoint. |
Implemented |
| Unique User Identification (164.312(a)(2)(i)) | Technical | UUID-based user IDs. Unique email constraint. User ID embedded in JWT and logged in every audit entry. | Implemented |
| Emergency Access Procedure (164.312(a)(2)(ii)) | Technical | OWNER role has full system access. AWS RDS backups with 35-day retention. Database deletion protection enabled. | Implemented |
| Automatic Logoff (164.312(a)(2)(iii)) | Technical | 15-minute sliding window session timeout. Cookie expires on inactivity. Middleware redirects to login on expiration. | Implemented |
| Encryption & Decryption (164.312(a)(2)(iv)) | Technical | AES-256-GCM field-level encryption for all PHI. KMS-encrypted database storage. KMS-encrypted S3 objects. | Implemented |
| Audit Controls (164.312(b)) | Technical | Append-only audit log table. 30+ tracked action types. IP address, user agent, user ID, role, resource, timestamp, and success/failure recorded. 7-year retention in CloudWatch. | Implemented |
| Integrity Controls (164.312(c)(1)) | Technical | AES-256-GCM authentication tag provides tamper detection. Zod schema validation on all inputs. Prisma ORM prevents SQL injection. S3 versioning for insurance card images. | Implemented |
| Authentication (164.312(d)) | Technical | Bcrypt password hashing. JWT session verification on every request. Rate-limited login (5 attempts/minute). | Implemented |
| Transmission Security (164.312(e)(1)) | Technical | TLS 1.3 enforced via ALB policy. HSTS with 1-year max-age. HTTP redirected to HTTPS. S3 bucket policy denies non-TLS access. | Implemented |
| Security Management (164.308(a)(1)) | Administrative | Infrastructure as Code (CloudFormation). HIPAA tags on all resources. Least-privilege IAM policies. Security headers on all responses. | Implemented |
| Workforce Security (164.308(a)(3)) | Administrative | Role-based access. User activation/deactivation. role_changed and user_deactivated audit events. |
Implemented |
| Information Access Management (164.308(a)(4)) | Administrative | Practice-scoped data isolation (multi-tenancy). Role hierarchy restricts data access per job function. | Implemented |
| Contingency Plan (164.308(a)(7)) | Administrative | RDS automated backups (35-day retention). S3 versioning. Deletion protection on database. CloudFormation enables infrastructure recreation. | Implemented |
| BAA Requirements (164.308(b)(1)) | Administrative | AWS BAA covers all HIPAA-eligible services used. BAAs required with Anthropic (Claude API) and all subprocessors. | In Progress |
| Facility Access Controls (164.310(a)(1)) | Physical | AWS manages physical security of data centers (covered under AWS BAA). No on-premises servers. | AWS Managed |
| Workstation Security (164.310(b)) | Physical | 15-minute auto-logoff. No PHI caching (no-store headers). X-Frame-Options: DENY prevents embedding. |
Implemented |
IntakeIQ exposes a RESTful API through Next.js API Routes. All endpoints return JSON and follow consistent patterns for authentication, validation, error handling, and audit logging.
| Method | Endpoint | Auth Required | Description |
|---|---|---|---|
POST | /api/auth/login | No | Authenticate user, return session cookie |
POST | /api/auth/logout | Yes | Clear session cookie |
GET | /api/auth/me | Yes | Return current session user |
GET | /api/patients | Yes | List patients (practice-scoped) |
POST | /api/patients | Yes | Create patient with encrypted PHI |
GET | /api/patients/[id] | Yes | Get patient by ID (decrypted) |
PUT | /api/patients/[id] | Yes | Update patient record |
GET | /api/intake-sessions | Yes | List intake sessions (practice-scoped) |
POST | /api/intake-sessions | Yes | Create new intake session |
GET | /api/intake-sessions/[id] | Varies | Get session by ID |
PUT | /api/intake-sessions/[id] | Varies | Update session (status, responses, step) |
GET | /api/forms | Yes | List form templates |
POST | /api/forms | Yes | Create form template |
GET | /api/dashboard | Yes | Dashboard metrics and summaries |
POST | /api/insurance/ocr | No* | Upload insurance card for OCR processing |
GET | /api/roi | No | ROI calculator data |
* Insurance OCR is called from the patient intake flow (no staff auth), but is rate-limited and scoped to active sessions.
// 1. Login request POST /api/auth/login { "email": "user@practice.com", "password": "..." } // 2. Server validates credentials, creates JWT, sets cookie Set-Cookie: intakeiq-session=<jwt>; HttpOnly; Secure; SameSite=Lax; Max-Age=900 // 3. Subsequent requests include cookie automatically GET /api/patients Cookie: intakeiq-session=<jwt> // 4. Middleware verifies JWT and refreshes cookie (sliding window) // 5. After 15 min inactivity, cookie expires → redirect to /login
All API errors follow a consistent JSON structure:
{
"error": "Human-readable error message",
"code": "VALIDATION_ERROR", // Machine-readable error code
"details": [...] // Optional: Zod validation errors
}
| HTTP Status | Meaning | When Used |
|---|---|---|
| 200 | Success | Successful read or update |
| 201 | Created | Successful resource creation |
| 400 | Bad Request | Zod validation failure, malformed input |
| 401 | Unauthorized | Missing or invalid session |
| 403 | Forbidden | Insufficient role permissions |
| 404 | Not Found | Resource does not exist or is outside practice scope |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Unexpected server error (details not exposed) |
| Metric | Current Configuration | Estimated Capacity |
|---|---|---|
| Concurrent Users | 1 Fargate task (0.25 vCPU, 512 MB) | 50-100 simultaneous sessions |
| Database | db.t4g.micro (2 vCPU, 1 GB, burstable) | ~100 concurrent connections |
| Storage | 20 GB (auto-scaling to 100 GB) | ~500,000 patient records |
| API Rate | 60 requests/min per client | Adequate for single-practice workflows |
DesiredCount can be increased from 1 to N. The ALB distributes traffic across tasks. Session state is in JWTs (stateless), so any task can serve any request.db.t4g.micro to db.t4g.small or db.t4g.medium with zero-downtime Multi-AZ failover.practiceId, patientId, status, and timestamp columns are already in place. Read replicas can be added when query load justifies it.| Decision | Savings | Trade-off |
|---|---|---|
| No NAT Gateway | $32/month | Fargate in public subnets (mitigated by security groups) |
| Single-AZ RDS | ~$13/month | No automatic failover (35-day backup retention provides recovery) |
| Container Insights disabled | ~$3/month | Less granular container metrics (CloudWatch logs still captured) |
| Minimal Fargate (0.25 vCPU) | ~$6/month | Lower burst capacity (scales horizontally when needed) |
IntakeIQ is written in TypeScript with strict mode enabled. This provides compile-time guarantees around null safety, type correctness, and exhaustive pattern matching — critical when handling PHI where a mistyped field name could lead to data leakage or corruption.
All database access goes through the Prisma client, which uses parameterized queries exclusively. There are zero raw SQL queries in the codebase. The Prisma schema is the single source of truth for the data model, and the generated client provides type-safe access that is validated at compile time.
IntakeIQ implements a defense-in-depth validation strategy:
The application uses error boundaries at multiple levels to prevent a single error from cascading:
PHI encryption uses only the Node.js native crypto module — zero external dependencies for the most security-critical code path. The JWT library (jose) is a widely-audited, standards-compliant implementation. Dependencies are kept minimal to reduce the attack surface.
IntakeIQ uses a multi-stage Docker build that produces a minimal production image:
# Stage 1: Install production dependencies only FROM node:20-alpine AS deps COPY package.json package-lock.json* ./ RUN npm ci --omit=dev # Stage 2: Build the Next.js application FROM node:20-alpine AS builder COPY --from=deps /app/node_modules ./node_modules COPY . . RUN npx prisma generate RUN npm run build # Stage 3: Production runtime (minimal) FROM node:20-alpine AS runner RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs USER nextjs # Non-root execution CMD ["node", "server.js"]
| Security Property | Implementation |
|---|---|
| Minimal base image | Alpine Linux (~5 MB base) |
| Non-root execution | Dedicated nextjs user (UID 1001) |
| No dev dependencies | npm ci --omit=dev in deps stage |
| Standalone output | Next.js standalone mode — no node_modules in production image |
| No secrets in image | All secrets injected at runtime via SSM |
| Telemetry disabled | NEXT_TELEMETRY_DISABLED=1 |
Multi-stage build produces a minimal production image with the standalone Next.js server.
The Docker image is tagged and pushed to Amazon Elastic Container Registry (ECR).
The CloudFormation template is applied (or updated) with the new container image URI.
ECS performs a rolling deployment: MinimumHealthyPercent: 100, MaximumPercent: 200. A new task starts and passes health checks before the old task is drained.
The ALB shifts traffic to the new task only after it passes health checks (2 consecutive checks at 30-second intervals). The old task drains connections gracefully.
| Feature | Priority | Description |
|---|---|---|
| Multi-Factor Authentication (MFA) | High | TOTP-based MFA for all staff accounts. HIPAA addressable specification that will become a de facto requirement for healthcare SaaS. |
| Real-Time Notifications | High | WebSocket or Server-Sent Events for live dashboard updates when patients complete intake. Twilio SMS notifications for staff alerts. |
| Open Dental Integration | High | Bi-directional sync with Open Dental practice management system. Automatic patient record creation and intake data import. |
| Redis-Backed Rate Limiting | Medium | Replace in-memory rate limiter with Redis for consistent enforcement across multiple Fargate tasks. |
| Multi-Tenancy Hardening | Medium | Row-Level Security (RLS) policies at the PostgreSQL level for defense-in-depth tenant isolation. |
| Vyne Dental Integration | Medium | Real-time insurance eligibility verification through Vyne Dental's API. |
| Stripe Billing | Medium | Subscription management, usage-based billing, and payment processing for practice accounts. |
| SOC 2 Type II Certification | Medium | Formal third-party audit of security controls. Target completion within 12 months of launch. |
| Encryption Key Rotation | Medium | Automated PHI encryption key rotation with re-encryption of existing records. |
| Conversational AI Intake | Low | Claude-powered natural language intake experience as an alternative to traditional form fields. |
| Multi-Language Support | Low | Spanish, Mandarin, and Vietnamese intake form translations for diverse patient populations. |
IntakeIQ represents a purpose-built, HIPAA-compliant approach to dental patient intake automation. Every architectural decision — from the choice of AES-256-GCM for field-level PHI encryption to the 15-minute sliding window session timeout to the append-only audit log with 7-year retention — was made with healthcare regulatory requirements as a primary design constraint, not an afterthought.
The platform's technology choices (Next.js, TypeScript strict mode, Prisma ORM, Zod validation, AWS HIPAA-eligible infrastructure) reflect a deliberate balance between developer velocity and security rigor. The monolithic-first architecture keeps the compliance surface area small while supporting clear scaling paths through horizontal ECS scaling and managed AWS services.
IntakeIQ's AI integrations — Claude for intelligent intake processing and Textract for insurance card OCR — demonstrate how AI can meaningfully reduce administrative burden in dental practices without compromising patient safety or data security. The platform's governance model ensures that AI always assists rather than replaces clinical and administrative judgment.
For technical questions, security reviews, or to request a detailed architecture walkthrough, please contact the IntakeIQ engineering team.