KrinosAI — Software Requirements Specification (SRS)¶
Template ID:
TPL-02-04| Stage: 02-Requirements | Version: 0.3
Record:KAI-VORAL-SRS-001— retrospective draft for Visionary Oral. Not approved.
Purpose: State every verifiable software requirement with a unique ID, so design, code and tests can trace to it.
Required inputs: Approved PRD; use cases; DPIA findings; risk-control measures; interface constraints.
Document control¶
| Field | Required entry |
|---|---|
| Document ID | KAI-VORAL-SRS-001 |
| Template used | TPL-02-04 Software Requirements Specification (SRS) v0.3 |
| Product / project / software version or commit SHA | VORAL (Visionary Oral) / PRJ-001 / a6b4429e3165 (branch app_dev of AI-Dental-Project/Visionary_Oral) |
| Record status and version | Draft v0.1 |
| Author / technical reviewer / quality reviewer | Claude Code (drafted with Claude Code for KrinosAI) / Tech Lead (name to be assigned) / Security & Privacy Officer (name to be assigned) |
| Created / updated / approved dates | 2026-10-27 / 2026-10-27 / Pending |
| Applicable SOP and revision | SOP-LC-02 v0.3 |
| Related issue, commit, requirement and evidence links | KAI-VORAL-BRF-001, KAI-VORAL-IRS-001, KAI-VORAL-CHR-001, KAI-VORAL-DEC-001; docs/lifecycle/_evidence/api-inventory-a6b4429.md |
| Approver and decision record | Pending |
Applicability and evidence baseline¶
Product / system boundary: Web app and API (dentalapp/), doctor/admin mobile app (mobile/), PDF Lambda (dentalapp/pdf-lambda/) at a6b4429e3165, and the external services they call (see KAI-VORAL-IRS-001).
Related approved requirements, risks and change records: None approved. Related drafts are listed in document control.
Retrospective record? Yes — follows the Retrospective Documentation Protocol (KrinosAI lifecycle pack, 05-References/). Items are labelled Observed (code or Git at a6b4429), Measured (dated run), Stated (named person, dated) or Not recorded. Requirements are written from the behaviour observed in code (what the system does today), plus the security/privacy controls the risk screen requires; requirements not met by today's code say so and cite the OPEN item.
Acceptable evidence: an implementation reference (file:line at a commit SHA), a dated test record, a signed decision, a vendor agreement, or another independently verifiable artifact. Never invent approvals, clinical results, measurements or performance data.
1. System boundary and operating context¶
| Element | Inside / outside | Notes |
|---|---|---|
Web app and API (dentalapp/, Next.js) |
Inside | 75 API route files — docs/lifecycle/_evidence/api-inventory-a6b4429.md |
Doctor/admin mobile app (mobile/, Expo) |
Inside | On-device ONNX detectors; offline queue |
PDF Lambda (dentalapp/pdf-lambda/) |
Inside | Renders the print page to PDF; stores in S3 |
ML service (Visionary_oral_ML, Hugging Face Space) |
Outside — integration | Called with ML_BACKEND_URL |
| Clerk, MongoDB, Cloudflare R2, AWS S3/Lambda, OpenRouter, Groq, Resend, Cashfree, Expo EAS | Outside — integrations | See KAI-VORAL-IRS-001 §5 |
| Clinical diagnosis, treatment planning, radiographs | Outside — excluded | KAI-VORAL-BRF-001 §4 |
2. Atomic functional requirements with REQ IDs¶
| REQ ID | Requirement | Source | Priority | Verification |
|---|---|---|---|---|
| REQ-001 | The system shall authenticate web and mobile users through Clerk and reject API calls without a valid session or bearer token with HTTP 401. | dentalapp/src/lib/auth-helpers.js:20-27; mobile/src/lib/api/client.ts @ a6b4429 |
Must | Test |
| REQ-002 | The system shall resolve each user's role (admin, doctor, patient) from the profiles collection and route the user to the matching area. |
dentalapp/src/app/api/user/role/route.js; mobile/app/_layout.tsx @ a6b4429 |
Must | Test |
| REQ-003 | The system shall block a suspended doctor from doctor routes (HTTP 403 "Account suspended") and show the mobile "Account suspended" screen. | dentalapp/src/lib/auth-helpers.js:72-74; dentalapp/src/app/api/user/role/route.js:34-41; mobile/src/lib/api/auth.ts @ a6b4429 |
Must | Test |
| REQ-004 | The mobile app shall re-check the account status when it returns to the foreground and every 2 minutes while online. | mobile/app/_layout.tsx:162 @ a6b4429 |
Should | Test |
| REQ-005 | An admin shall be able to invite a doctor by email; the system shall create a Clerk invitation, record it and report whether the invitation email was sent. | dentalapp/src/app/api/admin/doctors/route.js:208 @ a6b4429 |
Must | Test |
| REQ-006 | An admin shall be able to resend an invitation, including an expired one. | dentalapp/src/app/api/admin/invitations/[invitationId]/resend-invitation/route.js:12 @ a6b4429 |
Should | Test |
| REQ-007 | A doctor who signs up without an invitation shall be stored with status "pending" and shall not use doctor features until an admin approves the account. | dentalapp/src/app/api/onboarding/route.js:105; dentalapp/src/app/api/admin/doctors/[clerkId]/approve/route.js:14 @ a6b4429 |
Must | Test |
| REQ-008 | An admin shall be able to suspend and unsuspend a doctor, with the reason and the acting admin recorded. | dentalapp/src/app/api/admin/doctors/[clerkId]/suspend/route.js:14; …/unsuspend/route.js:12 @ a6b4429 |
Must | Test |
| REQ-009 | An admin shall be able to set a doctor's offline access limit as days + hours + minutes (max 365 days) or remove it. | dentalapp/src/app/api/admin/doctors/[clerkId]/offline-days/route.js:66 @ a6b4429 |
Must | Test |
| REQ-010 | A doctor shall be able to create, view, edit and delete their own patients; access to another doctor's patient shall be refused. | dentalapp/src/app/api/patients/route.js:163; dentalapp/src/app/api/patients/[id]/route.js:127; verifyPatientOwnership in dentalapp/src/lib/auth-helpers.js @ a6b4429 |
Must | Test |
| REQ-011 | The mobile app shall let a doctor create and edit patients offline and send the changes when the backend is reachable. | mobile/src/lib/offline/patientOutbox.ts:245 @ a6b4429 |
Must | Test |
| REQ-012 | The scan flow shall capture exactly three guided views: front, upper jaw, lower jaw. | dentalapp/src/app/scan/page.js:23; mobile/src/features/scan/steps.ts:23,39,60 @ a6b4429 |
Must | Inspection |
| REQ-013 | Each captured photo shall pass a quality check (teeth found, coverage, centring, sharpness) and the user shall be asked to retake a photo that fails the minimums. | mobile/src/ml/qualityGate.ts:14; mobile/src/ml/qualityDecision.ts:46; web dentalapp/src/app/api/validate-scan/route.js:8 @ a6b4429 |
Must | Test |
| REQ-014 | The mobile app shall save each captured photo to app storage before any upload, so a scan survives loss of connection. | mobile/src/lib/offline/scanQueue.ts:29 @ a6b4429 |
Must | Test |
| REQ-015 | The system shall upload scan photos to object storage and attach them to one scan document per scan ID, retrying failed uploads. | dentalapp/src/app/api/upload/route.js:121; mobile/src/lib/api/upload.ts:34; mobile/src/lib/offline/syncManager.ts:188 @ a6b4429 |
Must | Test |
| REQ-016 | Each patient shall have at most one report (scan) on the website flow. | dentalapp/src/app/api/scans/route.js:99-111 @ a6b4429 |
Should | Test |
| REQ-017 | The system shall run the cavity, calculus, gum recession and swollen gums detectors on the front photo, and only cavity and calculus on upper- and lower-jaw photos. | mobile/src/ml/analysis.ts:18-24; server dentalapp/src/app/api/analyze-gemini/route.js:641-650 @ a6b4429 |
Must | Test |
| REQ-018 | The mobile app shall run the detectors on the phone (ONNX) without internet, with a 120 s limit per detector step. | mobile/src/ml/analysis.ts:123, DETECTOR_TIMEOUT_MS @ a6b4429 |
Must | Test |
| REQ-019 | The mobile app shall send on-device findings to the backend, which stores them on the matching photos of the scan owned by that doctor. | dentalapp/src/app/api/scans/analysis/route.js:37 @ a6b4429 |
Must | Test |
| REQ-020 | The report shall show the three photos with detection boxes, counts per finding, a risk level per finding and an overall hygiene score computed by the fixed rules. | dentalapp/src/lib/reportCalculations.js:9,173-175; mobile/report-renderer/entry.jsx:741 @ a6b4429 |
Must | Test |
| REQ-021 | The report shall include AI-generated personalized text based on the findings and the patient's stated concern. | dentalapp/src/app/api/personalized-analysis/route.js:216-228,561 @ a6b4429 |
Should | Inspection |
| REQ-022 | The report shown for a scan taken on the phone shall be the same every time it is opened: the phone's full copy until the server copy of the same scan has all photos with findings. | mobile/src/report/reportData.ts:182 @ a6b4429 |
Must | Test |
| REQ-023 | Users shall be able to download the report as a PDF (web via the PDF Lambda and download tokens; mobile generated on the phone). | dentalapp/src/app/api/download-report/route.js:9; dentalapp/src/lib/download-tokens.js:13; mobile/src/report/savePdf.ts:56 @ a6b4429 |
Must | Test |
| REQ-024 | Reports and patient-facing pages shall be available in English, Hindi and Marathi according to the patient's preferred language. | dentalapp/src/lib/i18n.js:35; dentalapp/src/translations/en.js, hi.js, mr.js @ a6b4429 |
Should | Inspection |
| REQ-025 | The mobile app shall keep reports available offline by saving patients' latest reports on the phone while online. | mobile/src/report/precache.ts:77 @ a6b4429 |
Should | Test |
| REQ-026 | When a doctor's offline access limit runs out while offline, the mobile app shall lock; once back online it shall report this and the backend shall suspend the account until an admin unsuspends it. | mobile/src/lib/offline/sessionGate.ts; dentalapp/src/app/api/user/offline-limit-exceeded/route.js:21 @ a6b4429 |
Must | Test |
| REQ-027 | The mobile app shall treat the device as online only when the backend answers (reachability checked against the backend). | mobile/src/lib/netReachability.ts:15 @ a6b4429 |
Should | Test |
| REQ-028 | A doctor shall be able to view and edit clinic details and generate a patient-registration QR code; the mobile screen shall open from a saved copy without waiting for the network. | dentalapp/src/app/api/clinic/generate-qr/route.js:6; mobile/app/(doctor)/clinic-info.tsx @ a6b4429 |
Should | Test |
| REQ-029 | A patient shall be able to self-register through a clinic QR code and take a scan in a time-limited public session tied to that clinic. | dentalapp/src/app/api/public/patient-registration/route.js:30; dentalapp/src/app/api/public/create-scan-session/route.js:6 @ a6b4429 |
Should | Test |
| REQ-030 | Doctors shall be able to buy plans and subscriptions through Cashfree; payment status shall be updated from signed Cashfree webhooks. | dentalapp/src/app/api/payments/create-order/route.js:8; dentalapp/src/app/api/billing/subscription/create/route.js:8; dentalapp/src/app/api/webhooks/cashfree/route.js:5 @ a6b4429 |
Should | Test |
| REQ-031 | Admins shall be able to see per-doctor usage (reports, images, AI and ML calls) and global statistics. | dentalapp/src/app/api/admin/global-stats/route.js; dentalapp/src/app/api/admin/api-usage/route.js:6 @ a6b4429 |
Should | Test |
| REQ-032 | Users shall be able to raise support tickets and exchange messages with admins. | dentalapp/src/app/api/support/route.js:20; dentalapp/src/app/api/support/messages/route.js @ a6b4429 |
Could | Test |
| REQ-033 | Doctors shall receive in-app notifications and milestone feedback prompts. | dentalapp/src/app/api/doctor/notifications/route.js:6; dentalapp/src/lib/milestone-helpers.js:70 @ a6b4429 |
Could | Inspection |
| REQ-034 | Every API route that returns personal data, admin data or triggers paid AI calls shall require an authenticated and authorized caller. | Required by the risk screen; not met by 20 routes in docs/lifecycle/_evidence/api-inventory-a6b4429.md (e.g. dentalapp/src/app/api/admin/patient-sample/route.js:5-11) — OPEN-026 |
Must | Test |
| REQ-035 | Secrets shall come only from environment variables or a vault: no credentials in the repository and no hard-coded fallback secrets. | Required by the risk screen; not met: OPEN-007, OPEN-017 (dentalapp/src/lib/admin/session.js:4) |
Must | Inspection |
| REQ-036 | Photos and report files shall be served only to the scan's owner, an admin, or a holder of a valid time-limited token. | dentalapp/src/app/api/image/route.js:19; dentalapp/src/app/api/scans/route.js:173-223 (public session) @ a6b4429 |
Must | Test |
3. Input and output specifications¶
| REQ ID | Data item | Format / range | Invalid input behavior |
|---|---|---|---|
| REQ-012 | Scan photos | JPEG from camera, cropped to the guide; front/upper/lower | Quality gate asks for a retake (REQ-013) |
| REQ-010 | Patient record | firstName, lastName, phone, email, dob, gender, message, preferredLanguage (dentalapp/src/app/api/patients/route.js:102-112) |
HTTP 400 with a field error; mobile shows the server message |
| REQ-009 | Offline limit | Whole numbers: days 0–365, hours 0–23, minutes 0–59; total ≥ 1 minute and ≤ 365 days | HTTP 400 "must be a whole number" / "at most 365 days" (…/offline-days/route.js) |
| REQ-019 | Findings payload | { scanId, views: { front, upper, lower: [{ class, confidence, box[4] }] } }, values clamped to 0–1 |
HTTP 400 if scanId or views missing (dentalapp/src/app/api/scans/analysis/route.js:42-46) |
| REQ-005 | Invitation | firstName, lastName, email (valid format), clinicName, optional phone | HTTP 400 per field; 409 if the doctor or invitation already exists |
4. Performance availability reliability constraints¶
| REQ ID | Requirement | Condition |
|---|---|---|
| REQ-018 | Each on-device detector step completes or fails within 120 s | Per photo, per model (DETECTOR_TIMEOUT_MS) |
| REQ-015 | Failed uploads are retried with growing delays up to 5 times | MAX_RETRIES in mobile/src/lib/offline/syncManager.ts @ a6b4429 |
| REQ-001 | API calls time out after 75 s (allows a cold-started host) | DEFAULT_TIMEOUT_MS in mobile/src/lib/api/client.ts @ a6b4429 |
| REQ-028 | Response-time and availability targets | Proposed (Claude Code, for confirmation): API p95 ≤ 2 s; availability 99.5 % |
5. Usability and accessibility needs¶
| REQ ID | Requirement |
|---|---|
| REQ-024 | Patient-facing text in English, Hindi and Marathi |
| REQ-012 | Each capture step shows instructions and a reference image before the camera opens (mobile/src/features/scan/steps.ts) |
| REQ-030 | Accessibility requirements: Proposed (Claude Code, for confirmation): WCAG 2.1 AA for web pages; screen-reader labels and system text scaling in the app |
6. Interfaces and security requirements¶
| REQ ID | Requirement |
|---|---|
| REQ-001 | All non-public API routes require a Clerk session or bearer token |
| REQ-034 | Every route returning personal/admin data or calling paid AI requires an authorized caller — not met today (OPEN-026) |
| REQ-035 | No secrets in the repository; no fallback secrets — not met today (OPEN-007, OPEN-017) |
| REQ-036 | Photos and PDFs only to owner, admin or valid token holder |
| REQ-030 | Cashfree webhooks accepted only with a valid signature (CASHFREE_WEBHOOK_SECRET) |
7. Error handling and negative behaviors¶
| REQ ID | Condition | Required behavior |
|---|---|---|
| REQ-003 | Account suspended | HTTP 403 "Your account has been suspended"; mobile shows "Account suspended" |
| REQ-007 | Account pending approval | Doctor routes refuse ("Account waiting for approval"); mobile shows "Waiting for approval" |
| REQ-013 | Photo fails quality minimums | Retake requested; "Use anyway" offered when the check could not run |
| REQ-015 | Upload fails | Photo stays queued on the phone and is retried; after 5 failures the user can retry manually |
| REQ-005 | Invitation email fails | Invitation still saved; response says emailSent: false with the reason |
| REQ-026 | Offline limit runs out offline | App locks; suspension is reported when back online |
8. Measurable verification criteria¶
| REQ ID | Pass criterion |
|---|---|
| REQ-001 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-002 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-003 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-004 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-005 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-006 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-007 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-008 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-009 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-010 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-011 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-012 | Verified by inspection of code and UI at the release commit — OPEN-032 |
| REQ-013 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-014 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-015 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-016 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-017 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-018 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-019 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-020 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-021 | Verified by inspection of code and UI at the release commit — OPEN-032 |
| REQ-022 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-023 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-024 | Verified by inspection of code and UI at the release commit — OPEN-032 |
| REQ-025 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-026 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-027 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-028 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-029 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-030 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-031 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-032 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-033 | Verified by inspection of code and UI at the release commit — OPEN-032 |
| REQ-034 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
| REQ-035 | Verified by inspection of code and UI at the release commit — OPEN-032 |
| REQ-036 | Verified by test case(s) to be defined in stage 07 — OPEN-032 |
9. Baselining and change control¶
| Baseline | Date | Approved by | Change process |
|---|---|---|---|
| SRS baseline v0.1 (draft, retrospective) | 2026-10-27 | Product Owner (name to be assigned) | Changes through a Requirements Change Request (KAI-VORAL-RCR-001) and the RTM |
Open issues and decisions¶
| ID | Specific gap or decision | Responsible owner | Due date | Blocks gate? | Evidence required | Status |
|---|---|---|---|---|---|---|
| OPEN-001 | Tracker project ID, named requester and sponsor, and named reviewers are not recorded | Product Owner | 2026-11-10 (proposed) | Yes | Tracker entry; names with roles | Open |
| OPEN-007 | Credential files committed to Git: dentalapp/google-credentials.json, dentalapp/mongoDb_usernamePassword (contents not opened) |
Security & Privacy Officer | 2026-10-31 (proposed) | Yes | Credentials rotated; files removed and purged from history; confirmation | Open |
| OPEN-017 | Admin session signing uses a hard-coded fallback secret when JWT_SECRET is unset (dentalapp/src/lib/admin/session.js:4) |
Backend Lead | 2026-11-10 (proposed) | Yes | Code fix; secret confirmed set | Open |
| OPEN-026 | Critical: 20 API routes have no authentication check, incl. /api/admin/patient-sample (patient emails) and /api/admin/api-usage (doctor names and emails), support tickets/messages, and paid AI routes (/api/detect-gemini, /api/speech-to-text, /api/validate-scan) — see docs/lifecycle/_evidence/api-inventory-a6b4429.md |
Backend Lead | 2026-10-31 (proposed) | Yes | Auth added to each route; re-run of the inventory shows none unprotected | Open |
| OPEN-028 | No nonfunctional targets (response time, availability, analysis time, offline period) are defined | Product Owner | 2026-11-30 (proposed) | No | Approved NFR targets | Open |
| OPEN-030 | No accessibility requirements or checks (contrast, screen readers, text size) | Product Owner | 2026-12-15 (proposed) | No | Accessibility requirements and a test record | Open |
| OPEN-032 | Design (DES) and test (TC) links for requirements are added by stages 03 and 07; requirements without them stay open | Tech Lead | 2026-12-15 (proposed) | No | RTM with DES and TC links | Open |
Review and approval¶
| Review role | Named individual | Decision | Date | Signed / controlled record |
|---|---|---|---|---|
| Author | Claude Code (drafted with Claude Code) | Draft | 2026-10-27 | This file at the commit that adds it |
| Technical reviewer | Tech Lead (name to be assigned) | Pending | Pending | Pending |
| Quality / regulatory reviewer (if applicable) | Qualified regulatory reviewer (name to be assigned) | Pending | Pending | Pending |
| Authorized approver | Product Owner (name to be assigned) | Pending | Pending | Pending |