Files
dyolink/frontend
Amin Mousavi db9d7d280a feat(backend): voice extraction endpoint
POST /voice/extract behind JwtAuthGuard + ClinicOrgGuard, plus
GET /voice/availability so the frontend can decide whether to render the
microphone — it cannot learn that from NEXT_PUBLIC_*, which are baked in at
build time.

Audio is held in memory for the request only: never written to disk, never a
Prisma row. The transcript goes back to the client and is not persisted. What
is logged is structured and patient-free — clip length, which fields resolved,
unresolved count, vendor cost, outcome — with log lines as the interim sink
until this repo has metrics infrastructure.

On extraction failure the transcript still travels back in the error details,
so the words the clinician already paid for can be salvaged into a note.

v1 ships ungated beyond a configured locale profile; the Plan.features design
is deferred, not dropped.

From review of this commit, four of which were load-bearing:

- Express's 100 kb default body limit rejected any recording past ~20 seconds,
  making the endpoint unusable at its own 2-minute cap. Body parsers are now
  registered explicitly with a 10 MB limit scoped to the voice route only.
  Verified empirically: 600 KB reaches /api/voice/extract, while /api/auth/login
  still 413s.
- ThrottlerGuard keys on req.ip, so behind nginx the whole deployment would
  share one bucket and an abuser rotating IPs would bypass it. VoiceThrottlerGuard
  keys on the user id instead — with no plan gate, this is the only control on
  metered vendor spend.
- ThrottlerException had no 429 fallback and surfaced as INTERNAL_ERROR; the
  guard now throws VOICE_RATE_LIMITED directly.
- durationMs was optional, so omitting it bypassed VOICE_MAX_RECORDING_MS
  entirely. It is required.
- VOICE_UNSUPPORTED_FORMAT was dead code — the DTO's @IsIn already rejects
  unknown containers — so it is gone rather than left unreachable.

ThrottlerModule is deliberately not bound as a global APP_GUARD: a global
ThrottlerGuard rate-limits every route against every named throttler, which
would have capped the whole API at the voice limit.

All seven remaining VOICE_* codes have errors.* keys in en, fa and nl.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 23:05:30 +03:30
..

Dyolink — Frontend (Next.js)

Prerequisites

  • Node.js 20+ and npm

First-time setup

  1. Clone the monorepo and go to the frontend app:

    git clone <repository-url> dyolink
    cd dyolink/frontend
    
  2. Install dependencies

    npm install
    
  3. Environment

    Create .env.local in this folder (not committed to git) with the public URLs your browser will use:

    NEXT_PUBLIC_APP_URL=http://localhost:3001
    NEXT_PUBLIC_API_URL=http://localhost:3000/api
    NEXT_PUBLIC_APP_NAME=Dyolink
    
    • Adjust NEXT_PUBLIC_API_URL if the Nest API runs on another host/port.
    • These values are baked in at build time for production images; for local dev, restart npm run dev after changing them.

Run (development)

npm run dev

Open http://localhost:3001 (dev server uses port 3001 so it does not clash with the API on 3000).

Ensure the backend is running and NEXT_PUBLIC_API_URL matches its base URL (including /api if your API is mounted there).

After pulling latest main

git pull
npm install

Useful commands

Command Purpose
npm run dev Development server (port 3001)
npm run build Production build
npm run start Serve production build (port 3000 — used inside Docker)
npm run lint ESLint

Docker

Image build and build-args (NEXT_PUBLIC_*) are documented in the repository root README.md.