docs: reorganize tree, restore architecture + research from archive, add Phase 0 reports

Active docs/ was stub scaffolding while the real docs sat in docs/_archive/.
Restore and correct them, and record the Phase 0 work.

- docs/architecture/current.md: verified system map (from archived SYSTEM_OVERVIEW,
  9 corrections against code).
- docs/research/competitors.md: sourced competitor analysis (from archived
  PRODUCT_RESEARCH, feature matrix corrected).
- docs/decisions/ADR-002-job-application-model.md: the Job/JobApplication split.
- docs/application-discovery-report.md, docs/implementation-roadmap.md,
  docs/phase-0-foundation-report.md, docs/career-workspace-branch-assessment.md.
- Remove 10 zero-byte placeholder files that advertised content that never existed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
cesnimda
2026-07-17 17:04:32 +02:00
parent aa3567d8a8
commit b176a44627
275 changed files with 12554 additions and 0 deletions
View File
View File
View File
View File
+53
View File
@@ -0,0 +1,53 @@
# Jobbjakt Architecture Evolution
## Guiding constraints
- Preserve the existing single-master-profile model.
- Keep job applications and their workflow at the centre of the domain.
- Make AI providers replaceable and optional.
- Add SaaS foundations without prematurely building a billing platform or team product.
- Keep feature slices small while reducing the current controller concentration.
## Target boundaries
```text
Web UI
-> Application APIs
-> Application workflow domain
-> Career profile and document domain
-> Discovery provider adapters
-> Connected-account adapters
-> AI provider boundary
-> Entitlements and usage policy
```
### Career profile and documents
`ApplicationUser.ProfileCvStructureJson` remains the canonical master profile during the transition. A later migration may normalize high-change sections (projects and portfolio items) into user-owned tables, but generated CVs and application-specific drafts must remain immutable copies with a profile-version reference.
### Discovery
Create an `IJobDiscoveryProvider` contract with normalized query and result types. Providers own authentication, source-specific filters, terms-aware attribution, and mapping. The UI and import flow must not know provider payload shapes. Cache public results briefly, do not persist an external job until the user imports it.
### AI
Extract AI prompts and model transport from controllers behind task-focused interfaces: CV extraction, CV tailoring, draft generation, interview preparation, and summarization. Each request records provider, model, input profile version, job context, and user review state. Local and online providers implement the same boundary.
### Entitlements
Introduce account-level plan, entitlement, and usage-ledger records before payment integration. Product code checks named capabilities (for example `ai.tailor_cv`, `cv.premium_theme`, `storage.attachments`) rather than payment-provider state. This supports trials, manual access, subscriptions, and future organisation plans.
## Incremental engineering work
1. Add targeted feature services beside the existing controllers for every touched feature; do not attempt a big-bang controller rewrite.
2. Replace local-only preferences that affect behaviour with user-owned persisted settings.
3. Replace the in-memory CV queue with a database-backed work item before horizontal hosting.
4. Use PostgreSQL for hosted multi-tenant deployment; retain SQLite for self-hosted/single-user deployments.
5. Add provider health, job processing, AI usage, and entitlement audit telemetry before paid hosting.
## Explicit non-goals for the first SaaS release
- Teams/organisations and shared candidate data.
- Auto-apply automation or scraping-proxy infrastructure.
- A browser-extension marketplace release.
- A billing-provider integration before commercial policy is decided.
+78
View File
@@ -0,0 +1,78 @@
# Merge Request — Wave 0 quick wins + Tier-1/Tier-2 features
**Branch:** `chore/wave0-quick-wins` → `main`
**Scope:** 24 commits · 62 files · +3,165 / −489
**Status:** all tests green (backend 135, frontend 23 suites / 54 tests), production build compiles.
> Prepared for human review. Do **not** auto-merge. One operator action is required after merge
> (DataProtection key rotation — see *Known limitations*).
---
## Summary
Delivers the first two roadmap tiers plus the engineering-health groundwork, developed as small
conventional commits. Two design principles run through it:
1. **Deterministic over "AI-guessy."** Match scoring, status suggestions, and pipeline logic are
pure/deterministic — instant, reproducible, and safe (the user confirms every state change). This
directly answers the market's most common complaint (hallucinated/generic AI output).
2. **One pathway, not two.** The bookmarklet and the PWA share-target feed a single `/?add=` capture
flow rather than parallel implementations.
## What's included
**Engineering health (Wave 0)**
- `security:` untracked committed DataProtection keys + daily exports; removed dead legacy controllers.
- `feat:` automated daily SQLite backups (`VACUUM INTO`, retention, startup catch-up) — prod previously
had **no** automated backup on Linux.
- `ci:` run the **entire** frontend suite (the old whitelist was hiding 3 broken suites, now fixed).
- `feat:` dev-only OpenAPI at `/openapi/v1.json`; `feat:` structured salary fields.
**Tier-1 features**
- **Match score** (`GET /jobapplications/{id}/match-score`) — deterministic CV↔job keyword coverage
(0–100) + matched/missing keywords + section coverage. Instant panel on the Candidate Fit tab.
- **Canonical pipeline** — `JobPipeline` single source of truth; status normalized on write (custom
values preserved); UI deduped across 5 files; `GET .../pipeline`.
- **Analytics v2** — time-in-stage medians (from `StatusChanged` history) + funnel driven by the
pipeline (fixes a bug that omitted the Waiting stage).
- **Status suggestions** — deterministic email→status classifier surfaced as a human-confirmed banner.
**Tier-2 features**
- **Bookmarklet** quick-capture (Settings) reusing `jobimport/preview`.
- **Installable PWA** with a mobile share-target into the same capture flow.
**Quality**
- Phase-6 security review (`docs/SECURITY_REPORT.md`): tenant isolation on new endpoints verified +
regression-tested; no injection/ReDoS; dev-only OpenAPI.
- Bug fixes: `SkillTagger` C#/.NET regex (silently missed those skills everywhere), a React
stale-closure, a duplicated DB query, and 3 pre-existing hidden test failures.
## Test coverage added
New pure/unit-tested services: `JobCvMatchService` (7), `JobPipeline` (14), `StageAnalytics` (4),
`EmailStatusClassifier` (7). New endpoint integration + authorization tests (match-score,
status-suggestion). New frontend tests: match-score panel, status-suggestion banner, pipeline,
quick-capture, capture-url resolution.
## Docs
New: `docs/SYSTEM_OVERVIEW.md`, `docs/PRODUCT_RESEARCH.md`, `docs/ROADMAP.md`,
`docs/SECURITY_REPORT.md`. README updated with the new endpoints, backup/pipeline config, and
quick-capture/PWA notes.
## Known limitations / follow-ups
- **ACTION REQUIRED (security):** the removed DataProtection key XMLs remain in git **history**.
Rotate them on the production host after merge (see `SECURITY_REPORT.md` §6).
- **Per-user custom pipeline stages** were deliberately deferred (unproven demand; large surface).
- **No offline service worker** by design — the app deploys frequently and an aggressive cache would
risk serving stale builds. The PWA is installable and share-capable without it.
- Not yet done (future branches): interview hub (M3), contacts CRM (M4), god-controller decomposition,
performance pass, Vite migration.
## Reviewer notes
- Repo quirk: controllers/services compile via the `JobTrackerBackend` library, **not** the
`JobTrackerApi` host project (see `docs/SYSTEM_OVERVIEW.md` §2).
- All AI-adjacent features are deterministic and make no model calls.
+81
View File
@@ -0,0 +1,81 @@
# Jobbjakt Product Evolution Plan
> Confirmed 2026-07-15. This document is the product decision record for the career-management evolution.
## Product position
Jobbjakt is a job-tracking and career-management product. The application workflow remains the core loop:
```text
Discover opportunity -> Track application -> Prepare application -> Follow up -> Learn and progress
```
Career profile, CV generation, cover letters, portfolio, interview preparation, and discovery support this loop. They must not displace it or turn Jobbjakt into a CV-builder-first product.
## Confirmed decisions
| Decision | Direction |
| --- | --- |
| Primary discovery market | Nordics and Europe; global later |
| Discovery sources | Permitted provider APIs and existing URL capture; no scraping or browser extension in the first release |
| Career workspace | Dedicated top-level navigation item |
| Add-job flow | Wizard; create the application after job review, then keep preparation steps optional and resumable |
| Portfolio | Lightweight links and project items connected to the master career profile |
| AI | Retain local and online capability behind a provider boundary and explicit user controls |
| SaaS priority | Hosted subscriptions and feature entitlements before organisations/teams |
| Brand | Keep the Jobbjakt name |
## Target information architecture
| Area | Purpose | Initial destinations |
| --- | --- | --- |
| Dashboard | Daily direction | priorities, follow-ups, recent activity |
| Applications | Core tracker | list, board, companies, application workspace |
| Career Workspace | Reusable career source of truth | master profile, CV builder, portfolio, interview preparation |
| Discover Jobs | Find then act | provider search, saved searches later, import into tracker |
| Settings | Product preferences | general, follow-ups, notifications, connected accounts, data |
| Account | Identity and security | personal details, password, providers, sessions, 2FA |
## Delivery roadmap
### Phase 1 — Workflow clarity
1. Create the Career Workspace and move CV-facing functionality out of Account Profile.
2. Move Gmail, Outlook, and IMAP management to Settings > Connected Accounts.
3. Reorganise Settings: remove normal-user export/import controls, hide admin-only status controls, and improve follow-up explanations.
4. Simplify application workspace navigation into task-oriented sections.
### Phase 2 — Application preparation
1. Replace the dense Add Job modal with a six-step wizard.
2. URL capture and extraction lead the flow; manual details remain an easy fallback.
3. Save the application after review; CV, cover letter, portfolio, and documents are explicitly optional.
4. Link job-specific CV copies and draft material to the application without mutating the master profile.
### Phase 3 — Career workspace completion
1. Strengthen the structured master career profile: experience, education, skills, projects, certifications, languages, achievements, and portfolio links.
2. Turn the existing template system into a guided three-step CV builder: theme, preview/customise, save defaults.
3. Keep five professional templates and persisted visual preferences; add drag-and-drop ordering after the underlying configuration is durable.
### Phase 4 — Nordic/European discovery
1. Introduce a provider-adapter contract and a normalized result model.
2. Implement approved public/provider APIs beginning with Nordic sources; add European sources only when their terms permit product use.
3. Provide search, filters, source attribution, map/distance enrichment where data permits, and one-click import to the wizard.
4. Add fuzzy role matching locally through a role/skill synonym catalog before any external AI ranking.
### Phase 5 — Hosted SaaS foundations
1. Add account-level entitlement and usage records independent of a billing provider.
2. Gate premium themes, AI allowances, storage, and discovery quotas through policy checks.
3. Integrate a billing provider only after pricing, tax, trial, cancellation, and support policy decisions are recorded.
4. Move restart-sensitive CV processing to durable storage before multi-instance hosting.
## Success measures
- A new user can create a tracked application from a URL in under two minutes.
- A user can find their master profile, create a CV, and manage email connections without visiting Account Profile.
- Optional preparation never blocks capture of an opportunity.
- Every AI-generated output visibly states its source profile/job context and requires user review before it is saved or sent.
- Discovery always preserves source attribution and sends users to the original job advert to apply.
+121
View File
@@ -0,0 +1,121 @@
# PRODUCT_RESEARCH.md — Job Application Tracking Market (2026)
> Phase 2 deliverable. Research conducted 2026-07-02 via web sources (linked throughout).
> Purpose: position Jobbjakt against the market and rank the features worth building next.
---
## 1. Market landscape
The market splits into five clusters:
| Cluster | Representatives | Model |
|---|---|---|
| **Tracker-first + AI resume** | [Teal](https://www.tealhq.com/), [Huntr](https://huntr.co/pricing), JibberJobber | Freemium SaaS; premium $29–40/mo |
| **Autofill / volume** | [Simplify](https://simplify.jobs/job-application-tracker) (autofill), [LazyApply](https://lazyapply.com/) ($99–999/yr), LoopCV (auto-apply) | Extension-centric |
| **Matching + copilot** | [Jobright](https://jobright.ai/blog/teal-review-2026-walkthrough-alternatives-and-faqs/) | AI job matching, resume tailoring, autofill |
| **Resume/ATS optimization** | [Jobscan](https://www.jobscan.co/) ($49.95/mo!), Resume Worded, Rezi | Match-score per job description |
| **Self-hosted / privacy** | [JobSync](https://github.com/Gsync/jobsync), [CareerSync](https://github.com/Tomiwajin/CareerSync), [career-ops](https://career-ops.org/), various [GitHub projects](https://github.com/topics/job-application-tracker) | OSS, local-first, often Ollama-based |
| **Email auto-tracking** | [Trackr](https://www.trackrjobs.com/), [G-Track](https://jobtrack-ai.com/gmail-job-tracker), Gmail [Chrome extensions](https://chromewebstore.google.com/detail/gmail-job-application-tra/lkpjngmdfncejiomkofogfdoppgifmkh) | Inbox scanning → status updates |
### Competitor snapshots
**Teal** — market leader for tracker+resume. Free: unlimited tracking, Chrome extension (50+ job boards), kanban (Saved/Applied/Interview/Offer/Rejected), 10 ATS templates, contact manager, ATS score (15 checks). Premium ($9/wk, $29/mo, [$79/qtr](https://www.tealhq.com/pricing)): keyword match scoring, AI bullets/cover letters, analytics. Cons reported: [billing-after-cancellation complaints, generic/hallucinating AI content, ATS failures on two-column templates](https://resumehog.com/blog/posts/teal-hq-review-april-2026-is-the-job-tracker-worth-your-time.html), [high-maintenance workflow, overwhelming UI, poor support](https://resumejudge.com/blog/tealhq-review/), no automation.
**Huntr** — best visual kanban + CRM layer. Free: 100 tracked jobs cap, unlimited base resumes, basic scoring. [Pro $40/mo](https://huntr.co/pricing): AI tailored resumes, unlimited cover letters, advanced matching/insights. 4.9★ extension (clip from any site + autofill). Cons: [must rebuild resume inside their builder, plain templates, free plan stops being useful fast](https://resumejudge.com/blog/huntr-review/), online-only.
**Simplify** — free autofill extension for 100+ ATS portals (Workday, Greenhouse, iCIMS), real-time keyword flagging, pipeline tracking. Execution-focused, light on CRM depth.
**Jobscan** — per-job resume match score (1–100, 30+ checks, "aim ≥75%"), cover-letter optimization report. Expensive ($49.95/mo). This single feature is the most-cited reason people pay for job-search tools.
**Email auto-trackers** (Trackr, G-Track, extensions) — scan Gmail, AI-classify (Applied/Next step/Rejected/Offer), auto-update statuses, apply labels. This is rapidly becoming table stakes; users love "zero manual data entry".
**Self-hosted OSS** (JobSync, CareerSync, career-ops) — privacy pitch ("no cloud, no telemetry, no account"), Ollama/local-LLM parsing, but all are far less complete than Jobbjakt: mostly CRUD + basic AI, no CV pipeline, no correspondence CRM, no rules engine.
### Standard vs premium features across the market
- **Table stakes (free everywhere):** kanban board, status stages, notes, basic contact tracking, browser clipper, export.
- **Premium (what people pay for):** per-job resume↔JD **match scoring with keyword gaps**, AI tailored resumes/cover letters, analytics (response rate, funnel conversion, time-in-stage), email/interview follow-up automation, autofill at scale.
- **Emerging differentiators:** inbox auto-tracking, interview prep hubs (question banks, scheduling, calendar sync — cf. [interview scheduling tools](https://www.selectsoftwarereviews.com/buyer-guide/interview-scheduling-software)), job-match scoring against a profile, salary/offer comparison.
### Recurring user frustrations (opportunities)
1. **Privacy/data anxiety** — sensitive career data on VC-funded SaaS; [breach/misuse concerns](https://www.saashub.com/compare-job-tracker-by-teal-vs-huntr). Jobbjakt's core moat.
2. **Paywall fatigue** — free tiers cap exactly at the point of seriousness (Huntr's 100 jobs, Teal's AI credits, Jobscan's 5 scans/mo).
3. **AI slop** — hallucinated skills, misspelled names, generic bullets; users want AI grounded in *their* real CV (Jobbjakt's structured-CV grounding is the right architecture).
4. **Manual data entry** — retyping jobs and statuses; solved by clippers + inbox scanning.
5. **Vendor lock-in** — resumes trapped in proprietary builders (Huntr), hard exports.
6. **Tool sprawl** — tracker + Jobscan + resume builder + calendar = 4 subscriptions; users want one hub.
---
## 2. Feature matrix — Jobbjakt vs market
✅ has it · 🟡 partial · ❌ missing
| Feature | Teal | Huntr | Simplify | OSS self-hosted | **Jobbjakt today** |
|---|---|---|---|---|---|
| Kanban pipeline | ✅ | ✅ | ✅ | 🟡 | 🟡 board view exists; status is free-text, no drag-drop canonical pipeline |
| Job capture from URL | ✅ ext | ✅ ext | ✅ ext | 🟡 | 🟡 server-side parse (Finn/NAV/LinkedIn/Jobbnorge + JSON-LD); no extension/bookmarklet |
| Inbox auto-tracking | ❌ | ❌ | 🟡 | 🟡 | ✅ **Gmail OAuth import + human review queue** (ahead of paid SaaS) |
| Contacts/recruiter CRM | ✅ | ✅ | ❌ | ❌ | 🟡 company-level only, no people entities |
| Resume/CV builder | ✅ | ✅ | 🟡 | ❌ | ✅ structured CV parse + templates + PDF export |
| Per-job tailored resume (AI) | 💰 | 💰 | 💰 | ❌ | ✅ **local-AI tailored drafts** (privacy-unique) |
| Resume↔JD match score + keyword gaps | 💰 | 💰 | 🟡 | ❌ | ❌ (handoff doc lists "missing-keyword analysis" as planned) |
| AI cover letters / messages | 💰 | 💰 | 💰 | ❌ | ✅ free, local |
| Follow-up reminders | ✅ | ✅ | 🟡 | ❌ | ✅ + rules engine (auto-ghost) — richer than most |
| Analytics dashboard (funnel, response rate, time-in-stage) | 💰 | 💰 | 🟡 | 🟡 | 🟡 basic stats endpoint only |
| Interview management (schedule, prep notes, calendar) | 🟡 | 🟡 | ❌ | ❌ | ❌ (only generic follow-up dates) |
| Calendar integration (ICS/Google) | 🟡 | 🟡 | ❌ | ❌ | ❌ |
| Salary/offer tracking & comparison | 🟡 | 🟡 | ❌ | ❌ | 🟡 salary text field only |
| Autofill applications | ❌ | ✅ | ✅ | ❌ | ❌ (out of scope — needs extension) |
| Multi-language (EN/NB) + translation | ❌ | ❌ | ❌ | ❌ | ✅ unique for Nordic market |
| Self-hosted / data ownership | ❌ | ❌ | ❌ | ✅ | ✅ |
| Mobile experience | ✅ apps | ✅ | ✅ | ❌ | 🟡 responsive-ish desktop web; no PWA |
| Export/portability | 🟡 | 🟡 | 🟡 | ✅ | ✅ JSON/CSV + daily export |
**Position:** Jobbjakt is already **ahead of every OSS competitor** and matches or beats paid SaaS on AI drafting, Gmail import, and data ownership. Its gaps versus paid SaaS are: match scoring, canonical pipeline/kanban UX, interview & calendar layer, analytics depth, capture friction (no extension), and contact-level CRM.
---
## 3. Market gap — what would make Jobbjakt significantly better than existing solutions
> **"The private, self-hosted career hub: everything Teal+Huntr+Jobscan charge $70–90/mo for, powered by your own local AI, with your data never leaving your server."**
No product today combines: serious tracker UX + inbox auto-tracking + local-LLM tailoring + match scoring + interview hub, self-hosted. Jobbjakt is uniquely ~60% of the way there.
---
## 4. Ranked feature ideas (value × effort)
Effort: S (<1 day) · M (1–3 days) · L (1–2 wk) · XL (>2 wk). Grounded in the Phase 1 codebase map.
| # | Feature | User impact | Effort | Notes |
|---|---|---|---|---|
| 1 | **CV↔job match score + keyword gap analysis** (per job: score, missing keywords, section coverage; reuse structured CV JSON + existing Ollama path) | ★★★★★ — the #1 paid feature in the market, free & local here | M–L | Backend has all inputs already; add endpoint + UI panel in job workspace |
| 2 | **Canonical pipeline + drag-drop kanban** (status enum/ordering, custom stages per user, drive board/badges from it) | ★★★★★ — core daily UX; free-text status blocks analytics too | M–L | Already on README wish list; needs migration for status normalization |
| 3 | **Analytics dashboard v2** (funnel conversion, response rate, time-in-stage, weekly activity, source effectiveness) | ★★★★ — retention feature; needs #2 for clean stages | M | Data all exists in `JobEvent` history |
| 4 | **Interview hub** (interview entity: rounds, type, scheduled time, prep notes, outcome; ICS feed/export + reminders) | ★★★★ — biggest functional gap vs SaaS | L | New entity + timeline integration; ICS is cheap, Google Calendar sync later |
| 5 | **Bookmarklet / minimal browser capture** (one-click "save to Jobbjakt" using existing `jobimport/preview`) | ★★★★ — kills the biggest friction (manual entry); full extension can wait | S–M | Server parsing already exists; a bookmarklet or share-target PWA is days not weeks |
| 6 | **Contacts (people) CRM** (recruiter/hiring-manager entities linked to companies/jobs/correspondence) | ★★★ | M | Natural extension of company recruiter fields |
| 7 | **PWA pass** (installable, mobile nav polish, share-target for job URLs) | ★★★ — mobile is where users check status | M | CRA supports PWA manifest; pairs with #5 |
| 8 | **Salary/offer tracker** (structured salary min/max/currency, offer comparison view) | ★★ | S–M | Currently a free-text field |
| 9 | **Smarter inbox** (extend existing Gmail review with AI status suggestions: "this looks like a rejection → move to Rejected?") | ★★★★ — compounds an existing unique strength | M | Classification via existing Ollama service |
| 10 | **Web push / digest notifications** (beyond SMTP) | ★★ | M | Needs service worker (pairs with #7) |
Deliberately **not** recommended: auto-apply bots (ToS/ethics/quality problems, LazyApply-style tools are poorly reviewed), building a full Chrome-store extension now (high maintenance; bookmarklet first), multi-provider cloud AI (undermines the privacy moat — keep local-first with optional cloud later).
## 5. Recommended implementation order (input to Phase 3 roadmap)
1. **Match score + keyword gaps** (#1) — flagship differentiator, builds on freshest code (structured CV).
2. **Canonical pipeline + kanban** (#2) — unblocks analytics, fixes daily UX.
3. **Analytics v2** (#3) — quick follow-on.
4. **Bookmarklet capture** (#5) + **PWA** (#7) — friction killers.
5. **Interview hub** (#4) — biggest new surface, schedule after the above land.
6. Then #9, #6, #8, #10 by appetite.
Engineering-health work (CI test whitelist, prod DB backups, god-controller decomposition) is tracked separately in `docs/SYSTEM_OVERVIEW.md` §15–17 and should interleave with feature work in Phase 3.
---
Sources: [Prentus tracker roundup](https://prentus.com/blog/we-found-the-5-best-job-tracker-tools-on-the-market) · [ApplyArc comparison](https://applyarc.com/compare/best-job-application-trackers) · [Teal pricing](https://www.tealhq.com/pricing) · [Teal reviews (ResumeHog)](https://resumehog.com/blog/posts/teal-hq-review-april-2026-is-the-job-tracker-worth-your-time.html) · [Teal cons (ResumeJudge)](https://resumejudge.com/blog/tealhq-review/) · [Huntr pricing](https://huntr.co/pricing) · [Huntr cons (ResumeJudge)](https://resumejudge.com/blog/huntr-review/) · [Huntr vs Teal](https://huntr.co/blog/huntr-vs-teal) · [Simplify tracker](https://simplify.jobs/job-application-tracker) · [Jobright review of Teal](https://jobright.ai/blog/teal-review-2026-walkthrough-alternatives-and-faqs/) · [LazyApply](https://lazyapply.com/) · [Auto-apply tools compared](https://blog.fastapply.co/auto-apply-jobs-tools-compared-2026) · [Jobscan](https://www.jobscan.co/) · [Jobscan pricing](https://onlineatschecker.com/blog/jobscan-pricing-2026-free-plan-worth-it) · [JobSync (OSS)](https://github.com/Gsync/jobsync) · [CareerSync (OSS)](https://github.com/Tomiwajin/CareerSync) · [career-ops](https://career-ops.org/) · [Trackr](https://www.trackrjobs.com/) · [G-Track](https://jobtrack-ai.com/gmail-job-tracker) · [Gmail tracker extension](https://chromewebstore.google.com/detail/gmail-job-application-tra/lkpjngmdfncejiomkofogfdoppgifmkh) · [Interview scheduling software guide](https://www.selectsoftwarereviews.com/buyer-guide/interview-scheduling-software) · [SaaSHub Teal vs Huntr](https://www.saashub.com/compare-job-tracker-by-teal-vs-huntr)
+75
View File
@@ -0,0 +1,75 @@
# ROADMAP.md — Jobbjakt Product & Engineering Roadmap
> Phase 3 deliverable (2026-07-02). Sources: `docs/SYSTEM_OVERVIEW.md` (Phase 1) and `docs/PRODUCT_RESEARCH.md` (Phase 2).
> Scoring: Value/Complexity/Risk on ▲ high / ● medium / ▽ low. Effort: S <1 day · M 1–3 days · L 1–2 wk · XL >2 wk.
**North star:** the private, self-hosted career hub — the tracker UX of Huntr, the tailoring/scoring of Teal+Jobscan, powered by local AI, with data that never leaves your server.
---
## Tier 0 — Quick Wins (do first; days, low risk, compounding payoff)
| # | Item | Type | Value | Effort | Risk | Rationale |
|---|---|---|---|---|---|---|
| Q1 | **CI: run the full frontend test suite** (replace the hand-maintained 10-file whitelist with the whole suite; fix/quarantine any flaky test explicitly) | eng | ▲ | S | ▽ | New tests currently silently skipped in CI; already caused a gap once |
| Q2 | **Automated production DB backup** (scheduled SQLite `VACUUM INTO`/copy to `exports/` with retention; document restore) | eng | ▲ | S–M | ▽ | Prod currently has *no working automated backup* (backup endpoint is Windows-DPAPI-only, prod is Linux) |
| Q3 | **Repo hygiene** (delete dead root `Controller/`; remove `temp_job.json`, `temp_post_job.py`; gitignore `JobTrackerApi/CvArtifacts/`, `bin_build/`, stray artifacts; commit pending WIP fixes on a branch) | eng | ● | S | ▽ | Removes footguns before refactors; working tree currently dirty |
| Q4 | **Swagger/OpenAPI** (Swashbuckle or built-in OpenAPI, dev-only exposure) | eng | ● | S | ▽ | README endpoint list already drifts; prerequisite for a generated TS client later |
| Q5 | **Structured salary fields** (min/max/currency/period alongside the free-text field, backfill-friendly) | product | ● | S–M | ▽ | Cheap now, prerequisite for offer comparison + analytics later |
## Tier 1 — High Value (the differentiators; next 2–4 weeks of feature work)
| # | Item | Value | Effort | Risk | Notes |
|---|---|---|---|---|---|
| H1 | **CV↔Job match score + keyword gap analysis** — per-job score, missing keywords, section coverage; reuse `ProfileCvStructureJson` + existing Ollama path; panel in job workspace | ▲▲ | M–L | ● | The market's #1 paid feature (Jobscan $50/mo), free & local here. Flagship differentiator |
| H2 | **Canonical pipeline + drag-drop kanban** — status enum + ordering + per-user custom stages; migration normalizing existing free-text statuses; board becomes drag-drop | ▲▲ | M–L | ● | Fixes daily UX; unblocks H3; the riskiest part is the status migration (needs careful mapping + tests) |
| H3 | **Analytics dashboard v2** — funnel conversion, response rate, time-in-stage, weekly activity, source effectiveness (data already in `JobEvent`) | ▲ | M | ▽ | Depends on H2 for clean stages |
| H4 | **Gmail AI status suggestions** — extend the existing review queue: classify incoming mail (rejection/interview/offer) via local AI and suggest status moves, human-confirmed | ▲ | M | ● | Compounds an existing unique strength; keep human-in-the-loop |
## Tier 2 — Medium Value (after Tier 1)
| # | Item | Value | Effort | Risk |
|---|---|---|---|---|
| M1 | **Bookmarklet / PWA share-target capture** — one-click save-to-Jobbjakt reusing `jobimport/preview` | ▲ | S–M | ▽ |
| M2 | **PWA pass** — manifest, installability, mobile nav polish | ● | M | ▽ |
| M3 | **Interview hub** — interview entity (round, type, time, prep notes, outcome), timeline integration, ICS export + reminders | ▲ | L | ● |
| M4 | **Contacts (people) CRM** — recruiter/hiring-manager entities linked to companies/jobs/correspondence | ● | M | ▽ |
| M5 | **Durable CV processing queue** — DB-backed queue replacing in-memory (jobs survive restart) | ● | M | ● |
| M6 | **ProblemDetails + validation consistency** across API | ● | M | ▽ |
## Tier 3 — Long-Term Improvements (structural; interleave carefully)
| # | Item | Value | Effort | Risk |
|---|---|---|---|---|
| L1 | **Decompose god controllers** (`JobApplicationsController` 151 KB, `ProfileCvController` 117 KB, `GmailController` 60 KB) into feature services; extract AI prompt construction behind interfaces. Strictly behavior-preserving, test-first, one slice per PR | ▲ (maintainability) | XL | ▲ |
| L2 | **Finish the project-layout migration** — physically move linked `Models/`/`Data/`/controller/service files into real projects, retire glob-include `JobTrackerBackend` | ● | L | ● |
| L3 | **Vite migration** (CRA/react-scripts is EOL; 4 GB-heap builds) | ● | L | ● |
| L4 | **OpenAPI-generated TypeScript client** replacing hand-written `api.ts` surface | ● | M–L | ● |
| L5 | **Staging environment / deploy gate** (compose profile or second host; smoke test before prod) | ▲ (ops) | L | ● |
## Tier 4 — Future Ideas (not scheduled)
- Full browser extension (Chrome/Firefox store) with autofill.
- Web push notifications + weekly digest.
- Company research assistant (local AI summarizing company info).
- Offer comparison & salary analytics dashboards.
- Job feed matching from saved searches (Finn/NAV polling).
- Native mobile wrappers; CalDAV/Google Calendar two-way sync.
- Multi-instance/scale-out readiness (distributed cache/queue).
---
## Recommended execution sequence (Phase 4+)
Interleaving product and engineering so debt never blocks features:
1. **Wave 0 (hygiene):** Q3 → Q1 → Q2 → Q4 → Q5 (each a small conventional commit on a feature branch; Q1/Q2 are the two items with real operational risk today)
2. **Wave 1 (flagship):** H1 match scoring (design doc → backend endpoint → UI panel → tests)
3. **Wave 2 (core UX):** H2 canonical pipeline/kanban, then H3 analytics
4. **Wave 3:** H4 Gmail suggestions, M1 bookmarklet, M2 PWA
5. **Wave 4:** M3 interview hub, M4 contacts, M5 durable queue
6. **Continuous:** L1 controller decomposition proceeds opportunistically — whenever a wave touches a god-controller area, extract that slice first (M6 rides along); L2–L5 scheduled after Wave 3 checkpoint.
Phases 5–10 of the mission (bug hunt, security audit, performance, refactoring, testing, docs) run after or between waves as checkpoints; Phase 11 rules apply throughout (feature branches, conventional commits, full test suite before commit, no auto-merge to main).
**Explicitly deprioritized:** auto-apply automation (quality/ToS problems), cloud AI providers (undermines privacy moat), Chrome-store extension before the bookmarklet proves demand.
+122
View File
@@ -0,0 +1,122 @@
# SECURITY_REPORT.md — Session Change Review
> Phase 6 deliverable. Scope: security review of the changes made in this work session
> (Wave 0 + roadmap H1–H4), plus confirmation that the tenant-isolation model still holds.
> Date: 2026-07-03. Complements the prior standalone assessments in
> `docs/security-assessments/` (M013 adversarial, M014 remediation, M015 authorization replay).
This is **not** a full re-audit of the whole application — those live in `docs/security-assessments/`.
It is a focused review of the new/changed surface so nothing shipped this session introduces a regression.
---
## 1. Summary
No new vulnerabilities were introduced. Tenant isolation on the new endpoints is carried by the
existing `JobTrackerContext` global query filters and is now covered by regression tests. One latent
correctness issue (a routable background-service method) was closed, and leaked runtime secrets were
removed from version control (rotation recommended — see §6).
| Severity | Count | Items |
|---|---|---|
| Critical | 0 | — |
| High | 0 | — |
| Medium | 1 (mitigated) | DataProtection keys present in git history (untracked this session; rotation recommended) |
| Low / hardening | 3 | see §5 |
---
## 2. New/changed attack surface reviewed
| Change | Surface | Verdict |
|---|---|---|
| `GET /jobapplications/{id}/match-score` | route int id; reads own CV + job | Safe — tenant-scoped |
| `GET /jobapplications/{id}/status-suggestion` | route int id; reads own correspondence | Safe — tenant-scoped |
| `GET /jobapplications/pipeline` | none (static metadata) | Safe |
| `PATCH .../status`, Create/Update (status normalization) | user string → `JobPipeline.Normalize` | Safe — no injection, values stored parameterized |
| Structured salary fields | numeric + short strings, `NormalizeSalary` | Safe — clamps negatives, whitelists period |
| Automated DB backup (`VACUUM INTO`) | server-controlled path | Safe — see §4 |
| Dev OpenAPI (`/openapi/v1.json`) | schema | Safe — `Development` environment only |
| `EmailStatusClassifier` | reads stored correspondence text | Safe — deterministic, no eval/injection |
---
## 3. OWASP-oriented checklist for the new code
- **A01 Broken Access Control** — The two new data endpoints load the job via
`_db.JobApplications.FirstOrDefaultAsync(j => j.Id == id)`, which is filtered by the global
query filter `CurrentUserId != null && OwnerUserId == CurrentUserId` (deny-on-null, hardened in
M013-2). A cross-user id returns `NotFound`, not another tenant's data. The correspondence lookup
in `status-suggestion` and the `JobEvent` lookup in analytics are likewise filtered through their
parent's owner. **Verified by `JobApplicationsAuthorizationTests` (match-score + status-suggestion).**
- **A03 Injection** — All new persistence goes through EF Core parameterized queries. The only raw
SQL added is `VACUUM INTO '<path>'` with a fully server-derived path (see §4). No string
concatenation of user input into queries.
- **A03 ReDoS** — New regexes (`JobCvMatchService.TokenPattern`, the revised `SkillTagger` C#/.NET
patterns with fixed-width look-behinds) are linear with no catastrophic backtracking.
- **A04 Insecure Design** — Status suggestions and match scoring are deterministic and
**human-confirmed** (a status only changes when the user clicks). No automated outbound actions.
- **A05 Security Misconfiguration** — OpenAPI is exposed only under `IsDevelopment()`; production
deployments (`ASPNETCORE_ENVIRONMENT=Production`) do not serve it.
- **A08 Data Integrity** — `JobPipeline.Normalize` canonicalizes status on write but preserves
unknown custom values (no silent data loss).
- **A09 Logging** — No secrets or PII added to logs by the new code.
---
## 4. Database backup — path handling
`SqliteDatabaseBackupRunner` runs `VACUUM INTO '<target>'`. The target is
`<Data:Root>/backups/jobtracker_backup_<UTC-timestamp>.db` — no user input reaches it — and single
quotes are escaped defensively. Backups contain the full database (sensitive) and are written to the
same data volume as the live DB, i.e. the same trust boundary; they are git-ignored. For defense in
depth, operators should ship backups off-host with transport encryption and restrict volume
permissions. **Recommendation (low):** document an off-host, encrypted backup rotation in the
deployment guide.
---
## 5. Low / hardening findings
1. **match-score input size (low).** `GetMatchScore` does not cap job-description length before
tokenizing. Descriptions are bounded in practice (imported/typed), and the algorithm is linear, so
this is not a DoS, but a defensive cap (e.g. 50 KB) would be prudent.
2. **New read endpoints are not rate-limited (low).** `match-score`/`status-suggestion` are cheap and
deterministic (no AI, one indexed query), and auth-gated in production, so abuse potential is low.
Consider a general authenticated-read limiter if the API is exposed publicly.
3. **status-suggestion is conservative for custom statuses (informational).** A job in a non-canonical
custom status (pipeline order = max) never receives a suggestion. This is safe (fails closed) but
slightly under-surfaces; acceptable given custom statuses are rare.
---
## 6. Secrets hygiene (actioned this session)
- Committed ASP.NET **DataProtection key XML files** (`keys/`, `JobTrackerApi/keys/`) and daily export
JSON were removed from tracking and added to `.gitignore`
(commit `security: untrack DataProtection keys and runtime exports…`).
- **These key files remain in git history.** DataProtection keys sign auth/session artifacts, so
**rotating them on the production host is recommended** (generate fresh keys; the app regenerates the
key ring in the persisted `keys/` directory on next start). Until rotated, anyone with history access
could read the old key material.
- Local `.env` remains git-ignored; `appsettings.Development.json` contains only `CHANGE_ME_*`
placeholders. No live secrets are tracked.
---
## 7. Confirmed intact from prior assessments
Spot-checked that the M013–M015 remediations are still in force after this session's changes:
- Owner query filters still deny on null `CurrentUserId` (`Data/JobTrackerContext.cs`).
- Local JWT still requires a concrete subject claim (`LocalAuthIdentity`, `Program.cs`).
- Job-import SSRF guard (DNS resolution + private-range rejection, redirects disabled) untouched.
- CSRF double-submit middleware and CORS allowlist untouched.
---
## 8. Retest
All backend tests pass (135), including the two new tenant-isolation tests for the new endpoints.
No fix in this report required code changes beyond what already landed; the residual **action for the
operator is DataProtection key rotation** (§6).
+293
View File
@@ -0,0 +1,293 @@
# Jobbjakt (Job Tracker) — System Overview
> Phase 1 deliverable: full-system map produced before any code changes.
> Last updated: 2026-07-02. Verified against commit `eea327e1` plus local working-tree changes.
---
## 1. What the product is
Jobbjakt is a self-hosted, multi-user job application tracking platform with heavy AI assistance:
- Track job applications end-to-end (status pipeline, follow-ups, deadlines, salary, tags, notes).
- Company/recruiter CRM (pipeline stage, contact dates, recruiter details).
- Correspondence log per application, including **Gmail OAuth import with review workflow**.
- Attachments per application with purpose metadata and AI-inclusion toggles.
- **CV platform**: upload → OCR/text extraction → structured CV parsing (Ollama-assisted block classification) → per-job tailored CV drafts → templated PDF export via Playwright.
- AI drafts: cover letters, recruiter messages, follow-up drafts, job description summaries, translation (LibreTranslate optional).
- Rules engine (auto-ghosting, follow-up "needs attention"), reminder emails, daily JSON export, history/event trail, encrypted backup (Windows/DPAPI).
- Admin surface: user management, audit log, system readiness page.
- Deployed to production at `https://jobs.cesnimda.uk` via Gitea Actions → SSH → Docker Compose.
---
## 2. Architecture overview
```mermaid
flowchart LR
subgraph Client
UI[React 19 SPA<br/>MUI 7, react-router 6<br/>CRA/react-scripts]
end
subgraph Frontend container
NGINX[nginx 1.29-alpine<br/>serves build + proxies /api]
end
subgraph Backend container
API[ASP.NET Core net9.0 API<br/>JobTrackerApi host]
BG[Hosted services:<br/>Rules, FollowUpReminder,<br/>DailyExport, JobEnrichment,<br/>SummarizerProbe, CvProcessing]
DB[(SQLite default<br/>or MariaDB/MySQL)]
FS[/Data root:<br/>Attachments, CvArtifacts,<br/>exports, DP keys/]
end
subgraph AI stack
AISVC[FastAPI ai-service :8001<br/>distilbart summarizer,<br/>OCR pytesseract/PyMuPDF,<br/>docx/pdf extraction]
OLLAMA[Ollama :11434<br/>qwen2.5:7b<br/>CV classification + rewrite]
end
EXT1[Google OAuth / Gmail API]
EXT2[Job sites: Finn, NAV,<br/>LinkedIn, Jobbnorge]
EXT3[SMTP - Gmail app password]
EXT4[LibreTranslate optional]
UI --> NGINX --> API
API --> DB
API --> FS
API --> AISVC --> OLLAMA
API --> EXT1
API --> EXT2
API --> EXT3
API --> EXT4
BG --> DB
```
### Solution layout (unusual — read this first)
| Project | Role |
|---|---|
| `JobTrackerApi/` | Web **host** only: `Program.cs`, appsettings, migrations, Dockerfile. Its csproj **excludes** `Controllers/**` and `Services/**` from its own compilation. |
| `JobTrackerBackend/` | "Transitional shared-backend" **library** that compiles, via `<Compile Include>` links, the files physically located in `../Data`, `../Models`, `../JobTrackerApi/Controllers`, `../JobTrackerApi/Services`. Exists so tests can reference controllers/services without the web-entry project. |
| `JobTrackerApi.Tests/` | xUnit test project (~20 test classes incl. authorization/hostile-fixture tests). |
| `Models/`, `Data/` (repo root) | The *real* EF models and `JobTrackerContext`, compiled into JobTrackerBackend. |
| `Controller/` (repo root) | **Legacy stub controllers (~1 KB each) — dead code**, not referenced by any csproj. |
| `job-tracker-ui/` | React SPA. |
| `tools/summarizer/` | FastAPI AI service (own Dockerfile, pytest tests). |
| `deploy/`, `.gitea/workflows/` | Prod deploy script + CI/CD pipeline. |
| `docs/` | Session handoffs, security assessments (M013–M015), UAT notes. |
---
## 3. Technology stack
**Backend**: ASP.NET Core net9.0, EF Core 9 (SQLite default; Pomelo MySQL/MariaDB switchable via `Database:Provider`), ASP.NET Identity Core (users/roles), JWT bearer auth (local + Google policy scheme), built-in RateLimiter, DataProtection (file-system keys), Playwright (CV PDF export).
**Frontend**: React 19, TypeScript 4.9, MUI 7 (+ x-data-grid, x-date-pickers, lab), axios, react-router-dom 6, @tanstack/react-table, CRA `react-scripts` 5 (build needs `--max-old-space-size=4096`), i18n EN + NB (custom provider), Jest/RTL tests.
**AI**: FastAPI + transformers (`sshleifer/distilbart-cnn-12-6`) for summaries; pytesseract/PyMuPDF/pypdf/python-docx for extraction/OCR; Ollama (`qwen2.5:7b`) for CV block classification and rewrite paths; TTL cache.
**Infra**: Docker Compose (4 services: backend, frontend/nginx, ai-service, ollama w/ GPU), Gitea Actions CI (build + backend tests + selected frontend tests + frontend build) → SSH deploy → `deploy/deploy.sh` on the prod host, external `jobtracker_shared` network.
---
## 4. Authentication & authorization
- **Smart policy scheme**: inspects the bearer token issuer — Google-issued ID tokens (`accounts.google.com`) route to the `google` JWT handler (validated against `Auth:GoogleClientId`); everything else routes to `local` JWT (symmetric key `Auth:JwtKey`, issuer/audience validated, 2-min clock skew).
- **Cookie session support**: local handler also reads the session cookie (`AuthSessionOptions.SessionCookieName`); **CSRF double-submit** middleware enforces cookie+header match for all mutating requests when a session cookie is present (login/register/reset/csrf endpoints exempt).
- `Auth:Require=true` sets a fallback authorize-all policy (prod compose sets it). Dev without a JWT key generates an ephemeral key + warning; **fails closed** if auth required but no key.
- Local tokens **must** carry a subject claim (`LocalAuthIdentity`), enforced in `OnTokenValidated` — hardened after finding M013-2.
- **Multi-tenancy**: every tenant entity carries `OwnerUserId`; `JobTrackerContext` applies global query filters `CurrentUserId != null && OwnerUserId == CurrentUserId` (deny-on-null). Correspondence/JobEvents/CV entities filter through their parent's owner.
- Roles via ASP.NET Identity: admin-only controllers (`UsersController`, `AdminAuditController`, `AdminSystemController`).
- Password policy: min 8, digit + lowercase required. Password reset via emailed token (SMTP required). Registration disabled by default.
- Rate limiting: `auth-login` (10/5 min/IP) and `auth-email` (5/15 min/IP) fixed-window policies.
---
## 5. Database schema (EF Core, 8 migrations)
```mermaid
erDiagram
ApplicationUser ||--o{ Company : owns
ApplicationUser ||--o{ JobApplication : owns
ApplicationUser ||--o| UserRuleSettings : has
ApplicationUser ||--o{ GmailConnection : has
ApplicationUser ||--o{ CvUploadArtifact : owns
ApplicationUser ||--o{ CvExtractionRun : owns
Company ||--o{ JobApplication : "has jobs"
JobApplication ||--o{ Correspondence : messages
JobApplication ||--o{ Attachment : attachments
JobApplication ||--o{ JobEvent : events
JobApplication ||--o| TailoredCvDraft : "1:1 draft"
CvUploadArtifact ||--o{ CvExtractionRun : "source of"
ApplicationUser ||--o{ GmailReviewDecision : decides
```
Key notes:
- `ApplicationUser` (IdentityUser) also stores profile CV text, **structured CV JSON** (`ProfileCvStructureJson`), avatar data-URL, Google link info, current CV artifact/run pointers.
- `JobApplication`: status string (default "Applied"), soft delete (`IsDeleted`/`DeletedAt`), tags as JSON string, imported description + translation, persisted `ShortSummary`, tailored CV text, reminder bookkeeping. Cascade deletes to messages/attachments/events/draft.
- `RuleSettings` (global, seeded Id=1) + per-user `UserRuleSettings`.
- `SystemEmailSettings`: DB-stored SMTP override (resolved by `EmailSettingsResolver`).
- Indexes: `OwnerUserId` on Company/JobApplication/GmailConnection; composite `(OwnerUserId, UploadedAtUtc)`, `(OwnerUserId, StartedAtUtc)`, unique `(OwnerUserId, JobApplicationId)` on draft, unique `(OwnerUserId, GmailAddress)`.
- SQLite file lives at `DataRoot/jobtracker.db` (WAL mode); migrations applied automatically at startup (`StartupInitializationExtensions`, 62 KB — also seeds admin, creates Identity tables where `dotnet ef` unavailable, ignores `PendingModelChangesWarning`).
---
## 6. API surface (all under `/api`, ~15 controllers)
| Controller | Highlights |
|---|---|
| `JobApplicationsController` (**151 KB!**) | CRUD, paging/filtering/sorting, board, reminders, stats, history, unified timeline, status/follow-up PATCH, soft delete/restore, **plus** AI surface: application package material, follow-up drafts, cover-letter/recruiter drafts ("Maria" drafts), workflow signals. |
| `ProfileCvController` (**117 KB**) | CV upload artifacts, extraction runs, structure parsing, rebuild/improve, tailored CV generation via Ollama rewrite, template rendering + Playwright PDF preview/export, benchmark corpus harness. |
| `GmailController` (**60 KB**) | OAuth connect/callback, sync, message review queue, import decisions, job matching. |
| `AuthController` (22 KB) | login/register/me/config, Google exchange, password reset request/reset, session cookie + CSRF endpoints. |
| `CompaniesController` | CRUD, idempotent create by name, recruiter/pipeline fields. |
| `CorrespondenceController` | per-job messages CRUD. |
| `AttachmentsController` | multipart upload to disk, download, rename, delete, purpose/AI-inclusion metadata. |
| `RulesController` | global + per-user rule settings, clamped. |
| `ExportController` | JSON/CSV export. |
| `BackupController` | DPAPI-encrypted backup (Windows only). |
| `JobImportController` | URL preview via plugin parsers (SSRF-hardened). |
| `UsersController`, `AdminAuditController`, `AdminSystemController` | admin: user/role management, audit trail, system readiness (DB/Gmail/AI). |
| `ClientErrorsController` | frontend error intake → logs. |
No OpenAPI/Swagger is wired up; the README is the de-facto API doc (already drifting).
---
## 7. Background services (6 hosted services)
| Service | Function |
|---|---|
| `RulesHostedService` → `RulesEngine` | periodic auto-transitions (e.g., → Ghosted) from rule settings |
| `FollowUpReminderHostedService` | reminder emails for due/upcoming follow-ups (dedup via `LastReminderEmailSentAt`) |
| `DailyExportHostedService` | daily JSON export at configured local hour |
| `JobEnrichmentHostedService` | backfills summaries/enrichment for jobs |
| `SummarizerProbeHostedService` | probes AI service readiness |
| `CvProcessingHostedService` + `CvProcessingQueue` | in-memory queue for CV extraction/processing jobs |
All state is in-process (`IMemoryCache`, in-memory queue) — single-instance assumption; no distributed locks; queue contents lost on restart.
---
## 8. AI pipeline (data flow)
1. **Job import**: URL → plugin parse (Finn/NAV/LinkedIn/Jobbnorge or universal JSON-LD parser) → optional LibreTranslate → language detect + skill tagging → preview → user accepts → stored on `JobApplication`.
2. **Summaries**: API → `SummarizerService` (31 KB) → FastAPI `/summarize` (distilbart, TTL-cached, GPU-if-available) → persisted `ShortSummary`.
3. **CV ingest**: upload (PDF/DOCX/image ≤ 8 MB) → FastAPI extract/OCR → block classification (Ollama-assisted, `CvAiClassifier`/`CvAiNormalizer`) → `ProfileCvStructureJson` on user.
4. **Tailoring**: job description + structured CV sections → Ollama rewrite path (recent commits: clamped lengths, hardened diagnostics) → `TailoredCvDraft` (JSON blocks) → `CvTemplateRenderer` (25 KB, template carousel) → Playwright → PDF.
5. **Drafts**: cover letter / recruiter message / follow-up drafts generated per job with attachment-aware context selection.
Degradation: if AI service or Ollama is down, core tracking still works (probe service + "AI is not a deploy gate" in CI).
---
## 9. Email
- `SmtpEmailSender` with `EmailSettingsResolver`: config from env/appsettings **or** DB-stored `SystemEmailSettings` (admin-editable).
- Uses Gmail SMTP + app password in prod. Flows: password reset, follow-up reminders. `App:PublicBaseUrl` builds links.
---
## 10. Configuration & secrets
- `.env` (git-ignored) → docker-compose env → ASP.NET config. `.env.example` documents the shape. Real secrets currently present in local `.env` (JWT key, admin password, SMTP app password, Google client secret).
- `appsettings.Development.json` contains only `CHANGE_ME_*` placeholders (good).
- Key knobs: `Database:Provider`, `ConnectionStrings:JobTracker`, `Data:Root`, `Cors:Origins`, `Ai:BaseUrl`, `Auth:*`, `Email:*`, `Exports:*`, `Translation:*`, `App:PublicBaseUrl`, `HttpsRedirection:*` (TLS terminated at reverse proxy; HSTS/redirect off in-container).
- `ProductionConfigTests.cs` exists to guard prod config shape.
---
## 11. Build, CI/CD, deployment
- **CI** (`.gitea/workflows/ci-deploy.yml`): on PR + push-to-main → build backend (Release), run backend tests, `npm ci`, run an **explicit whitelist of 10 frontend test files** (not the whole suite), build frontend.
- **Deploy** (push to main only): SSH to prod host → `git reset --hard <sha>` in `/opt/job-tracker/app` → `deploy/deploy.sh` (docker compose build/up with retry/cache-prune fallbacks) → verify containers; AI service health is non-blocking.
- Frontend Dockerfile: node build stage → nginx 1.29-alpine (working-tree bump from 1.27 pending commit); nginx proxies `/api` to backend.
- No staging environment; deploys go straight to prod after CI.
---
## 12. Testing strategy
- **Backend**: xUnit integration-style tests via `TestHostFactory`; notable coverage: authorization (`JobApplicationsAuthorizationTests`, `OwnershipGuardTests`, hostile fixture DB project), auth/system, Gmail, CV corpus harness, summarizer, SQLite migration helper, production config.
- **Frontend**: ~20 Jest/RTL test files (workspace flows, Gmail review, login, admin, attachments, drafts, trust-loop e2e-ish component tests). CI runs only the whitelisted subset.
- **AI service**: pytest (`tools/summarizer/tests/test_app.py`).
- No true end-to-end browser tests; no load/perf tests.
---
## 13. Logging & error handling
- Console/debug logging; custom middleware logs every request (method, path, status, ms, traceId, sub claim). Unhandled exceptions logged then rethrown (500).
- Client errors POSTed to `/api/client-errors` and logged server-side; React `ErrorBoundary` + route error page in UI.
- No structured sink (Seq/OTLP), no log rotation policy in-app (container stdout), no correlation to frontend errorIds beyond log text, no ProblemDetails standardization.
---
## 14. Security posture (current)
Strong points (much already hardened via M013–M015 adversarial assessments in `docs/security-assessments/`):
- SSRF on job import **fixed & retested** (DNS resolution check, private/loopback/link-local rejection, redirects disabled).
- Subjectless-JWT / owner-filter bypass **fixed & retested** (fail-closed identity, deny-on-null query filters).
- Cross-user job history leak fixed (`81196374`); authorization replay findings recorded (M015).
- CSRF double-submit for cookie sessions; CORS allowlist; rate-limited login/email endpoints; ephemeral JWT key refused when auth required; Identity password hashing (PBKDF2); DataProtection keys persisted outside repo runtime path.
Open questions / watch areas (to verify in Phase 6):
- `AllowCredentials()` combined with configurable `Cors:Origins="*"` wildcard mode (SetIsOriginAllowed(true) + credentials) — dangerous if ever enabled.
- Attachment upload: file-type/size limits, path handling, content-type on download need re-audit.
- Avatar stored as data-URL on user record (size/XSS considerations).
- Gmail OAuth token storage encryption at rest; scopes; audit of `GmailController` (60 KB).
- Global rate limiting only on 2 auth policies — AI/expensive endpoints unthrottled.
- Backup endpoint Windows-only DPAPI — silently unavailable on Linux prod.
- Dependency freshness (axios, react-scripts 5/CRA is deprecated upstream; transformers/torch pinning).
- Secrets present in local `.env` (expected, git-ignored) — confirm no history leaks.
---
## 15. Technical debt report
1. **God controllers**: `JobApplicationsController` (151 KB), `ProfileCvController` (117 KB), `GmailController` (60 KB), `StartupInitializationExtensions` (62 KB). Massive single files mixing HTTP, business logic, AI prompt construction, and persistence. Highest-leverage refactor target — but high risk, needs test cover first.
2. **Transitional project layout**: `JobTrackerBackend` compiles files it doesn't own via glob includes; root `Models/`/`Data/` folders; **dead** root `Controller/` folder; `JobTrackerBackend/bin`+`obj` artifacts and `JobTrackerApi/jobtracker.db` + `bin_build/`, `CvArtifacts/`, `exports/`, `keys/` polluting the repo/working tree. `.gitignore` needs review.
3. **CI runs a hand-maintained subset** of frontend tests — new test files silently not run (already bit them once; `profile-page.test.tsx` had to be added manually).
4. **CRA/react-scripts 5** is EOL-ish, slow builds (needs 4 GB heap), TS 4.9. Vite migration is the obvious path (medium effort).
5. **Naming drift**: `Summarizer*` vs `AiService*`; "Jobbjakt" vs "Job Tracker" branding split; EN/NB translation consistency flagged in handoff doc.
6. No OpenAPI; README endpoint list already drifts from code (e.g., Gmail/profile/admin endpoints missing there).
7. In-memory queue/cache single-instance coupling undocumented.
8. Root-level clutter: `temp_job.json`, `temp_post_job.py`, `todo jobtracker.txt`, `test/`, `tmp/`, `vendor/`, `.venv/`.
9. `DaysSince` compares `DateTime.UtcNow` with `.Days` truncation — timezone/UX edge cases; status is a free string, no canonical pipeline enum (README itself lists this as a wanted improvement).
10. Windows-only backup path.
---
## 16. Areas of concern
- **Single point of data**: SQLite in a Docker volume; backups are manual/Windows-only; no automated off-host backup.
- **Deploy risk**: `git reset --hard` + straight-to-prod with no staging and non-exhaustive CI test coverage.
- **AI coupling**: prompt logic buried in controllers makes model/provider changes and testing hard.
- **Restart data loss**: queued CV processing jobs are lost on restart (in-memory queue).
- **Uncommitted working tree**: 3 modified files (Dockerfile nginx bump, `useViewResource` stale-closure fix, handoff doc) + untracked `scripts/start-ollama-cv.ps1` and a stray `JobTrackerApi/CvArtifacts/` data folder.
---
## 17. Opportunities for improvement (input to Phase 2/3)
Product (initial hypotheses, to be validated by market research):
- Canonical pipeline model + customizable Kanban stages (already on README wish list).
- Interview scheduling/prep hub (calendar integration, prep notes, question banks).
- Salary/offer comparison and analytics dashboards (funnel conversion, response rates, time-in-stage).
- Browser extension / bookmarklet for one-click job capture (plugins already exist server-side).
- Saved searches/views, full-text search, date-range and tag filters.
- Notifications beyond email (web push, digest).
- Contact-level recruiter CRM (people, not just companies).
- Mobile-friendly PWA pass.
Engineering:
- Swagger/OpenAPI + generated TS client; ProblemDetails everywhere.
- Split god controllers into feature services; move AI prompting behind interfaces.
- Run full frontend test suite in CI (`npm test -- --watchAll=false` without whitelist) once flaky tests are addressed; add `dotnet format`/eslint gates.
- Vite migration; dependency refresh.
- Durable job queue (DB-backed) for CV processing; automated DB backup job.
- Repo hygiene: delete dead `Controller/`, ignore build artifacts, remove committed DB files.
@@ -0,0 +1 @@
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJKb2JUcmFja2VyQXBpIiwiYXVkIjoiam9iLXRyYWNrZXItdWkiLCJuYmYiOjE3NzQ2MDE0ODEsImV4cCI6MTc3NDY0NDY4NiwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbmFtZWlkZW50aWZpZXIiOiIyM2RjMTk2Yi1mMjI3LTQ0OTktOTNmZS00MDNkODgwMWUyMWMiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9lbWFpbGFkZHJlc3MiOiJhZG1pbkBleGFtcGxlLmNvbSIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJhZG1pbkBleGFtcGxlLmNvbSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6IkFkbWluIn0.xraA-RMiGjTYEwH27uwgoDrqkgTkVa86Q54A9b15Vts
+20
View File
@@ -0,0 +1,20 @@
# Jobjakt Development Context
Before making changes:
1. Read docs/00-ai-context.md
2. Read relevant feature documentation
3. Check existing implementation
4. Prefer incremental changes
The application is a job tracking platform.
The CV builder is a supporting Career Workspace feature.
Never redesign Jobjakt into only a CV builder.
Existing working functionality must be preserved.
When uncertain:
- Ask for clarification.
- Do not make large assumptions.
@@ -0,0 +1,224 @@
# CV builder, parser, benchmark, and Ollama admin integration
## What changed
This branch upgrades the Profile CV flow from a text-only rewrite helper into a template-driven CV builder backed by the server-side renderer/PDF pipeline, strengthens CV normalization around location and qualification handling, adds a repeatable local corpus benchmark workflow, and expands the admin system page with richer Ollama visibility.
## Profile CV builder
### New backend capabilities
`JobTrackerApi/Controllers/ProfileCvController.cs`
- Hardened `POST /api/profile-cv/rewrite-section`
- accepts flexible `jobApplicationId` payloads (number or blank string)
- uses richer saved-job context for tailoring
- logs empty AI responses with useful context
- Added `GET /api/profile-cv/templates`
- Added `POST /api/profile-cv/rewrite-preview`
- rewrites either the whole CV or one selected section
- rebuilds structured CV from the rewritten full text
- maps the result into the shared template renderer
- returns rendered HTML, file name, rewritten text, and full replacement text
- Added `POST /api/profile-cv/export-pdf`
- uses the same rendered HTML and the shared Playwright exporter
### Frontend flow
`job-tracker-ui/src/pages/ProfilePage.tsx`
- Replaced the old rewrite draft box with a template-driven builder section.
- Users can:
- choose from 6 templates
- optionally target one section
- target by free-text role or saved job
- inspect the rewritten content
- inspect the actual rendered preview
- download a PDF
- replace the master CV with the rebuilt full-text result
## Templates
Shared renderer: `JobTrackerApi/Services/CvTemplateRenderer.cs`
Available templates:
- `ats-minimal`
- `harvard`
- `auckland`
- `edinburgh`
- `monarch`
- `fjord`
### Adding a new template
1. Add the new template id to `NormalizeTemplateId()` in:
- `JobTrackerApi/Services/CvTemplateRenderer.cs`
- `JobTrackerApi/Controllers/ProfileCvController.cs`
2. Add a render branch in `CvTemplateRenderer.Render()`.
3. Add a descriptor to `GetCvTemplateDescriptors()`.
4. Add the matching card entry in `job-tracker-ui/src/pages/ProfilePage.tsx` if you want a custom preview card.
## PDF generation
The master CV builder now reuses the existing server-side pipeline:
1. rewrite full text / section
2. rebuild structured CV
3. map to `TailoredCvDocument`
4. render HTML via `ICvTemplateRenderer`
5. export PDF via `ICvPdfExporter` / Playwright
This keeps PDF output visually aligned with the selected template and avoids a separate client-only print implementation.
## Parser and structured CV changes
### Shared schema
`Models/StructuredCvProfile.cs`
Added:
- `education[].qualificationLevel`
- top-level `certifications[]`
- top-level `projects[]`
`qualification` remains the original preserved text.
### Normalization improvements
`Models/StructuredCvProfileJson.cs`
- tighter location sanitization to avoid skill or role spillover into location fields
- qualification level normalization to one of:
- `Secondary`
- `Diploma/Certificate`
- `Bachelor`
- `Master`
- `PhD`
- `Other`
- first-class normalization for certifications and projects
- section reconstruction now includes certifications and projects
### Extraction prompt improvements
`JobTrackerApi/Controllers/ProfileCvController.cs`
The LLM extraction prompt now explicitly asks for:
- qualification level enum
- certifications
- projects
- strict location separation rules
- preservation of original qualification text
## Benchmark workflow
### Runner
Use:
```bash
./scripts/run-cv-benchmark.sh
```
Optional overrides:
```bash
CV_BENCHMARK_OUTPUT_DIR=/absolute/output/path \
CV_BENCHMARK_APPROVED_DIR=/absolute/approved/fixtures/path \
./scripts/run-cv-benchmark.sh
```
### Inputs
The runner scans:
- `/home/pi/cvs`
Supported corpus file types:
- PDF
- DOCX
- TXT
- MD
### Outputs
The runner writes:
- `index.json` — machine-readable summary
- `report.md` — markdown overview
- `outputs/*.json` — latest normalized structured output per CV
- `candidate-fixtures/*.json` — created when no approved fixture exists yet
Approved fixtures are local by design and should be reviewed manually before being promoted into the approved fixture path you use for regression comparisons.
### Admin review
`GET /api/admin/system/cv-benchmark`
The admin system page surfaces:
- benchmark root path
- last benchmark update time
- latest markdown summary
## Ollama admin visibility
### Python health endpoint
`tools/summarizer/app.py`
`GET /health` now returns additional Ollama metadata when configured/reachable:
- `ollama_version`
- `ollama_installed_models`
- `ollama_loaded_models`
- `ollama_loaded_count`
### Backend propagation
`JobTrackerApi/Services/SummarizerService.cs`
The backend metrics shape now carries those fields through to admin consumers.
### Admin UI
`job-tracker-ui/src/pages/AdminSystemPage.tsx`
The system page now shows:
- Ollama version
- loaded model count
- installed model chips
- loaded model chips
- benchmark summary panel
## Verification used on this branch
### Backend
```bash
dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter ProfileCvControllerTests
dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter "ProfileCvControllerTests|AuthAndSystemControllerTests|JobApplicationsApplicationPackageTests"
dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter CvCorpusHarnessTests
```
### Frontend
```bash
cd job-tracker-ui && CI=true npm test -- --runInBand --watch=false src/profile-page.test.tsx
cd job-tracker-ui && CI=true npm test -- --runInBand --watch=false src/admin-system-page.test.tsx
cd job-tracker-ui && CI=true npm test -- --runInBand --watch=false src/profile-page.test.tsx src/admin-system-page.test.tsx src/job-details-generated-drafts.test.tsx
```
### Benchmark runner
```bash
CV_BENCHMARK_OUTPUT_DIR="$(pwd)/tmp/cv-benchmarks/latest" \
CV_BENCHMARK_APPROVED_DIR="$(pwd)/tmp/cv-benchmarks/approved" \
./scripts/run-cv-benchmark.sh
```
### Python service tests
The summarizer Python unit tests were updated for the new health payload, but this machine currently lacks `pip` / `venv` support (`python3 -m venv` fails because `python3.12-venv` is not installed), so test execution is environment-blocked here. Once Python packaging is available, run:
```bash
cd tools/summarizer
python3 -m pytest -q tests/test_app.py
```
+732
View File
@@ -0,0 +1,732 @@
# AI Development Context
## Jobjakt
Version: 1.0
Status: Living document
Last Updated: YYYY-MM-DD
---
# Purpose
This document is the primary source of truth for AI-assisted development.
Every AI assistant (Claude Code, Codex, ChatGPT, GitHub Copilot, etc.) should read this document before making architectural decisions or implementing new features.
If another document conflicts with this file, this file takes precedence unless an Architecture Decision Record (ADR) explicitly supersedes it.
---
# What is Jobjakt?
Jobjakt is an AI-powered job tracking and career management platform.
Its purpose is to help people organise, improve and manage their entire job search from one place.
Unlike traditional job trackers, Jobjakt assists users throughout the complete application lifecycle using AI-powered career tools.
The application is designed to evolve into a SaaS platform but currently prioritises an excellent single-user experience.
---
# Product Philosophy
Jobjakt is NOT:
- just a CV builder
- just another AI wrapper
- another job board
- another Kanban clone
Instead, Jobjakt is a Career Workspace.
The job tracking workflow remains the primary product.
Everything else exists to improve the user's ability to secure employment.
Always remember:
Jobs are the product.
Career tools support the product.
Never invert this relationship.
---
# Product Hierarchy
Core Product
Job Tracking
↓
Applications
↓
Application Workflow
↓
Communication
↓
Follow Ups
↓
Career Workspace
↓
Career Profile
↓
CV Builder
↓
Cover Letters
↓
Portfolio
↓
Interview Preparation
↓
Future Career Outputs
Future enhancements should strengthen this workflow, never replace it.
---
# Target Audience
Primary:
- Individual job seekers
Secondary:
- Graduates
- Career changers
- Software engineers
- Technical professionals
- Knowledge workers
Future:
- SaaS customers
- Premium subscribers
There is currently no requirement for recruiter functionality.
---
# Design Philosophy
The application should feel:
- Modern
- Professional
- Fast
- Calm
- Clean
- Premium
- AI-native
- Notion-inspired
- Productivity focused
Primary inspirations:
- Notion
- Linear
- FlowCV
- Jobscan
Avoid:
- clutter
- unnecessary dialogs
- confusing navigation
- feature overload
- excessive configuration
The UI should feel approachable while remaining powerful.
---
# Core Principles
## Principle 1
Working software is more valuable than rewrites.
Prefer incremental improvements.
---
## Principle 2
Do not rewrite large areas unless absolutely necessary.
Refactor gradually.
---
## Principle 3
Preserve backwards compatibility wherever practical.
---
## Principle 4
Every new feature should integrate naturally into the existing workflow.
Avoid bolting features onto random pages.
---
## Principle 5
Reduce complexity whenever possible.
If something can be achieved with one screen instead of three, prefer one.
---
## Principle 6
Everything should have one obvious place.
Avoid duplicated functionality.
---
# Core Workflow
The application revolves around a single journey.
Discover Job
↓
Import Job
↓
Review Job
↓
Apply
↓
Track Progress
↓
Receive Communication
↓
Prepare Interview
↓
Accept / Reject Offer
Career tools enhance this process.
---
# Career Workspace
Career Workspace is the second major feature area.
It should never overshadow Job Tracking.
Purpose:
Maintain one structured professional profile.
Generate multiple outputs.
Everything should originate from one source of truth.
---
# Source of Truth
There is exactly ONE master career profile.
It contains:
- personal information
- experience
- education
- skills
- projects
- certifications
- languages
- awards
- publications
- organisations
- references
Users may edit this manually at any time.
The master profile is never automatically overwritten.
---
# CV Strategy
The CV builder is NOT the user's data.
It is only a presentation layer.
Relationship:
Master Career Profile
↓
CV Builder
↓
Theme
↓
Generated CV
↓
PDF / HTML / DOCX
Never duplicate user data between templates.
---
# Tailored CV Strategy
Users create tailored CVs from their master profile.
Workflow:
Master Career Profile
↓
Job Analysis
↓
AI Suggestions
↓
User Review
↓
User Edits
↓
Save Against Application
↓
Export
Users may manually edit every generated CV.
AI never has final control.
---
# Public CVs
Supported feature.
Users can choose whether a CV is public.
If enabled:
Generate:
/cv/{random-guid}
No usernames initially.
Privacy first.
---
# Job Tracking
The application revolves around Applications.
Data hierarchy:
Company
↓
Job Opportunity
↓
Application
↓
Communication
↓
Follow Ups
↓
Documents
Companies are reusable.
Users may apply for multiple roles at the same company.
---
# Communication
Every application should eventually contain:
- Emails
- Notes
- Follow Ups
- Attachments
- Timeline
- AI Insights
---
# User Journey
Ideal onboarding:
Register
↓
Verify Email
↓
Create Profile
↓
Import CV
↓
Review Career Profile
↓
Connect Email
↓
Import First Job
↓
Generate First CV
↓
Begin Tracking Applications
The onboarding experience should guide the user through this journey.
---
# Authentication
Supported:
- Email/password
- Google
- Microsoft
Future:
- Passkeys
- Additional OAuth providers
Security features:
- Email verification
- Password reset
- 2FA
- CAPTCHA
- Rate limiting
- Session management
---
# AI
The application supports multiple providers.
Architecture:
Provider Interface
↓
OpenAI
Gemini
Claude
Ollama
Future Providers
The admin controls available providers.
Users should never be locked into one AI model.
---
# AI Behaviour
AI assists.
Users decide.
AI must never silently alter important user data.
Every generated result should be reviewable.
---
# UI Principles
Every page should:
Have one clear purpose.
One primary action.
Consistent spacing.
Consistent typography.
Predictable navigation.
Avoid overwhelming new users.
---
# CV Builder Inspiration
Reference applications:
FlowCV
ElegantCV
Reactive Resume
Novoresume
Purpose:
Study:
- UX
- Workflows
- Features
- Theme systems
Do NOT:
- Copy code
- Copy branding
- Copy assets
---
# HTML Reference
Reference HTML:
D:\FlowCV
For research only.
Never copy.
---
# Future Vision
The application should gradually evolve into a Career Workspace.
Possible future outputs:
- CV
- Cover Letter
- Public Profile
- Portfolio
- LinkedIn Summary
- Interview Preparation
- Personal Website
These all originate from one career profile.
---
# SaaS Readiness
Architecture should support:
- subscriptions
- premium themes
- AI limits
- storage limits
- billing
- Stripe
- feature flags
Do not over-engineer before needed.
Excellent UX is more important.
---
# Coding Philosophy
Prefer:
Small services
Small components
Good naming
Composition
Dependency injection
Testability
Readable code
Avoid:
Massive controllers
God services
Duplicated logic
Large React components
Magic strings
Hidden business logic
---
# Working Style
Before implementing anything:
1. Read relevant documentation.
2. Analyse current implementation.
3. Compare current state with target state.
4. Produce a short implementation plan.
5. Implement incrementally.
6. Update documentation.
7. Test thoroughly.
---
# Decision Making
When multiple solutions exist:
Choose the solution that:
- improves UX
- reduces maintenance
- keeps architecture clean
- supports future SaaS
- preserves current functionality
---
# What AI Should Never Do
Never:
Rewrite the application from scratch.
Break existing functionality.
Duplicate existing systems.
Ignore existing architecture.
Remove features without justification.
Invent requirements.
Ignore documentation.
---
# Documentation
Whenever a significant architectural decision is made:
Create or update an ADR.
Keep documentation current.
Documentation is considered part of the application.
---
# Final Reminder
Jobjakt exists to help people get jobs.
Every feature should ultimately help users:
- discover opportunities
- apply faster
- improve applications
- stay organised
- secure interviews
- secure employment
If a proposed feature does not support that mission, reconsider whether it belongs in the product.
+270
View File
@@ -0,0 +1,270 @@
# Jobjakt Glossary
## Purpose
Defines common terminology used throughout the application.
This prevents ambiguity between product, UX, backend, frontend, and AI development.
---
# Core Terms
## Job
A job opportunity that a user may be interested in.
Examples:
- Software Engineer role.
- Developer position.
- Analyst role.
A Job may exist before an application is submitted.
---
## Job Opportunity
A specific role offered by a company.
Contains:
- Job title.
- Company.
- Description.
- Location.
- Salary information.
- Requirements.
---
## Application
A user's attempt to obtain a specific job.
Relationship:
Company
↓
Job Opportunity
↓
Application
---
## Application Stage
The current state of an application.
Examples:
- Interested
- Preparing
- Applied
- Screening
- Interview
- Offer
- Rejected
- Withdrawn
---
## Company
An organisation offering employment.
Companies are reusable entities.
Example:
A user may apply for:
- Backend Developer
- Frontend Developer
at the same company.
---
# Career Workspace
## Career Profile
The user's professional source of truth.
Contains:
- Personal details.
- Experience.
- Education.
- Skills.
- Projects.
- Certifications.
- Achievements.
The career profile is NOT a CV.
It is the data used to create outputs.
---
## Master CV
A generated representation of the Career Profile.
Purpose:
Provide a default CV.
It can be customised but should originate from the Career Profile.
---
## CV Variant
A different presentation of the same career information.
Examples:
- Software Engineer CV.
- Management CV.
- Academic CV.
Variants should not duplicate career data.
---
## Tailored CV
A CV adapted for a specific job application.
Created from:
Master Career Profile
+
Job Description
+
AI Suggestions
---
## CV Theme
The visual design system used to render a CV.
Contains:
- Layout.
- Typography.
- Colours.
- Spacing.
- Components.
Themes should not contain user data.
---
# AI Terms
## AI Provider
A service capable of generating AI responses.
Examples:
- OpenAI.
- Gemini.
- Claude.
- Ollama.
---
## AI Generation
Any content created or improved by AI.
Examples:
- CV bullet improvements.
- Cover letters.
- Job matching.
---
## AI Suggestion
A recommendation from AI that requires user approval.
---
# Documents
## Cover Letter
A document explaining why a user is suitable for a specific role.
---
## Portfolio
A collection of professional work.
Examples:
- Projects.
- Case studies.
- Publications.
---
# User
A person using Jobjakt.
---
# Admin
A user with system management permissions.
Admins manage:
- AI providers.
- System settings.
- Feature controls.
---
# Career Workspace
The collection of tools supporting the user's career development.
Includes:
- Career Profile.
- CV Builder.
- Cover Letters.
- Portfolio.
- Future career tools.
---
# SaaS
Future commercial version of Jobjakt.
Potential features:
- Subscriptions.
- Premium themes.
- AI limits.
- Storage limits.
+105
View File
@@ -0,0 +1,105 @@
# Product Principles
## Purpose
Defines the principles that guide product decisions.
---
# Principle 1
## Job Tracking Comes First
Jobjakt exists primarily to help users manage their job search.
Every major decision should support:
- Finding jobs.
- Applying efficiently.
- Tracking progress.
- Improving outcomes.
---
# Principle 2
## Career Data Is the Foundation
Users should maintain one professional identity.
The application should avoid:
- Multiple disconnected profiles.
- Re-entering information.
- Duplicating career history.
---
# Principle 3
## AI Assists, Humans Decide
AI should:
- Suggest.
- Improve.
- Analyse.
- Accelerate.
AI should not:
- Replace user judgement.
- Modify facts silently.
- Invent experience.
---
# Principle 4
## Simplicity Over Complexity
Powerful features should remain approachable.
Avoid:
- Complex workflows.
- Excessive configuration.
- Feature overload.
---
# Principle 5
## Progressive Disclosure
Show users what they need when they need it.
Example:
New users:
Simple CV creation.
Advanced users:
Custom themes, AI tools, detailed controls.
---
# Principle 6
## Quality Over Quantity
A small number of excellent features is better than many unfinished features.
---
# Principle 7
## SaaS Ready, Not SaaS First
Architecture should allow future growth.
However:
Do not sacrifice user experience today for hypothetical future requirements.
+113
View File
@@ -0,0 +1,113 @@
# Design Principles
## Goal
Create a premium, modern career management experience.
---
# Visual Direction
The application should feel:
- Professional.
- Modern.
- Calm.
- Intelligent.
- Trustworthy.
---
# Inspirations
## Notion
For:
- Organisation.
- Clean interfaces.
- Flexible content.
## Linear
For:
- Professional software feel.
- Speed.
- Keyboard-friendly workflows.
## FlowCV
For:
- CV creation experience.
- Template selection.
- Visual editing.
## Jobscan
For:
- Career optimisation.
---
# Navigation
Users should always understand:
Where am I?
What can I do?
What happens next?
---
# Forms
Forms should:
- Be grouped logically.
- Explain fields.
- Validate clearly.
- Avoid unnecessary questions.
---
# Empty States
Every empty state should explain:
- Why it matters.
- What action to take.
- How to get started.
---
# Errors
Errors should:
- Explain what happened.
- Suggest next steps.
- Avoid technical language.
---
# Dark Mode
Dark mode should be supported.
It should feel designed, not inverted.
---
# Accessibility
All features should consider:
- Keyboard navigation.
- Screen readers.
- Contrast.
- Clear focus states.
+3
View File
@@ -0,0 +1,3 @@
# overview
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# prompts
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# providers
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# safety
TODO: Complete documentation.
@@ -0,0 +1,3 @@
# backend
TODO: Complete documentation.
@@ -0,0 +1,3 @@
# current
TODO: Complete documentation.
@@ -0,0 +1,3 @@
# database
TODO: Complete documentation.
@@ -0,0 +1,3 @@
# deployment
TODO: Complete documentation.
@@ -0,0 +1,3 @@
# frontend
TODO: Complete documentation.
@@ -0,0 +1,3 @@
# future
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# 2fa
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# login
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# oauth
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# overview
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# signup
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# education
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# experience
TODO: Complete documentation.
@@ -0,0 +1,3 @@
# master-profile
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# overview
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# projects
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# skills
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# ai
TODO: Complete documentation.
@@ -0,0 +1,3 @@
# builder
TODO: Complete documentation.
@@ -0,0 +1,3 @@
# overview
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# ai
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# content
TODO: Complete documentation.
@@ -0,0 +1,3 @@
# customisation
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# exports
TODO: Complete documentation.
@@ -0,0 +1,3 @@
# overview
TODO: Complete documentation.
@@ -0,0 +1,3 @@
# rendering
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# themes
TODO: Complete documentation.
@@ -0,0 +1,3 @@
# workflow
TODO: Complete documentation.
@@ -0,0 +1,3 @@
# documentation-rules
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# applications
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# companies
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# followups
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# job-import
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# job-search
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# overview
TODO: Complete documentation.
@@ -0,0 +1,3 @@
# business-model
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# goals
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# mission
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# non-goals
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# personas
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# roadmap
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# vision
TODO: Complete documentation.
+3
View File
@@ -0,0 +1,3 @@
# flowcv
TODO: Complete documentation.

Some files were not shown because too many files have changed in this diff Show More