jobb

Jobb project context

Det här dokumentet är den app-specifika, versionsstyrda tekniska kontexten för det tidigare monorepot / apps/jobb.

Senast verifierad mot repositoryt: 2026-10-02

Auktoritet och läsordning

Vid konflikt för repo-specifik teknik gäller följande ordning:

  1. Filer på aktuell main i det tidigare monorepot, under apps/jobb.
  2. Versionerade D1-migrationer och runtimekonfiguration i repositoryt.
  3. Publika upstream-kontrakt för de externa API:er och tjänster implementationen använder.
  4. Det här dokumentet.
  5. Äldre pull requests, issues och historik.

docs/organization/ innehåller delad kontext för det tidigare monorepot. Jobbs app-local current-state ägs av apps/jobb, medan Cloudflare-live-state verifieras hos respektive provider. Historik hör hemma i Git.

Syfte och säkerhetsgräns

Jobb söker jobb automatiskt på StudentConsulting och samlar månadens ansökningar i en .txt med jobb-ID, jobbtyp, stad och omfattning. Arbetsförmedlingen har inget API för aktivitetsrapporten, så Jobb rapporterar inte dit.

Systemets hårda mål är 10 verifierade lämpliga ansökningar per kalendermånad. Det är ett tak i automationsflödet, inte bara en dashboard-mätare.

Viktiga säkerhetsgränser:

Runtime-arkitektur

Primär runtime är Cloudflare Worker jobb med entrypoint apps/web/src/index.ts.

Appens apps/jobb/wrangler.jsonc är deployment-konfigurationen och binder:

Workspace använder pnpm 10.17.1. Root-skripten kör repoövergripande typecheck/test och produktionens deploykommando applicerar D1-migrationer före Wrangler deploy.

Körningsmodell

Manuell körning

Den skyddade dashboarden kan starta samma pipeline manuellt under den 1:a–14:e varje månad i Europe/Stockholm.

Manuell start kräver:

  1. Cloudflare Access-dashboardautentisering,
  2. exakt same-origin mutation guard,
  3. konfigurerat StudentConsulting-konto med autosubmit aktiverat,
  4. öppet applikationsfönster.

Starten gör därefter en atomisk D1-claim: högst en running automation får finnas åt gången över manuella och schemalagda starter. Run-raden skapas eller, för en failed schemalagd retry, återställs till ett rent running-state innan Workflow startas. Workflow-ID länkas både direkt efter create och som första Workflow-step. Startfel och Workflow-undantag skrivs tillbaka som failed; gamla running-rader utan Workflow-länk eller ansökningsaktivitet klassas/reconcileras som orphaned efter fem minuter.

Automatisk säkerhetskörning

Cron kör en gång per dag den 10:e–13:e vid 09:00 UTC.

Data och state

Produktionsbindingen DB ska peka på en D1-databas som skapats med Cloudflare-jurisdiction eu. Jurisdiction är creation-time providerkonfiguration och ska verifieras i Cloudflare när databasen ersätts; repositoryts UUID/name-binding är inte i sig bevis på data locality.

D1-migrationerna är canonical schemahistorik:

Centrala stateflöden:

Evidens

Verifierad StudentConsulting-evidens skrivs som JSON till privata R2-bucketen jobb-evidence. D1-tabellen evidence lagrar metadata och R2 object key.

Schemafältet evidence.sha256 finns men fylls inte av nuvarande lagringsväg. Det ska därför inte beskrivas som ett aktivt integritetsskydd förrän hashing faktiskt implementerats och verifierats.

Dashboarden visar evidence-metadata men är inte en generell R2 object-browser.

StudentConsulting

StudentConsulting-integrationen använder Browser Run för autentisering, discovery, formulärkontroll, submission och verifiering. Discovery läser navigationsvärden från href, data-href, data-url och inline onclick på den verifierade Matcha-jobb-vyn. Absoluta URL:er behåller sin ursprungliga authority vid validering; endast betrodda StudentConsulting-rutter av formen /sv/lediga-jobb/.../<Jobb-ID> får bli kandidater.

Autonom submission kräver:

Ett definitivt misslyckande kan frigöra en reserverad slot. Ett osäkert resultat behåller sloten för att förhindra dubbel/elfte ansökan.

Månadsfil och e-post

När månaden har tio verifierade ansökningar sparas en .txt i D1 (activity_report_exports). Varje jobb får fyra rader: Jobb-ID, Jobbtyp (specifikt yrke, eller yrkesordet i rubriken när StudentConsulting bara anger en kategori som “Logistik / Transport”), Stad och Omfattning (från annonsen, annars heltid/deltid/extrajobb i rubriken). Filen heter jobbansokningar_ÅÅÅÅ-MM-DD.txt efter dagen då den tionde ansökan verifierades. Filer i det äldre formatet byggs om en gång vid första nedladdning eller utskick.

En ny fil mejlas automatiskt till NOTIFY_EMAIL_TO (en eller flera adresser). NOTIFY_EMAIL_MODE=group skickar ett gemensamt mail, separate ett mail per mottagare. Filen bifogas och står även i brödtexten. Varje utskick loggas i notifications; ett misslyckat utskick fäller aldrig körningen.

