feat: complete release readiness work

- consolidate API ownership and remove dead vendor code

- add Stripe billing, learning paths, and public CV hardening

- add migration, recovery, security, audit, and browser gates
This commit is contained in:
cesnimda
2026-07-31 16:54:16 +02:00
parent a23c3dfc97
commit ce76046a29
1634 changed files with 6889 additions and 135429 deletions
+20 -4
View File
@@ -5,6 +5,7 @@ Job Tracker is a simple, self-hosted app for tracking job applications with a Re
## Features (high level)
- Track job applications (status, applied date, notes, tags, follow-up dates, deadlines, salary, links, etc.)
- Share opt-in public CV links with recruiter-friendly PDF download
- Company management (location/source, recruiter details, pipeline stage, next contact date)
- Correspondence log per application (email/messages with subject/channel/date)
- Attachments per application (upload, list, download, rename, delete)
@@ -16,6 +17,7 @@ Job Tracker is a simple, self-hosted app for tracking job applications with a Re
- Note: no offline service-worker cache is bundled by design (the app is deployed frequently; an aggressive cache would risk serving stale builds). The manifest provides installability and share-to-capture without it.
- Optional local AI service for short/full descriptions
- Optional Google sign-in (Google ID tokens) to protect the API
- Standard Problem Details responses with trace IDs for unhandled API errors
## Architecture
@@ -103,7 +105,18 @@ npm start
The UI defaults to calling `http://localhost:5202/api` when running on localhost (see `job-tracker-ui/src/api.ts`).
### 3) (Optional) Run the AI service
### 3) Run the browser smoke suite
```bash
cd job-tracker-ui
npx playwright install chromium
npm run test:e2e
```
The suite starts isolated API/SQLite and Next.js processes, then covers login, saved-job creation,
Career Workspace, and anonymous public-CV/PDF access. It is also a required CI gate.
### 4) (Optional) Run the AI service
The API calls a local FastAPI service to generate summaries. If its not running, the app still works (summary generation may be empty / best-effort).
@@ -130,7 +143,8 @@ Common keys:
- `ConnectionStrings:JobTracker`: overrides SQLite location (otherwise uses `DataRoot/jobtracker.db`)
- `Data:Root`: folder for the SQLite DB + exports (defaults to API content root)
- `Data:AttachmentsRoot`: override attachments folder (defaults to `<Data:Root>/Attachments`)
- `Cors:Origins`: list of allowed origins (defaults to `http://localhost:3000`; use `"*"` to allow all)
- `CvExports:RetainDays`: generated PDF retention in days (default `30`, clamped to `1``365`)
- `Cors:Origins`: list of allowed origins (defaults to `http://localhost:3000`; wildcard origins are rejected because requests use credentials)
- `Ai:BaseUrl`: AI service base URL (default `http://127.0.0.1:8001`)
- `Exports:DailyEnabled`: enable/disable daily export background job
- `Exports:DailyFolder`: export destination (relative to `Data:Root` if not absolute)
@@ -147,6 +161,8 @@ Common keys:
- `Auth:AdminEmail` / `Auth:AdminPassword`: optional seed admin user (created on startup if missing)
- `Auth:AllowRegistration`: allow self-service registration via `POST /api/auth/register` (default `false`)
- `Auth:Require`: if `true`, all endpoints require auth (except endpoints explicitly marked anonymous)
- `Stripe:SecretKey`, `Stripe:PricePremium`, `Stripe:WebhookSecret`: enable hosted Premium checkout,
the customer portal, and signed subscription webhooks when all are configured
- `Translation:Provider`: `none` (default) or `libretranslate`
- `Translation:LibreTranslate:BaseUrl`: base URL for LibreTranslate (only if provider enabled)
- `Translation:LibreTranslate:ApiKey`: optional API key for LibreTranslate
@@ -163,7 +179,7 @@ Common keys:
### UI settings
- `REACT_APP_API_BASE_URL`: override the API base URL (example: `http://localhost:5202/api`)
- `NEXT_PUBLIC_API_BASE_URL`: override the API base URL (example: `http://localhost:5202/api`)
## API endpoint reference
@@ -206,7 +222,7 @@ Authentication:
- `GET /api/jobapplications/stats`
- Returns totals, counts by status, applied-last-30-days, and average days since applied.
- `GET /api/jobapplications/{id}/match-score`
- Deterministic CV↔job keyword-coverage score (0100) with matched/missing keywords and per-CV-section coverage. No AI calls: results are instant and reproducible. Requires profile CV text/structure and a job description. (The AI narrative equivalent is `GET /api/jobapplications/{id}/candidate-fit`.)
- Deterministic CV↔job keyword-coverage score (0100) with matched/missing keywords and per-CV-section coverage. Missing skills also seed a checklist-backed job-specific learning path, so users can mark them learned or dismiss them. No AI calls: results are instant and reproducible. Requires profile CV text/structure and a job description. (The AI narrative equivalent is `GET /api/jobapplications/{id}/candidate-fit`.)
- `GET /api/jobapplications/{id}/status-suggestion`
- Deterministic status suggestion derived from the job's most recent inbound message (interview invite / offer / rejection). Returns a forward-only suggestion (`hasSuggestion`, `suggestedStatus`, `signal`, …) or `hasSuggestion: false`. Applying it is a normal `PATCH .../status` — always user-confirmed.
- `DELETE /api/jobapplications/{id}`