docs: consolidate repository guides and preserve audit history

This commit is contained in:
cesnimda
2026-09-11 14:22:41 +02:00
parent 115441a409
commit 682a3028bb
404 changed files with 3402 additions and 2621 deletions
+13
View File
@@ -0,0 +1,13 @@
# AI
AI is an optional assistive subsystem. Manual job tracking and document editing remain usable without it.
- [Architecture and feature boundaries](architecture.md)
- [Providers and routing](providers.md)
- [Prompt and output rules](prompts.md)
- [Safety and privacy](safety.md)
- [Document processing](document-processing.md)
Implemented behavior must be verified in the API and `tools/summarizer/`; future ideas are tracked only in [roadmap](../roadmap/README.md).
For local service commands and parser limits, see the [summarizer service README](../../tools/summarizer/README.md).
-55
View File
@@ -1,55 +0,0 @@
# AI Principles
## 1. User First
The user owns all generated content.
---
## 2. Never Invent Facts
AI must not create:
- Jobs.
- Companies.
- Qualifications.
- Skills.
- Experience.
---
## 3. Explain Changes
Where possible show:
Before
↓
After
---
## 4. Preserve Context
AI should understand:
- User career.
- Target job.
- Industry.
---
## 5. Allow Manual Editing
Every AI output must be editable.
---
## 6. Fail Safely
If AI fails:
- Show error.
- Allow retry.
- Do not lose user data.
+7
View File
@@ -0,0 +1,7 @@
# AI architecture
The API calls the internal FastAPI service at `AI_SERVICE_BASE_URL`. The service provides local job summarisation, text extraction/OCR, and CV normalization/classification/rewrite routes. The local summarizer uses `sshleifer/distilbart-cnn-12-6`; structured CV tasks use Ollama by default and may use Gemini or Groq only when external processing is enabled and policy permits it.
Current feature surfaces include job summaries, deterministic match scoring, candidate-fit/focus-plan narratives, CV extraction and normalization, section rewriting, tailored CVs, cover-letter/application drafts, recruiter/follow-up drafts, and interview preparation. AI output is reviewable/editable; sending mail is a separate user action.
The API owns user authorization, quotas, and feature policy. The sidecar owns provider routing, parser limits, and the shared service-token check. `/health` is the only intentionally open sidecar path.
-39
View File
@@ -1,39 +0,0 @@
# AI Cost Control
## Purpose
Prevent uncontrolled AI expenses.
---
# Requirements
Track:
- User requests.
- Tokens.
- Provider usage.
---
# Future SaaS
Support:
Free:
Limited usage.
Premium:
Higher limits.
---
# Optimisation
Prefer:
- Smaller models for simple tasks.
- Caching where appropriate.
- Reusing generated results.
-49
View File
@@ -1,49 +0,0 @@
# Cover Letter AI
## Purpose
Generate personalised cover letters.
---
# Inputs
Use:
- Career Profile.
- Master CV.
- Job description.
---
# Features
Generate:
- First draft.
- Improvements.
- Tone changes.
---
# User Control
Allow:
- Editing.
- Regeneration.
- Manual writing.
---
# Rules
Avoid generic letters.
Focus on:
Why this person.
Why this company.
Why this role.
-58
View File
@@ -1,58 +0,0 @@
# CV AI Features
## Purpose
Improve CV creation.
---
# Features
## Improve Writing
Example:
Original:
"Worked on websites"
AI:
"Developed and maintained customer-facing web applications."
---
## Suggest Content
AI can suggest:
- Missing skills.
- Better wording.
---
## Rewrite
Options:
- More professional.
- More concise.
- More technical.
---
## Generate
Create:
- Summary.
- Bullet points.
- Sections.
---
# Rules
AI suggestions require approval.
Never overwrite original content.
+5
View File
@@ -0,0 +1,5 @@
# Document processing
Supported extraction includes PDF, DOCX, TXT, Markdown, and PNG/JPEG/WEBP image inputs. Scanned documents can use Tesseract OCR. `/extract-text` performs size/signature checks in the web process and delegates decoding to a bounded child process; temporary work directories are removed and stale work is reconciled.
Relevant limits are configured with `PARSER_TIMEOUT_SECONDS`, `PARSER_CPU_SECONDS`, `PARSER_MEMORY_MIB`, and `PARSER_STALE_WORK_SECONDS`. `PARSER_TEMP_ROOT` is an optional local override. When a document exceeds safe limits, reject it or ask the user for a smaller/cleaner file; do not disable validation to make a parser pass.
-49
View File
@@ -1,49 +0,0 @@
# Future AI Features
Possible future features:
---
## AI Career Assistant
A contextual assistant aware of:
- Career history.
- Goals.
- Applications.
---
## Interview Coach
Generate:
- Questions.
- Answers.
- Feedback.
---
## Career Recommendations
Suggest:
- Skills.
- Roles.
- Learning paths.
---
## Automatic Application Assistant
Potential:
- Find relevant jobs.
- Prepare documents.
- Track progress.
---
# Priority
Only build after core workflows are excellent.
-48
View File
@@ -1,48 +0,0 @@
# Job AI Features
## Purpose
Help users understand opportunities.
---
# Features
## Job Analysis
Extract:
- Required skills.
- Responsibilities.
- Seniority.
- Keywords.
---
## Matching
Compare:
Job
against
Career Profile
---
Output:
- Strengths.
- Gaps.
- Suggestions.
---
## Application Assistance
Suggest:
- CV improvements.
- Cover letter topics.
- Interview preparation.
-60
View File
@@ -1,60 +0,0 @@
# AI Model Selection
## Goal
Use appropriate models for tasks.
---
# Task Categories
## Simple Tasks
Examples:
- Grammar correction.
- Shortening text.
Use:
Fast/cheap models.
---
## Complex Tasks
Examples:
- CV generation.
- Career analysis.
Use:
Higher quality models.
---
## Long Context Tasks
Examples:
- Analysing full CV.
- Comparing job descriptions.
Use:
Large context models.
---
# Principles
Do not use expensive models unnecessarily.
Balance:
Quality.
Speed.
Cost.
-72
View File
@@ -1,72 +0,0 @@
# AI System Overview
## Purpose
AI enhances Jobjakt workflows.
It helps users:
- Create better applications.
- Improve documents.
- Understand opportunities.
- Prepare for interviews.
AI does not replace user decisions.
---
# AI Philosophy
Jobjakt is not an AI chatbot.
AI should appear where it provides clear value.
Examples:
Good:
"Improve this CV bullet point"
Good:
"Tailor this CV for this job"
Good:
"Suggest interview questions"
Bad:
Empty chat window with no context.
---
# AI Sources
AI can use:
- Career Profile.
- Master CV.
- Job descriptions.
- User-provided documents.
- Application history.
---
# User Control
AI output must:
- Be visible.
- Be editable.
- Require approval before saving.
---
# Important Rule
Never silently modify:
- Career profile.
- Master CV.
- Application documents.
-37
View File
@@ -1,37 +0,0 @@
# AI Privacy
## Principles
Users control their data.
---
# External AI Providers
Before sending data:
Clearly communicate:
- What is sent.
- Why it is needed.
- Provider used.
---
# Future SaaS
Support:
- User consent.
- Data deletion.
- Export.
---
# Sensitive Information
Be careful with:
- Personal details.
- Employment history.
- Documents.
+3 -49
View File
@@ -1,51 +1,5 @@
# AI Prompt Management
# Prompt and output rules
## Purpose
Prompts are assembled by feature services/controllers from the job, career profile, reviewed correspondence, and explicitly selected attachments. Inputs are bounded before leaving the API/sidecar. Structured tasks request typed JSON or constrained sections; callers validate and sanitize the result before storing or rendering it.
Centralise prompts.
Avoid random prompts scattered throughout code.
---
# Requirements
Prompts should:
- Be version controlled.
- Be documented.
- Have tests where possible.
---
# Prompt Structure
Every prompt should define:
Purpose.
Inputs.
Expected output.
Restrictions.
---
# Example
Task:
Improve CV bullet point.
Input:
Existing bullet.
Output:
Improved bullet.
Restrictions:
Do not add unsupported achievements.
Prompts must preserve factual career data, avoid inventing credentials or experience, respect the selected locale, and keep user edits recoverable. Do not add automatic employer-facing sends to an AI feature without a separate review and delivery design.
+3 -64
View File
@@ -1,66 +1,5 @@
# AI Providers
# AI providers and routing
## Purpose
`AI_PROVIDER` selects the structured CV provider: `ollama` (default/local), `gemini`, or `groq`. `AI_ROUTING_MODE` is `local_only`, `local_first`, or `external_only`; external processing also requires the administrator gate, an allowed task, and the user's applicable opt-in/entitlement. Job summarisation remains local in the sidecar.
Support multiple AI providers.
---
# Current/Future Providers
Possible:
- OpenAI.
- Anthropic.
- Google Gemini.
- Groq.
- Ollama.
- Other compatible APIs.
---
# Provider Architecture
Use abstraction:
AI Provider Interface
↓
Provider Implementation
↓
Model
---
# Requirements
Users should eventually be able to:
- Select provider.
- Select model.
- Configure API keys.
---
# Admin Controls
Admins should control:
- Available providers.
- Allowed models.
- Usage limits.
---
# SaaS Consideration
Different plans may have:
Free models.
Premium models.
BYO-key support.
Ollama uses `OLLAMA_BASE_URL` and `OLLAMA_MODEL`. Gemini and Groq use their model, base URL, and API-key variables. Keep provider keys in the environment only. If a provider/model is unavailable, show a retriable/unavailable state rather than silently selecting an unevaluated model.
+3 -6
View File
@@ -1,8 +1,5 @@
# safety
# AI safety and privacy
AI output is suggestion-only and cannot overwrite the Career Profile automatically. Prompts delimit
untrusted source text, require preservation of factual claims, and instruct providers not to invent
employers, titles, dates, or metrics. Attachments are included only when explicitly selected.
Local processing is the default. External CV processing is opt-in and gated; provider selection and task type are recorded in the AI interaction/usage paths. The sidecar is private to the backend network in Compose, requires `AI_SERVICE_TOKEN` on protected endpoints, runs with reduced container privileges, and bounds parser work.
Provider outages degrade AI features without blocking core tracking. Calls and tokens are metered and
limited by plan. See `docs/ai/security.md` and `docs/ai/privacy.md`.
Known limits: local tests do not prove provider equivalence, production privacy configuration, or real outage behavior. Do not paste personal CVs, tokens, or provider responses into audit notes. See [security notes](../security/security-notes.md) for open verification gates.
-44
View File
@@ -1,44 +0,0 @@
# AI Security
## Purpose
Protect user data.
---
# Prompt Injection Protection
Job descriptions and uploaded documents are untrusted input.
Never allow external text to override system instructions.
---
# Data Protection
Protect:
- CV data.
- Personal information.
- Documents.
---
# Validation
Validate:
- AI outputs.
- Generated files.
- User inputs.
---
# File Processing
Uploaded files may contain:
- Malicious content.
- Hidden instructions.
Treat all files as untrusted.
-44
View File
@@ -1,44 +0,0 @@
# JobTracker AI workload inventory
Date: 2026-08-02
This inventory is code-derived, not a production measurement. Typical sizes and latency targets are initial evaluation bands for synthetic benchmarks; they are not observed production SLOs. Current provider means the repository default path, not a verified production setting.
Privacy classes used by the next policy package:
- `P0 public`: synthetic/public job text without user data.
- `P1 account`: user settings or application metadata without CV/email bodies.
- `P2 private`: CV/profile, notes, drafts, contacts or email content.
- `P3 credential`: provider tokens/secrets; never a model input.
| ID | Task and reachable path | Input / typical → max | Output | Language | Target / quality | Privacy and fallback candidate | Mode | Deterministic? | Current provider/model | Pro |
|---|---|---|---|---|---|---|---|---|---|---|
| DOC-EXTRACT | CV/attachment text extraction; `/extract-text` | PDF/DOCX/image/text; 50 KB–2 MB → API 5 MB, sidecar 8 MB | text + OCR metadata | any OCR-supported | background ≤30 s; high | P2; external prohibited | interactive/background | parser/OCR, not generative | local parser/Tesseract | Yes when used for AI CV import/context |
| CV-NORMALIZE | CV structure normalization; `/cv/normalize` | extracted CV text; 2k–15k → 50k chars | strict profile JSON | EN/NO/mixed | background ≤45 s; critical factuality | P2; local default, external only explicit future consent | background | deterministic parser first; AI only unresolved structure | configurable `/cv/*`, default Ollama `qwen2.5:7b` | Yes |
| CV-CLASSIFY | ambiguous CV block classification; `/cv/classify-block` | one block; 100–2k → 6k chars | strict classification JSON | EN/NO/mixed | background ≤10 s; medium/high | P2; same as CV-NORMALIZE | background | deterministic headings first | configurable `/cv/*`, default Ollama `qwen2.5:7b` | Yes |
| PROFILE-EXTRACT | Career Profile extraction in `BuildStructuredCvAsync` | CV text; 2k–15k → composed prompt 20k | strict `StructuredCvProfile` JSON | EN/NO/mixed | background ≤60 s; critical | P2; external prohibited by default | background | deterministic parsing/fallback remains required | `/cv/rewrite`, default Ollama `qwen2.5:7b` | Yes |
| PROFILE-DIFF | conservative import/merge suggestions | old/new structured profile | field diff with explicit accept/reject | any | interactive <1 s; critical | P2; no fallback needed | interactive | Yes: `CvProfileDiffService`; keep AI out | local C# | No model call |
| JOB-CLEAN | language, stop words, keyword/phrase/skill cleanup | job advert; 200–15k → 20k chars | language/tags/phrases | EN/NO/mixed | <1 s; high precision | P0/P1; no external need | interactive/background | Yes for language/basic tags; semantic phrase extraction may be evaluated separately | local `LanguageDetector`/`SkillTagger` | No model call |
| JOB-SUMMARY | create/detail/refresh/enrichment summary | job text; 500–10k → 20k chars | short text + sidecar signals | EN/NO | interactive ≤5 s or queued; medium | P0–P2 when notes included; local default | both | AI for abstractive summary; tags stay deterministic | local `sshleifer/distilbart-cnn-12-6` `/summarize` | Yes for model call |
| JOB-MATCH | skills/missing skills/score | job text + reviewed profile | score, matched/missing skills, evidence | EN/NO | <1 s; high/reproducible | P2; no external need | interactive | Yes: `JobCvMatchService`/`ApplicationIntelligenceService` | local C# | No model call |
| STRATEGY | candidate fit, focus plan, Strategy Snapshot | job + CV + optional notes/email/attachments; 4k–20k | typed DTO/markdown narrative | EN/NO/mixed | queued target ≤60 s; high | P2; external prohibited by default | interactive → durable background planned | deterministic match evidence first; AI narrative | `/cv/rewrite`, default Ollama `qwen2.5:7b` | Yes |
| CV-TAILOR | tailored CV/headline/bullets | reviewed profile + job + optional private context; 4k–20k | editable CV draft | EN/NO | queued ≤90 s; critical factuality | P2; external prohibited by default | interactive → background planned | No, but deterministic evidence selection should constrain prompt | `/cv/rewrite`, default Ollama `qwen2.5:7b` | Yes |
| APPLICATION-DRAFT | cover letter/application answer/recruiter message | CV + job + optional email/notes; 4k–20k | editable text variants | EN/NO | queued ≤90 s; high | P2; external prohibited by default | interactive → background planned | No | `/cv/rewrite`, default Ollama `qwen2.5:7b` | Yes |
| FOLLOWUP-DRAFT | follow-up email draft | job/application state + saved drafts + optional email; 1k–20k | editable subject/body | EN/NO | interactive/queued ≤30 s; high | P2; external prohibited by default; never auto-send | interactive | No; mode/recipient validation deterministic | `/cv/rewrite`, default Ollama `qwen2.5:7b` | Yes |
| EMAIL-CLASSIFY | pipeline status from received email | subject/body; 50–10k | status suggestion + signal | EN/NO | <1 s; high precision | P2; no external need | background/interactive | Yes: `EmailStatusClassifier` | local C# | No model call |
| RECRUITMENT-DETECT | detect/link recruitment messages | headers/body/job/company signals | suggested link/category/confidence | EN/NO | background <1 s; high precision | P2; no external need for current rules | background | Yes until measured semantic gap | local C# matching/import rules | No model call |
| INTERVIEW | generated interview brief/questions | job + profile + saved state | editable brief/questions | EN/NO | queued ≤45 s; high | P2; external prohibited by default | interactive → background planned | checklist/board CRUD deterministic; brief generative | `/cv/rewrite`, default Ollama `qwen2.5:7b` | Yes |
| WRITING | CV Builder improve/shorten/expand/ATS/bullets/summary/tailor | selected user text + optional role; 50–20k | editable suggestion | EN/NO/mixed | interactive ≤20 s; high factuality | P2; external prohibited by default | interactive | grammar-only may use local deterministic tools later; no current equivalent | `/cv/rewrite`, default Ollama `qwen2.5:7b` | Yes |
| HEALTH-PROBE | service capability/latency probe | fixed synthetic sentence | metrics only | EN | ≤10 s; operational | P0; external provider probe requires later explicit policy | background/admin | fixed local request | `/summarize`; local DistilBART | Admin/operational |
## Reachability and policy observations
- `/summarize` always uses local DistilBART in the current sidecar. `/cv/*` routes dispatch through `AI_PROVIDER`, whose repository default is local Ollama but which can currently be set globally to Gemini or Groq.
- The current global provider switch cannot enforce the task/privacy distinctions above. POL-002/AI-002 must replace it before external fallback is enabled.
- `ISummarizerService` truncates composed rewrite prompts at 20,000 characters. Sidecar request models cap rewrite text at 20,000, CV normalization at 50,000, classification blocks at 6,000, and extraction bytes at 8 MB; the application CV upload boundary is 5 MB.
- Deterministic keyword cleanup, skill matching, profile diffing and email classification must not be routed through a model.
- P3 credentials are configuration inputs only and must never appear in prompts, fixtures, logs or provider payloads.
## Synthetic evaluation data
Machine-readable cases are in `JobTrackerApi.Tests/Fixtures/AiEvaluation/cases.json`. They cover all required English/Norwegian/mixed/noisy/sparse/technology/email/follow-up/strategy/strict-JSON/adversarial/injection/long/empty/invalid categories. Expected assertions are constraints rather than golden prose so later model comparisons do not reward one exact wording.