Amin Mousavi 10408058c4 feat(voice): keep the transcript on the server
The review sheet rendered the full dictation at the top of the modal,
unconditionally. A raw transcript can carry the patient's spoken name — the
spec said so itself in §9, while §10 said telemetry must never contain it.

The transcript no longer reaches the browser by any route:

- removed from the success response (VoiceExtractionResponse is now plain
  ResolvedExtraction, which never had the field)
- removed from the error body. VOICE_EXTRACT_FAILED carried
  details.transcript for a salvage dialog that was never built, and
  ApiError['details'] is an array, so the shape never even matched — it was
  serialized onto the wire and dropped
- removed from the sheet, and from VoiceExtractionResult. tsc proves that
  <p> was the only reader in the whole frontend

It is logged instead: one info line per recording, written immediately after
the emptiness check so a failed extraction still records it, and deliberately
outside logTelemetry so that method's patient-free guarantee stays literally
true.

Accepted consequence, recorded in §10: patient words now persist in
production server logs at default level, so whatever retention and access
control applies to those logs applies to dictation. The repo's other
sensitive-text path (openrouter.provider.ts) uses debug level with
truncation; moving this line to debug is a one-word change.

Transcript salvage is dropped rather than deferred, which settles §11 open
item 16 by taking its second option. When extraction fails the clinician
re-dictates; an operator can read the words in the log, the person who spoke
them cannot.

Spec: §7, §9 and §10 rewritten, item 16 resolved, decisions 51-53 added, and
decisions 10 and 25 marked superseded so the log stops contradicting itself.

No automated coverage for the response shape or the log line: there is no
voice.service.spec.ts — the service is I/O orchestration and has never been
unit tested. Removing the type field is what proves no reader survives.

Gates: backend 216 tests, nest build, ESLint clean on the voice module;
frontend tsc --noEmit clean, 52 Vitest tests, next build clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-10 17:39:27 +08:00

Dyolink

Monorepo: NestJS backend (backend/), Next.js frontend (frontend/), Docker stack under infrastructure/..

Local development: see backend/README.md and frontend/README.md.

Cursor AI: project conventions for agents are in AGENTS.md, .cursor/rules/, and .cursor/skills/.


Production deploy (https://nudentic.ir)

Full guide: infrastructure/DEPLOY.md

Git tag v1.0.1 → Gitea workflow .gitea/workflows/prod-tag-deploy.yml builds images (URLs baked for nudentic.ir), pushes to Gitea registry, SSH-deploys the Linux stack.

First-time SSL / Hub fallback: same DEPLOY.md.


Staging deploy (https://wixur.ir)

Full guide: infrastructure/STAGING-DEPLOY.md

Merge or push to master → Gitea Actions builds images → deploys to https://wixur.ir (Gitea: http://wixur.ir:3000).

Workflow: .gitea/workflows/registry-build-deploy.yml


Path Role
backend/Dockerfile API image
frontend/Dockerfile Web image
infrastructure/STAGING-DEPLOY.md Staging setup, CI variables, testing
infrastructure/docker-compose.registry.yml Pull-only staging stack (registry images + nginx + postgres)
infrastructure/deploy.registry.env.example Template for deploy.registry.env
Description
The whole dockerized structure of the project repo
Readme 10 MiB
Languages
TypeScript 97.4%
Shell 1.1%
CSS 0.8%
JavaScript 0.3%
Dockerfile 0.3%
Other 0.1%