Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0ec9f98e6e | |||
| 2c38d40c92 |
@@ -0,0 +1,45 @@
|
||||
# Acceptance and evidence matrix
|
||||
|
||||
28 October 2026. **All implementation scenarios below are NOT RUN in GJ-00.** This is the proposed acceptance contract, requiring owner approval for quantitative targets. Documentation checks are separately recorded in [Evidence](EVIDENCE.md).
|
||||
|
||||
| ID / stage | Required proof | Failure / boundary |
|
||||
|---|---|---|
|
||||
| GJ-PREF /01 | NO residence + SE/GB work countries; 0..N choices; second-device persistence; explicit save/default actions | No nationality requirement or silent permanent override |
|
||||
| GJ-REV /01,06 | Concurrent preference/search writes; stale response preserves draft, expected revision at DB write; deleted account cannot schedule | No acknowledged edit loss, tenant bleed or stale worker notification |
|
||||
| GJ-LANG /01,05,08 | English/local prominence; native labels, More Languages, Coming Later; independent advert/UI/document language; missing keys/plurals/errors | No enabled unqualified locale or false Swedish/Nynorsk completion |
|
||||
| GJ-LOC /02 | Whole Warwickshire → Warwick only → Warwick OR Leamington → whole county after clearing towns; parent remains scope; deselect clears descendants | No parent-wide OR after refinement, no auto-child checkboxes or hidden filters |
|
||||
| GJ-LOC-DATA /02 | Vestfold/Tønsberg/Sandefjord, Vestland/Bergen, Oslo dual type, Stockholm and UK unitary/overlap data; real versioned IDs | No district used as town, no substring precision or old-ID silent broadening |
|
||||
| GJ-RADIUS /02 | Known point inside/on/outside 10/25/50km, multiple origins, country constraint, absent/coarse coordinate, remote eligibility | No county-centroid false pass, driving-time or worldwide-remote claim |
|
||||
| GJ-OCC /03 | Ten sector groups × EN/Bokmål/SV queries; aliases, ambiguity, exact/related/free keyword; cancellation and outage | No IT-only vocabulary, lost unknown term or silent broadening |
|
||||
| GJ-RIGHTS /04 | Deny unapproved capability in API/details/cache/export/notifications; reviewed manifests/grants and source labels | Public documentation/key/fixture cannot stand in for commercial grant |
|
||||
| GJ-NAV /04 | Complete bootstrap, durable cursor, replay/out-of-order/update/INACTIVE/masking/expiry and changed geography; crash/429/401 | No stale contact exposure, skipped deletion, fake live search or public-token production mode |
|
||||
| GJ-SE /04 | JobSearch permitted details; JobAd Links truncated text/original link/IDs/daily freshness/window; 404 | No follow-up third-party scrape or exhaustive result count from bounded window |
|
||||
| GJ-GB /04 | Commercial Adzuna grant + permitted snippet/redirect; NHS/DWP connector only if independently approved | External/manual fallback shown honestly; no trial-based ongoing production |
|
||||
| GJ-FINN /04 | New discovery and existing preview/import flows perform zero FINN network calls; manual URL/fields work | Plugin/network parsers cannot bypass source-rights denial |
|
||||
| GJ-DEDUP /04,06 | Same authoritative ID clusters; similar teacher/restaurant vacancies stay distinct; one source withdraws | No false automatic merge or rights borrowed across duplicates |
|
||||
| GJ-DETAIL /05 | Desktop 3-pane, tablet, mobile full detail/deep link; salary period/currency/prediction/unknown; original completeness/provenance | Missing fact never invented; restricted content absent from API and DOM |
|
||||
| GJ-ALERT /06 | Initial baseline, daily/weekly/timezone/DST, cross-search dedupe, pause/unsubscribe, restart/duplicate worker, changed search, withdrawn before send | No spam, stale/expired alert or another user's data; ambiguous email retry reported |
|
||||
| GJ-MATCH /06 | Explicit Career fact/version + advert requirement + ESCO relation; regulated licence absent/unknown, cleaner/no profile | No inferred fluency/authorisation/hiring probability or AI requirement |
|
||||
| GJ-TRACK /06 | Save versus Track distinction; reviewed idempotent application association and native CV/letter flow | Preserve Job/Application split, revisions/history/null inheritance/frozen packages |
|
||||
| GJ-ADMIN /07 | Rights/access/health/lag/backlog/quota/expiry, system sync versus owned import, correlation/structured redaction | Server Admin denial on list/detail/stream/export, no fake owner or raw host logs |
|
||||
| GJ-SEC /04–08 | SSRF DNS/private IP/redirect/credential leakage, malformed oversized compressed payload, unsafe HTML/links/images, injection, pagination loops, tenant IDs | Zero accepted critical data loss, isolation failure, misleading rights/content or secret exposure |
|
||||
| GJ-PRIV /06–08 | Preferences/bookmarks/subscriptions export+erase, contact minimization, queued alert cancellation, source revocation and restored-backup suppression | Copied provider content not exempted as “user data”; lawful frozen-history policy separately approved |
|
||||
| GJ-OPS /07–08 | DB cursor/lease failure, worker crash, provider/index outage, bounded fanout/backoff, additive migration and previous-binary rollback | No loss of user records; rollback cannot republish deleted source data |
|
||||
| GJ-PRESERVE /08 | All57 functionality groups/33 routes, Career/CV/import/application/RD21/letter/package/PDF regressions at frozen integrated source | No weakening old acceptance or replacing manual/provider evidence with fixtures |
|
||||
| GJ-A11Y /05,08 | Keyboard/screen-reader semantics, focus recovery, reduced motion, themes, 200% zoom, 320/390/768/1440 CSS widths, actual device/native-language review | Automated axe incomplete results stay incomplete; emulation is not physical device acceptance |
|
||||
|
||||
## Proposed quantitative qualification protocol
|
||||
|
||||
Approve before feature performance/relevance claims; targets here are **not measured**. Use frozen dataset, hardware/runtime/config, warm/cold distinction, 20 concurrent search clients for 10 minutes, source-cached versus upstream latency reported separately, error counts and DB query plans. Suggested capacity corpus: 250k active source ads, 1m lifecycle events, 10k private saved searches; synthetic records cover all countries/sectors, geography precision and deletion rates.
|
||||
|
||||
- Autocomplete: warmed local p95 <=200ms for 10 suggestions, UI debounce measured separately. Relevant suggestion precision@5 >=0.90 / recall@5 >=0.80 for every sector/language, frozen/native-reviewed labels.
|
||||
- Local indexed search: warmed p95 <=500ms for page50; API aggregate p95 <=2s when upstream meets bounded timeout. Do not conceal slow upstream by returning stale/rights-invalid data. Missing upstream results must be partial, not exact-global counts.
|
||||
- Feed: proposed healthy NAV steady-state lag p95 <=2min after observation availability; local observed withdrawal suppression and queued-alert cancellation <=60s. Provider terms requiring immediate changes take precedence; validate actual polling/lag with NAV and do not call these target windows a permission to delay removal. Stale/outage policy must fail closed.
|
||||
- Delivery: zero duplicate in-app notification for identical delivery key under retries/crash; proposed per-owner daily digest consolidation and max1 daily email digest unless explicitly chosen weekly. External mail ambiguity remains observable, not “exactly once”.
|
||||
- Data/security/rights: zero accepted canonical data loss, unauthorized cross-owner access, unlicensed full-content display, fabricated credentials or secret leakage. These do not depend on statistical sample averages.
|
||||
|
||||
## Evidence accounting
|
||||
|
||||
Every result records test ID/native command/config, source SHA plus dirty/input hashes, fixture/dataset/licence version, environment, timestamp, native exit, discovered/passed/failed/skipped and reason. Keep RED and corrected runs. Full-suite unique membership is primary; focused reruns are references, not extra passes. Staged passes do not establish integrated acceptance.
|
||||
|
||||
Separate lanes: local deterministic fixtures; actual MariaDB; hosted isolated CI; authorised live source contracts; human/native-language/device/AT; live-model semantic qualification; deployed identity; production. NOT RUN, BLOCKED and OPEN are not passes. A source needs legal eligibility AND technical tests before enabled capability GO. Production/main remain withheld regardless of development success.
|
||||
@@ -0,0 +1,85 @@
|
||||
# Architecture ADRs — proposed, not implemented
|
||||
|
||||
28 October 2026. Design baseline `4a8c907d70cbed235728f7d690b5409e72b93abe`. Authoritative architecture: [current pointer](../../architecture/current.md) → [overview](../../architecture/overview.md), [frontend](../../architecture/frontend.md), [backend](../../architecture/backend.md). The overview was originally verified September 2026 and has October updates; source inspection below resolves discovery-specific reality. Graphify was queried first; its AST scope excludes docs/config/deploy and is navigation evidence only.
|
||||
|
||||
## ADR-01 — extend existing owners
|
||||
|
||||
| Existing source owner (repository-relative) | Source-backed behavior / planned reuse |
|
||||
|---|---|
|
||||
| `job-tracker-ui/src/views/JobDiscoveryPage.tsx` | Current `/discover` query/location, saved searches, result sorting/dismissal. Extend with filters/list/details, not a parallel tracker. |
|
||||
| `src/i18n/I18nProvider.tsx`, `translations.ts`; `JobTrackerApi/Controllers/AuthController.cs:597` | EN/Bokmål dictionaries, persisted account language, legacy normalization. Extend qualification registry and preferences, retaining API/auth/save-failure behavior. |
|
||||
| `JobTrackerApi/Models/ApplicationUser.cs`; `Controllers/RulesController.cs` | Account preferences and owner settings patterns. Add discovery preference aggregate; do not reuse reminder settings for unrelated fields. |
|
||||
| `Controllers/JobDiscoveryController.cs:37`; `Services/JobDiscoverySearchService.cs` | Current q/location interface; NAV request scans <=20 pages from last14days, substring filters, <=100 results, configured/public-token fallback. This is incomplete country inventory, not a reusable compliant persistent index. |
|
||||
| `Models/SavedJobSearch.cs`; `Services/SavedJobSearchRunner.cs`; `SavedJobSearchAlertHostedService.cs` | Owner-scoped saved query/location, seen/dismissed IDs, initial-run baseline, periodic in-app new-result notifications. Extend rather than duplicate; add revisions/provider identity/schedules/durable delivery. Existing bare external ID cannot distinguish providers. |
|
||||
| `Services/JobImport/JobImportService.cs:35`, `Plugins/FinnPlugin.cs` | Preview fetches HTML before parsing/plugins; skill tagging/optional translation. GJ04 must enforce source rights **before any fetch**, including legacy route and Add Job callers. SSRF safety is not a licence grant. No fetch executed by this research. |
|
||||
| `Services/JobImport/SkillTagger.cs` | Mostly technical regex vocabulary. Preserve existing import contract; not the universal taxonomy owner. |
|
||||
| `Data/JobTrackerContext.cs`; `Services/CurrentUserService.cs`; `BackgroundTenantRunner.cs` | EF context, owner filtering and scoped background processing; fail closed on absent owner. MariaDB standard; explicit SQLite compatibility retained. |
|
||||
| `Models/CareerProfile.cs`; `Models/JobApplication.cs`; `Services/ApplicationAssetsService.cs` | Canonical Career Profile and separate application version domain. Discovery reads selected facts with consent; tracking and letter changes stay with existing revision/history owners. |
|
||||
| `src/components/KanbanBoard.tsx`; `src/App.tsx`; `src/views/ApplicationWorkspacePage.tsx` | Preserve pipeline/routes and tracking workflow; no new automatic application state or second router. |
|
||||
| `Models/UserOperation.cs`; `Services/UserOperationStore.cs`; `Controllers/AdminSystemController.cs:12`; `src/views/AdminSystemPage.tsx` | Owned recoverable operations and admin-only system surface. Integrate monitoring presentation, do not fake a user owner for source-wide ingestion. Existing maintenance dispatcher can invoke production benchmark jobs; do not reuse it as discovery sync. |
|
||||
|
||||
Exact proposed files below are new design names, not claims that they already exist. Before implementation re-resolve their callers/DI/current paths through Graphify and source; later accepted stages may move them. Existing theme/MUI/PageLayout/ViewStateNotice/API client/dialog/toast patterns remain owners. No new state library, AI service or UI framework.
|
||||
|
||||
## ADR-02 — hybrid source execution, MariaDB first
|
||||
|
||||
| Alternative | Benefit | Cost / decision |
|
||||
|---|---|---|
|
||||
| Live queries for everything | Least local storage | NAV is a feed; no complete/lifecycle-safe search. Reject. |
|
||||
| Index every source | Consistent query semantics | Not all storage rights granted; extra ingestion and staleness. Reject blanket index. |
|
||||
| Hybrid, source-specific | NAV feed index, SE live queries, licensed GB query or external fallback | Chosen proposal. Partial coverage explicit, common query/results contract, no new search infrastructure. |
|
||||
|
||||
Use EF/MariaDB indexed predicates for active inventory (country/status/modified/provider/source IDs), versioned location/occupation mapping tables and bounded text lookup. Evaluate native FULLTEXT against frozen multilingual corpus before selecting collation/token rules; fall back to bounded indexed metadata plus explicit keyword coverage, not unbounded `%term%` country scans. SQLite compatibility needs a provider-specific query implementation/test where retained; it cannot prove MariaDB behavior.
|
||||
|
||||
No Elasticsearch, queue broker, map SaaS or geocoder purchase. Proposed qualification load: 250,000 active source records plus 1,000,000 lifecycle events; cap ingest batches and retention. Capacity is a test target, not a measured result. If native storage fails agreed p95 gates, bring measured plans/storage cost to a separate ADR before adding infrastructure.
|
||||
|
||||
Cost model: database bytes per retained permitted ad × measured active count + mapping/index overhead + lifecycle retention; API calls = shared query misses + bounded detail checks + feed polls, not one full feed traversal per user/search alert. Infrastructure estimate requires measured row/index size and current operator rates. NAV/SE documented API access is free; storage/operations are not. Adzuna price is unknown pending quote. ESCO local data avoids runtime API dependency; exact artefact licence still gates import. No invented monthly total or new paid resource is authorized.
|
||||
|
||||
## ADR-03 — canonical contracts and ownership
|
||||
|
||||
All contracts are proposed. IDs and schema versions are explicit; absent source fields stay null/unknown. No mandate to create one table per concept.
|
||||
|
||||
| Concept | Minimum fields / invariant | Reconciliation |
|
||||
|---|---|---|
|
||||
| `SearchPreference` | owner, revision, schemaVersion, residence?, workCountries[], locationScopes[], occupation refs[], explicit skills[], arrangements[], advertLanguageTags[] | New aggregate linked to existing account; `UiLanguage` remains existing account field. |
|
||||
| `LocationNode` | internal ID, authority/code/type/country/edition, names/aliases, validity, typed edges, geometry/point precision/licence | Public reference catalogue; [geography contract](GEOGRAPHY_DECISIONS.md). |
|
||||
| `LocationScope` | rootId, refinements[], mode, radiusOrigins[], datasetVersion | Validated query value, not auto-selected descendants. |
|
||||
| `OccupationConcept` | namespace/URI/version, language labels, typed related/skill edges, licence/validity | Shared public reference data; [taxonomy](CROSS_INDUSTRY_TAXONOMY.md). |
|
||||
| `ProviderCapability` | rights evidence, modes/filters/content/storage/lifecycle/link/quotas, enabled/status | Registry + reviewed versioned config; secret references only. |
|
||||
| `SourceAdvertisement` | canonical inventory ID; source records; title/employer; locations/precision; occupations; pay/currency/period/predicted; schedule/contract/language/requirements; description format/completeness; original/apply URLs; posted/updated/retrieved/expiry/status; provenance | External inventory; never a tenant `JobApplication`. |
|
||||
| `ProviderSourceRecord` | providerId + externalId unique, content/version hash, observed revision/time, rights version, nullable fields, freshness/status | Multiple records may reference one conservative dedupe group; each retains its rights. |
|
||||
| `SourceLifecycleEvent` | provider/event key, source ID/version, observedAt, operation upsert/withdraw/mask, cursor reference | Idempotent event + atomic cursor; no expired raw contact content retained by default. |
|
||||
| `SavedJob` | owner + source identity unique, savedAt, own notes, optional Job/Application link, revision | New bookmark relationship; saving does not create an application. Avoid duplicating source descriptions. |
|
||||
| `SavedSearch` | existing SavedJobSearch ID/owner/name; revision + schemaVersion + typed query + active state | Extend existing entity/DTO; retain legacy q/location migration and dismissals. |
|
||||
| `SearchAlert` | owner/search/revision, channel/frequency/timezone, schedule, enabled, delivery idempotency/status | Extend existing alert runner + UserNotification, separate durable delivery/outbox state as needed. |
|
||||
|
||||
Proposed request `DiscoveryQueryV1`: workCountries, scopes, occupations + mode, keyword, skills, advertLanguages, arrangements, sourceIds, sort, cursor, pageSize. Proposed response `DiscoveryPageV1`: results, nextCursor, per-source availability/freshness/coverage/unsupportedFilters, exactness, queryFingerprint. Do not report a global total from live windows as exhaustive. Detail `AdvertisementDetailV1` returns permitted fields, completeness and provenance; inactive/rights-denied content is not leaked through an alternate endpoint.
|
||||
|
||||
Proposed services: `DiscoveryQueryService.SearchAsync(DiscoveryQueryV1, ownerContext, CancellationToken) -> DiscoveryPageV1`; `LocationScopeCompiler.Compile(scopes, datasetVersion) -> LocationQueryPlan`; `OccupationQueryCompiler.Compile(mode, terms, taxonomyVersion) -> OccupationQueryPlan`; `ProviderRightsPolicy.Evaluate(providerId, capability, now) -> Allowed/Blocked(reason)`; capability-specific live-search, detail and change-feed interfaces. Existing `IJobDiscoverySearchService.SearchAsync(q, location, ct)` remains a compatibility adapter until callers/tests are migrated. Proposed v2 route `/api/job-discovery/v2/search`; do not silently change old array response shape.
|
||||
|
||||
## ADR-04 — ingestion, dedupe and freshness
|
||||
|
||||
Background feed worker uses bounded pages/bytes/time/retries; allowlisted provider URLs, ETag/conditional requests where supported. Fetch outside DB transaction; commit idempotent latest source state, lifecycle event and cursor together. On crash retry same page; never advance cursor ahead of accepted deletion. Reject invalid status/schema/cursor loops, quarantine safe diagnostics and pause source; preserve last committed checkpoint. Out-of-order events cannot resurrect deleted content. Bootstrap completeness and ongoing lag are separate metrics.
|
||||
|
||||
Use a distinct system-owned provider cursor/lease record, not `UserOperation.OwnerUserId="system"`. Reuse bounded processing concepts, correlation/status/redaction and admin presentation; user URL-import tasks keep actual owner. Source sync stays single-writer initially under database lease; multiple backend replicas require explicit claim/fencing/expiry tests before enabling. This does not rewrite existing CV worker leasing.
|
||||
|
||||
Deduplicate providerId+externalId deterministically first. Cross-provider automatic grouping requires a shared authoritative requisition/canonical source identity and corroborating employer/location/time. Similar title/body at the same school/restaurant is insufficient. Uncertain pairs stay separate or reviewable. Groups retain source records and show which supplies each field; a permissive duplicate cannot expand another record's rights. Withdrawal recomputes visible alternatives and suppresses restricted fragments.
|
||||
|
||||
## ADR-05 — preferences, alerts and tracking integrity
|
||||
|
||||
Expected revision is checked at database write, including background search runs. Save a query revision/fingerprint; before publishing notifications recheck search still active, same revision, owner not deleting, source active/fresh and current rights. The first run establishes a baseline. Unique delivery key `(owner, searchId, revision, sourceIdentity, eligibleVersion, channel)` plus durable outbox avoids duplicate generation; do not claim exactly-once email delivery after ambiguous network failure. Default daily in-app digest, optional weekly/email opt-in; timezone/DST scheduling, pause/unsubscribe and bounded retries. Proposed cross-search per-owner daily digest consolidation prevents repeated copies of the same vacancy. Quiet hours and channel limits require explicit product approval.
|
||||
|
||||
Tracking uses existing opportunity/application creation service and owner uniqueness checks in one transaction/idempotent request. Preserve `JobApplication.Version`, Career revision, history, CV null-as-inherit, old extraction runs, CV/letter settings, frozen submitted HTML/PDF/packages and compatibility dual writes. A source update must never overwrite a user's reviewed application description, personal notes or canonical profile. If copied source content must be purged, retain user facts separately and use approved redaction/retention handling; do not rewrite frozen evidentiary documents without a separately approved lawful policy.
|
||||
|
||||
## ADR-06 — privacy and trust boundaries
|
||||
|
||||
Default private user data: optional residence, search interests/scopes/skills references, saved vacancies and subscriptions. Minimize exact home addresses: radius uses chosen public place point, not compulsory home GPS. Process matching locally from consented profile fields, not raw CV sharing with job providers. No nationality/sensitive-class relevance weighting, inferred fluency/licence or automatic application.
|
||||
|
||||
Maintain CSRF/auth/owner filters, rate limits and role checks server-side. Public provider inventory is separately authorized from user-owned bookmarks/searches/operations. Test cross-owner IDs and absent identities in API/worker/export/deletion. Admin lists/detail/stream/export require Admin and redact secrets/PII/prompts; log structured error code/correlation rather than raw provider payload. Propose 30-day content-free operations diagnostics, pending owner policy; source PII retention is the shortest allowed necessity/contract period, never this generic diagnostic number.
|
||||
|
||||
Enforce URL rights before transport, strict scheme/host validation, DNS/IP checks at connection and redirects, bounded decompress/response/pagination, no cookies/token forwarding. Strip scripts/styles/event handlers/iframes/unsafe links and remote tracking images from permitted descriptions; render plain text until safe HTML sanitizer qualification. Malicious ad text must not control tools/prompts. AI remains disconnected from core discovery and gated independently. Account export/delete must include new private state and remove queued alerts, delivery identifiers and derived private matches. Backup restore policy replays deletions/rights revocations before exposure.
|
||||
|
||||
## ADR-07 — additive migration and rollback
|
||||
|
||||
GJ-01 adds preference schema/revision without deleting columns; empty old accounts remain valid. GJ-02/03 version reference data with staged import/swap, retaining old IDs. GJ-04 creates inventory/source cursor state; GJ-06 extends SavedJobSearch query schema plus bookmarks/delivery state. Backfill old q/location as legacy keyword/explicit unresolved location, not guessed canonical IDs; preserve ID/name/active/dismissed/first-seen history. Old bare NAV IDs migrate with explicit NAV namespace and unique constraints; never silently dedupe across providers.
|
||||
|
||||
Test MariaDB forward migration, old-data read, concurrent writes, rollback/restart and restore. Retain SQLite transition compatibility where still supported. Roll back behavior with feature gates and previous binary while additive tables remain; do not issue destructive Down migrations or erase user-authored rows. A rollback of UI cannot roll back provider deletion obligations: lifecycle suppression/policy enforcement must continue or source content stays disabled. No production migration under this plan.
|
||||
@@ -0,0 +1,48 @@
|
||||
# Cross-industry taxonomy — proposed
|
||||
|
||||
28 October 2026. Implements the design contract of [GJ-03](../../planning/global-jobs-prompts/04_GJ_03_OCCUPATIONS.md); no dataset import or model inference performed.
|
||||
|
||||
## Taxonomy choice and evidence
|
||||
|
||||
Use versioned ESCO concept URIs/labels/aliases/skills as the shared vocabulary. The official site reports v1.2.1 and downloadable data/API, including English, Swedish and Norwegian `no`; that pack must not be relabelled as separately qualified Bokmål/Nynorsk. Prefer a pinned local data subset over bundling the reference local API software. [Use ESCO](https://esco.ec.europa.eu/en/use-esco), [download](https://esco.ec.europa.eu/en/use-esco/download), [API/software licensing](https://esco.ec.europa.eu/en/use-esco/use-esco-services-api), accessed 2026-10-28.
|
||||
|
||||
Data and API software licences are different: API software is EUPL 1.2 with component licences; EU-owned web content defaults to attributed reuse under [Commission notice](https://commission.europa.eu/legal-notice_en). GJ03-A must retain the exact downloaded dataset licence/readme/checksum and attribution, identify exceptions and approve commercial redistribution of that artefact. General web reuse is not proof of every downloadable file's licence. No email/download registration was submitted here.
|
||||
|
||||
Swedish JobTech taxonomy is public CC0 and provides SSYK-2012/ISCO-08 relations, occupation aliases and skills. Pin its versioned export, preserving concept IDs distinct from numeric SSYK codes. [Taxonomy service](https://data.arbetsformedlingen.se/dataservice/employer-market-taxonomy/), [versioned catalogue](https://data.arbetsformedlingen.se/taxonomy), accessed 2026-10-28.
|
||||
|
||||
UK ONS supplies SOC2020 and extended job-title indexes, with a 27 August 2026 edition visible at research time. Cross-referencing ESCO during classification development is not a validated one-to-one crosswalk. Import an explicitly licensed/pinned title index only after GJ03-A review; leave uncertain SOC↔ISCO↔ESCO mappings unmapped. [ONS extended SOC](https://www.ons.gov.uk/methodology/classificationsandstandards/standardoccupationalclassificationsoc/standardoccupationalclassificationsocextensionproject), accessed 2026-10-28.
|
||||
|
||||
## Contract and matching
|
||||
|
||||
`OccupationConcept`: namespace + immutable URI/code + taxonomy version, preferred/alternative labels keyed by original language tag, broader/related/skill edges with evidence, validity/deprecation/replacement and source/licence. Mapping edges carry source/target versions, exact/broad/narrow/related relation and reviewed confidence. A many-to-many crosswalk is not equality.
|
||||
|
||||
Occupation describes work; employer title remains original advert text; industry describes economic activity; skill is capability; qualification/licence is an explicit requirement/evidence; schedule and experience are separate facets. “Weekend work” is valid free text, not a forced occupation. Unknown terms never disappear when the taxonomy fails.
|
||||
|
||||
Query modes: `exact` resolves selected concept/approved aliases without broadening; `related` adds labelled related concepts only with user opt-in; `keyword` preserves unclassified input. Accent/case normalization supports lookup without rewriting displayed titles; ambiguous tokens (e.g. English “chef” versus Swedish “chef” manager) require language context/disambiguation. `cook/kokk/kock` is a proposed reviewed alias example, not an asserted frozen ESCO mapping. Skills only use explicit user choices or consented profile facts; no pooled private CV text.
|
||||
|
||||
Debounce/cancel suggestions, ignore stale responses, cap results, use locale-aware ranking and accessible combobox behavior. Order exact/local preferred labels before aliases and explicit related roles. Allow search without selecting a suggestion; taxonomy outage falls back to literal keyword. UI language affects labels, not an implicit advert-language restriction. Unsupported provider occupation/skill filters require auditable query expansion or disclosed exclusion.
|
||||
|
||||
Current `JobImport/SkillTagger.cs` is largely technical regex tags, used by `JobImportService.PreviewAsync`. Retain its existing caller contract while adding universal discovery vocabulary; it cannot define all-occupation search or candidate qualification. GJ-03/GJ-06 must trace every caller before changing shared tagging/matching behavior.
|
||||
|
||||
## Frozen benchmark to create in GJ03-A
|
||||
|
||||
These are proposed human-reviewed query examples; translations are not yet linguistic acceptance or complete taxonomic equivalents.
|
||||
|
||||
| Sector | English queries | Bokmål / Swedish candidates | Required distinction |
|
||||
|---|---|---|---|
|
||||
| Education | teacher, teaching assistant | lærer, lærerassistent / lärare, lärarassistent | Teacher versus assistant, subject/level |
|
||||
| Hospitality | chef, cook, kitchen assistant | kokk, kjøkkenassistent / kock, köksbiträde | Manager ambiguity, assistant not chef |
|
||||
| Health | nurse, care worker | sykepleier, pleiemedarbeider / sjuksköterska, vårdbiträde | Registration not inferred |
|
||||
| Trades | electrician, plumber, carpenter | elektriker, rørlegger, tømrer / elektriker, rörmokare, snickare | Different trade licences |
|
||||
| Logistics | driver, warehouse operator | sjåfør, lagermedarbeider / chaufför, lagerarbetare | Licence category, no inferred permission |
|
||||
| Retail | shop assistant | butikkmedarbeider / butiksbiträde | Part-time/evening availability |
|
||||
| Cleaning | cleaner | renholder / lokalvårdare | No formal qualification needed to search |
|
||||
| Office/finance | accountant, administrator | regnskapsfører, administrator / redovisningsekonom, administratör | Credential and role ambiguity |
|
||||
| Agriculture | farm worker | gårdsarbeider / lantarbetare | Seasonal roles, not farmer-owner only |
|
||||
| Technology | software developer | programvareutvikler / systemutvecklare | One sector with equal benchmark weight |
|
||||
|
||||
Freeze at least these ten sector groups × three query languages, positive and confusing negative terms, unfamiliar/free-text jobs, shifts/apprenticeships/no experience and missing requirements. Record intended relevant concepts and allowed expansions with provenance and native review. Proposed GJ03-E targets: precision@5 >=0.90 and relevant suggestion recall@5 >=0.80 **per sector/language**; report macro averages and failures rather than hiding weak sectors in a tech-heavy total. Targets need owner approval before execution. Zero invented credentials is mandatory regardless of relevance scores.
|
||||
|
||||
Match explanation includes explicit profile fact reference/version, advert requirement field/source version, relation used, matched/not supplied/unknown, and no hiring-probability claim. Profile revision change invalidates cached explanation; AI remains optional and gated. Public taxonomy contains no tenant PII; profile-derived ranking remains owner-scoped.
|
||||
|
||||
The frozen corpus must also include waiter, mechanic and public administrator explicitly, as required by GJ-03. Test bounded typo tolerance without overriding exact-title mode or allowing broad roles to swamp precise titles.
|
||||
@@ -0,0 +1,42 @@
|
||||
# Dependencies, source authority and entry gates
|
||||
|
||||
28 October 2026. GJ-00 research is authorized by the current owner instruction; no implementation approval is inferred.
|
||||
|
||||
## Verified development baseline
|
||||
|
||||
Local HEAD and remote `refs/heads/test/cv-integration-acceptance` both: `4a8c907d70cbed235728f7d690b5409e72b93abe`. Existing development ancestry includes CV-import `ef425c288b38ae0e91dcc216a5c8b6c02c433ab5`, CV-UX `4a0af62` and QA remediation `89974a257e4192b3d93779000a7df6998afc4051`; ancestry is checked in the GJ-00 evidence lane. `main` is not this planning base.
|
||||
|
||||
Current authority order: [CV-QA acceptance](../../cv-integration-qa/ACCEPTANCE.md), [Phase 10 handoff](../../cv-integration-qa/PHASE_10_HANDOFF.md), [CV-QA regression record](../../cv-integration-qa/REGRESSION_RESULTS.md), [architecture](../../architecture/overview.md), [Phase 10 requirements](../../redesign/IMPLEMENTATION_PLAN.md#phase-10--cleanup), [roadmap](../../roadmap/README.md), [TODO](../../roadmap/todo.md), [operator blockers](../../../BLOCKERS.md). Older Phase 7/9 decisions and roadmap continuations retain historical scope; they cannot override the newer bounded CV-QA decision.
|
||||
|
||||
The 27 October acceptance grants CONDITIONAL GO for implemented model-independent CV import/development review. Phase 10 is **candidate assessment/planning only**, broad cleanup implementation NO-GO; no unused deletion candidate is verified. Preserve 57 functionality groups and 33 routes, older-run review/accept paths and redirects. Human/device/AT/native-language/contrast/print qualification remains open; live CV-model compatibility/accuracy blocked; production NO-GO. Reported prior totals (backend1336, frontend995, ordinary browser364, separate configurations53, real import7, MariaDB80, Python90) are **historical report claims, not rerun by GJ-00**, and overlap rules remain intact.
|
||||
|
||||
No completed `PRODUCT-REVIEW-01` decision or initiative entry approval was found in current docs/roadmap and the supplied pack. Absence is a gate, not permission. Request a concrete review artefact with scope, baseline, unresolved debt and authorized next stage.
|
||||
|
||||
## Independent decisions
|
||||
|
||||
| Gate | Current disposition | Evidence needed / responsible owner |
|
||||
|---|---|---|
|
||||
| GJ-00 safe planning/research | GO | Current instruction; documentation-only output |
|
||||
| GJ-00 design review | CONDITIONAL GO | Proposed architecture complete enough for review; settle listed rights/data/acceptance qualifications |
|
||||
| Phase 10 entry/completion as applicable | NOT SATISFIED for global implementation | Development owner records candidate-specific scope/preservation acceptance and required handoff; this plan cannot close it |
|
||||
| PRODUCT-REVIEW-01 | NOT ESTABLISHED | Product owner publishes signed decision and approved global scope/order |
|
||||
| INT-GLOBAL-JOBS-01 implementation scope | NO-GO | Owner approves implementation and issues GJ-01 instruction after applicable prior gates |
|
||||
| GJ-01 current execution | NO-GO | All preceding entries plus fresh accepted development source; no automatic continuation |
|
||||
| Country live providers | Separate, blocked/conditional | Per-source grants, credentials, lifecycle and bounded live tests; see rights matrix |
|
||||
| UI language support | EN/Bokmål source support only | Coverage checks + native QA; Swedish and other locales require actual implementation/qualification |
|
||||
| Geography/occupation imports | Not qualified | Exact artefact versions/hashes/licences, mappings and benchmark approval |
|
||||
| Hosted MariaDB CI | Inherited blocker | Isolated runner qualification; current workflow explicitly fails closed before DB execution |
|
||||
| Live AI | BLOCKED | Independent artifact/environment/security/semantic qualification and owner authorization |
|
||||
| Main merge / production | NO-GO / not authorized | Independent release owner action; never implied by stage pass |
|
||||
|
||||
## Stage dependency order
|
||||
|
||||
GJ-00 → entry approvals → GJ-01 preferences/i18n → GJ-02 geography → GJ-03 occupations → GJ-04 providers → GJ-05 UI → GJ-06 saved searches/alerts/matching → GJ-07 operations/security → GJ-08 integrated acceptance. Stage prompts remain authoritative. Provider approvals may be pursued independently; an unavailable UK/FINN connector does not block truthful manual/external fallback or a qualified NO/SE source, but blocks any complete live UK/full FINN claim.
|
||||
|
||||
Each later branch starts from the latest accepted integration-complete predecessor history, not this old baseline or `main`. Recheck Git ancestry, source hashes, acceptance scope and gates at entry. Keep approved missing-provider scope explicit rather than declaring an unconditional three-country live-search GO.
|
||||
|
||||
## Workspace and publication boundaries
|
||||
|
||||
At entry the checkout had unrelated tracked changes to `.gitignore`, `AGENTS.md`, `docker-compose.dev.yml`, plus untracked tool/security/Graphify files and supplied `docs/planning/`. Preserve them; do not reset/stash/delete or commit them indiscriminately. Created the specifically authorized planning branch after local/remote collision check. Only `docs/global-jobs/00/` and the supplied `docs/planning/global-jobs-prompts/` are eligible for this planning commit. Existing application source is unchanged.
|
||||
|
||||
Remote: `origin`, `https://git.cesnimda.uk/cesnimda/jobtrackingapp.git`. Inspected workflows: push deployment targets `main`; planning branch is outside that trigger and MariaDB branch allowlist; maintenance/backup dispatch is not invoked. No force push, PR, merge or deployment. Verify remote branch HEAD after push and retain exact publication identity in the completion report/evidence record.
|
||||
@@ -0,0 +1,31 @@
|
||||
# GJ-00 evidence ledger
|
||||
|
||||
28 October 2026, Europe/Paris date. Planning/research only. Runtime feature acceptance is not claimed.
|
||||
|
||||
## Source and research
|
||||
|
||||
- Baseline: `4a8c907d70cbed235728f7d690b5409e72b93abe`, `test/cv-integration-acceptance`; `git ls-remote` confirmed the exact remote SHA. Planning branch did not exist locally/remotely before creation.
|
||||
- Current architecture pointer/overview/topics, current roadmap/TODO, Phase 10 requirements, CV-QA acceptance/handoff/regression references and BLOCKERS were reviewed. No completed PRODUCT-REVIEW-01 found; Phase 10 implementation approval not established.
|
||||
- Graphify query located discovery, saved-search, i18n and related owners; scoped graph-node inventory resolved imports/operations/taxonomy seams. Graph contains 10,691 nodes at entry, excludes documentation/config/deployment; not runtime proof. Some broad queries truncated or found no matching node; followed source references/graph labels rather than treating those as exhaustive results.
|
||||
- Source inspection verified existing per-request NAV feed scan, substring location filtering, public-token fallback, owned saved-search/alert baseline, EN/Bokmål-only UI, HTML URL preview including FINN, technical skill tagger, owner filters/version domains and Admin system checks.
|
||||
- Official public pages were browsed under the current explicit research authorization. Each substantive source is linked beside its claim in provider/geography/taxonomy/product documents with access date. Swagger UI home pages initially produced empty parsed content; JobAd Links raw OpenAPI 1.4.5 was readable. JobSearch raw Swagger fetch failed through the browser tool; current official service/dataset pages establish public CC0/no-registration status, not tested response contracts. A guessed ESCO licence URL failed; exact dataset licence qualification is left open, not inferred from that failure.
|
||||
- ONS confirms county/district/parish relationships; precise town settlement polygons/IDs were not acquired. SCB simplified boundaries are explicitly unsuitable for analysis; exact spatial claims remain gated. General Kartverket terms currently state CC BY 4.0, so older NLOD assumptions were not carried forward.
|
||||
- Some exploratory Windows wildcard paths did not resolve; explicit known paths were used. One nested PowerShell variable expression failed from shell expansion; replaced with a read-only Python graph-label inventory. Neither failure mutated application data or constitutes a feature test failure.
|
||||
|
||||
## Validation and publication
|
||||
|
||||
Executed documentation checks: 9/9 required outputs present; UTF-8 reads succeeded without replacement characters; 45 local Markdown targets checked, zero broken; ancestry checks for `4a8c907`, `ef425c2`, `4a0af62`, `89974a2` all passed (native exit 0). Source diff lists only the three pre-existing tracked changes; no application changes. Prompt cross-check corrected the GJ-05 branch/checkpoint labels and explicitly retained waiter/mechanic/public-administrator benchmark cases. These are documentation checks, not application test passes. Staged whitespace/scope and remote publication are checked before completion; exact publication SHA is reported to the owner.
|
||||
|
||||
Eligible commit paths: `docs/global-jobs/00/`, `docs/planning/global-jobs-prompts/`. Supplied prompt pack retained unchanged. Pre-existing tracked/untracked changes remain outside the index. Check staged diff before commit; do not use `git add .`.
|
||||
|
||||
Publish with ordinary commit/push to `planning/int-global-jobs-00`, then `git ls-remote` exact equality. Completion report provides publication SHA; a commit cannot contain its own hash. No PR or main/deploy workflow action is requested. Post-publication evidence may use a second docs-only checkpoint, with both SHAs reported.
|
||||
|
||||
## Lanes not executed
|
||||
|
||||
## Publication result
|
||||
|
||||
Planning content committed locally as `2c38d40c9213aa511684910bce57b691435a9930`. Staged whitespace check passed; an assertion verified exactly 23 documentation files under the two allowed paths. Two ordinary push attempts failed because `git.cesnimda.uk:443` was unreachable; a subsequent remote-head read also failed. **Push BLOCKED; remote publication NOT VERIFIED.** No force push or alternate remote was attempted. Retry `git push -u origin planning/int-global-jobs-00` when connectivity returns, then compare `git rev-parse HEAD` with `git ls-remote --heads origin refs/heads/planning/int-global-jobs-00`. The later documentation-only publication-status commit records this failure; its hash is supplied in the completion report.
|
||||
|
||||
## Unexecuted runtime lanes
|
||||
|
||||
Backend/frontend/browser/contract/MariaDB/Python suites: **NOT RUN** for this docs-only stage. Prior acceptance counts are referenced historically only. No live advertisement query/detail/feed call, provider credentials, consumer registration, commercial approval, taxonomy/geography data import, benchmark/load test, physical device/AT/native-language check, live-model inference, hosted CI qualification, deployed-identity check or production operation. Researching documentation is not a live provider contract pass. No Graphify rebuild: application code unchanged and docs are excluded from its code-only build scope.
|
||||
@@ -0,0 +1,53 @@
|
||||
# Geography decisions — proposed, exact GJ-02 semantics
|
||||
|
||||
28 October 2026. The [GJ-02 prompt](../../planning/global-jobs-prompts/03_GJ_02_GEOGRAPHY.md) is authoritative. No geography ingestion, geometry validation or distance test was run in GJ-00.
|
||||
|
||||
## Source and identity decisions
|
||||
|
||||
| Country | Authoritative candidates / observed facts | Licence/version and unresolved qualification |
|
||||
|---|---|---|
|
||||
| NO | SSB county/municipality classifications; Kartverket administrative geometry and SSR official place names. Vestfold `39`, Tønsberg municipality `3905`, Sandefjord `3907`; Vestland `46`, Bergen `4601`; Oslo county `03`, municipality `0301`. | Pin SSB 2026 IDs/validity plus exact Kartverket download/API metadata and geometry edition/hash in GJ02-A. Kartverket free products are CC BY 4.0, credit © Kartverket and link. Verify SSB export licence separately. SSR point/name is not a settlement polygon. |
|
||||
| SE | SCB län/kommun plus statistical tätort/locality. Stockholm municipality `0180` must remain distinct from Stockholm settlement; settlement boundaries may cross municipality boundaries. | SCB publishes CC0 simplified county/municipality boundaries but explicitly says they are unsuitable for analysis. Choose qualified Lantmäteriet administrative geometry for exact spatial work or disclose lower precision. Pin exact current SCB locality edition at GJ02-A (2023 listed on inspected download page); verify metadata, not “latest” URL. |
|
||||
| GB | ONS/GSS administrative IDs, lookup relations and settlement geography; country-specific settlement sources for Scotland/NI need qualification. Warwickshire `E10000031` contains Warwick district `E07000222`; district contains both Warwick and Royal Leamington Spa parishes. Neither district nor a combined built-up area is Warwick town alone. | ONS OGL v3 + product-specific OS/other attribution; Northern Ireland postcode data needs a separate commercial licence. Pin individual product epoch/hash. Exact Warwick/Leamington settlement IDs/geometries and Scottish/NI settlement metadata remain GJ02-A blockers to precision claims. No made-up town IDs. |
|
||||
|
||||
Official sources accessed 2026-10-28: [SSB county 2026](https://dataportal.ssb.no/classifications/104/versions/3315/correspondences/2808), [SSB municipalities](https://dataportal.ssb.no/classifications/131/correspondences/1358), [Kartverket services](https://www.kartverket.no/en/api-and-data/eiendomsdata/apent-tilgjengelige-data-og-tjenester), [Kartverket terms](https://www.kartverket.no/api-og-data/vilkar-for-bruk), [SSR guide](https://kartverket.no/en/api-and-data/stedsnavndata/brukarrettleiing-stadnamn-api), [SCB boundaries](https://www.scb.se/hitta-statistik/regional-statistik-och-kartor/regionala-indelningar/digitala-granser/), [SCB localities](https://www.scb.se/vara-tjanster/oppna-data/oppna-geodata/statistiska-tatorter/), [Warwickshire](https://www.ons.gov.uk/explore-local-statistics/areas/E10000031-warwickshire), [Warwick district/parishes](https://www.ons.gov.uk/explore-local-statistics/areas/E07000222-warwick), [ONS licences](https://www.ons.gov.uk/methodology/geography/licences/).
|
||||
|
||||
## Canonical contract
|
||||
|
||||
`LocationNode` has stable internal ID, source namespace/code/type/country, edition, validity, original/localized names and aliases, optional geometry/representative point with CRS/precision/provenance, and deprecation/replacement links. External code identity is versioned; no code is assumed eternal or globally unique. Preserve original provider location and confidence (`exact`, `area-only`, `approximate`, `unresolved`). Postal areas are not administrative ancestry.
|
||||
|
||||
Use typed relationship edges (`administrative-parent`, `settlement-intersects`, `alias-of`) rather than one false universal tree. Country → county/län → municipality/district → town is a **navigation projection** where valid; unitary authorities skip absent levels. Settlement overlaps remain many-to-many. Oslo has distinct county/municipality type identities linked to the same administrative footprint; selecting one should not duplicate results. Tønsberg municipality and settlement likewise remain distinct. Stockholm settlement does not become wholly contained in Stockholm municipality by UI nesting.
|
||||
|
||||
`LocationScope` serializes branch root + explicit refinements + mode (`whole`/`specific`) + optional radius origins, schema version and taxonomy edition. Store scopes, not thousands of child checkboxes. Browser tree expansion is lazy/paginated and independent of selection; collapsed branches retain filters. Unknown/stale IDs cause visible review, never silently broaden to a parent. Dataset upgrades retain old IDs and versioned crosswalks; ambiguous replacements require confirmation.
|
||||
|
||||
## Exact interaction/query contract
|
||||
|
||||
For a selected branch b: effective(b) = union of its explicit deepest refinements when any exist; otherwise whole selected root. Recurse the same rule for nested refinements. Combine independent branches as OR; combine location with occupation/language/other dimensions as AND. Explicit selections on one ancestry path refine that path, never add the broad parent back into the OR union. A separately selected whole-country branch must visibly explain that it subsumes narrower branches.
|
||||
|
||||
| Action / state | Effective query | Visible state |
|
||||
|---|---|---|
|
||||
| Select Warwickshire | Whole county | County selected, children unchecked |
|
||||
| Expand only | Still whole county | Expansion changes no filters |
|
||||
| Select Warwick under selected Warwickshire | Warwick **town only** | County retained as scope being refined; `Warwick only` summary |
|
||||
| Add Royal Leamington Spa | Warwick town OR Royal Leamington Spa town | Both refinements; no other county areas |
|
||||
| Remove Warwick | Royal Leamington Spa only | Summary updates |
|
||||
| Remove last town, keep county | Whole Warwickshire | Whole area state restored |
|
||||
| Add Bergen branch | Previous effective GB scope OR chosen Bergen scope | Country branches both visible |
|
||||
| Deselect county | Remove that branch and its descendants | Announce removal; no hidden child filters |
|
||||
| Collapse / reopen / save / reload | Same scopes | Checked scope/refinement distinction preserved |
|
||||
|
||||
Use a scope checkbox plus separate Whole area/Specific places controls and effective summary. Do not expose a checked parent as the conventional “all descendants selected” or mixed-state checkbox. A direct town selection through lookup includes ancestry for navigation; deselecting that selected ancestor clears the associated branch visibly. Do not auto-check children when selecting a parent.
|
||||
|
||||
Provider query compiler emits supported area IDs and a local exact filter over permitted data. Provider codes need versioned canonical mapping; ambiguous text alone remains unresolved. A county-only posting cannot pass a strict Warwick-town filter. Approximate/unresolved results may appear only in an explicitly labelled optional broad-results section, excluded from exact counts/alerts. No `Contains("Warwick")` geography. Live-query result-window limits prevent exhaustive local filtering claims.
|
||||
|
||||
## Optional radius and remote rules
|
||||
|
||||
Radius is off by default. Choose town origin(s) explicitly with known point provenance; examples 10/25/50 km. Radius replaces the town polygon test for that origin, so nearby places outside the parent boundary may be included; keep the selected **country** constraint and disclose “within X km of town”, not “town only”. Multiple origins OR together; whole-area branches still OR with radius branches. Different dimensions still AND. Do not apply a county centroid as if it were a town or job coordinate.
|
||||
|
||||
Compute geodesic distance on WGS84 coordinates, inclusive boundary with documented numerical tolerance and fixture points just inside/outside. Missing/area-centroid-only job coordinates fail strict radius membership and remain visibly unknown. No driving-time claim; actual commute time requires a separately licensed routing provider, deferred.
|
||||
|
||||
Remote filter is explicit: on-site/hybrid use workplace scope/radius; fully remote matches selected work-country eligibility where declared, with geographic/radius exception visibly labelled and opt-in; region-limited remote still requires that declared region. Unknown eligibility does not mean worldwide. Work location constraints cannot be bypassed by a remote tag.
|
||||
|
||||
## GJ02 acceptance obligations
|
||||
|
||||
Freeze real licensed IDs/geometries for Warwickshire/Warwick/Leamington, Vestfold/Tønsberg/Sandefjord, Vestland/Bergen, Oslo dual identity and Stockholm län/municipality/settlement. Test all transitions above, nested/sibling branches, cross-country OR, unitary/overlapping geography, stale IDs, missing coordinates, radius bounds, provider code mismatch and persistence roundtrips. Measure index/query plan, lazy lookup and accessible mobile/keyboard behavior; never render 1,000 child checkboxes. Until exact settlement data is qualified, town-precision implementation remains blocked rather than using district substitutes.
|
||||
@@ -0,0 +1,126 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,24 @@
|
||||
# Owner actions and external approvals
|
||||
|
||||
28 October 2026. No registrations, agreements, emails, purchases or production changes were made. These are actionable handoffs, not drafts sent on the owner's behalf.
|
||||
|
||||
| Action / owner | Exact requested outcome | Blocks |
|
||||
|---|---|---|
|
||||
| Development owner — Phase 10 | Read `docs/cv-integration-qa/PHASE_10_HANDOFF.md`; nominate exact candidates and current callers/compatibility/preservation tests, then record applicable Phase 10 completion/entry decision. Do not treat “legacy” names as unused. | Global implementation entry; no cleanup authorized here |
|
||||
| Product owner — PRODUCT-REVIEW-01 | Publish baseline-bound review, approved scope/non-goals, outstanding qualification acceptance, country/locale/provider fallback policy and explicit INT-GLOBAL-JOBS-01/GJ-01 authorization. | GJ-01 |
|
||||
| Owner — design review | Approve hybrid architecture, branch order, hierarchy/radius/remote behavior, language release policy and proposed metrics/retention; identify required changes. Issue next-stage instruction only after entry gates. | Implementation sign-off; GJ-00 itself is delivered for review |
|
||||
| Business/operator — NAV | Using [official instructions](https://navikt.github.io/pam-stilling-feed/), send terms acceptance, company identifier, contact person/email/phone to the listed NAV team address. Ask for consumer JWT and approved polling, stale-outage/removal/contact handling expectations. Install secret via approved development secret store and record nonsecret grant evidence. Do not use public token as production access. | NAV live feed enablement/smoke |
|
||||
| Business/legal — FINN | If broad integration is desired, obtain written grant covering third-party commercial search, accessible inventory, caching/full display, attribution, expiry/removal, quotas and price. Advertiser ownership-only access is insufficient for global search. Otherwise accept manual bookmark/record + external link. | FINN API/full content; manual fallback remains possible |
|
||||
| Business/legal — Adzuna | Request commercial SaaS licence for NO/SE/GB scope as needed (GB first), approved snippet/redirect/branding, saved-search alerts, local storage/TTL, deletions/termination, quota/SLA and quote. Capture signed permitted scope; no automatic trial/account creation. | GB Adzuna live connector; no full descriptions promised |
|
||||
| Provider owner — Swedish services | Confirm current OpenAPI/schema/terms and suitable request volume with official JobTech contact; qualify JobSearch details/lifecycle and JobAd Links daily refresh/truncation/window. Ask about quotas/cache and update/delete reconciliation where docs do not specify. Preserve CC0 metadata and origin links. | Source operational acceptance; no registration prerequisite inferred |
|
||||
| Business/legal — NHSBSA | Ask whether third-party commercial multi-employer search/index/display/alerts are allowed, not merely employer self-serve/ATS posting; request exact feed scope, terms, refresh/removal, attribution and limits. | NHS direct connector |
|
||||
| Provider owner — DWP/other UK boards | Ask for explicit search-consumer agreement and documented retrieval interface if desired. Bulk upload is not search access. Leave Reed/Indeed/other boards external-only until source-specific rights review. | Other UK connectors |
|
||||
| Data owner — geography | Freeze canonical administrative/settlement artefacts with version, checksum, codes/edges, CRS/geometry precision and licence; resolve Warwick/Leamington town footprints, NO settlement/municipality differences, SE multi-municipality tätort, Scotland/NI data. Obtain commercial NI postcode permission before BT postcode reuse or omit that dataset. | Precise geographic capability; broad admin-only fallback disclosed |
|
||||
| Taxonomy owner | Acquire ESCO v1.2.1 candidate files through official process, exact file licence/readme/checksum and attribution; pin JobTech/SOC indexes/crosswalks; review EN/Bokmål/SV benchmark, unknown terms and “chef” ambiguity. | GJ03 data import/relevance qualification |
|
||||
| Localization owner | Qualify Swedish UI if required for initial SE release; native-review all new EN/Bokmål/SV legal/professional language. Confirm Norway/Sámi and GB regional mappings; Nynorsk/Welsh/Gaelic/Scots/minority languages stay Coming Later until complete. | Shipped-locale claims and related journeys |
|
||||
| Privacy/release owner | Approve lawful retention of source PII, user notes/copied descriptions/frozen evidence, diagnostic metadata, alert frequency/email consent, export/erase, backup expiry and restored-backup suppression. Consider DPIA need against concrete processing. | PII persistence/alerts and release scope |
|
||||
| Infrastructure owner | Qualify isolated nonproduction MariaDB CI runner and resource/cost envelope; keep production benchmark/maintenance jobs out of discovery tests. | Hosted provider/DB/load evidence, not local planning |
|
||||
| Human QA owner | Complete actual device/keyboard/AT/native-language/contrast/print qualifications and record identity/date/scope. | Human/release acceptance only |
|
||||
| AI owner | Independently qualify environment/artifact/security and semantic quality, then explicitly authorize inference if needed. | Optional AI only; deterministic discovery must work without it |
|
||||
|
||||
No one approval substitutes for another. If a provider declines rights, leave it disabled/manual/external-only and document coverage; do not seek undocumented endpoints or scrape the source to bypass the decision. Keep secret agreements/credentials outside public docs; store only reviewed scope and evidence references.
|
||||
@@ -0,0 +1,54 @@
|
||||
# Product requirements — proposed, GJ-00
|
||||
|
||||
28 October 2026. Authority: [master prompt](../../planning/global-jobs-prompts/00_MASTER_ORCHESTRATOR.md). Implementation remains gated by [entry decisions](DEPENDENCIES_AND_GATES.md).
|
||||
|
||||
## Product scope and journeys
|
||||
|
||||
Discovery serves all occupations in Norway, Sweden and the United Kingdom initially. ISO country identifiers are `NO`, `SE`, `GB`; UI may display “UK”. Country availability and provider availability are separate. Unavailable sources cannot turn a country into a fabricated searchable inventory.
|
||||
|
||||
| Journey | Persisted choice and resulting behavior |
|
||||
|---|---|
|
||||
| New resident | Optional residence NO; English UI; Norwegian/English adverts; choose NO work scope. Do not request nationality to enable search. |
|
||||
| Multi-country mover | Lives in NO, searches SE + GB; separate geographic branches OR together. Residence does not restrict results. |
|
||||
| Returning jobseeker | Recover defaults across devices; load named search, override a query temporarily, explicitly update defaults only on request. |
|
||||
| No formal occupation | Search free text such as “no experience”, “weekend work”, kitchen assistant or cleaner. No required taxonomy selection, skill inventory or CV upload. |
|
||||
| Mixed jobs/shift work | Search retail and care roles, part-time/evenings, multiple towns; unknown schedule fields remain unknown. Missing filters are disclosed per provider. |
|
||||
| Regulated occupation | Nurse/electrician matches show advertised credentials against explicit profile evidence; no claim of professional authorisation or eligibility. |
|
||||
|
||||
## Preference boundaries
|
||||
|
||||
`SearchPreference` holds optional residence, desired work countries (0..N), favourite location scopes, occupation interests, explicit skills references, work arrangements, advert languages and revision. Residence, nationality, home country and work countries are distinct; do not add compulsory demographic fields. UI locale stays in existing account preferences. CV and cover-letter languages remain document-specific.
|
||||
|
||||
Named `SavedSearch` profiles capture a versioned query, rather than a pointer to mutable defaults. Discovery initializes from defaults; filter edits change draft query state only. “Save search”, “Update this search” and “Update defaults” are explicit, different actions with revision checks. Empty preferences show a country-choice invitation and usable keyword search. Changing UI language never changes advert-language filters or document content.
|
||||
|
||||
## Language selection and qualification
|
||||
|
||||
Current code supports `en` and `nb` UI dictionaries; API accepts `en`, normalizes `nb`/`nb-NO`/`no` to `nb-NO`, and rejects other locales. This is source-verified support, not fresh linguistic acceptance. Proposed locale registry uses BCP 47, native + English labels, coverage/QA status, fallback and regional relevance. Maintain compatibility for existing stored values; do not silently rewrite document languages.
|
||||
|
||||
English and applicable local languages appear prominently, combining residence, selected region/work countries and explicit user preference, with stable ordering and no duplicate choices. Other **qualified** UI languages go under More Languages. Unsupported relevant languages appear separately as Coming Later, without an enabled switch. English fallback must be visible if a requested locale is unavailable. Do not infer language from nationality.
|
||||
|
||||
| Context | Prominent language candidates | Current qualification / next work |
|
||||
|---|---|---|
|
||||
| Norway | English; Norsk bokmål — Norwegian Bokmål; Norsk nynorsk — Norwegian Nynorsk; relevant Sámi language choices by region | EN/Bokmål implemented. Nynorsk and specific Sámi locales require translation and native review; `no` ESCO labels prove neither. |
|
||||
| Sweden | English; Svenska — Swedish; regionally relevant minority-language choices | Swedish is a required target, currently unimplemented. Finnish, Meänkieli, Sámi, Romani and Yiddish need separate qualification, not generic “Swedish translation”. |
|
||||
| GB / Wales | English; Cymraeg — Welsh for Wales | Welsh remains Coming Later until complete and reviewed. |
|
||||
| GB / Scotland | English; Gàidhlig — Scottish Gaelic; Scots | Region-aware candidates, not currently supported switches. |
|
||||
| GB / Northern Ireland | English; relevant Irish/Ulster Scots candidates | Confirm local language mapping/status and BCP 47 representation at GJ01-C; no inferred blanket UK official-language list. |
|
||||
|
||||
Language-policy evidence accessed 2026-10-28: [ISOF](https://www.isof.se/flersprakighet/lar-dig-mer-om-flersprakighet/spraken-i-sverige), [Welsh Government](https://www.gov.wales/planning-and-environment-decisions-wales/welsh-language-standards), [Scottish Government](https://www.gov.scot/news/growing-scotlands-languages/). These inform prominence; they do not certify translations or impose an assumed legal duty on Jobjakt. Norway/Sámi and Northern Ireland detailed regional mappings remain explicit GJ01-C qualification work.
|
||||
|
||||
New controls, validation, empty/error/help text, date/number/plural forms, accessible names and alert text require EN/Bokmål coverage. Swedish cannot be advertised as a supported UI until all shipped surfaces meet the approved coverage/native review gate; a “Swedish UI” acceptance journey stays blocked until then.
|
||||
|
||||
## Discovery experience
|
||||
|
||||
Retain React Router and MUI ownership: desktop filter rail, results list, in-app details; tablet adaptive panes; mobile full-screen detail with return focus/filter state. A stable in-app details URL supports full-page expansion. Preserve country/role/language/location filters on navigation and saved-query recovery.
|
||||
|
||||
Details show permitted original description with completeness badge (`full`, `truncated`, `metadata`, `link-only`), original title, employer, location precision, source, posted/updated/retrieved/expiry timestamps and source/apply links. Structured pay retains amount/range/currency/period plus advertised versus predicted status; unknown is not zero. Show requirements, responsibilities, qualifications, shifts/hours, arrangement and contract only when supplied. Translation is separately labelled and never replaces original text or expands licensed content.
|
||||
|
||||
Saved vacancy does not mean applied. Track Application enters existing reviewed application workflow; CV/letter links reuse current owners and never trigger AI or submission. Source withdrawal hides restricted content without deleting user-authored notes/status. Source alternatives remain separate and attributed after conservative dedupe.
|
||||
|
||||
Loading, empty, partial coverage, unavailable, stale and expired states must differ. Never label external search links as integrated search. Filters unsupported by a provider must either be applied exactly to authorised data or show the coverage exclusion; silently ignoring them is unacceptable.
|
||||
|
||||
## Requirement ownership
|
||||
|
||||
Preferences/language GJ-01; hierarchy/radius GJ-02; universal terms GJ-03; rights/source lifecycle/dedupe GJ-04; panels/details/actions GJ-05; alerts/skills/tracking GJ-06; admin/privacy/resilience GJ-07; combined proof GJ-08. Acceptance scenarios are in [the matrix](ACCEPTANCE_MATRIX.md); no part of this document authorizes implementation.
|
||||
@@ -0,0 +1,42 @@
|
||||
# Provider rights and feasibility — GJ-00
|
||||
|
||||
Access date: **2026-10-28**. Official documentation research only; no consumer registration, account creation, credential use, live advertisement search or provider contract test was performed. “Conditional” means suitable for design with stated gates, not enabled or approved for Jobjakt. No provider has live operational acceptance here.
|
||||
|
||||
## Feasibility matrix
|
||||
|
||||
| Country / immutable proposed provider ID | Documented access / cost / commercial position | Search and in-app content | Lifecycle / attribution / approval | Decision |
|
||||
|---|---|---|---|---|
|
||||
| NO / `nav-feed` | Free; JWT. Private token requires consumer registration and written acceptance; rotating public token is experimental. | Change feed, not live keyword search; local index. Detail fetch supplies original description; FINN adverts excluded. | Apply updates/removals immediately; mask stopped content/contact data. Preserve application deep link. [Feed](https://navikt.github.io/pam-stilling-feed/), [terms](https://arbeidsplassen.nav.no/vilkar-api). | CONDITIONAL GO design; consumer token and lifecycle proof required before enablement. |
|
||||
| NO / `finn-manual` | Advertiser/business relationship, ownership of accessible data and agreement required for API. No general third-party search grant. | URL bookmark/manual fields + external link only. No page fetch, preview extraction, bulk search or full descriptions assumed. | Any broader caching/display/removal/price rights need explicit agreement. [FINN access](https://www.finn.no/api/). | GO manual-only design; NO-GO API/full-content connector without suitable grant. |
|
||||
| SE / `se-jobsearch` | Public, CC0, no key/registration listed; no paid access prerequisite documented. | Live free-text/structured search and detail endpoint; design for available original descriptions, not guaranteed populated fields. | Recheck active detail before display/alert; reconcile withdrawals. Source labels/links retained. Rate/SLA/cache specifics need current contract qualification. [Service](https://data.arbetsformedlingen.se/dataservice/jobsearch/), [dataset](https://data.arbetsformedlingen.se/dataset/job-ads/). | CONDITIONAL GO; strongest initial live-query candidate, not tested here. |
|
||||
| SE / `se-jobad-links` | Public, CC0, no key/registration listed. | Search and referenced metadata; descriptions deliberately truncated; original-site link required by service guidance. Never retrieve full third-party page to fill gaps. | Daily source refresh; SSYK classification is provider-generated. [Service](https://data.arbetsformedlingen.se/dataservice/jobad-links/), [OpenAPI 1.4.5](https://links.api.jobtechdev.se/swagger.json). | CONDITIONAL GO preview/link design; no full-content grant. |
|
||||
| SE / `se-jobstream` | Public, CC0, no registration listed. | Platsbanken feed candidate for later local indexing; not a second inventory to count twice. | Detailed change/delete protocol, snapshots, lag and reconciliation must be qualified in GJ04-A before choosing ingestion. [Service](https://data.arbetsformedlingen.se/dataservice/jobstream/). | CONDITIONAL future adapter; initial SE plan uses JobSearch. |
|
||||
| GB / `gb-adzuna` | ID/key; free evaluation tier, commercial trial limited to 14 days. Ongoing revenue/lead service needs licence; price/limits negotiated. No trial begun. | Search response contains description snippet, not full advert; retain provider redirect. | Adzuna branding/link rules; termination requires data removal. Contract must settle caching, alert use, expiry, quotas and link handling. [Terms](https://developer.adzuna.com/docs/terms_of_service), [search](https://developer.adzuna.com/docs/search). | NO-GO live commercial connector pending written approval; conditional snippet-only design. |
|
||||
| GB / `gb-nhs` | NHS documents employer self-serve XML/RSS and ATS integrations; not evidence of unrestricted SaaS aggregation rights. | External NHS search/link fallback; no bulk/full-detail connector approved. | Ask NHSBSA for commercial job-board eligibility, scope, display, caching, quotas and withdrawal rules. [Official integration guidance](https://www.nhsbsa.nhs.uk/about-nhs-jobs/nhs-jobs-integration-and-benefits). | NO-GO direct integration until rights confirmed. |
|
||||
| GB / `gb-find-a-job` | Documented DWP bulk upload is employer/ATS publishing, not a search-consumer grant. | External search/manual URL only. | Consumer access/display/retention remain unverified. [Official uploader specification](https://static.findajob.dwp.gov.uk/images/find_a_job_bulk_upload_spec_v3.0.pdf). | NO-GO search API; do not repurpose upload credentials. |
|
||||
|
||||
Reed, Indeed, Totaljobs, CV-Library, Civil Service and other boards are **unqualified prospects**, with no connector or rights assumed. External links may be offered without server fetching; a new source requires its own reviewed manifest before any integration. Optional DK/DE/FR/NL expansion is deferred, not claimed researched or supported.
|
||||
|
||||
## Capability manifest and enforcement proposal
|
||||
|
||||
Each manifest records `providerId`, countries, API/document version, terms URL, evidence/reviewer/date, rights validity/review date, commercial eligibility, credential reference/status, allowed modes, filters, geographic precision, content level, stored fields, cache/PII retention limits, deletion mechanism, attribution, original/apply-link policy, quota/concurrency/backoff and enabled state. Numeric rights limits are nullable **unknown**, never unlimited. Unknown rights deny that capability. Quota absence means bounded conservative traffic plus provider confirmation before load, not permission to stress the service.
|
||||
|
||||
Effective permission = reviewed grant AND operational enablement AND valid credentials where required AND supported API capability. Store no tokens in the manifest, query strings in logs, or repository. Capability-specific interfaces avoid fake `Search` implementations for feeds/manual sources. Display permission is enforced server-side for search, details, exports, saved-job views and notifications; UI badges alone are insufficient.
|
||||
|
||||
Current JobAd Links schema permits `q`, region/municipality/country concept IDs and occupation fields/groups, with limit <=100 and offset <=2000. This is a bounded search window, not exhaustive pagination or exact town/radius support. API metadata was read; responses were not exercised. The old 1,000-request/day wording seen in a 2023 report is not a verified current quota. Contact provider before higher volume.
|
||||
|
||||
No full description is promised for snippet sources. For Adzuna, use approved redirect/attribution rather than bypassing to extracted third-party URLs. Verify usable HTTPS destinations during qualification; never forward provider credentials to redirects. Estimated salaries must remain visibly estimated.
|
||||
|
||||
## Lifecycle decisions
|
||||
|
||||
NAV: normalize ACTIVE/INACTIVE changes into internal `SourceLifecycleEvent`; “tombstone” is Jobjakt's internal deletion marker, not an invented NAV endpoint/status. Ingest removals even if geography/occupation changed or the ad now fails a filter. Apply record/masking/cache invalidation and cursor advancement transactionally. Do not leave a persistent cache backed by request-time partial feed scans. Detail rechecks and source-health fail-closed policy are required when freshness cannot be maintained. No claim of instantaneous detection beyond the provider feed is possible.
|
||||
|
||||
For all sources, distinguish official requirement from proposed operational bound. Proposed: active query caches <=5 minutes, no alert if the source is stale, provider-specific health/freshness threshold reviewed in GJ04-A, and immediate local suppression when a withdrawal is observed. These numbers do not substitute for provider terms. For NAV, outage handling should hide searchable cached content once freshness cannot be assured, and disclose availability loss; owner/provider must approve polling and stale thresholds.
|
||||
|
||||
SE live query: short rights-permitted cache, current detail/404 handling, expiry checks, and periodic reconciliation of retained saved references. Daily JobAd Links refresh cannot prove minute-level freshness. Withdrawal checks and uncertainty must remain visible. Historical API presence does not make a job active or justify retaining contact PII.
|
||||
|
||||
On expiry/withdrawal/revocation: suppress search/detail, cancel queued alerts and clear source-derived restricted text/contacts across cache/index/exports. Keep minimal provider ID/status event without content where lawful. A dedupe cluster may still show independently authorised active sources; never inherit a wider grant from another source. User-authored notes/status remain separately retained under approved account policy; copied source text does not become user-owned merely by saving it. Backup/restore purge and policy replay must prevent republication.
|
||||
|
||||
## Required qualification before GJ04 source GO
|
||||
|
||||
Review exact terms/version and written agreement where applicable; record price/quota/retention/display/application-link obligations; obtain operator-managed credentials without printing them; freeze permitted redacted fixtures and schema hash; prove update/delete/404/429/auth failure and rights-revocation behavior; run authorised bounded smoke separately. No fixture pass upgrades commercial approval or provider health.
|
||||
@@ -0,0 +1,23 @@
|
||||
# INT-GLOBAL-JOBS-01 — GJ-00 planning checkpoint
|
||||
|
||||
28 October 2026. **Planning/research only. Design: CONDITIONAL GO for review. GJ-01 implementation: NO-GO. Production: NO-GO.**
|
||||
|
||||
This is a proposed architecture, not implemented behavior or owner sign-off. The authoritative [prompt pack](../../planning/global-jobs-prompts/README.md) governs each later stage. Stop after GJ-00; obtain the next stage instruction and entry decisions before implementation.
|
||||
|
||||
| Deliverable | Purpose |
|
||||
|---|---|
|
||||
| [Product requirements](PRODUCT_REQUIREMENTS.md) | Journeys, preferences, languages and discovery experience |
|
||||
| [Provider rights matrix](PROVIDER_RIGHTS_MATRIX.md) | Dated official evidence, capabilities, commercial and lifecycle limits |
|
||||
| [Cross-industry taxonomy](CROSS_INDUSTRY_TAXONOMY.md) | Occupations, aliases, skills, national mappings and benchmark |
|
||||
| [Geography decisions](GEOGRAPHY_DECISIONS.md) | Typed locations, exact refinement rules, radius and data licences |
|
||||
| [Architecture ADRs](ARCHITECTURE_ADRS.md) | Existing owners, proposed contracts, processing, integrity and migration |
|
||||
| [Dependencies and gates](DEPENDENCIES_AND_GATES.md) | Current source authority and independent entry decisions |
|
||||
| [Implementation checkpoints](IMPLEMENTATION_CHECKPOINTS.md) | Ordered GJ-01–08 execution plan and file/test ownership |
|
||||
| [Acceptance matrix](ACCEPTANCE_MATRIX.md) | Checkable future acceptance and evidence boundaries |
|
||||
| [Owner actions](OWNER_ACTIONS.md) | External approvals and exact operator handoffs |
|
||||
| [Evidence](EVIDENCE.md) | Research/verification ledger and publication procedure |
|
||||
| [TODO](TODO.md) | Bounded GJ-00 checklist and deferred execution |
|
||||
|
||||
Source baseline: `4a8c907d70cbed235728f7d690b5409e72b93abe`, remote-confirmed `test/cv-integration-acceptance`. Planning branch: `planning/int-global-jobs-00`. No application, migration, Docker, AI or production change belongs to this checkpoint.
|
||||
|
||||
Recommendation: review this design now; **do not begin GJ-01** until Phase 10, PRODUCT-REVIEW-01 and initiative entry approval are evidenced. NAV consumer registration and UK licensing can proceed as separate owner actions, without blocking unrelated planning.
|
||||
@@ -0,0 +1,16 @@
|
||||
# GJ-00 TODO
|
||||
|
||||
28 October 2026. Scope: planning/research only.
|
||||
|
||||
- [x] Read README, master and GJ-00 first; read all later stage-specific requirements for dependency planning.
|
||||
- [x] Verify current branch/source, remote baseline, architecture, roadmap, latest acceptance and Phase 10 boundary.
|
||||
- [x] Query Graphify before source exploration; inspect scoped existing discovery/import/preferences/alerts/admin/data owners.
|
||||
- [x] Research official provider access/commercial/display/lifecycle rules; distinguish missing rights and untested API behavior.
|
||||
- [x] Document product journeys, locale qualification, universal taxonomy, exact geographic refinements and radius.
|
||||
- [x] Produce nine required deliverables, proposed contracts/ADRs, migration/privacy/security boundaries and ordered implementation plan.
|
||||
- [x] Run documentation completeness/link/scope/ancestry checks and retain actual results.
|
||||
- [x] Commit only authorized planning documents and supplied prompt pack.
|
||||
- [ ] Push planning branch and verify remote HEAD — BLOCKED: two connection failures to git.cesnimda.uk:443.
|
||||
- [x] Stop after GJ-00; no feature code, provider registration, live AI, main merge or production deployment.
|
||||
|
||||
Deferred execution is tracked in [Implementation checkpoints](IMPLEMENTATION_CHECKPOINTS.md); external decisions are tracked in [Owner actions](OWNER_ACTIONS.md). Do not tick later stage boxes from planning evidence.
|
||||
@@ -0,0 +1,61 @@
|
||||
# Jobjakt — INT-GLOBAL-JOBS-01 — MASTER CODEX / ASTRA PROMPT
|
||||
## International, multilingual, cross-industry job discovery
|
||||
|
||||
### Mission
|
||||
Build Jobjakt into a trustworthy, professional job-discovery and application-tracking experience for **everyone**: educators, chefs, cleaners, nurses, drivers, retail workers, construction trades, engineers, office staff, IT professionals and every other occupation. Start with Norway, Sweden and the United Kingdom, using an extensible, provider-aware foundation that can add countries without rebuilding search. Make users' preferred countries and languages persistent rather than requiring repeated filtering.
|
||||
|
||||
**All agreed product requirements are in scope:**
|
||||
1. During onboarding/Settings ask country of residence and separately one or more countries to search; never equate nationality, home country, residence and desired work countries. Save preferred regions/cities, occupation interests, skills, work arrangement and ad languages; apply defaults automatically at discovery; allow temporary overrides without modifying the user's profile. Support multiple named saved search profiles.
|
||||
2. Provide country-aware interface language choices: **English plus the selected country's local official language(s)** prominently, with all other actually-supported UI languages under More Languages. Countries with several official languages and region-specific languages must be handled properly. Store interface locale, ad language filters and each CV/cover-letter language separately; never imply all translations already exist.
|
||||
3. Universal occupational title autocomplete: multilingual title aliases and related occupations across **all sectors**, not developer-centric heuristics; optional skills-based suggestions; exact-title vs related roles vs open keyword; preserve local terms and original advert text. Use qualified ESCO and appropriate national classifications with explicit versioning and licences; support unknown/free-text occupations.
|
||||
4. Accurate hierarchical locations: country → appropriate region/county → municipality/district → town/locality. Use provider-specific geographical adapters and authoritative canonical IDs/geometries, not substring matching. For example Warwickshire selected searches whole county; then selecting Warwick refines **that branch** to Warwick only while parent remains visibly selected; selecting Leamington Spa too searches both towns, not the rest of county. Other selected branches combine as OR. No automatic child-checkbox selection. Add optional radius/commute filtering around a location with explicit semantics for multiple selections, remote roles and missing coordinates.
|
||||
5. Responsive results with persistent filters and three-column desktop design (filter rail, job list, in-app detail panel), and mobile full-screen detail; optionally expand panel to full Job Details page. Show as much **authorised** source information as available: full or truncated original description, employer, location, requirements, responsibilities, qualifications, salary with period/currency and predicted/estimated distinction, shift/hour schedule, working arrangements, contract, deadlines, original source, posted/updated time, and apply link. Sanitise content; show source completeness and provenance. Link original application method directly; do not fabricate anything.
|
||||
6. Source adapters with capability flags: direct search, event feed + compliant local indexing, authorised details, URL bookmark/manual import, external search link; provider rules for licensing, caching, update, removal, attribution and click-through. Norway: NAV feed and manual FINN URL workflows; Sweden: JobTech sources; UK: investigate official and licensed aggregators such as Adzuna, job boards, public sector sources. No forbidden scraping. Providers may be disabled independently without preventing other countries from working.
|
||||
7. Cross-provider deduplication (conservative confidence, separate source records, source labels), saved vacancies, application-tracker integration, job-specific CV and cover letter links, job expiry handling, saved searches, new-job alerts, optional commute radius, occupation/skills/qualification matching with reasoned evidence and no invented claims.
|
||||
8. Admin source health, sync/index queues, API quotas, failures and job import events integrated where practical with Jobjakt's processing monitor; admin-only redacted diagnostics. Keep external advertisements separate from user applications.
|
||||
9. Commercial product standards: scalable feed processing, accessible design, English and local languages, localisation coverage, strict multi-tenant security, privacy, GDPR-conscious data handling, good empty/disabled/failure UX, comprehensive cross-sector and cross-country test suites, metrics, rollback strategy.
|
||||
|
||||
### Architecture and boundaries
|
||||
Inspect the actual React, .NET, MariaDB and sidecar code and reuse existing auth, settings, dashboard, application tracker, Career Profile, CV Builder, documents, alerts, admin processing, multilingual framework, concurrency and migration patterns. Do not create a second job tracker or duplicate profile master. Build an explicit provider capability/rights manifest and canonical data contracts; separate job-ad inventory from user-owned saved/job-application records. Do not invent an unlimited global index or require AI for basic features.
|
||||
|
||||
### Sequence (run one stage at a time)
|
||||
- **GJ-00 Discovery, access and architecture** → `01_GJ_00_DISCOVERY.md` (planning only)
|
||||
- **GJ-01 Country, language and search preferences** → `02_GJ_01_PREFERENCES_I18N.md`
|
||||
- **GJ-02 Geographic hierarchy, selection semantics and radius** → `03_GJ_02_GEOGRAPHY.md`
|
||||
- **GJ-03 Cross-sector occupation suggestions and queries** → `04_GJ_03_OCCUPATIONS.md`
|
||||
- **GJ-04 Provider adapters, rights and ingestion** → `05_GJ_04_PROVIDERS.md`
|
||||
- **GJ-05 Unified search UI and in-app listing details** → `06_GJ_05_SEARCH_UI.md`
|
||||
- **GJ-06 Saved searches, alerts, matches and tracking** → `07_GJ_06_ALERTS_MATCHING.md`
|
||||
- **GJ-07 Admin operations, hardening and resilience** → `08_GJ_07_ADMIN_SECURITY.md`
|
||||
- **GJ-08 Full QA and release qualification** → `09_GJ_08_ACCEPTANCE.md`
|
||||
|
||||
For each stage, read its full prompt, respect the shared rules, begin from the accepted predecessor baseline, implement safe checkpoints, commit/push each, provide actual acceptance verdict and **stop without starting the next stage automatically**. Stage 00 may run before Phase 10 only as non-mutating research. Later stages require the documented Phase 10 and product-review handoff and owner-approved scope. If an API requires commercial permission, generate exact operator steps and leave its connector blocked; do not misrepresent external links or sample data as full integration.
|
||||
|
||||
### Provider research to verify anew at execution
|
||||
- NAV feed and terms: https://navikt.github.io/pam-stilling-feed/ and https://arbeidsplassen.nav.no/vilkar-api
|
||||
- FINN API eligibility: https://www.finn.no/api/
|
||||
- Sweden JobAd Links: https://links.api.jobtechdev.se/ and JobTech official APIs (verify current names/availability)
|
||||
- Adzuna search/terms: https://developer.adzuna.com/docs/search and https://developer.adzuna.com/docs/terms_of_service
|
||||
- ESCO multilingual occupations: https://esco.ec.europa.eu/en/use-esco/use-esco-services-api
|
||||
- UK geographic datasets: https://geoportal.statistics.gov.uk/
|
||||
|
||||
### Cross-industry benchmark
|
||||
Every major behaviour must be tested with examples spanning teacher/teaching assistant, chef/kitchen assistant, nurse/care worker, electrician/plumber/carpenter, driver/warehouse operator, shop assistant, cleaner, accountant/administrator, farm worker, and software developer. Include English, Bokmål, Swedish and other supported source terms; qualifications, shifts and multiple employment modes; do not optimise relevance exclusively for tech roles.
|
||||
|
||||
### Final output
|
||||
Report completed stage list, exact Git ancestry/commits, live-vs-fixture provider coverage by country, current user-facing capabilities, translation completeness, geography correctness, occupation coverage, data provenance/expiry, alerts and dedupe, performance, security and accessibility, all remaining external approvals/human tests, independent GO decisions and **production withholding status**. Never merge main or deploy. Stop after the approved stage.
|
||||
|
||||
## Shared rules for every INT-GLOBAL-JOBS-01 stage
|
||||
|
||||
- Product: **Jobjakt**, a general-purpose, commercial job-search and career-management SaaS. It is **not** an IT-only product. Current architecture includes React/TypeScript, .NET backend, MariaDB, an AI sidecar, existing Career Profile/CV/document/application features, and an established EN/NO localisation approach. Verify actual repository reality before making assumptions.
|
||||
- **Entry gates:** Do not implement new global-job-discovery features until the authoritative Phase 10 and product-review/development-entry decisions permit this initiative. Planning-only reconnaissance may precede them. If an entry gate remains NO-GO, produce safe analysis and stop before code changes.
|
||||
- **Baseline:** Find the latest accepted, integration-complete development commit by reading Git history and the latest authoritative acceptance reports. Do not assume `main` is current. `main` deploys production: NEVER merge to `main` or trigger production. Never change live MariaDB, Docker, Ollama, storage, secrets or other production services.
|
||||
- **Branches:** Use the specified independent stage branch from the latest accepted development integration history including the preceding accepted stage. Verify ancestry, remote, clean tree and existing branch collisions. Use checkpoint commits; push each validated checkpoint; verify remote HEAD equals local HEAD. Do not force-push. Do not advance to another stage without its actual entry criteria.
|
||||
- **Autonomy:** Investigate, design, implement, add tests, document, commit and push safe work without pausing for routine decisions. Stop only for external API agreements, new paid resources, security-risk acceptance, destructive changes, privileged infrastructure actions and production operations. Continue independent work when one provider or model capability is blocked.
|
||||
- **Sources:** Integrate only documented, authorised sources. Verify current licensing, commercial eligibility, credentials, permitted display, storage, cache lifetime, update/delete/tombstone, attribution, user-click-through and rate-limit rules. No covert scraping, private APIs, stolen cookies, bypassing anti-bot controls or fetching protected listing content without authorisation. An external-link-only source is not a direct searchable provider.
|
||||
- **Data trust:** All provider data, job descriptions and user-provided URLs are untrusted. Guard SSRF, XSS/unsafe HTML, prompt injection, HTML injection, unsafe redirects, credential leakage, denial of service and cross-user/tenant access. Do not present missing facts, inferred salaries, regulated-profession eligibility, or AI-generated job details as verified employer facts.
|
||||
- **Availability:** Preserve offline/disabled provider states. Use realistic fixtures in automated tests; any live contract test needs authorised test credentials and bounded rates. Never claim unavailable external API functionality passed.
|
||||
- **User-facing quality:** Desktop/tablet/phone, keyboard and screen-reader access, light/dark, EN/Bokmål plus future qualified locales, loading/empty/error states, responsive design, sensible defaults, performance, source transparency, internationalisation and accessible non-drag alternatives.
|
||||
- **Data integrity:** Source advertisements and user-owned saved jobs/applications are separate records and lifecycles. Preserve existing Career Profile, historical CVs, cover letters, saved applications, revisions, RD21 protections and MariaDB compatibility. Follow source rules for removing or masking withdrawn advertisements, while handling user-owned records under a separately justified retention policy.
|
||||
- **AI:** Existing live-model inference and semantic quality must remain gated unless separately qualified. Rule-based/ESCO-backed title suggestions and auditable matching should function without a generative model. Do not invent user qualifications or automate application submissions.
|
||||
- **Evidence:** At every checkpoint provide exact tests (pass/fail/skip/not run), security/coverage evidence, dated docs, commit hashes, branch and remote verification. Report individual stage GO / CONDITIONAL GO / NO-GO; separate production NO-GO from development readiness.
|
||||
@@ -0,0 +1,38 @@
|
||||
# GJ-00 — Product and Provider Discovery / Architecture Sign-off
|
||||
**Suggested branch:** `planning/int-global-jobs-00` | **Mode: planning/research ONLY**
|
||||
|
||||
## Objective
|
||||
Establish an evidence-backed implementation plan for international, multilingual, cross-industry job discovery, integrating with the real Jobjakt code and accepted roadmap, without changing application behaviour. You may perform this planning stage before Phase 10 completion, but code implementation requires later confirmed development entry.
|
||||
|
||||
## Mandatory investigations
|
||||
1. Verify current Git baseline and latest Phase 10 / PRODUCT-REVIEW-01 handoff. Inspect code for existing job imports, Kanban, Career Profile, search, preferences, geolocation, translations, notifications, dashboard, admin monitor, user/tenant authorization and MariaDB entities.
|
||||
2. Map user journeys for new resident, multi-country mover, returning jobseeker, jobseeker with no formal occupation, and mixed jobs/shift work. Distinguish country of residence, nationality, desired search countries, ad language(s), UI language and document language.
|
||||
3. Review current official API terms and capabilities for Norway (NAV feed including tombstones and consumer token; FINN partner-restricted), Sweden (JobTech JobSearch and JobAd Links, including truncation/attribution and classification), UK (Adzuna commercial agreement and description snippets; government/public-sector APIs where legitimately available); optionally Denmark/Germany/France/Netherlands as future prospects. Cite URL/access date. No claiming API access without proof.
|
||||
4. Review authoritative geography: Norway county/municipality and locality; UK country/county/unitary authority/district/built-up area/town and overlap issues; Swedish län/kommun/tätort. Include immutable IDs, dataset version, ancestry, geometry/licence, alias/local names, postal code mapping where licensed, and provider data quality. Explicitly verify Warwickshire/Warwick/Leamington Spa, Vestfold/Tønsberg, Vestland/Bergen and Oslo edge cases.
|
||||
5. Research ESCO multilingual occupation taxonomy, mappings to Swedish SSYK and UK SOC where viable; distinction among occupation, keyword, industry, required credential, skill, employer title and free text. Do not limit taxonomy to IT.
|
||||
6. Determine options and costs for local index vs live provider queries, data updates/deletes and cache limits, rate limiting and search technology compatible with actual stack. Avoid adding Elasticsearch/third-party SaaS automatically.
|
||||
7. Model source-rights metadata and per-provider capability gating. Document what can be fully displayed in-app vs preview-only vs external-link-only. Detail redirects/apply links, licences, price, approval needs.
|
||||
8. Define privacy, PII retention, alert frequency and anti-spam, admin diagnostics, multi-tenant threats, disabled-source fallback and data lineage.
|
||||
|
||||
## Produce
|
||||
`docs/global-jobs/00/PRODUCT_REQUIREMENTS.md`, `PROVIDER_RIGHTS_MATRIX.md`, `CROSS_INDUSTRY_TAXONOMY.md`, `GEOGRAPHY_DECISIONS.md`, `ARCHITECTURE_ADRS.md`, `DEPENDENCIES_AND_GATES.md`, `IMPLEMENTATION_CHECKPOINTS.md`, `ACCEPTANCE_MATRIX.md`, `OWNER_ACTIONS.md`.
|
||||
|
||||
Architecture must include canonical `SearchPreference`, `LocationNode`, `LocationScope`, `OccupationConcept`, `ProviderCapability`, `SourceAdvertisement`, `SourceLifecycleEvent`, `SavedJob`, `SavedSearch`, and `SearchAlert` concepts, reconciled against existing names—not a mandate to create all those tables. Define data contracts and safe migration strategy, not code changes.
|
||||
|
||||
## Sign-off
|
||||
Identify GO / CONDITIONAL GO / NO-GO for design completeness and each proposed provider. Separate paid/approval/deployment gates. Commit and push planning docs. Do not implement features, register consumers on behalf of the user, or start GJ-01.
|
||||
|
||||
## Shared rules for every INT-GLOBAL-JOBS-01 stage
|
||||
|
||||
- Product: **Jobjakt**, a general-purpose, commercial job-search and career-management SaaS. It is **not** an IT-only product. Current architecture includes React/TypeScript, .NET backend, MariaDB, an AI sidecar, existing Career Profile/CV/document/application features, and an established EN/NO localisation approach. Verify actual repository reality before making assumptions.
|
||||
- **Entry gates:** Do not implement new global-job-discovery features until the authoritative Phase 10 and product-review/development-entry decisions permit this initiative. Planning-only reconnaissance may precede them. If an entry gate remains NO-GO, produce safe analysis and stop before code changes.
|
||||
- **Baseline:** Find the latest accepted, integration-complete development commit by reading Git history and the latest authoritative acceptance reports. Do not assume `main` is current. `main` deploys production: NEVER merge to `main` or trigger production. Never change live MariaDB, Docker, Ollama, storage, secrets or other production services.
|
||||
- **Branches:** Use the specified independent stage branch from the latest accepted development integration history including the preceding accepted stage. Verify ancestry, remote, clean tree and existing branch collisions. Use checkpoint commits; push each validated checkpoint; verify remote HEAD equals local HEAD. Do not force-push. Do not advance to another stage without its actual entry criteria.
|
||||
- **Autonomy:** Investigate, design, implement, add tests, document, commit and push safe work without pausing for routine decisions. Stop only for external API agreements, new paid resources, security-risk acceptance, destructive changes, privileged infrastructure actions and production operations. Continue independent work when one provider or model capability is blocked.
|
||||
- **Sources:** Integrate only documented, authorised sources. Verify current licensing, commercial eligibility, credentials, permitted display, storage, cache lifetime, update/delete/tombstone, attribution, user-click-through and rate-limit rules. No covert scraping, private APIs, stolen cookies, bypassing anti-bot controls or fetching protected listing content without authorisation. An external-link-only source is not a direct searchable provider.
|
||||
- **Data trust:** All provider data, job descriptions and user-provided URLs are untrusted. Guard SSRF, XSS/unsafe HTML, prompt injection, HTML injection, unsafe redirects, credential leakage, denial of service and cross-user/tenant access. Do not present missing facts, inferred salaries, regulated-profession eligibility, or AI-generated job details as verified employer facts.
|
||||
- **Availability:** Preserve offline/disabled provider states. Use realistic fixtures in automated tests; any live contract test needs authorised test credentials and bounded rates. Never claim unavailable external API functionality passed.
|
||||
- **User-facing quality:** Desktop/tablet/phone, keyboard and screen-reader access, light/dark, EN/Bokmål plus future qualified locales, loading/empty/error states, responsive design, sensible defaults, performance, source transparency, internationalisation and accessible non-drag alternatives.
|
||||
- **Data integrity:** Source advertisements and user-owned saved jobs/applications are separate records and lifecycles. Preserve existing Career Profile, historical CVs, cover letters, saved applications, revisions, RD21 protections and MariaDB compatibility. Follow source rules for removing or masking withdrawn advertisements, while handling user-owned records under a separately justified retention policy.
|
||||
- **AI:** Existing live-model inference and semantic quality must remain gated unless separately qualified. Rule-based/ESCO-backed title suggestions and auditable matching should function without a generative model. Do not invent user qualifications or automate application submissions.
|
||||
- **Evidence:** At every checkpoint provide exact tests (pass/fail/skip/not run), security/coverage evidence, dated docs, commit hashes, branch and remote verification. Report individual stage GO / CONDITIONAL GO / NO-GO; separate production NO-GO from development readiness.
|
||||
@@ -0,0 +1,43 @@
|
||||
# GJ-01 — Country Preferences, Multilingual UI and Search Defaults
|
||||
**Suggested branch:** `feature/gj01-country-language-preferences`
|
||||
|
||||
## Objective
|
||||
Give every user an easy first-run and Settings experience that saves where they live, where they want to work, what roles they seek and in which languages. Automatically prefill job discovery from persisted preferences without locking the search page to a single country.
|
||||
|
||||
## Implement
|
||||
1. Audit auth/onboarding/Settings, localization and existing preference persistence. Add migration-safe per-user search preferences using established MariaDB and revision semantics; retain backwards compatibility.
|
||||
2. Model **country of residence** separately from nationality/home country, **desired work countries** (0..N), preferred regions/places (0..N), advertised-job languages (0..N), interface locale (single), each CV/cover letter's language (document-specific), occupations/skills, work arrangements and saved profiles. Defaults should be understandable and editable; no forced demographic collection.
|
||||
3. Provide country selector with ISO country identifiers, display names localized where supported, searchable options, multi-select for job-search countries, optional city/region suggestions and clear default/override semantics. A user can live in Norway and search Sweden + UK.
|
||||
4. **Language menu:** show `English` and official/local language(s) relevant to residence/selected region at the top, rendered as native label + English label (e.g. `Norsk bokmål — Norwegian Bokmål`, `Svenska — Swedish`, `Deutsch — German`). Account for multilingual countries, region-specific Welsh in Wales, Bokmål vs Nynorsk in Norway, and user-chosen overrides. Do NOT equate ESCO translations with complete Jobjakt UI support. Unsupported UI locales may appear under Coming Later, not as functional toggles.
|
||||
5. Use BCP 47 language tags and explicit fallback rules (e.g. `en-GB`, `nb-NO`, `nn-NO`, `sv-SE`; verify support). Keep UI locale independent of ad-language filtering and document language. Persist across sessions/devices; initial suggestion may use browser locale but never lock it.
|
||||
6. Localise all new Settings, onboarding, search-preference controls, validation, empty/error/help text in the actually approved interface languages; avoid machine-translated legal/professional terminology without review. Provide translation completeness report and automated missing-key checks.
|
||||
7. Search page loads saved defaults; user can override for one query, save overrides to a named search profile, or explicitly Update defaults. Never silently overwrite permanent settings from temporary filter changes.
|
||||
|
||||
## Acceptance examples
|
||||
- Norwegian-resident user, English UI, Norwegian + English ad languages, searches both Norway and UK.
|
||||
- Swedish-resident user with Swedish UI and English ad results; switch UI English without changing query language.
|
||||
- Welsh user sees Welsh and English prominently if Welsh UI is supported; non-Wales UK user isn't forced into Welsh.
|
||||
- Reopen account on another device and recover default countries, occupations, languages and regions.
|
||||
- Empty preference fallback: usable search with explicit country-choice invitation rather than empty broken state.
|
||||
- Tenant isolation, concurrent editing, revision conflict, account deletion/data export, migration and reset.
|
||||
|
||||
## Checkpoints
|
||||
`GJ01-A` schema/compatibility, `GJ01-B` onboarding/Settings, `GJ01-C` selector/localisation, `GJ01-D` search defaults/overrides, `GJ01-E` full regression and handoff. Commit/push validated checkpoints.
|
||||
|
||||
## Deliverables
|
||||
`docs/global-jobs/01/` for preference schema, screen states, local-language mapping, supported-vs-planned locales, localisation checks, permissions, regressions and acceptance. End with GO/CONDITIONAL GO/NO-GO and GJ-02 readiness; stop.
|
||||
|
||||
## Shared rules for every INT-GLOBAL-JOBS-01 stage
|
||||
|
||||
- Product: **Jobjakt**, a general-purpose, commercial job-search and career-management SaaS. It is **not** an IT-only product. Current architecture includes React/TypeScript, .NET backend, MariaDB, an AI sidecar, existing Career Profile/CV/document/application features, and an established EN/NO localisation approach. Verify actual repository reality before making assumptions.
|
||||
- **Entry gates:** Do not implement new global-job-discovery features until the authoritative Phase 10 and product-review/development-entry decisions permit this initiative. Planning-only reconnaissance may precede them. If an entry gate remains NO-GO, produce safe analysis and stop before code changes.
|
||||
- **Baseline:** Find the latest accepted, integration-complete development commit by reading Git history and the latest authoritative acceptance reports. Do not assume `main` is current. `main` deploys production: NEVER merge to `main` or trigger production. Never change live MariaDB, Docker, Ollama, storage, secrets or other production services.
|
||||
- **Branches:** Use the specified independent stage branch from the latest accepted development integration history including the preceding accepted stage. Verify ancestry, remote, clean tree and existing branch collisions. Use checkpoint commits; push each validated checkpoint; verify remote HEAD equals local HEAD. Do not force-push. Do not advance to another stage without its actual entry criteria.
|
||||
- **Autonomy:** Investigate, design, implement, add tests, document, commit and push safe work without pausing for routine decisions. Stop only for external API agreements, new paid resources, security-risk acceptance, destructive changes, privileged infrastructure actions and production operations. Continue independent work when one provider or model capability is blocked.
|
||||
- **Sources:** Integrate only documented, authorised sources. Verify current licensing, commercial eligibility, credentials, permitted display, storage, cache lifetime, update/delete/tombstone, attribution, user-click-through and rate-limit rules. No covert scraping, private APIs, stolen cookies, bypassing anti-bot controls or fetching protected listing content without authorisation. An external-link-only source is not a direct searchable provider.
|
||||
- **Data trust:** All provider data, job descriptions and user-provided URLs are untrusted. Guard SSRF, XSS/unsafe HTML, prompt injection, HTML injection, unsafe redirects, credential leakage, denial of service and cross-user/tenant access. Do not present missing facts, inferred salaries, regulated-profession eligibility, or AI-generated job details as verified employer facts.
|
||||
- **Availability:** Preserve offline/disabled provider states. Use realistic fixtures in automated tests; any live contract test needs authorised test credentials and bounded rates. Never claim unavailable external API functionality passed.
|
||||
- **User-facing quality:** Desktop/tablet/phone, keyboard and screen-reader access, light/dark, EN/Bokmål plus future qualified locales, loading/empty/error states, responsive design, sensible defaults, performance, source transparency, internationalisation and accessible non-drag alternatives.
|
||||
- **Data integrity:** Source advertisements and user-owned saved jobs/applications are separate records and lifecycles. Preserve existing Career Profile, historical CVs, cover letters, saved applications, revisions, RD21 protections and MariaDB compatibility. Follow source rules for removing or masking withdrawn advertisements, while handling user-owned records under a separately justified retention policy.
|
||||
- **AI:** Existing live-model inference and semantic quality must remain gated unless separately qualified. Rule-based/ESCO-backed title suggestions and auditable matching should function without a generative model. Do not invent user qualifications or automate application submissions.
|
||||
- **Evidence:** At every checkpoint provide exact tests (pass/fail/skip/not run), security/coverage evidence, dated docs, commit hashes, branch and remote verification. Report individual stage GO / CONDITIONAL GO / NO-GO; separate production NO-GO from development readiness.
|
||||
@@ -0,0 +1,48 @@
|
||||
# GJ-02 — Hierarchical Geographic Filters, Scopes and Optional Radius
|
||||
**Suggested branch:** `feature/gj02-geographic-search`
|
||||
|
||||
## Objective
|
||||
Implement accurate, discoverable and accessible country/region/county/municipality/town filtering across Norway, Sweden and UK without relying on false flat hierarchies or substring matching.
|
||||
|
||||
## User interaction contract (must not be changed silently)
|
||||
- Selecting **Warwickshire** alone: query the **whole Warwickshire scope**; all child checkboxes remain visually unchecked.
|
||||
- Expanding and selecting **Warwick** under selected Warwickshire: query **Warwick only** in that branch, not every other town in Warwickshire. Warwickshire remains shown as the selected *scope being refined*, with a clear summary `Warwick only`.
|
||||
- Add **Royal Leamington Spa**: query Warwick **OR** Royal Leamington Spa, excluding other Warwickshire areas.
|
||||
- Remove both towns while leaving Warwickshire selected: revert to the **whole Warwickshire** scope.
|
||||
- Separate selected branches (e.g. Warwick plus Bergen) combine as **OR**. Different filter dimensions (e.g. location + profession + languages) normally combine as **AND**.
|
||||
- Deselect a parent: remove or resolve its descendant filters visibly, with accessible announcement, never leave invisible active child selections.
|
||||
- A checked parent with refinements is **not** the conventional 'all descendants checked' tri-state checkbox. Design accessible controls as **scope checkbox/selection plus separate refinement state**; avoid misleading mixed-state semantics. Include explicit `Whole area` / `Specific places` options and a clear effective-filter summary if needed.
|
||||
|
||||
## Engineering requirements
|
||||
1. Inspect genuine geography sources and licences/versions. For Norway use authoritative county/municipality and locality datasets; Sweden län/kommun/settlements; UK ONS geography and appropriate settlement data. Handle UK county vs district vs built-up area accurately and atypical administrative cases (Oslo both county/municipality, UK unitary authority, etc.). Store canonical identifiers, types, country, parent relations, names/aliases, optional polygons/centroids/coordinates with provenance/version.
|
||||
2. Build geographic taxonomy ingestion/update routines and mapping from provider source location codes/free text; allow unresolved/approximate classifications (never silently attach a job to the wrong town).
|
||||
3. Support tree expansion without huge downloads, keyboard navigation, search-as-you-type town lookup, saved favourite locations and a compact filter summary/chips. Strictly preserve selected scopes when tree collapses.
|
||||
4. Define semantic query plan translating geographic selections to filter over canonical IDs/polygons and provider-supported area fields. If provider can't do exact region filtering, use compliant local filtering or clearly disclose approximation and missing data; do not claim full provider coverage.
|
||||
5. Optional town-centered radius (e.g. 10/25/50km), with geodesic distance, coordinates known/unknown rules, multi-origin OR semantics and units/localized display. Radius by distance is not a guaranteed travel-time commute. Keep a separate optional actual travel-time capability for later, only with a qualified routing provider.
|
||||
6. Define remote jobs explicitly: fully remote, remote limited to country/region, hybrid/on-site and unknown. Remote must not bypass legally specified work location constraints.
|
||||
7. Add indexes/performance checks for large country scopes, no 1,000-child checkbox DOM, data migration, stale taxonomy IDs and fallback on missing geographic data.
|
||||
|
||||
## Test corpus
|
||||
- Warwickshire > Warwick and Royal Leamington Spa, deselect/reselect/expand/collapse, selected parent + descendants, sibling mixing, multiple-country OR.
|
||||
- Vestfold > Tønsberg/Sandefjord; Vestland > Bergen; Oslo municipality/county dual identity; Sweden Stockholm län > Stockholm municipality/town.
|
||||
- A posting geocoded only at county level must not be misreported as located within Warwick town.
|
||||
- Radius from Warwick includes known nearby locations when within requested geometric distance, and doesn't claim driving time.
|
||||
- Keyboard/screen-reader semantics and mobile compact filtering; frozen profile roundtrips.
|
||||
|
||||
## Checkpoints/deliverables
|
||||
`GJ02-A` taxonomy/source decision; `GJ02-B` canonical model/import; `GJ02-C` refinement state & UI; `GJ02-D` query mapping/radius; `GJ02-E` precision/performance/acceptance. Document under `docs/global-jobs/02/`. Commit/push each. Report location precision and provider coverage honestly. Stop after acceptance.
|
||||
|
||||
## Shared rules for every INT-GLOBAL-JOBS-01 stage
|
||||
|
||||
- Product: **Jobjakt**, a general-purpose, commercial job-search and career-management SaaS. It is **not** an IT-only product. Current architecture includes React/TypeScript, .NET backend, MariaDB, an AI sidecar, existing Career Profile/CV/document/application features, and an established EN/NO localisation approach. Verify actual repository reality before making assumptions.
|
||||
- **Entry gates:** Do not implement new global-job-discovery features until the authoritative Phase 10 and product-review/development-entry decisions permit this initiative. Planning-only reconnaissance may precede them. If an entry gate remains NO-GO, produce safe analysis and stop before code changes.
|
||||
- **Baseline:** Find the latest accepted, integration-complete development commit by reading Git history and the latest authoritative acceptance reports. Do not assume `main` is current. `main` deploys production: NEVER merge to `main` or trigger production. Never change live MariaDB, Docker, Ollama, storage, secrets or other production services.
|
||||
- **Branches:** Use the specified independent stage branch from the latest accepted development integration history including the preceding accepted stage. Verify ancestry, remote, clean tree and existing branch collisions. Use checkpoint commits; push each validated checkpoint; verify remote HEAD equals local HEAD. Do not force-push. Do not advance to another stage without its actual entry criteria.
|
||||
- **Autonomy:** Investigate, design, implement, add tests, document, commit and push safe work without pausing for routine decisions. Stop only for external API agreements, new paid resources, security-risk acceptance, destructive changes, privileged infrastructure actions and production operations. Continue independent work when one provider or model capability is blocked.
|
||||
- **Sources:** Integrate only documented, authorised sources. Verify current licensing, commercial eligibility, credentials, permitted display, storage, cache lifetime, update/delete/tombstone, attribution, user-click-through and rate-limit rules. No covert scraping, private APIs, stolen cookies, bypassing anti-bot controls or fetching protected listing content without authorisation. An external-link-only source is not a direct searchable provider.
|
||||
- **Data trust:** All provider data, job descriptions and user-provided URLs are untrusted. Guard SSRF, XSS/unsafe HTML, prompt injection, HTML injection, unsafe redirects, credential leakage, denial of service and cross-user/tenant access. Do not present missing facts, inferred salaries, regulated-profession eligibility, or AI-generated job details as verified employer facts.
|
||||
- **Availability:** Preserve offline/disabled provider states. Use realistic fixtures in automated tests; any live contract test needs authorised test credentials and bounded rates. Never claim unavailable external API functionality passed.
|
||||
- **User-facing quality:** Desktop/tablet/phone, keyboard and screen-reader access, light/dark, EN/Bokmål plus future qualified locales, loading/empty/error states, responsive design, sensible defaults, performance, source transparency, internationalisation and accessible non-drag alternatives.
|
||||
- **Data integrity:** Source advertisements and user-owned saved jobs/applications are separate records and lifecycles. Preserve existing Career Profile, historical CVs, cover letters, saved applications, revisions, RD21 protections and MariaDB compatibility. Follow source rules for removing or masking withdrawn advertisements, while handling user-owned records under a separately justified retention policy.
|
||||
- **AI:** Existing live-model inference and semantic quality must remain gated unless separately qualified. Rule-based/ESCO-backed title suggestions and auditable matching should function without a generative model. Do not invent user qualifications or automate application submissions.
|
||||
- **Evidence:** At every checkpoint provide exact tests (pass/fail/skip/not run), security/coverage evidence, dated docs, commit hashes, branch and remote verification. Report individual stage GO / CONDITIONAL GO / NO-GO; separate production NO-GO from development readiness.
|
||||
@@ -0,0 +1,35 @@
|
||||
# GJ-03 — Universal Occupation Autocomplete, Skills and Cross-Language Queries
|
||||
**Suggested branch:** `feature/gj03-occupation-search`
|
||||
|
||||
## Objective
|
||||
Deliver fast, useful occupation and job-title suggestions for **every sector**, available in different languages, without coding a developer-only dictionary or requiring AI inference.
|
||||
|
||||
## Design and build
|
||||
1. Inspect search UI/backend and Career Profile, existing role categories and suggestions. Define distinction: occupation concept, advertised job title, related title, alias, skills, licence/qualification, free-text term and category. A text search like `weekend work` must remain possible.
|
||||
2. Integrate a verified version of ESCO occupational concepts/labels/aliases/skills using suitable licensed API/dataset/cache. Where helpful map to national classifications including Sweden SSYK and UK SOC; maintain ID provenance/version and explicit unmapped cases. Do not assume ESCO's `no` language pack provides fully distinguished Bokmål and Nynorsk translations.
|
||||
3. Build typeahead with debouncing/cancellation, typo tolerance, language-aware synonyms, ranked results, accessible keyboard selection, exact vs related query modes, optional skill chips. Present human-readable explanation for expansions across languages (e.g. `chef` ↔ `kokk`) and user control to turn them off.
|
||||
4. Source signals: user-chosen occupations, verified Career Profile entries (with consent/config), common local terms, prior searches, and role terms from supported providers. Do not mine raw private CVs globally or leak user data into other tenants.
|
||||
5. Support searches by job type and requirement not just formal title: part-time, evening shifts, weekend work, apprenticeships, no experience, teaching level, kitchen role, professional licensing. Filter capabilities must be source-aware, never fabricate unsupported advertised fields.
|
||||
6. Multi-lingual matching can expand keywords if justified; preserve original title and advert in results. Distinguish exact-match results from related recommendations and avoid conflating unrelated occupations.
|
||||
7. Generate a frozen multi-profession benchmark and evaluate suggestions for false positives, useful recall, language accuracy, query latency and index size. Include fallback to simple keyword on taxonomy outage.
|
||||
|
||||
## Acceptance matrix
|
||||
Explicit scenarios: teacher, teaching assistant, chef, kitchen assistant, cleaner, nurse, healthcare assistant, electrician, plumber, carpenter, delivery driver, warehouse worker, shop assistant, waiter, accountant, public administrator, mechanic, software developer, agricultural labourer. Include NO/SE/UK title variants and source text. Ensure broad roles do not swamp precise title searches; 'nurse' shouldn't blindly match uncredentialed carers as an exact title.
|
||||
|
||||
## Checkpoints
|
||||
`GJ03-A` taxonomy/licensing and mapping; `GJ03-B` search index/normalisation; `GJ03-C` suggestion UI; `GJ03-D` relevance controls and filters; `GJ03-E` benchmarks/accessibility/regression. Docs: `docs/global-jobs/03/`. Commit/push checkpoints. Report exact tested languages, source coverage and limitations. Stop.
|
||||
|
||||
## Shared rules for every INT-GLOBAL-JOBS-01 stage
|
||||
|
||||
- Product: **Jobjakt**, a general-purpose, commercial job-search and career-management SaaS. It is **not** an IT-only product. Current architecture includes React/TypeScript, .NET backend, MariaDB, an AI sidecar, existing Career Profile/CV/document/application features, and an established EN/NO localisation approach. Verify actual repository reality before making assumptions.
|
||||
- **Entry gates:** Do not implement new global-job-discovery features until the authoritative Phase 10 and product-review/development-entry decisions permit this initiative. Planning-only reconnaissance may precede them. If an entry gate remains NO-GO, produce safe analysis and stop before code changes.
|
||||
- **Baseline:** Find the latest accepted, integration-complete development commit by reading Git history and the latest authoritative acceptance reports. Do not assume `main` is current. `main` deploys production: NEVER merge to `main` or trigger production. Never change live MariaDB, Docker, Ollama, storage, secrets or other production services.
|
||||
- **Branches:** Use the specified independent stage branch from the latest accepted development integration history including the preceding accepted stage. Verify ancestry, remote, clean tree and existing branch collisions. Use checkpoint commits; push each validated checkpoint; verify remote HEAD equals local HEAD. Do not force-push. Do not advance to another stage without its actual entry criteria.
|
||||
- **Autonomy:** Investigate, design, implement, add tests, document, commit and push safe work without pausing for routine decisions. Stop only for external API agreements, new paid resources, security-risk acceptance, destructive changes, privileged infrastructure actions and production operations. Continue independent work when one provider or model capability is blocked.
|
||||
- **Sources:** Integrate only documented, authorised sources. Verify current licensing, commercial eligibility, credentials, permitted display, storage, cache lifetime, update/delete/tombstone, attribution, user-click-through and rate-limit rules. No covert scraping, private APIs, stolen cookies, bypassing anti-bot controls or fetching protected listing content without authorisation. An external-link-only source is not a direct searchable provider.
|
||||
- **Data trust:** All provider data, job descriptions and user-provided URLs are untrusted. Guard SSRF, XSS/unsafe HTML, prompt injection, HTML injection, unsafe redirects, credential leakage, denial of service and cross-user/tenant access. Do not present missing facts, inferred salaries, regulated-profession eligibility, or AI-generated job details as verified employer facts.
|
||||
- **Availability:** Preserve offline/disabled provider states. Use realistic fixtures in automated tests; any live contract test needs authorised test credentials and bounded rates. Never claim unavailable external API functionality passed.
|
||||
- **User-facing quality:** Desktop/tablet/phone, keyboard and screen-reader access, light/dark, EN/Bokmål plus future qualified locales, loading/empty/error states, responsive design, sensible defaults, performance, source transparency, internationalisation and accessible non-drag alternatives.
|
||||
- **Data integrity:** Source advertisements and user-owned saved jobs/applications are separate records and lifecycles. Preserve existing Career Profile, historical CVs, cover letters, saved applications, revisions, RD21 protections and MariaDB compatibility. Follow source rules for removing or masking withdrawn advertisements, while handling user-owned records under a separately justified retention policy.
|
||||
- **AI:** Existing live-model inference and semantic quality must remain gated unless separately qualified. Rule-based/ESCO-backed title suggestions and auditable matching should function without a generative model. Do not invent user qualifications or automate application submissions.
|
||||
- **Evidence:** At every checkpoint provide exact tests (pass/fail/skip/not run), security/coverage evidence, dated docs, commit hashes, branch and remote verification. Report individual stage GO / CONDITIONAL GO / NO-GO; separate production NO-GO from development readiness.
|
||||
@@ -0,0 +1,41 @@
|
||||
# GJ-04 — Country Provider Connectors, Rights Enforcement and Lifecycle
|
||||
**Suggested branch:** `feature/gj04-provider-connectors`
|
||||
|
||||
## Objective
|
||||
Implement a scalable source architecture that can serve Norway, Sweden and UK while accurately representing differing API permissions and content completeness. Provider blockers must not block already-authorised sources or manual user entry.
|
||||
|
||||
## Mandatory source strategy
|
||||
**Norway NAV:** Verify current `pam-stilling-feed` docs/terms. This is an authenticated change feed, not a free-text search endpoint; permitted local indexing/search requires consumer access and incremental updates. Verify JWT consumer registration (the public experimentation token is not a production solution), updates, tombstones/inactive masking, source application deep links, attribution and PII requirements. **FINN listings are not included in NAV's feed.**
|
||||
|
||||
**Norway FINN:** Official FINN API requires authorised advertiser/business relationship and ownership of accessible data; general third-party search is NOT available by default. Implement user-pasted URL recognition, deduplication, legitimate manual record entry, and original-site link. Do not silently fetch FINN pages, circumvent protection or call this 'full FINN integration'. Only implement full details if explicit suitable rights are established.
|
||||
|
||||
**Sweden:** Verify official JobTech JobSearch and JobAd Links capabilities and licence. JobAd Links provides truncated details/reference links, not guaranteed full vacancy content. Respect original-site link requirements, daily freshness and occupational-code mappings. If other JobTech APIs permit full descriptions, expose source-specific completeness and follow those actual terms.
|
||||
|
||||
**United Kingdom:** Evaluate Adzuna documented job search; results contain a **description snippet**, and ongoing commercial SaaS use requires licensing/written approval. Evaluate appropriate public-sector/other licensed sources and externally linked searches; don't assume Reed/Indeed/Totaljobs/CV-Library/Find a Job/NHS APIs allow third-party bulk search. For blocked providers, create operator instructions and a permitted fallback, not an invented API.
|
||||
|
||||
## Architecture
|
||||
1. Provider registry with immutable ID, geo/occupation search capabilities, feed vs query mode, allowed detail level, supported filters, source link policy, commercial rights, credential status, effective dates, retention, updates/deletes, quota and telemetry. Make unavailable/blocked sources visible to admins with actionable reason but do not expose keys.
|
||||
2. Typed interfaces: `Search`, `ReadDetails`, `IngestChanges`, `MapLocation`, `MapOccupation`, `Normalize`, `GetLifecycle`, `BuildApplyLink`, conditional on capabilities. Do not force every provider to implement methods it does not support.
|
||||
3. Canonical SourceAdvertisement plus ProviderSourceRecord with provider ID, source ID, canonical link, employer/title, structured location, pay amount/range/currency/period, shifts, occupation, qualification, languages, contract, description format/completeness, created/modified/expiry, original apply URL, source-restriction flags and provenance. Preserve unknown values; avoid inventing salaries/hours or dropping original titles.
|
||||
4. Safe ingestion/index queue with cursor/checkpoint, bounded pagination, backoff/rate limit, idempotency, incremental updates/deletes, stale-data policy, audit events, resumability, transactional MariaDB and provider-specific compliance. No infinite poll loops or API-key logs.
|
||||
5. Deterministic, conservative cross-provider duplicate detection (source IDs, canonical links and supporting content/time/location) with false-positive review. Do not merge distinct teaching vacancies at same school or identical restaurant positions automatically. Display multiple sources only when identity is sufficiently proven.
|
||||
6. Separate external ad cache from user-owned application tracking. Remove/mask inactive content per source terms; preserve user-owned notes/status legally and transparently, not secretly republish deleted ads.
|
||||
7. Provider fixture/contracts and authorised bounded live smoke tests. Do not run live provider tests without actual access.
|
||||
|
||||
## Checkpoints
|
||||
`GJ04-A` rights & provider registry; `GJ04-B` canonical/ad lifecycle; `GJ04-C` NAV connector if authorised; `GJ04-D` Swedish connectors; `GJ04-E` UK approved connector or external-link-only fallback; `GJ04-F` manual FINN URL workflow; `GJ04-G` dedupe, security, operational tests. Block unavailable subcheckpoint honestly; continue independent ones. Docs: `docs/global-jobs/04/`, source by source eligibility, test evidence, permissions, rate limits, update/delete compliance and owner actions. Commit/push each completed checkpoint. Stop.
|
||||
|
||||
## Shared rules for every INT-GLOBAL-JOBS-01 stage
|
||||
|
||||
- Product: **Jobjakt**, a general-purpose, commercial job-search and career-management SaaS. It is **not** an IT-only product. Current architecture includes React/TypeScript, .NET backend, MariaDB, an AI sidecar, existing Career Profile/CV/document/application features, and an established EN/NO localisation approach. Verify actual repository reality before making assumptions.
|
||||
- **Entry gates:** Do not implement new global-job-discovery features until the authoritative Phase 10 and product-review/development-entry decisions permit this initiative. Planning-only reconnaissance may precede them. If an entry gate remains NO-GO, produce safe analysis and stop before code changes.
|
||||
- **Baseline:** Find the latest accepted, integration-complete development commit by reading Git history and the latest authoritative acceptance reports. Do not assume `main` is current. `main` deploys production: NEVER merge to `main` or trigger production. Never change live MariaDB, Docker, Ollama, storage, secrets or other production services.
|
||||
- **Branches:** Use the specified independent stage branch from the latest accepted development integration history including the preceding accepted stage. Verify ancestry, remote, clean tree and existing branch collisions. Use checkpoint commits; push each validated checkpoint; verify remote HEAD equals local HEAD. Do not force-push. Do not advance to another stage without its actual entry criteria.
|
||||
- **Autonomy:** Investigate, design, implement, add tests, document, commit and push safe work without pausing for routine decisions. Stop only for external API agreements, new paid resources, security-risk acceptance, destructive changes, privileged infrastructure actions and production operations. Continue independent work when one provider or model capability is blocked.
|
||||
- **Sources:** Integrate only documented, authorised sources. Verify current licensing, commercial eligibility, credentials, permitted display, storage, cache lifetime, update/delete/tombstone, attribution, user-click-through and rate-limit rules. No covert scraping, private APIs, stolen cookies, bypassing anti-bot controls or fetching protected listing content without authorisation. An external-link-only source is not a direct searchable provider.
|
||||
- **Data trust:** All provider data, job descriptions and user-provided URLs are untrusted. Guard SSRF, XSS/unsafe HTML, prompt injection, HTML injection, unsafe redirects, credential leakage, denial of service and cross-user/tenant access. Do not present missing facts, inferred salaries, regulated-profession eligibility, or AI-generated job details as verified employer facts.
|
||||
- **Availability:** Preserve offline/disabled provider states. Use realistic fixtures in automated tests; any live contract test needs authorised test credentials and bounded rates. Never claim unavailable external API functionality passed.
|
||||
- **User-facing quality:** Desktop/tablet/phone, keyboard and screen-reader access, light/dark, EN/Bokmål plus future qualified locales, loading/empty/error states, responsive design, sensible defaults, performance, source transparency, internationalisation and accessible non-drag alternatives.
|
||||
- **Data integrity:** Source advertisements and user-owned saved jobs/applications are separate records and lifecycles. Preserve existing Career Profile, historical CVs, cover letters, saved applications, revisions, RD21 protections and MariaDB compatibility. Follow source rules for removing or masking withdrawn advertisements, while handling user-owned records under a separately justified retention policy.
|
||||
- **AI:** Existing live-model inference and semantic quality must remain gated unless separately qualified. Rule-based/ESCO-backed title suggestions and auditable matching should function without a generative model. Do not invent user qualifications or automate application submissions.
|
||||
- **Evidence:** At every checkpoint provide exact tests (pass/fail/skip/not run), security/coverage evidence, dated docs, commit hashes, branch and remote verification. Report individual stage GO / CONDITIONAL GO / NO-GO; separate production NO-GO from development readiness.
|
||||
@@ -0,0 +1,42 @@
|
||||
# GJ-05 — Unified Discover Jobs UI and In-App Vacancy Details
|
||||
**Suggested branch:** `feature/gj05-discovery-ui`
|
||||
|
||||
## Objective
|
||||
Make searching intuitive: saved defaults, smart suggestions, fast results, hierarchical location filter, and a full permitted vacancy-detail experience within Jobjakt—not forcing a new site for every listing.
|
||||
|
||||
## Design
|
||||
Desktop: responsive three-panel layout—collapsible filter sidebar, scrollable results list, vacancy detail. Tablet: two-pane or overlay; phone: list with full-screen detail. Offer `Expand details` route that deep-links to an individual permitted advert, with refresh, back button and pagination. Do not rely exclusively on huge modal overlays.
|
||||
|
||||
Use profile countries/occupation/ad languages automatically; allow temporary override and `Save this search`. Filters must be explainable and backed by provider data quality: location scopes (county→town), radius, roles/exact vs related, skills, advertised languages, contract type, full/part-time, shift/evening/weekend, apprenticeship/seasonal, remote/hybrid/on-site with country eligibility, salary currency/period and type (actual vs predicted), post date/deadline, source, and experience/licences where supplied. Mark unsupported fields as unavailable; no fabricated 'strict' enforcement.
|
||||
|
||||
Suggestions: accessible typeahead for any profession; recent/favourites but privacy-preserving; empty input suggestions where helpful. Provide query chips/effective selection summary including `Warwickshire: Warwick + Leamington only` without misleading parent checkbox semantics.
|
||||
|
||||
Results: title, employer, geographic accuracy label, source, work type, salary only where provided, last updated, active/expired status, original language, whether description is full or snippet, one canonical duplicate grouping with alternate sources when safe. Sorting/pagination/cursor; skeleton/empty/error/stale/partial-source and accessibility.
|
||||
|
||||
Vacancy detail: permitted original description (sanitised), duties, requirements, qualifications/licences, schedule/shifts, salary with period/currency, employer, locations, source citations/attribution, posted/updated, deadline, apply method and transparent gaps (`not provided by source`). **Never scrape the linked website to fill a provider's legally truncated excerpt.** Link to original listing and original application flow. Preserve original employer words; any translated summary must be clearly labelled and optional.
|
||||
|
||||
Actions: `Save Job`, `Track Application`, `Attach Existing CV`, `Create CV Variant`, `Prepare Cover Letter` (reuse current app; AI gated), original `Apply` link. Distinguish saved job from tracked application. Preserve source record vs user-owned notes.
|
||||
|
||||
## Testing
|
||||
- Listings from multiple permitted providers, full and snippet-only previews, unavailable sources, missing salaries, expired ads, unsafe HTML and malicious links, missing coordinates, Norway/Sweden/UK location hierarchies.
|
||||
- Occupations: teachers, chefs, carers, nurses, trades, transport, retail, office and IT; job details fit shift and hourly work as well as salaried roles.
|
||||
- Mobile portrait/landscape, keyboard, 200% zoom, screen reader, EN/Bokmål, responsive transitions, deep-link/back navigation, filters retaining context.
|
||||
- Correct URL/apply behavior; no external content loaded in an unsafe iframe by default; do not misreport full detail from snippet-only APIs.
|
||||
|
||||
## Checkpoints
|
||||
`GJ05-A` wireframes and routes; `GJ05-B` filters/responsive UI; `GJ05-C` results/query semantics; `GJ05-D` in-app detail and source rules; `GJ05-E` tracker/doc actions; `GJ05-F` accessibility/fidelity/regression. Docs: `docs/global-jobs/05/`. Commit/push per validated checkpoint. Stop.
|
||||
|
||||
## Shared rules for every INT-GLOBAL-JOBS-01 stage
|
||||
|
||||
- Product: **Jobjakt**, a general-purpose, commercial job-search and career-management SaaS. It is **not** an IT-only product. Current architecture includes React/TypeScript, .NET backend, MariaDB, an AI sidecar, existing Career Profile/CV/document/application features, and an established EN/NO localisation approach. Verify actual repository reality before making assumptions.
|
||||
- **Entry gates:** Do not implement new global-job-discovery features until the authoritative Phase 10 and product-review/development-entry decisions permit this initiative. Planning-only reconnaissance may precede them. If an entry gate remains NO-GO, produce safe analysis and stop before code changes.
|
||||
- **Baseline:** Find the latest accepted, integration-complete development commit by reading Git history and the latest authoritative acceptance reports. Do not assume `main` is current. `main` deploys production: NEVER merge to `main` or trigger production. Never change live MariaDB, Docker, Ollama, storage, secrets or other production services.
|
||||
- **Branches:** Use the specified independent stage branch from the latest accepted development integration history including the preceding accepted stage. Verify ancestry, remote, clean tree and existing branch collisions. Use checkpoint commits; push each validated checkpoint; verify remote HEAD equals local HEAD. Do not force-push. Do not advance to another stage without its actual entry criteria.
|
||||
- **Autonomy:** Investigate, design, implement, add tests, document, commit and push safe work without pausing for routine decisions. Stop only for external API agreements, new paid resources, security-risk acceptance, destructive changes, privileged infrastructure actions and production operations. Continue independent work when one provider or model capability is blocked.
|
||||
- **Sources:** Integrate only documented, authorised sources. Verify current licensing, commercial eligibility, credentials, permitted display, storage, cache lifetime, update/delete/tombstone, attribution, user-click-through and rate-limit rules. No covert scraping, private APIs, stolen cookies, bypassing anti-bot controls or fetching protected listing content without authorisation. An external-link-only source is not a direct searchable provider.
|
||||
- **Data trust:** All provider data, job descriptions and user-provided URLs are untrusted. Guard SSRF, XSS/unsafe HTML, prompt injection, HTML injection, unsafe redirects, credential leakage, denial of service and cross-user/tenant access. Do not present missing facts, inferred salaries, regulated-profession eligibility, or AI-generated job details as verified employer facts.
|
||||
- **Availability:** Preserve offline/disabled provider states. Use realistic fixtures in automated tests; any live contract test needs authorised test credentials and bounded rates. Never claim unavailable external API functionality passed.
|
||||
- **User-facing quality:** Desktop/tablet/phone, keyboard and screen-reader access, light/dark, EN/Bokmål plus future qualified locales, loading/empty/error states, responsive design, sensible defaults, performance, source transparency, internationalisation and accessible non-drag alternatives.
|
||||
- **Data integrity:** Source advertisements and user-owned saved jobs/applications are separate records and lifecycles. Preserve existing Career Profile, historical CVs, cover letters, saved applications, revisions, RD21 protections and MariaDB compatibility. Follow source rules for removing or masking withdrawn advertisements, while handling user-owned records under a separately justified retention policy.
|
||||
- **AI:** Existing live-model inference and semantic quality must remain gated unless separately qualified. Rule-based/ESCO-backed title suggestions and auditable matching should function without a generative model. Do not invent user qualifications or automate application submissions.
|
||||
- **Evidence:** At every checkpoint provide exact tests (pass/fail/skip/not run), security/coverage evidence, dated docs, commit hashes, branch and remote verification. Report individual stage GO / CONDITIONAL GO / NO-GO; separate production NO-GO from development readiness.
|
||||
@@ -0,0 +1,36 @@
|
||||
# GJ-06 — Saved Searches, Alerts, Skills Matching and Application Tracking
|
||||
**Suggested branch:** `feature/gj06-alerts-matching`
|
||||
|
||||
## Objective
|
||||
Help users act on relevant opportunities without overwhelming them: durable saved searches, reliable new-job alerts, explainable profession-neutral matching, and seamless use of Jobjakt's application tracker, Career Profile, CV Builder and cover letters.
|
||||
|
||||
## Features
|
||||
1. Save and name multiple search profiles, including countries, tree scopes (not flattened children), radius, roles/skills, languages, source filters, work type and disabled-source status. Load/duplicate/edit/delete/suspend/restore; update saved profiles only when explicitly requested, with revision-safe persistence.
|
||||
2. New matching jobs: scheduled bounded evaluation (according to each provider's data rights), idempotent matching by canonical provider ID + changed state, per-user subscriptions and timezone-friendly daily/weekly/in-app/email frequency; pause/unsubscribe, quiet hours where supported, anti-spam and delivery failure recovery. Don't notify about expired/deleted jobs or leak another user's preferences.
|
||||
3. Occupation/skills/qualification matching: use explicitly stored Career Profile facts, source advertised requirements, ESCO relations and supported match semantics; show evidence (`CV says`, `advert requests`, `not supplied`), reasons and gaps. Never infer qualifications/regulated professional authorisation, fluency, licences or job eligibility from general similarity. No black-box score claiming hiring probability.
|
||||
4. Cross-language matches: original job ad remains authoritative. Display translated title/summary only if supported, attributed and clearly labelled; distinguish exact vs related suggestions. Allow users to restrict results to ad languages they understand.
|
||||
5. Saved vs tracked: `Save job` doesn't imply application submitted; `Track Application` opens established workflow, avoids duplicates and links permitted source metadata and CV/letter. Expired ad content obeys provider source lifecycle; user's own notes and status remain separate.
|
||||
6. Optional relevance ranking and explanatory weights: location, title, skills, language, schedule, salary (if provided), remote eligibility and user preferences. Avoid geography bias, sensitive-class inference, nationality discrimination and misleading eligibility statements. No automatic external application submission.
|
||||
7. AI inference can be added later only after approved security/semantic qualification; core matching must work with transparent rules and catalogued data.
|
||||
|
||||
## QA scenarios
|
||||
- Teacher with pedagogy/subject preference, chef with evening shifts, nurse with mandatory authorisation, cleaner without formal qualifications, electrician with trade licence, part-time retail worker, remote English speaker, mixed-country mover and backend developer.
|
||||
- Same job from multiple providers, result withdrawn before alert, saved search changed mid-run, duplicate worker delivery, locale/timezone, overlapping searches, no results, disabled API source, invalid/missing salary/location and account deletion.
|
||||
|
||||
## Checkpoints
|
||||
`GJ06-A` saved-search storage; `GJ06-B` alert scheduling/dedupe; `GJ06-C` matching and explanations; `GJ06-D` tracker and documents; `GJ06-E` security/load/accessibility. Docs `docs/global-jobs/06/`. Commit/push checkpoints; final GO/CONDITIONAL GO/NO-GO and GJ-07 handoff. Stop.
|
||||
|
||||
## Shared rules for every INT-GLOBAL-JOBS-01 stage
|
||||
|
||||
- Product: **Jobjakt**, a general-purpose, commercial job-search and career-management SaaS. It is **not** an IT-only product. Current architecture includes React/TypeScript, .NET backend, MariaDB, an AI sidecar, existing Career Profile/CV/document/application features, and an established EN/NO localisation approach. Verify actual repository reality before making assumptions.
|
||||
- **Entry gates:** Do not implement new global-job-discovery features until the authoritative Phase 10 and product-review/development-entry decisions permit this initiative. Planning-only reconnaissance may precede them. If an entry gate remains NO-GO, produce safe analysis and stop before code changes.
|
||||
- **Baseline:** Find the latest accepted, integration-complete development commit by reading Git history and the latest authoritative acceptance reports. Do not assume `main` is current. `main` deploys production: NEVER merge to `main` or trigger production. Never change live MariaDB, Docker, Ollama, storage, secrets or other production services.
|
||||
- **Branches:** Use the specified independent stage branch from the latest accepted development integration history including the preceding accepted stage. Verify ancestry, remote, clean tree and existing branch collisions. Use checkpoint commits; push each validated checkpoint; verify remote HEAD equals local HEAD. Do not force-push. Do not advance to another stage without its actual entry criteria.
|
||||
- **Autonomy:** Investigate, design, implement, add tests, document, commit and push safe work without pausing for routine decisions. Stop only for external API agreements, new paid resources, security-risk acceptance, destructive changes, privileged infrastructure actions and production operations. Continue independent work when one provider or model capability is blocked.
|
||||
- **Sources:** Integrate only documented, authorised sources. Verify current licensing, commercial eligibility, credentials, permitted display, storage, cache lifetime, update/delete/tombstone, attribution, user-click-through and rate-limit rules. No covert scraping, private APIs, stolen cookies, bypassing anti-bot controls or fetching protected listing content without authorisation. An external-link-only source is not a direct searchable provider.
|
||||
- **Data trust:** All provider data, job descriptions and user-provided URLs are untrusted. Guard SSRF, XSS/unsafe HTML, prompt injection, HTML injection, unsafe redirects, credential leakage, denial of service and cross-user/tenant access. Do not present missing facts, inferred salaries, regulated-profession eligibility, or AI-generated job details as verified employer facts.
|
||||
- **Availability:** Preserve offline/disabled provider states. Use realistic fixtures in automated tests; any live contract test needs authorised test credentials and bounded rates. Never claim unavailable external API functionality passed.
|
||||
- **User-facing quality:** Desktop/tablet/phone, keyboard and screen-reader access, light/dark, EN/Bokmål plus future qualified locales, loading/empty/error states, responsive design, sensible defaults, performance, source transparency, internationalisation and accessible non-drag alternatives.
|
||||
- **Data integrity:** Source advertisements and user-owned saved jobs/applications are separate records and lifecycles. Preserve existing Career Profile, historical CVs, cover letters, saved applications, revisions, RD21 protections and MariaDB compatibility. Follow source rules for removing or masking withdrawn advertisements, while handling user-owned records under a separately justified retention policy.
|
||||
- **AI:** Existing live-model inference and semantic quality must remain gated unless separately qualified. Rule-based/ESCO-backed title suggestions and auditable matching should function without a generative model. Do not invent user qualifications or automate application submissions.
|
||||
- **Evidence:** At every checkpoint provide exact tests (pass/fail/skip/not run), security/coverage evidence, dated docs, commit hashes, branch and remote verification. Report individual stage GO / CONDITIONAL GO / NO-GO; separate production NO-GO from development readiness.
|
||||
@@ -0,0 +1,37 @@
|
||||
# GJ-07 — Provider Operations, Admin Monitoring, Privacy and Resilience
|
||||
**Suggested branch:** `feature/gj07-discovery-operations`
|
||||
|
||||
## Objective
|
||||
Make multi-country job discovery auditable and sustainable to operate without exposing user CVs, raw prompts or host internals. Integrate with existing administrator processing monitor where appropriate.
|
||||
|
||||
## Admin view
|
||||
- Provider registry: country, API eligibility/rights state, capability flags, feed/query mode, enabled status, last successful sync, health, API quotas/rate errors, source freshness, indexing backlog and next scheduled sync.
|
||||
- Processing jobs/events: provider, worker, job type, cursor/checkpoint, fetched/new/updated/deleted/ignored counts, duration, retry, error code, structured stage and correlation ID; user-submitted URL import tasks show the submitting user and linked saved job/application only to properly authorised admins. Provider-wide sync jobs normally have no submitting end-user—show 'system' rather than inventing one.
|
||||
- Diagnostics: filter by provider, country, status, error type, time and correlation ID; redacted timeline/log excerpt from structured application events, with bounded retention, pagination and optional authenticated SSE stream/polling. No full job-applicant CV text, prompts, OAuth tokens, provider secrets, unsafe original HTML, raw Docker logs or arbitrary shell.
|
||||
- Correctness metrics: source lag, cursor age, licensing expiry/credential failure, stale/deleted advert content, dedupe rate and uncertain matches, alert queue outcomes and error clusters. Show true service health vs fixture mode.
|
||||
|
||||
## Security hardening
|
||||
- Server-side admin role checking on list, detail, streaming and data export; tenant boundaries even if admin scope is restricted; audit privileged access and source credentials changes.
|
||||
- SSRF-resistant URL import with scheme/host allowlist, DNS re-resolution/address validation and redirect policy; never fetch internal network endpoints. Treat source descriptions as untrusted HTML and avoid script execution/sandbox iframe leaks.
|
||||
- Bounds: API requests, ingestion concurrency, result pagination, auto-complete rate, local index size, alert fanout, log volume, timed-out jobs, model inference remains disabled if not qualified.
|
||||
- Provider lifecycle compliance tests including deletion/tombstone, changed ads, contact masking, and legal separation of external ad cache from user-owned application history.
|
||||
- Privacy: document what is stored (search preferences, skills references, personal saved jobs, employer contact information), why, and deletion/retention/export rights. Don't store source data past permission; no uncontrolled tracking/marketing analytics.
|
||||
- Reproducible migrations/CI, secret scanning and dependency audits, loss-of-provider/backoff/partial outage drills. Never alter production infra to get passing tests.
|
||||
|
||||
## Checkpoints
|
||||
`GJ07-A` operational telemetry & job models; `GJ07-B` admin UI/filters/logs; `GJ07-C` authorization/privacy/redaction; `GJ07-D` resilience/performance/audits. Docs: `docs/global-jobs/07/`. Commit/push every validated checkpoint. End GO/CONDITIONAL GO/NO-GO. Stop.
|
||||
|
||||
## Shared rules for every INT-GLOBAL-JOBS-01 stage
|
||||
|
||||
- Product: **Jobjakt**, a general-purpose, commercial job-search and career-management SaaS. It is **not** an IT-only product. Current architecture includes React/TypeScript, .NET backend, MariaDB, an AI sidecar, existing Career Profile/CV/document/application features, and an established EN/NO localisation approach. Verify actual repository reality before making assumptions.
|
||||
- **Entry gates:** Do not implement new global-job-discovery features until the authoritative Phase 10 and product-review/development-entry decisions permit this initiative. Planning-only reconnaissance may precede them. If an entry gate remains NO-GO, produce safe analysis and stop before code changes.
|
||||
- **Baseline:** Find the latest accepted, integration-complete development commit by reading Git history and the latest authoritative acceptance reports. Do not assume `main` is current. `main` deploys production: NEVER merge to `main` or trigger production. Never change live MariaDB, Docker, Ollama, storage, secrets or other production services.
|
||||
- **Branches:** Use the specified independent stage branch from the latest accepted development integration history including the preceding accepted stage. Verify ancestry, remote, clean tree and existing branch collisions. Use checkpoint commits; push each validated checkpoint; verify remote HEAD equals local HEAD. Do not force-push. Do not advance to another stage without its actual entry criteria.
|
||||
- **Autonomy:** Investigate, design, implement, add tests, document, commit and push safe work without pausing for routine decisions. Stop only for external API agreements, new paid resources, security-risk acceptance, destructive changes, privileged infrastructure actions and production operations. Continue independent work when one provider or model capability is blocked.
|
||||
- **Sources:** Integrate only documented, authorised sources. Verify current licensing, commercial eligibility, credentials, permitted display, storage, cache lifetime, update/delete/tombstone, attribution, user-click-through and rate-limit rules. No covert scraping, private APIs, stolen cookies, bypassing anti-bot controls or fetching protected listing content without authorisation. An external-link-only source is not a direct searchable provider.
|
||||
- **Data trust:** All provider data, job descriptions and user-provided URLs are untrusted. Guard SSRF, XSS/unsafe HTML, prompt injection, HTML injection, unsafe redirects, credential leakage, denial of service and cross-user/tenant access. Do not present missing facts, inferred salaries, regulated-profession eligibility, or AI-generated job details as verified employer facts.
|
||||
- **Availability:** Preserve offline/disabled provider states. Use realistic fixtures in automated tests; any live contract test needs authorised test credentials and bounded rates. Never claim unavailable external API functionality passed.
|
||||
- **User-facing quality:** Desktop/tablet/phone, keyboard and screen-reader access, light/dark, EN/Bokmål plus future qualified locales, loading/empty/error states, responsive design, sensible defaults, performance, source transparency, internationalisation and accessible non-drag alternatives.
|
||||
- **Data integrity:** Source advertisements and user-owned saved jobs/applications are separate records and lifecycles. Preserve existing Career Profile, historical CVs, cover letters, saved applications, revisions, RD21 protections and MariaDB compatibility. Follow source rules for removing or masking withdrawn advertisements, while handling user-owned records under a separately justified retention policy.
|
||||
- **AI:** Existing live-model inference and semantic quality must remain gated unless separately qualified. Rule-based/ESCO-backed title suggestions and auditable matching should function without a generative model. Do not invent user qualifications or automate application submissions.
|
||||
- **Evidence:** At every checkpoint provide exact tests (pass/fail/skip/not run), security/coverage evidence, dated docs, commit hashes, branch and remote verification. Report individual stage GO / CONDITIONAL GO / NO-GO; separate production NO-GO from development readiness.
|
||||
@@ -0,0 +1,51 @@
|
||||
# GJ-08 — Full Cross-Country, Cross-Industry Acceptance and Release Qualification
|
||||
**Suggested branch:** `test/gj08-global-discovery-acceptance`
|
||||
|
||||
## Objective
|
||||
Independently qualify the integrated feature set with full regression, licensing proof, real dataset fixtures and bounded live provider evidence. Fix bounded confirmed defects. Do not count separate passing stage suites as proof the combined product works. No production deployment.
|
||||
|
||||
## Verify lineage and prerequisites
|
||||
Confirm accepted GJ-01 through GJ-07 stage commits are present in one integration-complete development history. Read source-rights matrix, licensing/approval evidence, country-specific data integrity contracts, Phase10 preservation baseline, security model and operator actions. Distinguish implementation complete from authorised live source operational status. Report blocked provider connectors independently.
|
||||
|
||||
## Mandatory acceptance journeys
|
||||
1. New account chooses country of residence, multiple search countries and local/English UI; set preferred ad languages; log out, sign in on second browser, confirm defaults and no implicit preference overwrite.
|
||||
2. NO: Norwegian user filters Vestfold > Tønsberg, Vestland > Bergen and Oslo; searches teacher, cook, nurse, cleaner and developer; NAV feed fixtures reflect updates/deletes, permitted in-app details and original application links. FINN URL import is manually safe if no partner access.
|
||||
3. UK: Warwickshire selects whole area, Warwick then narrows to town, add Leamington gives union of two towns only, clearing children restores all Warwickshire, OR a Bergen branch; radius; county/town ambiguous source-location handling. Source snippet-only job shows honest original link, no unauthorized full content.
|
||||
4. SE: Swedish title autocomplete/classification, Swedish-English ad-language filters, source truncation and proper linked-to-origin details.
|
||||
5. General: teacher, chef, kitchen assistant, nurse, care worker, electrician, plumber, delivery driver, warehouse worker, shop assistant, cleaner, accountant, administrator, farmer, IT developer. Verify contract/hourly/shift/part-time, qualifications, licence and seniority not falsely inferred.
|
||||
6. Full desktop 3-panel and mobile details; direct URL to in-app detail, display source metadata, safe HTML, saved jobs and tracked application integration, create CV variant and cover letter without accidental AI enablement.
|
||||
7. Save search, receive deduped eligible alert, quiet/suspend/unsubscribe, provider offline/stale/deleted, delayed update, job source deduped without merging similar separate posts.
|
||||
8. Admin source health, source job correlation, stale/expired processing, secured redacted diagnostic logs, non-admin denial, correlation IDs and no personal content leakage.
|
||||
9. Security: SSRF/redirect/rate tests, tenant isolation, injection and malicious descriptions, PII deletion, unsafe image/link, incomplete permissions, corrupted feed states, retries, migrations and rollback.
|
||||
10. Accessibility and localisation: keyboard, screen reader where actually available, 200% zoom, real phone where available, English and each shipped local UI language, no missing keys, source original text preserved; do not claim manual sign-off not performed.
|
||||
|
||||
## End-to-end quantitative gates
|
||||
Set explicit measured gates with the owner-approved acceptance plan rather than fabricating universal numbers: critical data loss/security/misleading content = zero accepted, source terms proof for any live connector, consistent hierarchy query semantics, real provider fixtures coverage, benchmark title precision/recall across sectors, latency and index capacity with bounded load, notification dedupe and freshness, regression against preserved routes/document/PDF expectations. Document failures, skips, not run and human checks separately.
|
||||
|
||||
## Full suites
|
||||
Backend/frontend/browser/contract/MariaDB/sidecar as applicable; content/legal-policy assertions, provider contract fixtures, feed update/delete, location mapping, all industries, prefs, localisation, role title, suggestions, filters, dedupe, CV/app integration, admin, security, TypeScript/lint/build, accessible navigation, responsive visual screenshots. Use real provider calls only with approved credentials/rate/test terms. Recheck RD21 and previous CV/PDF regression scope, do not weaken historical tests.
|
||||
|
||||
## Deliverables
|
||||
`docs/global-jobs/08/ACCEPTANCE.md`, `PROVIDER_GO_LIVE_MATRIX.md`, `TEST_EVIDENCE.md`, `MANUAL_QA.md`, `PERFORMANCE.md`, `SECURITY_AND_PRIVACY.md`, `RELEASE_AND_ROLLBACK.md`, `OPEN_GATES.md`, `FINAL_PRODUCT_CAPABILITIES.md`. Preserve previous reports.
|
||||
|
||||
## Independent verdicts
|
||||
- Preferences & localisation, geography, occupation taxonomy, NO, SE, UK (each connector separately), permitted full-detail viewing, source lifecycle, dedupe, saved searches/alerts, matching, admin monitor, security, multi-tenant integrity, accessibility/manual device, overall development, production.
|
||||
- Mark any country/provider BLOCKED if commercial agreement, API consumer registration or access missing. `External links available` is not `Live integrated search`.
|
||||
- Production GO only after independent host/backups/filesystem/ingress/CI/rollback/privacy/source-license/human acceptance criteria genuinely pass, plus explicit owner approval. No main merge or deployment here.
|
||||
|
||||
Commit/push verified QA checkpoints, report GO/CONDITIONAL GO/NO-GO with evidence and exact next owner actions, then stop.
|
||||
|
||||
## Shared rules for every INT-GLOBAL-JOBS-01 stage
|
||||
|
||||
- Product: **Jobjakt**, a general-purpose, commercial job-search and career-management SaaS. It is **not** an IT-only product. Current architecture includes React/TypeScript, .NET backend, MariaDB, an AI sidecar, existing Career Profile/CV/document/application features, and an established EN/NO localisation approach. Verify actual repository reality before making assumptions.
|
||||
- **Entry gates:** Do not implement new global-job-discovery features until the authoritative Phase 10 and product-review/development-entry decisions permit this initiative. Planning-only reconnaissance may precede them. If an entry gate remains NO-GO, produce safe analysis and stop before code changes.
|
||||
- **Baseline:** Find the latest accepted, integration-complete development commit by reading Git history and the latest authoritative acceptance reports. Do not assume `main` is current. `main` deploys production: NEVER merge to `main` or trigger production. Never change live MariaDB, Docker, Ollama, storage, secrets or other production services.
|
||||
- **Branches:** Use the specified independent stage branch from the latest accepted development integration history including the preceding accepted stage. Verify ancestry, remote, clean tree and existing branch collisions. Use checkpoint commits; push each validated checkpoint; verify remote HEAD equals local HEAD. Do not force-push. Do not advance to another stage without its actual entry criteria.
|
||||
- **Autonomy:** Investigate, design, implement, add tests, document, commit and push safe work without pausing for routine decisions. Stop only for external API agreements, new paid resources, security-risk acceptance, destructive changes, privileged infrastructure actions and production operations. Continue independent work when one provider or model capability is blocked.
|
||||
- **Sources:** Integrate only documented, authorised sources. Verify current licensing, commercial eligibility, credentials, permitted display, storage, cache lifetime, update/delete/tombstone, attribution, user-click-through and rate-limit rules. No covert scraping, private APIs, stolen cookies, bypassing anti-bot controls or fetching protected listing content without authorisation. An external-link-only source is not a direct searchable provider.
|
||||
- **Data trust:** All provider data, job descriptions and user-provided URLs are untrusted. Guard SSRF, XSS/unsafe HTML, prompt injection, HTML injection, unsafe redirects, credential leakage, denial of service and cross-user/tenant access. Do not present missing facts, inferred salaries, regulated-profession eligibility, or AI-generated job details as verified employer facts.
|
||||
- **Availability:** Preserve offline/disabled provider states. Use realistic fixtures in automated tests; any live contract test needs authorised test credentials and bounded rates. Never claim unavailable external API functionality passed.
|
||||
- **User-facing quality:** Desktop/tablet/phone, keyboard and screen-reader access, light/dark, EN/Bokmål plus future qualified locales, loading/empty/error states, responsive design, sensible defaults, performance, source transparency, internationalisation and accessible non-drag alternatives.
|
||||
- **Data integrity:** Source advertisements and user-owned saved jobs/applications are separate records and lifecycles. Preserve existing Career Profile, historical CVs, cover letters, saved applications, revisions, RD21 protections and MariaDB compatibility. Follow source rules for removing or masking withdrawn advertisements, while handling user-owned records under a separately justified retention policy.
|
||||
- **AI:** Existing live-model inference and semantic quality must remain gated unless separately qualified. Rule-based/ESCO-backed title suggestions and auditable matching should function without a generative model. Do not invent user qualifications or automate application submissions.
|
||||
- **Evidence:** At every checkpoint provide exact tests (pass/fail/skip/not run), security/coverage evidence, dated docs, commit hashes, branch and remote verification. Report individual stage GO / CONDITIONAL GO / NO-GO; separate production NO-GO from development readiness.
|
||||
@@ -0,0 +1,43 @@
|
||||
# Jobjakt — International Job Discovery Codex Prompt Pack
|
||||
|
||||
This package contains **one master prompt** and **nine standalone staged prompts** for `INT-GLOBAL-JOBS-01`. It is for a **cross-industry**, country-aware, multilingual discovery system for Norway, Sweden and the UK initially, with explicit extension paths.
|
||||
|
||||
## Recommended use
|
||||
|
||||
1. Use `00_MASTER_ORCHESTRATOR.md` when you want Codex/Astra to understand the full roadmap and overall constraints.
|
||||
2. Start with `01_GJ_00_DISCOVERY.md` for planning, architecture, provider-rights audit and source access checks. Planning can be done before Phase 10 completion; **do not implement** until Phase 10/Product Review entry gates actually permit it.
|
||||
3. Then run files `02` to `09` separately **in order**, only after the previous stage's acceptance and latest development baseline are verified. All implementation branches build on accepted predecessor development history, not on outdated `main`.
|
||||
4. Each stage's instruction to commit and push is restricted to its feature/planning/test branch. **No production/main merge or deployment.**
|
||||
|
||||
## Contents
|
||||
|
||||
| File | Purpose |
|
||||
| --- | --- |
|
||||
| 00_MASTER_ORCHESTRATOR.md | Overall master orchestration and universal requirements |
|
||||
| 01_GJ_00_DISCOVERY.md | Architecture, APIs, source rights, acceptance plan |
|
||||
| 02_GJ_01_PREFERENCES_I18N.md | Country, language and saved search defaults |
|
||||
| 03_GJ_02_GEOGRAPHY.md | Region/town refinements and optional radius |
|
||||
| 04_GJ_03_OCCUPATIONS.md | All-profession multilingual autocomplete and search |
|
||||
| 05_GJ_04_PROVIDERS.md | NAV/Swedish/UK sources, FINN manual fallback, rights |
|
||||
| 06_GJ_05_SEARCH_UI.md | Three-pane search, full permitted job description, actions |
|
||||
| 07_GJ_06_ALERTS_MATCHING.md | Saved searches, alerts, relevance and job-tracker integration |
|
||||
| 08_GJ_07_ADMIN_SECURITY.md | Provider/job sync monitoring, failures and secure logs |
|
||||
| 09_GJ_08_ACCEPTANCE.md | Final combined QA, source rights and rollout gating |
|
||||
|
||||
## What is deliberately not assumed
|
||||
|
||||
- No general FINN job-search API access without an approved business relationship.
|
||||
- No ongoing commercial Adzuna integration before approval/licensing.
|
||||
- No guaranteed full in-app descriptions from snippet-only providers.
|
||||
- No production-grade NAV consumer token unless the consumer has actually registered.
|
||||
- No new UI language shown as fully supported without complete translation and QA.
|
||||
- No automatically enabled live AI model, scraping, auto job applications, merge to main or production deployment.
|
||||
|
||||
## Official starting points (reverify when executing)
|
||||
|
||||
- NAV: https://navikt.github.io/pam-stilling-feed/ ; https://arbeidsplassen.nav.no/vilkar-api
|
||||
- FINN: https://www.finn.no/api/
|
||||
- Sweden JobAd Links: https://links.api.jobtechdev.se/
|
||||
- Adzuna: https://developer.adzuna.com/docs/search ; https://developer.adzuna.com/docs/terms_of_service
|
||||
- ESCO: https://esco.ec.europa.eu/en/use-esco/use-esco-services-api
|
||||
- UK ONS: https://geoportal.statistics.gov.uk/
|
||||
Reference in New Issue
Block a user