Voice extraction resolves spoken Jalali dates into ISO dates server-side, so
the backend needs the conversion the frontend already had. The resolvers live
here rather than in the frontend precisely because this half of the repo has a
test runner.
Ported from frontend/src/lib/i18n/persianCalendar.ts and verified faithful by
differential test: every day from 1900-2100 (73,414 days), zero mismatches on
conversion, leap years and month lengths.
Two deliberate divergences from the original:
- jalaliToIsoDate() returns null instead of throwing. It is fed model-supplied
values, which may be nonsense, and an invalid date must degrade to
"unresolved" rather than a 500. The year guard runs before jalaliDaysInMonth
so the throwing jalCal is unreachable from it.
- toLatinDigits() also handles the Arabic-Indic block (U+0660-U+0669), not just
Persian (U+06F0-U+06F9). ASR output can carry either, sometimes mixed with
ASCII in one transcript; the frontend version only parses keystrokes.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Design spec for filling a TreatmentDetail by voice, settled across three
grilling sessions (30 decisions, logged in the spec).
Key shape:
- two-stage pipeline: OpenRouter whisper-1 -> gemini-3.7-flash
- the LLM emits *intents*, never FDI codes or ISO dates; pure Jest-tested
backend resolvers own quadrant mapping and Jalali conversion
- provider registry keyed by locale so fa can diverge from en/nl
- review sheet confirms before anything touches the form
- audio and transcripts are never persisted
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Publish port 8088 on 127.0.0.1 only so netsh portproxy can expose staging
to LAN/public IPs; document the one-time portproxy setup on Windows.
Co-authored-by: Cursor <cursoragent@cursor.com>
Accept 2xx/3xx on / so next-intl redirect to /en no longer marks the
container unhealthy and blocks nginx from starting.
Co-authored-by: Cursor <cursoragent@cursor.com>
Strip CRLF from entrypoint scripts in backend/frontend images, use Docker
DNS in staging nginx config, and wait for healthy app services before nginx.
Co-authored-by: Cursor <cursoragent@cursor.com>
Logical API errors throw stable codes so users see translated messages instead of a generic bad request.
Co-authored-by: Cursor <cursoragent@cursor.com>