# Samarbejder V1

**Kontrakt til gennemsyn - 11. oktober 2026**

En virksomhed eller person kan lægge `samarbejder.json` i roden af sin egen hjemmeside. Filen fortæller, hvordan afsenderen vil beskrives hos steder, der bruger formatet. Den kan rumme navn, kontakt, adresser, ydelser, tilbud og priser, cases, stillinger og links. En almindelig statisk hjemmeside er nok. Formatets faste identitet er `https://dags.dk/samarbejder`. En fil med en anden værdi i `format` er ikke et dags.dk Samarbejder-dokument.

Dette er den samlede kontrakt, som afløser det tidligere udkast, der kun dækkede priser.

Formatet er lavet til mange fag. Afsenderens ord står i filen. Et sammenligningssted kan klassificere dem til sine egne filtre og sammenligninger, men må holde sin klassifikation adskilt fra det, afsenderen selv har skrevet.

Den maskinlæsbare kontrakt er [schema.json](schema.json). [dags.dk-filen](dags.json) viser et reelt eksempel med de oplysninger, vi har nu. Den er et lokalt udkast; `https://dags.dk/samarbejder.json` er den tiltænkte placering, når dags.dk har en hjemmeside på domænet.

## Den faste aftale

| Regel | V1 |
| --- | --- |
| Filnavn | `https://<eget-domæne>/samarbejder.json` |
| Formatmærke | `"format": "https://dags.dk/samarbejder"` |
| Version | `"version": 1` |
| Kodning | UTF-8 JSON, `application/json` over HTTPS |
| Størrelse | Højst 524.288 byte før komprimering |
| Indhold | Ét fuldt øjebliksbillede af én afsender |
| Ekstra felter | I `extensions`, under et omvendt domænenavn |
| Historik | Modtageren gemmer tidligere gyldige versioner og deres kilde |

V1's feltnavne og betydning ændres ikke efter godkendelse. Nye domænespecifikke felter går i `extensions`. En ændring af de faste reglers betydning kræver V2. En modtager skal afvise en version, den ikke forstår.

Et katalog, der allerede kender afsenderens hjemmeside, kan lede efter filen på den faste adresse. En ny afsender kan sende sit domæne til kataloget; kataloget henter selv filen fra roden. Afsenderen opdaterer den samme fil, når oplysninger ændrer sig. `www` og domænet uden `www` regnes som samme websted, hvis de peger på hinanden. En redirect til et andet domæne skal afvises.

## Hvem filen handler om, og hvem der har udgivet den

Seks felter er påkrævet øverst: `format`, `version`, `updated_at`, `language`, `origin` og `entity`. Resten kan udelades. `updated_at` er filens dato og tid for sidste indholdsændring med tidszone, for eksempel `2026-10-11T08:30:00+02:00`. `language` angiver sproget for tekstfelterne, for eksempel `da-DK`.

`origin.kind` er enten `self` eller `research`. `self` betyder, at virksomheden selv står bag filen. `research` betyder, at en udgiver har samlet oplysninger fra offentlige kilder. Begge angiver `origin.publisher`. En researchfil skal desuden have `origin.collected_at` og mindst én kilde i `origin.source_urls`. Priser, cases og stillinger i en researchfil har hver sin `source_url` og `observed_at`. Researchfiler ligger hos udgiveren og må ikke fremstå som virksomhedens egne erklæringer.

`entity` har `kind`, `name` og `website`. `kind` er `organization`, `person` eller `other`. `name` er det navn, der skal vises. `website` er afsenderens kanoniske HTTPS-hjemmeside. `legal_name` kan angive det juridiske navn. `identifiers` kan indeholde offentlige identifikatorer som `{"scheme":"dk:cvr","value":"25954572"}`. Modtageren må ikke opfatte et selvskrevet CVR-nummer som verificeret alene på grund af filen.

En selvudgivet fil skal have `participation` med `public_display: true` og `history: true`. Afsenderen tilkendegiver dermed, at indholdet må vises offentligt med kildeangivelse, og at tidligere versioner må gemmes til dokumentation af ændringer. Afsenderen skal kun medtage tekst og medier, som vedkommende har ret til at offentliggøre. Det er en praktisk deltagelseserklæring, ikke en overdragelse af ejerskab til data eller medier. En researchfil må ikke have `participation`, da udgiveren ikke kan give dette tilsagn på virksomhedens vegne.

## Oplysninger i V1

