feat: meter AI usage
CI and Deploy / test (push) Failing after 58s
CI and Deploy / deploy (push) Has been skipped

This commit is contained in:
cesnimda
2026-07-30 22:39:24 +02:00
parent f8466c2ebc
commit c08232b9d7
15 changed files with 2482 additions and 11 deletions
+5 -2
View File
@@ -55,10 +55,13 @@ master profile text ────────────┘ │
overwritten. This is deliberately distinct from `AiWorkspaceNote` (a one-row-per-type *cache* for
candidate-fit/focus-plan). History gives the user restore/reuse (re-surface a past result), compare
(view two side by side), copy, and delete. `ResultJson` is `{ text, meta? }`; `Provider` records which
provider produced it. Tenant-scoped (owner query filter), cascades with the application.
provider produced it. Each row also stores input/output character counts and a conservative estimated
token count (characters ÷ 4); the estimate is provider-neutral because the sidecar currently returns
text rather than provider billing metadata. Tenant-scoped (owner query filter), cascades with the application.
API (`AiWorkspaceController`, `/api/jobapplications/{id}/ai`): `GET modules` (+ current provider),
`POST generate`, `GET history?module=`, `DELETE history/{id}`.
`POST generate`, `GET history?module=`, `DELETE history/{id}`. `GET /api/ai/usage` returns current-month
and all-time totals; the workspace displays the monthly calls and estimated tokens.
## Provider abstraction
+1 -1
View File
@@ -391,7 +391,7 @@ No structured sink (Seq/OTLP), no in-app log rotation, no ProblemDetails standar
|---|---|---|
| Medium | DataProtection keys recoverable from git history (`519c32e`, `955cae6`) | **Open — rotation required, needs an operator** |
| Medium | **CORS: `Cors:Origins="*"` triggers `SetIsOriginAllowed(_ => true)` + `AllowCredentials()`** (`Program.cs:96-102`) — reflected-origin with cookies = session theft from any site. Not currently active (compose never sets `Cors__Origins`, so it defaults to `localhost:3000`), but it is one config value away. | **Open — landmine** |
| Medium | No AI cost ceiling (no quota, no metering, unthrottled) | Open |
| Medium | AI cost ceiling | Metering shipped in Phase 5; enforce quotas before open registration (Phase 7). |
| Low | No CAPTCHA (rate limiting only) | Open — blocks public signup |
| Low | Unbounded storage: attachments, CV artifacts, extraction runs, base64 avatars | Open |
| Low | Backup / DPAPI is Windows-oriented — verify behaviour on Linux prod | Unverified |
+4 -4
View File
@@ -146,14 +146,14 @@ Goal: polish. This is the healthiest area — grounding in the structured profil
> `ISummarizerService`/ai-service provider abstraction and stored as **append-only history**
> (`AiInteraction`) with reuse / compare / copy / delete. Suggestion-only throughout; nothing
> auto-applies; `Markdown` renders React nodes (no HTML-injection surface). See
> `docs/architecture/ai-career-assistant.md`. **Still open:** per-request user-selectable providers
> (needs an ai-service per-request override + a configured key per provider — deployment/credential
> work, documented as an extension point); 5.2 AI usage metering (Phase 7 blocker) remains.
> `docs/architecture/ai-career-assistant.md`. **Phase 5 completed 2026-07-30:** provider-neutral usage
> metering and visible monthly totals now close the Phase 7 cost-control prerequisite. Per-request
> provider choice remains deliberately deferred by ADR-004.
| # | Task | Priority | Difficulty | Dependencies | Expected value |
|---|---|---|---|---|---|
| 5.1 | ✅ **DONE (2026-07-30)** — fixed `docs/00-ai-context.md` to match the code. **Decided 2026-07-17: do NOT build the abstraction.** | **P1** | **S** | none | The doc describes a provider interface over OpenAI/Gemini/Claude/Ollama with admin control and per-user choice. Reality: one `AI_PROVIDER` env var over Ollama/Gemini/Groq. Multi-provider cloud AI also undermines the privacy moat (see `docs/research/competitors.md` §4). Revisit only if a customer asks. `docs/architecture/current.md` §9 already records the truth. |
| 5.2 | **AI usage metering** | **P1** | **M** | 1.5 | No quota, no tracking, no ceiling. Hard blocker for Phase 7; a cost risk today with `AI_PROVIDER=gemini`. |
| 5.2 | **DONE (2026-07-30)**AI usage metering | **P1** | **M** | 1.5 | No quota, no tracking, no ceiling. Hard blocker for Phase 7; a cost risk today with `AI_PROVIDER=gemini`. |
| 5.3 | ✅ **DONE (2026-07-30)** — surfaced optional CV generation inside the add-job wizard | **P2** | **S** | 1.4 | The target workflow says "Generate CV if needed" at step 3. `POST /generate-tailored-cv-draft` exists but only post-save. |
| 5.4 | ✅ **DONE** — keyword-gap analysis on match score | **P2** | **M** | none | `JobCvMatchService` + `/match-score` exist. Gap analysis is the specific thing people pay Jobscan $49.95/mo for. |
| 5.5 | ✅ **DONE (2026-07-30)** — wrote ADR-004 (AI provider system) | **P2** | **S** | 5.1 | 0-byte file naming a real decision. |