Files
jobtrackingapp/docs/global-jobs/00/IMPLEMENTATION_CHECKPOINTS.md
T

127 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# International Job Discovery Implementation Plan
> **For agentic workers:** Use superpowers:executing-plans to implement this plan task-by-task only after explicit stage authorization. Delegation is not required by this plan. Do not start implementation from this document alone.
**Goal:** Deliver cross-industry, multilingual NO/SE/GB discovery while preserving Jobjakt's current data and document owners.
**Architecture:** Extend existing React/MUI discovery, .NET services and MariaDB. Use a source-rights registry, NAV local index, eligible live-query adapters and honest external/manual fallbacks; no generative model dependency.
**Tech stack:** React 19/Next.js static shell, TypeScript, MUI, ASP.NET/EF Core 9, MariaDB, existing background services and test tools.
**Spec:** [Master](../../planning/global-jobs-prompts/00_MASTER_ORCHESTRATOR.md), separate GJ-01–08 prompts, [architecture/contracts](ARCHITECTURE_ADRS.md), [acceptance](ACCEPTANCE_MATRIX.md).
## Global constraints
- Planning only now; Phase 10, PRODUCT-REVIEW-01, initiative approval and next-stage instruction precede implementation.
- No main merge, production operation, destructive data change, restricted scraping, consumer registration or paid-resource purchase.
- Preserve Career Profile, CV Import/Editor, applications, frozen packages, revisions, histories, all 57 groups/33 routes and MariaDB compatibility.
- Never enable live AI without independent qualification; core suggestions/matching are deterministic.
- Each stage stops after acceptance and publication. Later source branch includes accepted predecessors. Stage prompts override this proposed file breakdown if they conflict.
- Run `graphify query` before code exploration, trace every shared caller before changes, and `graphify update .` after code changes (no update needed for this docs-only stage).
## Review focus
1. Legacy FINN URL preview reaches HTML fetch before plugin selection: GJ04-F must deny it before network while keeping reviewed manual entry usable.
2. A withdrawn source moves location or loses fields: GJ04-G must remove it independent of old/new query filters and surviving duplicate sources.
3. Parent remains checked after town refinement: GJ02-C/D must query only refinements and roundtrip exact scope state.
4. Search edited/deleted while worker is sending: GJ06-B must recheck revision/owner/status and suppress obsolete delivery, including restart.
5. Source-content purge and user application evidence differ: GJ06-D/GJ07-C must enforce approved retention without deleting user notes or silently changing frozen history.
## Execution and evidence pattern
For each checkpoint below: record exact source/callers and baseline → add the specified failing contract/scenario test → run and preserve RED → make smallest complete change → run focused checks then required stage regressions → review diff/security/rights → document measured outcomes, commit/push only its authorized branch and verify remote HEAD → stop at stage end. Do not count focused reruns twice. New fixtures are synthetic or lawfully retained/redacted; no private CVs or credentials in evidence.
Representative existing commands (verify local SDK/package scripts/config at entry): `rtk dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter FullyQualifiedName~JobDiscovery`, `rtk npm test -- --runInBand job-discovery.test.tsx` from UI, and configured Playwright discovery specs. These are planned commands, not executed results. MariaDB uses the repository's existing isolated integration lane after its entry check; do not start Docker/DB or tests with unknown live service targets. TypeScript/lint/build and ordinary/separate browser lanes use current package scripts and explicit configs, serialized with PDF/build lanes. Capture native exits and discovery membership.
## GJ-01 — preferences and languages
Branch `feature/gj01-country-language-preferences`; authority [GJ-01](../../planning/global-jobs-prompts/02_GJ_01_PREFERENCES_I18N.md). Entry: all global gates above. Produces `SearchPreference` contract and persisted locale/default semantics from ADR-03.
Files: extend `JobTrackerApi/Models/ApplicationUser.cs`, `Controllers/AuthController.cs`, `Data/JobTrackerContext.cs`; proposed `Models/SearchPreference.cs`, preference controller/service and additive migration. Extend `job-tracker-ui/src/components/SettingsView.tsx`, `views/JobDiscoveryPage.tsx`, `i18n/I18nProvider.tsx`, `i18n/translations.ts`, `api.ts`/types where existing ownership requires. Test proposed `SearchPreferenceTests.cs`, UI preference/locale tests, existing settings e2e and account export/deletion contracts.
- [ ] GJ01-A: freeze DTO/schema validation, expected revision and empty legacy defaults; RED cross-owner/missing-owner/concurrent-write/old-account tests, then additive persistence. No schema deletions.
- [ ] GJ01-B: first-run/Settings defaults and optional residence distinct from work countries; test cross-device recovery and no nationality collection.
- [ ] GJ01-C: locale registry/native labels/prominence/Coming Later/fallback; complete required translations and missing-key checks; native language review stays separate.
- [ ] GJ01-D: initialize draft query from defaults, explicit Update defaults/save named profile boundary; test temporary overrides never persist accidentally. Named rich saved-search lifecycle is completed in GJ-06 using same query contract.
- [ ] GJ01-E: tenant/export/delete/revision/EN-Bokmål regressions and approved shipped-locale proof. Publish `docs/global-jobs/01/` acceptance and stop. Unqualified Swedish UI journey remains blocked, not silently counted passing.
## GJ-02 — geography
Branch `feature/gj02-geographic-search`; [GJ-02](../../planning/global-jobs-prompts/03_GJ_02_GEOGRAPHY.md). Consumes preferences; produces `LocationNode`, `LocationScope`, `LocationQueryPlan` contracts from ADR-03/geography decisions.
Files: proposed `Models/DiscoveryLocation.cs`, `Services/Discovery/LocationScopeCompiler.cs`, versioned reference importer under existing tooling conventions, `Controllers/DiscoveryLocationsController.cs`, EF mapping/migration, `src/components/discovery/LocationScopePicker.tsx` and shared discovery query types. Test `LocationScopeCompilerTests.cs`, MariaDB mapping/index tests, UI scope transitions, browser discovery specs.
- [ ] GJ02-A: obtain exact licensed snapshots/IDs/geometries, especially Warwick **town** versus district and overlapping SE/NO settlements. Block precise town query if no qualified footprint exists.
- [ ] GJ02-B: idempotent versioned import + typed relations/provider mapping + stale-ID review; tests prove no orphan/broadened saved scopes and no partial dataset swap.
- [ ] GJ02-C: implement scope/refinement controls; test every geography decision-table transition, collapse/save/reload and accessible announcements.
- [ ] GJ02-D: compile exact IDs/polygons, radius/multi-origin/remote rules; assert county-only job fails strict town/radius filter and out-of-parent radius result is disclosed.
- [ ] GJ02-E: measured lookup/query/load, keyboard/mobile/zoom tests and edition/licence ledger. Publish `docs/global-jobs/02/` and stop.
## GJ-03 — occupations
Branch `feature/gj03-occupation-search`; [GJ-03](../../planning/global-jobs-prompts/04_GJ_03_OCCUPATIONS.md). Consumes query/scopes; produces `OccupationConcept`/`OccupationQueryPlan`, without AI.
Files: proposed `Models/DiscoveryOccupation.cs`, `Services/Discovery/OccupationQueryCompiler.cs`, versioned dataset importer, `Controllers/DiscoveryOccupationsController.cs`, `src/components/discovery/OccupationAutocomplete.tsx`; integrate `JobDiscoveryPage`, preserve `JobImport/SkillTagger.cs` callers. Test taxonomy/alias/compiler suites and browser combobox fixtures.
- [ ] GJ03-A: licence/checksum/version manifest for ESCO/SSYK/SOC, reviewed aliases/crosswalk relation types and frozen ten-sector/three-language benchmark; approve metrics before measuring.
- [ ] GJ03-B/C: concept lookup and accessible cancellable typeahead; test stale response, same word/different language, deprecated ID and taxonomy outage.
- [ ] GJ03-D: exact/related/keyword modes, optional skill chips and provider mapping; test “weekend work”, free text and no qualification inference.
- [ ] GJ03-E: report per-sector/language precision/recall and p95/index size; publish `docs/global-jobs/03/` and stop.
## GJ-04 — providers and inventory
Branch `feature/gj04-provider-connectors`; [GJ-04](../../planning/global-jobs-prompts/05_GJ_04_PROVIDERS.md). Consumes canonical query/location/occupation plans; produces source-aware `DiscoveryPageV1` and permitted detail/lifecycle data.
Files: existing `Controllers/JobDiscoveryController.cs`, `Services/JobDiscoverySearchService.cs`, `Services/JobImport/JobImportService.cs`, `Plugins/FinnPlugin.cs`; proposed `Services/Discovery/ProviderRightsPolicy.cs`, `DiscoveryQueryService.cs`, `Providers/` capability-specific adapters, inventory/cursor models, EF mappings/migrations and DI registration at current host owner. Tests extend `JobDiscoveryControllerTests`, `JobImportServiceTests`, transport tests and proposed provider/lifecycle/dedupe MariaDB tests.
- [ ] GJ04-A: reverify matrix, exact API schemas/grants, numeric cache/quota/lag policy and credential references; unknown capability denied. Test every denied mode and rights expiry/revocation before adapter work.
- [ ] GJ04-B: inventory/event/cursor transaction, replay/out-of-order/crash/bootstrap/backoff tests; additive migration and search compatibility adapter.
- [ ] GJ04-C: NAV ingestion only with consumer authorization; fixtures can proceed independently, clearly labelled. Test removal/masking independent of area and no public-token production fallback.
- [ ] GJ04-D: SE JobSearch and truncated JobAd Links, exact taxonomy IDs and bounded windows; original-link/completeness/404/429 tests. JobStream only after separately qualified need.
- [ ] GJ04-E: licensed GB adapter or explicit external-link-only state; do not mark a fixture connector live. No full Adzuna body reconstruction.
- [ ] GJ04-F: FINN URL recognition/bookmark/manual workflow with zero network fetch through both new and existing import entry points; test malicious hosts, redirects and approved-source exceptions.
- [ ] GJ04-G: conservative dedupe, source loss and field-rights lineage, SSRF/XSS/rate/rights tests; separately bounded approved live contracts. Publish `docs/global-jobs/04/` with provider-by-provider decisions and stop.
## GJ-05 — unified discovery UI
Branch `feature/gj05-discovery-ui`; [GJ-05](../../planning/global-jobs-prompts/06_GJ_05_SEARCH_UI.md). Consumes page/detail contracts; produces desktop/mobile results/detail and existing workflow actions.
Files: extend `views/JobDiscoveryPage.tsx`, `App.tsx` routes, existing `PageLayout`/theme/API/types; proposed `components/discovery/JobDetailPanel.tsx` and filter/list pieces only when independently needed. Reuse existing job dialog/actions. Extend `src/job-discovery.test.tsx`, `e2e/job-discovery.spec.ts`, `e2e/phase7-discovery.spec.ts`.
- [ ] GJ05-A/B: filter rail/list/detail with independent partial-source/loading/error/empty states; tests preserve draft filters, deep link/history and return focus.
- [ ] GJ05-C: results/query semantics, sorting/pagination, exact-filter coverage and conservative alternate-source grouping; test stale/partial-source results and missing fields.
- [ ] GJ05-D: render full/truncated/link-only details with safe HTML/plain-text fallback, salary period/prediction/unknown fields and provenance. Assert blocked content never appears in DOM/API/export.
- [ ] GJ05-E: reviewed Save/Track/original-apply actions and native CV/letter document links, with AI gated.
- [ ] GJ05-F: phone full-screen details, tablet/desktop, EN/Bokmål and qualified locales, keyboard/zoom/themes, accessibility/fidelity/regression. Publish `docs/global-jobs/05/`, exact visual/axe/manual limits and stop.
## GJ-06 — searches, alerts and matches
Branch `feature/gj06-alerts-matching`; [GJ-06](../../planning/global-jobs-prompts/07_GJ_06_ALERTS_MATCHING.md). Consumes permitted inventory/query and existing profile/application owners; produces revision-safe `SavedSearch`, `SavedJob`, `SearchAlert` behavior.
Files: extend `Models/SavedJobSearch.cs`, `Services/SavedJobSearchRunner.cs`, `SavedJobSearchAlertHostedService.cs`, `Controllers/JobDiscoveryController.cs`, owned export/deletion services; proposed bookmark/subscription/delivery models and deterministic match service; UI search profile/notification/actions; no parallel application/profile writer. Tests `SavedJobSearchAlertTests`, `SavedJobSearchSqliteTests`, account export/deletion, MariaDB races and browser tracking/documents.
- [ ] GJ06-A: versioned full queries, duplicate/edit/delete/suspend/restore and legacy bare-NAV-ID migration; test revision conflict and exact scope roundtrip.
- [ ] GJ06-B: durable delivery/initial baseline/frequency/DST/pause/unsubscribe/deduplication; test duplicate workers, crash, changed/deleted search, withdrawn job before dispatch, source stale, overlapping searches and ambiguous mail send failure.
- [ ] GJ06-C: evidence-backed occupation/skills/qualification explanations; tests include nurse licence absent, cleaner empty profile, language unknown and profile revision change.
- [ ] GJ06-D: Save distinct from Track, idempotent tracked link, CV/letter native workflow; assert no canonical/CV/frozen-package mutation from source update and approved purge policy behavior.
- [ ] GJ06-E: security/fanout/accessibility/retention checks; publish `docs/global-jobs/06/` and stop.
## GJ-07 — admin and resilience
Branch `feature/gj07-discovery-operations`; [GJ-07](../../planning/global-jobs-prompts/08_GJ_07_ADMIN_SECURITY.md). Consumes feed/alert state; produces admin health, redacted correlation diagnostics and incident/rollback runbooks.
Files: extend `Controllers/AdminSystemController.cs`, `src/views/AdminSystemPage.tsx`, existing operation response/presentation contracts where appropriate; proposed system source-sync state/log projection (not synthetic tenant user), rights/retention controls. Tests admin API/UI, provider failure drills, export/delete/restore and resource limits.
- [ ] GJ07-A/B: provider rights/access/health/quota/lag/cursor/backlog/count metrics and paginated correlation events; distinguish actual system sync from real submitting user.
- [ ] GJ07-C: Admin check on every list/detail/stream/export; assert tenant/non-admin denial, redaction, no unsafe HTML/PII/raw Docker logs, retained source purge and account erasure.
- [ ] GJ07-D: provider loss, invalid schema, repeated cursor, credential revocation, index outage, lease expiry, retry storm and bounded load; verify backup/restore suppression and additive rollback. No production maintenance dispatch. Publish `docs/global-jobs/07/` and stop.
## GJ-08 — integrated acceptance
Branch `test/gj08-global-discovery-acceptance`; [GJ-08](../../planning/global-jobs-prompts/09_GJ_08_ACCEPTANCE.md). Entry: actual GJ-01–07 accepted ancestry, rights scope and source freeze, not sum of stage test counts.
- [ ] GJ08-A: freeze integrated source/config/fixture/dataset/licence identity and discover exact full-suite membership; reconcile blocked capabilities.
- [ ] GJ08-B: run all matrix journeys, backend/frontend/browser/contracts/actual MariaDB/model-disabled sidecar where applicable, TypeScript/lint/build and unchanged preservation/PDF oracles. Serialize build/browser/PDF lanes; retain native exits and failures.
- [ ] GJ08-C: authorised provider smoke separately from fixtures; per-country/source/content/language/geographic coverage report. Complete human/device/native-language/AT/print checks only with real evidence, otherwise OPEN.
- [ ] GJ08-D: source lifecycle/security/load/rollback/release gate review; publish `docs/global-jobs/08/`, per-stage/provider development decisions and production NO-GO unless separately authorized and qualified. Commit/push and stop; never deploy or merge main.