Historiska luckor får repareras read-only från StudentConsultings autentiserade Ansökningar-historik. Endast poster som StudentConsulting själv returnerar för den uttryckligen valda månaden får backfillas; reparationsflödet får aldrig skicka eller bakdatera en ny ansökan.

Dashboard och API

Dashboarden på / är operativt kontrollplan. Den skyddas av Cloudflare Access och kräver komplett konfiguration för CF_ACCESS_TEAM_DOMAIN och CF_ACCESS_AUD; ofullständig konfiguration failar stängt.

Dashboarden erbjuder legacy, forest (med etiketten från SITE_FAMILY) och blackout med Legacy som fallback. Legacy bygger på Portalens faktiska pre-v2 portalen-uttryck med cyan/blå/magenta glow och diskret rutnät; de cyan/gröna operativa accenterna förblir Jobb-specifika. Dashboarden persisterar samma presentationspreferens som övriga monorepoappar; cookien är aldrig auth-, CSRF- eller sessionsstate.

Top-level-vyer:

Primära endpoints:

Alla skyddade mutationer kräver exakt same-origin Origin; inkompatibel Sec-Fetch-Site avvisas också när headern finns. Detta är ett extra CSRF-skydd ovanpå dashboard-auth. Manuell run, stop och delete kräver samma Access-auth och same-origin-skydd.

Dashboard-CSP tillåter endast egna scripts/styles/connect-källor; unsafe-inline används inte och ingen extern Turnstile-scriptkälla behövs.

Browser-felsidor använder separat same-origin CSS på /assets/auth.css, strikt CSP utan inline-script och en gemensam felvy med sanitiserad felkod och korrelations-ID.

Runtime configuration

Hemliga värden får aldrig committas. Produktionsvärden kan komma från Cloudflare/runtime eller, för de fält som dashboarden hanterar, från den krypterade D1-raden runtime_configuration. Deployment-värden har alltid företräde framför dashboard-värden.

Credential-/security-namn:

Icke-hemliga eller policyrelaterade runtime-värden:

Utskick använder Email-bindingen EMAIL.

Den autentiserade System-vyn kan spara StudentConsulting-konto, autosubmit, valfria extra lämplighetsfilter och e-postutskick av månadsfilen. Manuell körning skyddas av Cloudflare Access och exact same-origin mutation guard; Jobb bäddar inte in eller kräver Turnstile. Det dashboard-hanterade dokumentet krypteras med AES-GCM innan D1-write; krypteringsnyckeln härleds med separat HKDF-context från JOBB_CONFIG_KEY. StudentConsulting-lösenordet returneras aldrig efter sparning. Vid nyckelbyte binds den gamla nyckeln som JOBB_CONFIG_KEY_PREVIOUS; första läsningen krypterar om raden med den nya nyckeln, så inget behöver matas in igen.

Auth, request-säkerhet och privacy

Cloudflare Access är Jobbs identity authority. Access sköter inloggning och policy framför <din-host>; Workern verifierar på varje request att Cf-Access-Jwt-Assertion är en RS256-signerad JWT från teamets certs med rätt issuer, audience (CF_ACCESS_AUD) och giltighetstid. Jobb har ingen egen session, cookie eller login-provider.

Access är fail-closed och enda dashboard-authvägen: saknad eller halvkonfigurerad CF_ACCESS_TEAM_DOMAIN/CF_ACCESS_AUD ger fel i auth/readiness, och en request utan giltig assertion avvisas även om Access skulle ha förbigåtts. Legacy Basic Auth accepteras inte av koden.

Manuell körning kräver en verifierad Cloudflare Access-identitet och exact same-origin mutation guard. Körningsdetaljer erbjuder stop för aktiva Workflow-instanser och delete för terminala testkörningar utan ansökningshistorik; körningar med ansökningshistorik kan inte raderas via dashboarden.

Dashboardens mutationsendpoints har same-origin-kontroll. UI-responsen sätter CSP, X-Content-Type-Options: nosniff, Referrer-Policy: no-referrer, frame-ancestors 'none' och Cache-Control: no-store.

Wrangler sätter observability.redact_query_string=true. Det är ett krav eftersom OAuth-callbacken bär kortlivade code/state i query-strängen och de inte ska persisteras i Worker-logs/traces.

Verifiering och deployment

Appens versionerade verifieringsväg är:

pnpm install --frozen-lockfile
pnpm typecheck
pnpm test

apps/jobb/package.json definierar produktionskommandot:

pnpm deploy:cloudflare

Kommandot applicerar remote D1-migrationer och deployar därefter Workern med apps/jobb/wrangler.jsonc.

Vilket externt CI/CD-system som eventuellt kör kommandona är inte app-local current-state och dokumenteras inte här.

Ändringskontrakt

Uppdatera detta dokument när någon av följande ändras:

Materiella ändringar i security boundary, permissions eller deploymentarkitektur ska förankras innan implementation. Extern governance/live-state verifieras i sitt auktoritativa system och ska inte dupliceras som permanent repo-current-state.