| Felt | Indhold | Loft |
| --- | --- | ---: |
| `profile` | Overskrift, kort og lang beskrivelse, stiftelsesår, teamstørrelse, dækningsområde og frie emneord | Ét objekt |
| `contacts` | E-mail, telefon eller kontaktadresse | 20 |
| `locations` | Adresser og eventuelle koordinater | 20 |
| `services` | Hvad afsenderen arbejder med, også uden offentlig pris | 100 |
| `offers` | Konkrete pakker, produkter eller ydelser med valgfri pris | 200 |
| `cases` | Projekter og kundehistorier, med kundenavn når det må vises | 100 |
| `positions` | Stillinger, praktik og løbende rekruttering | 100 |
| `pages` | Hentede eller udvalgte sider med titel, kilde, dato og tekst | 150 |
| `links` | Præsentation, booking, sociale profiler og andre relevante sider | 50 |
| `media` | Logo, billeder, video og dokumenter med kilde og rettigheder | 50 |
| `extensions` | Ekstra oplysninger under afsenderens navnerum | 20 navnerum |

Det dækker den eksisterende virksomhedsprofil: virksomhedsnavn, webadresse og CVR går i `entity`; beskrivelse, teamstørrelse og dækningsområde går i `profile`; adresser går i `locations`; ydelser går i `services`. De nye områder bruger `offers`, `cases` og `positions`. Afsenderens egne billeder kan ligge i `media`. Researchsidens skærmbilleder og teknologivurdering er egne observationer og får deres egen kilde ved siden af filen.

Alle poster i listerne har et stabilt `id`. Et id er 1-80 tegn med små bogstaver, tal, punktum, understregning eller bindestreg. Samme id skal bruges, når en post ændres. Et slettet id er væk fra den aktuelle fil, mens tidligere versioner stadig viser, at posten har eksisteret. Id'er skal være unikke inden for hver liste.

`profile.team_size` kan angive et præcist tal med samme `min` og `max` eller et interval. `as_of` viser, hvornår tallet gjaldt. `locations` kan have land, sted, postnummer, gadeadresse og koordinater. Kun `country_code` er påkrævet i en adresse, så en afsender kan nøjes med at oplyse sit land.

`services` er afsenderens egne betegnelser. `offers` er konkrete tilbud og kan pege på en eller flere services via `service_ids`. En modtager må gerne lægge egne kategorier ovenpå, men må ikke ændre afsenderens ord i den gemte original.

`pages` bevarer sideindhold, som ikke kan beskrives fuldt med ydelser, tilbud, cases eller stillinger. Hver post har `url`, `kind` og `observed_at`; `title`, `summary`, `text` og `depth` kan tilføjes. `kind` er `homepage`, `service`, `price`, `case`, `position`, `about`, `contact`, `article` eller `other`. En researchfil kan bruge feltet til sine daterede hjemmesideaftryk. En selvudgiver kan bruge det til at udpege egne sider. Sidetekst er højst 12.000 tegn pr. post, og hele filen skal stadig holde sig under 512 KiB.

### Priser

En pris ligger i `offers[].price`. `type` er `fixed`, `from`, `range` eller `quote`. `fixed` og `from` har `amount`. `range` har `min_amount` og `max_amount`. `quote` har intet beløb. Et beløb er en decimalstreng som `"4900.00"`, uden tusindtalsseparator eller valutasymbol. Numeriske priser skal også have `currency`, `unit` og `vat`.

`currency` er en valutakode som `DKK`. `unit` er en maskinlæsbar enhed som `one_time`, `hour`, `month`, `year`, `item`, `person`, `day` eller `night`. Andre enheder kan bruges; `unit_label` kan forklare dem. `vat` er `excluded`, `included`, `not_applicable` eller `unknown`. `billing_note`, `includes` og `excludes` kan forklare betalingen og omfanget. `valid_from` og `valid_through` afgrænser en pris, når afsenderen kender perioden.

Priser bør kun indgå i samme talmæssige sammenligning, når valuta, enhed, momstilstand og pristype passer sammen. Forskelligt indhold i ydelserne skal stadig fremgå ved siden af tallene. En `from`-pris er et udgangspunkt, og en `quote` er ikke et tal på en farveskala.

### Cases og kunder

En case har `id` og `title`. Den kan også have `summary`, `description`, `url`, `published_on`, `customer`, `service_ids` og `media_ids`. `customer.name` er valgfrit, fordi nogle arbejder med fortrolige eller anonymiserede kunder. En case uden kundenavn kan stadig vises som projekt. En kundeliste kan derfor bestå af korte cases med kundenavn og URL, mens en gennemarbejdet case kan have mere tekst og billeder.

