d3ro-voice/docs/map/07-api-server.md
Yun Chan e87ce63440 docs: record Wave 3 surface consolidation and fold NAS-only whisper into compose
- docs/REFACTOR_WAVE3_REPORT.md and the Wave 3 policy: canonical map,
  production changes, verification and remaining external steps.
- Gap backlog: GAP-BILL-01 resolved; new GAP-BILL-02 (Payple renewal never ran,
  Payple client key never set), GAP-WEB-01 (tunnel host for /app), GAP-OPS-01
  (NAS compose/.env drift), GAP-CI-01, GAP-I18N-02, GAP-TEAM-02.
- design.md: hero loop decision (numbers taken from the app capsule), pricing
  mismatch closed; feature catalog SHELL-11 updated.
- docs/map, release guide and mobile release docs no longer describe the
  deleted wwwroot, binaries, Dockerfile.admin, NAS site copy or .github CI.
- docker-compose.nas.yml gains the d3ro-whisper service that only existed in
  the NAS copy, so the repository file is the complete definition.
- refactor-wave skill: Wave 3 index and lessons P10-P12.
2026-09-26 16:02:44 +09:00

6.5 KiB

07 — API Server (.NET) Map

Surface: apps/api-server (D3ROVoice.Api), tests in apps/api-server.Tests Stack: ASP.NET Core 10 + EF Core + SQLite Role: AI proxy (LLM/STT) + admin back-office backend for the .NET identity side


1. Composition root (Program.cs)

  • DI: AddControllers, AddHttpClient (proxies), Swagger (v1), rate limiter policy auth (fixed window 10/min per IP, 429), AddDbContext<AppDbContext> (SQLite; DATA_DIR/DB_PATH), scoped IAuthService, ILlmProxyService, ISttProxyService, IAdminOperationService.
  • Auth: JWT Bearer HS256; startup hard-fails unless JWT_SECRET (≥32 bytes), JWT_ISSUER, JWT_AUDIENCE are set. Zero clock skew.
  • Policies: ManagerOrAbove (manager/admin/superadmin), AdminOrAbove (admin/superadmin), SuperAdminOnly (superadmin). Role normalization strips _/-, lowercases.
  • CORS/Hosts: strict origin validation (CORS_ALLOWED_ORIGINS), ALLOWED_HOSTS required outside Development.
  • Startup DB init: EnsureCreated(), raw CREATE TABLE IF NOT EXISTS for admin operation/audit tables, legacy SHA-256 password lockdown (IsActive=false, Role="LegacyDisabled"), idempotent env admin provisioning (ADMIN_EMAIL/ADMIN_PASSWORD, only when no active user), default LLM/STT endpoints seeded.
  • Middleware order: Swagger (dev) → CORS → rate limiter → authentication → authorization. The API no longer serves static files: wwwroot (stale site build, download/invite pages, .well-known copy, legacy embedded admin SPA, 1.0.0 binaries) was deleted 2026-09-26 (Wave 3, cd9d199), and UseStaticFiles/the mobile-asset-block fallbacks were removed from Program.cs along with it. The Next.js admin (apps/admin) is the only admin UI.
  • Health: GET /health, GET /api/health → {status, service, version, uptimeSeconds, database, timestamp}.

2. Controllers & routes

AuthController (/api/auth)

Route Auth Behavior
POST /register anonymous + X-D3RO-Bootstrap-Token Rate-limited, ≤16KB; requires ADMIN_BOOTSTRAP_TOKEN; fixed-time compare; 409 if registered
POST /login anonymous Rate-limited; returns JWT; 401 invalid
GET /me [Authorize] UserInfoDto or 404

LlmController (/api/llm, class [Authorize])

Route Behavior
POST /generate Requires prompt; GenerateAsync
POST /chat ChatAsync (last message = prompt)

SttController (/api/stt, class [Authorize])