### Stillinger

En stilling har `id`, `title` og `status`. `status` er `open`, `closed`, `evergreen` eller `unknown`. `evergreen` er til løbende interesse for kandidater, praktik eller uopfordrede ansøgninger. `unknown` bruges til et indsamlet opslag, hvor den aktuelle status ikke er bekræftet. En `open` stilling skal have `valid_through`; efter den dato må den ikke vises som åben. `posted_on`, `employment_type`, `location_ids`, `url`, `summary` og `description` er valgfrie.

## Udvidelser uden ny version

Et ekstra felt skal ligge i `extensions`. Nøglen er afsenderens domæne skrevet baglæns, for eksempel `dk.dags.research`. Værdien er et JSON-objekt:

```json
"extensions": {
  "dk.dags.research": {
    "technology_orientation": "open"
  }
}
```

`extensions` kan ligge øverst og i de vigtigste poster. Modtagere skal bevare ukendte navnerum, når de gemmer originalen, og kan ignorere dem i deres egen visning. De faste V1-felter må ikke have en anden betydning inde i en udvidelse. Et felt uden for skemaet bliver afvist, så en stavefejl ikke lydløst bliver til et nyt felt.

## Grænser og kontrol

Filens samlede loft er 512 KiB. Tekstfelter har egne grænser: navn og titel højst 240 tegn, kort beskrivelse højst 2.000 tegn og lang beskrivelse højst 12.000 tegn. Den samme JSON-nøgle må ikke gentages i et objekt. Referencer til `service_ids`, `location_ids` og `media_ids` skal pege på poster i samme fil. Prisintervaller skal gå fra lav til høj, og datointervaller skal gå fremad. En fil, der bryder kontrakten, afvises samlet; den bliver ikke beskåret automatisk.

En modtager henter en selvudgivet fil fra afsenderens eget offentlige HTTPS-domæne. Redirects til andre værter accepteres ikke. Domænekontrol viser, at afsenderen kan udgive filen på sit websted. Researchfiler kan ligge på udgiverens eget domæne og beholder tydelig kildeangivelse. Et oplyst registreringsnummer kan kontrolleres særskilt, før filen kobles til en eksisterende virksomhedsprofil. Filen er offentlig; den må ikke indeholde adgangskoder eller interne oplysninger.

## Kilde, forrang og historik

En gyldig selvudgivet `samarbejder.json` er afsenderens aktuelle udsagn. Når den findes, bruger modtageren dens felter som den primære virksomhedsprofil. Manglende sektioner fyldes ikke lydløst med gamle crawl-data. Modtageren kan vise egne observationer og analyser ved siden af, med tydelig kilde og dato. Det gælder for eksempel teknologiprofil, skærmbilleder og de researchfiler, som modtageren har lavet for virksomhederne.

Hver modtager gemmer den rå gyldige fil, tidspunktet den blev hentet, URL, HTTP-status, en SHA-256-kontrolsum og en normaliseret kopi til søgning. En ny indholdsversion gemmes, når den normaliserede JSON ændrer sig; en ændring af indrykning alene tæller ikke som nyt indhold. Den gamle version overskrives ikke. Afsenderens `updated_at` og modtagerens hentetid er to forskellige tidspunkter og skal opbevares hver for sig. Hvis filen fjernes eller bliver ugyldig, markeres den seneste egenangivelse som utilgængelig eller forældet; den må ikke fremstå som netop bekræftet. Historikken skal kunne bruges til at se, hvad der ændrede sig, og hvornår modtageren så ændringen.

Et felt eller en post, der fjernes i en ny gyldig fil, fjernes fra den aktuelle visning. Den tidligere værdi ligger i historikken. Håndtering af en konkret anmodning om sletning af historiske oplysninger er modtagerens ansvar og ligger uden for dataformatet.

## Hvad der er fast, og hvad modtageren selv bestemmer

V1 fastlægger datafelter, filplacering, grænser, betydning af priser og stillingsstatus samt hvordan ændringer kan spores. Modtageren bestemmer sine egne søgefiltre, emnekategorier, farveskalaer, kontrolhyppighed og præsentation. Andre brancher kan bruge samme fil med deres egne kategorier. Et modtagersystem skal vise, hvilke oplysninger der kommer direkte fra afsenderen, og hvilke der er dets egne observationer.

Skemaet følger [JSON Schema Draft 2020-12](https://json-schema.org/draft/2020-12). Kontrakten og kontrolkoden kan bruges under [MIT-licensen](LICENSE). Afsenderens indhold og medier følger deres egne rettigheder.