Route Auth Behavior
POST /transcribe any auth Always 410 Gone stt_edge_gateway_required — user transcription is Edge-only
POST /internal/transcribe anonymous + X-D3RO-STT-Gateway-Token multipart, ≤26MB; requires D3RO_API_TOKEN; fixed-time compare; provider orchestration; error map 503/400/502
GET /providers ManagerOrAbove List STT endpoints
POST /test?endpointId= ManagerOrAbove Test endpoint

AdminController (/api/admin, class ManagerOrAbove)

All mutations flow through ExecuteAdminMutationAsync (idempotent + audited).

Route Effective policy
GET /stats Manager+
GET /users Manager+
GET/POST/PUT/DELETE /endpoints[/{id}] Manager+ read; Admin+ write
GET /stt-endpoints, /stt-endpoints/{id} Manager+
POST/PUT/DELETE /stt-endpoints[/{id}], POST .../set-default Admin+
POST /stt-endpoints/{id}/test Manager+
POST /stt-endpoints/test-direct Admin+
GET /stt-usage, GET /usage Manager+
POST /license-audit SuperAdminOnly

3. Services

Service Purpose
AuthService Register (one-time SuperAdmin bootstrap only, PasswordHasher<User>, serialized), login (timing-safe dummy verify, inactive rejection, rehash), JWT gen (8h, claims id/email/role)
LlmProxyService Resolve endpoint by model → fallback → Mock echo; OpenAI-style POST; parse content+usage; token cost → ApiUsageLog; errors → ServerErrorLog + fallback text
SttProxyService (~1182 lines) Provider adapters (groq/openai/custom, deepgram, google, assemblyai, azure, local-sidecar), candidate resolution + fallback, content-type/duration detection, SttUsageLog cost, synthetic-tone endpoint test, CRUD with exclusive default, usage report
AdminOperationService Validates actor/idempotency key/memo, SHA-256 request hash, Serializable transaction, idempotent replay, before/after audit entry

4. Data (Data/AppDbContext.cs)

DbSet / table Key fields
Users Id, unique Email, PasswordHash, Role (default "User"), IsActive, CreatedAt, LastLoginAt
ModelEndpoints Id, unique ModelId, ModelName, Provider, EndpointUrl, ApiKey, per-1k costs, IsActive
UsageLogs UserId/Email, model, tokens, cost, duration, status
ErrorLogs ErrorType, Message, StackTrace, Endpoint
SttProviderEndpoints Name, ProviderType, URL, ApiKey, ModelId, Method, Language, Prompt, Temperature, per-minute/second cost, IsDefault, FallbackPriority, ExtraHeadersJson
SttUsageLogs User, endpoint, provider, duration, cost, latency, status, transcript preview
AdminOperationRequests ActorEmail + IdempotencyKey (unique), Operation, RequestHash, ResponseJson
AdminAuditEntries ActorEmail, Action, TargetType/Id, BeforeJson, AfterJson, Memo, IdempotencyKey

DTOs (Dtos/Dtos.cs): auth, license audit, LLM, admin/model endpoints, STT (transcribe, endpoints, test, usage reports).


5. Tests (apps/api-server.Tests/, xUnit)

AdminAuthorizationE2ETests, AdminOperationServiceTests, AuthBootstrapControllerTests, AuthSecurityTests, SttControllerSecurityTests, SttFailClosedTests, SttGatewayAuthorizationE2ETests (26/26 per SSOT).


6. API server status summary

  • Auth, login, JWT, role policies, rate limiting, CORS, host restrictions: implemented.
  • LLM proxy: implemented (with local Mock echo fallback for standalone testing).
  • STT proxy: implemented for internal gateway; public /transcribe intentionally 410 (Edge-only by design).
  • Admin API: users, endpoints (LLM + STT), usage, license audit: implemented with idempotency + audit.
  • Known intentional states (not bugs):
    • Legacy SHA-256 users force-disabled.
    • No hardcoded/seeded admin credentials.
    • No static file serving — wwwroot and its mobile/legacy release asset block were deleted 2026-09-26 (Wave 3, cd9d199); downloads/releases are served only from site/.
    • LlmProxyService Mock fallback.
  • This backend holds a separate identity from Supabase; see 11-gap-backlog.md ID-01.