Skip to main content
Petanque Life
← Back to all features
14

Integration & API

152 features · 18 subsystems

External system integrations, API strategy, data exchange, and machine-to-machine communication. Provides M2M OAuth2, webhooks, and file import capabilities.

API-klientaxeln, den publika verifieringen: det som FAKTISKT är byggt

F14.00
Shipped

Raderna .01–.09 levererades av **D-PUBAPI `a95566cc.m-1`** (t-1 axeln i API:t, t-2 ytorna),

  • F14.00.01 Shipped

    M2M-/klientidentiteten — m2m_client utvidgad med kind (developer · federation_integration · service_account), tier, rate_limit_per_minute, is_sandbox, owner_identity_id; status HÄRLEDS ur stämplarna (aldrig en lagrad kolumn)

    ✅ a95566cc.m-1 t-1
  • F14.00.02 Shipped

    Nycklarna (api_token) — flera per klient, token_prefix synlig, hemligheten bara som sha-256-hash och visad EXAKT en gång; överlappande rotation

    ✅ a95566cc.m-1 t-1
  • F14.00.03 Shipped

    Client-credentials-granten POST /v1/oauth/token (RFC 6749 §4.4, client_secret_basic + client_secret_post), alias POST /auth/m2m/token; varje misslyckande svarar BYTE-IDENTISKT 401 invalid_client (enumerationsskydd)

    ✅ a95566cc.m-1 t-1
  • F14.00.04 Shipped

    Fyra grindar per anrop — revocation vid decode (401 invalid_token, OMEDELBAR), IP-allowlist (403 ip_not_allowlisted), scope→capability i authz-UNIONEN (403 insufficient_scope, deny-by-default) och klient-limitern per tier/override/sandbox ×10 (429 rate_limited)

    ✅ a95566cc.m-1 t-1
  • F14.00.05 Shipped

    Self-service-nycklar POST/GET/DELETE /v1/developer/keys + /v1/developer/client (människosession, aldrig en M2M-token); PL_DEVELOPER_SIGNUP_ENABLED=false ⇒ 403 registration_disabled

    ✅ a95566cc.m-1 t-1
  • F14.00.06 Shipped

    Förbundets klienter /v1/api-clients[...] med scope-katalogen, If-Match-låsning, livscykeln :suspend

    :reactivate|:revoke och eskaleringsspärren 422 scope_exceeds_grantor | ✅ a95566cc.m-1 t-1
  • F14.00.07 Shipped

    Sys-läsytan /v1/sys/developer-platform/clients[...] (cross-tenant, aldrig en hash) + F1-3:s befintliga fresh-auth-gatade servicekonto-CRUD

    ✅ a95566cc.m-1 t-1
  • F14.00.08 Shipped

    Ytorna — admin /webhooks-api (sektionen *API-klienter*: tabellen, scope-katalogens kryssrutor, nyckeln vars hemlighet visas en gång, If-Match-redigeringen och livscykeln) och sys /utvecklarplattform (flikarna *Utvecklare* och *Servicekonton*)

    ✅ a95566cc.m-1 t-2
  • F14.00.09 Shipped

    Fixturen seed-api-clients — fem klienter genom API:ts egna sömmar, kända hemligheter bara i PL_ENV ∈ {local,test}

    ✅ a95566cc.m-1 t-1
  • F14.00.10 Shipped

    Publik, privacy-säker licensverifiering över tenant-gränsen — GET /v1/public/licenses/verify?federation=&license_number=&birth_year=&discipline= (sluten utfalls-enum valid|blocked|expired|not_found, byte-identisk not_found = inget existens-orakel, blocked säger aldrig varför, identitetsavtäckning bara vid valid och publik profil, födelseåret BEKRÄFTAR och ekas aldrig) + GET /v1/public/players/{user_id}/licenses (PII-fri cross-tenant-översikt på husets EGEN auth_identity). Anonyma, taggade cross-tenant-public-read och med i den filtrerade partnerprojektionen; per-avsändartak PL_LICENSE_VERIFY_RATE_MAX (default 300/h, DELAT mellan rutterna), Cache-Control: public, max-age=60 utan ETag. Noll migrationer, noll skrivningar, ingen uppslagshistorik. Fixtur: seed-license-verify. Kontrakt: specs/api/endpoints/public-license-verification.md

    ✅ a95566cc.m-4 t-1
  • F14.00.11 Planned

    Batch-/bulk-verifiering (en hel startlista i ett anrop) och en M2M-scope-skopad högvolymyta ovanpå F14.00.10

    ⊘ a95566cc.m-7/m-8 — öppnas när ett scope motiverar den; m-4:s yta frågar EXAKT ett förbund per anrop med flit
  • F14.00.12 Shipped

    Bulk-exportjobbet — löv-paketet internal/bulkexport (dataset-registryn med kolumner, pii-flaggor, maskeringsregler och ett DEKLARERAT filterschema; strömmande, deterministiska csv/json/xlsx-skrivare där två identiska exporter ger IDENTISKA bytes och samma sha256), migration 00256, capabilityn export:manage som ger YTAN medan datasetets EGEN capability prövas utöver den — BÅDE vid beställningen och en gång till i vågen — POST/GET /v1/exports, GET /v1/exports/{id} med MÄTTA tal, :cancel, och F1-7-vågen bulk_export_run (claim med for update skip locked, batchad läsning, failed:worker_lost bortom PL_BULK_EXPORT_STALE_MINUTES)

    ✅ a95566cc.m-10 t-1
  • F14.00.13 Shipped

    Exportmallarna — /v1/export-templates (skapa · lista · läs · If-Match-skriv · :archive · :preview), kolumnmappning husets kolumn → mottagarens rubrik → transform ur en SLUTEN, parametriserad mängd, delad/personlig (403 template_not_owned), och förhandsvisningen på ≤ 20 RIKTIGA rader maskerade som default, utan en enda sidoeffekt

    ✅ a95566cc.m-10 t-1
  • F14.00.14 Shipped

    Schemalagda leveranser — /v1/export-schedules (skapa · If-Match-skriv · DELETE · :pause/:resume · :run-now · /deliveries · :retry), sex frekvenser räknade i TENANTENS zon och lagrade i UTC (inget hourly), F1-7-svepet bulk_export_schedule_tick med single-fire som DB-invariant unique (schedule_id, scheduled_for), och tre kanaler med MÄTTA utfall per mottagare (email med LÄNKEN genom husets ENDA utgång + delade spärrlista · webhook genom förbundets EGEN prenumeration · in_app). Beställarens mandat prövas i VÅGEN: har hon förlorat det blir jobbet failed:capability_denied med noll bytes

    ✅ a95566cc.m-10 t-2
  • F14.00.15 Shipped

    Retention-begränsade nedladdnings-URL:er — GET /v1/exports/{id}/download?token=… (token-verifierad i handlaren, fungerar ur ett mejl utan session), klartexten lagras ALDRIG (bara sha256), länken mintas i KLICKÖGONBLICKET och den föregående dör samtidigt, :revoke-links dödar varje levande länk, varje fel svarar byte-identiskt 404 (inget uppräkningsorakel), och F1-7-svepet bulk_export_retention_tick river bytesen bortom fristen medan talen och sha256 står kvar för alltid

    ✅ a95566cc.m-10 t-1/t-2
  • F14.00.16 Shipped

    Tävlingsexporten — POST/GET /v1/competitions/{id}/exports som SAMMA jobb (source='competition', samma kö, samma frist, samma signerade länk): fipjp_json = husets EGET petanque-life-v1-kuvert (typen competition_results, kanonisk serialisering, exchange.ScanForbidden FÖRE första byten ⇒ inget fullt födelsedatum, ingen adress) och generic_csv = datasetet results genom förbundets egen mall. Läst ur den PUBLICERADE ögonblicksbilden — ett opublicerat resultat följer aldrig med. Plus webhook-typen export.ready (cross_tenant_public: false)

    ✅ a95566cc.m-10 t-2
  • F14.00.17 Shipped

    Ytan — admin /dataexport med mockupens fyra export-flikar LEVANDE (*Exportjobb* · *Schemalagda rapporter* · *Exportmallar* · *Tävlingsexport*), nav-postens »någon av«-villkor utvidgat med export:manage, grinden PER FLIK med mandatet i klartext, *Maskera personuppgifter* förvald PÅ med sin bokföringstext, inga förhandsutgråade knappar (serverns 403/422/429 VID åtgärden) och INGEN katalog, frist eller formatetikett i ytan. Vy-spec specs/admin/views/dataexport.md, runbook docs/engineering/runbooks/bulk-export.md, bevis node tools/gate/dpubapi-m10-e2e.mjs

    ✅ a95566cc.m-10 t-3
  • F14.00.18 Shipped

    Det signerade, återkallbara widget-tokenet — wgt_<16 hex kortid>.<epok>.<sig> där kortidet är widget-uuid:ts första 64 bitar (genererad kolumn med unikt index ⇒ O(1)-uppslag) och signaturen 16 byte HMAC-SHA256(nyckel, "<kortid>

    <epok>"). Epoken ÄR återkallelsen (:regenerate-token höjer den; inget token lagras, så det finns ingenting att radera), formen prövas statlöst FÖRE varje databasfråga (en förfalskningsflod kostar noll store-anrop) och utan PL_WIDGET_TOKEN_SIGNING_KEY är allt fail-closed (503 på skapandet, 404 publikt) — ett osignerat token får aldrig existera | ✅ a95566cc.m-11 t-1
  • F14.00.19 Shipped

    Den publika familjen på rotnivå, ANONYM: GET /public/widgets/{token} (HTML-dokumentet), …/data (JSON, embed_version på toppnivå, rows alltid en array, CORS * utan credentials) och /public/widgets.js (loadern: beroendefri, < 8 KiB, aldrig innerHTML — grep-vaktat — och en loader per sida oavsett antal widgets). Handlarens ordning är tak → form → uppslag → grind → innehåll → räkning, och varje misslyckande svarar BYTE-IDENTISKT 404 med no-store (ingen skillnad mellan »finns inte«, »pausad« och »fel signatur« — annars vore ytan ett orakel)

    ✅ a95566cc.m-11 t-1
  • F14.00.20 Shipped

    Ursprungslistan och taket — allowed_origins blir frame-ancestors i dokumentets CSP (webbläsaren fäller inbäddningen) och prövas mot Origin på JSON-ytan ⇒ 403 origin_not_allowed; en begäran utan Origin släpps igenom med flit (listan skyddar mot obehörig INBÄDDNING, den är inget autentiseringsmedel). Per-IP-taket 3 600/timme (PL_WIDGET_PUBLIC_RATE_MAX) gäller hela familjen utom loadern och körs FÖRST i varje handler

    ✅ a95566cc.m-11 t-1
  • F14.00.21 Shipped

    Katalogen, anpassningen och embed-kod-generatorn — GET /v1/widgets/catalog serverar de fyra typerna med sina fält och husets mängder (färger · teman · typsnitt · språk · empty_reasons), kontrasten döms server-side mot WCAG 2.2 AA med den uppmätta kvoten i detail (422 contrast_insufficient), custom_css går genom husets ENDA sanerare (som avvisar, aldrig strippar tyst) och GET /v1/widgets/{id}/embed-code bygger de tre snippetarna (iframe sandboxad utan allow-same-origin · script + mount-div · direktadress) — ytan bygger aldrig en egen. Plus …/stats (värdar, aldrig vägar), …/preview (samma renderare, utan räkning, fungerar även pausad) och F1-7-svepet embed_widget_view_retention_tick

    ✅ a95566cc.m-11 t-1
  • F14.00.22 Shipped

    Ytan — admin /inbaddning med mockupens fyra flikar, TVÅ LEVANDE (*Widgets* · *Anpassning & inbäddningskod*) och TVÅ ⊘ MED ÄGARE (*Streaming & video* = F14.14 · *Kartor & geokodning* = F14.11, synliga och aria-disabled — en dold flik är lika osann som en attrapp). Nav-posten 🖇️ gatad på widget:manage, MÄTTA *Visningar 30 d* (»—« utan svar, aldrig 0), den SERVERBYGGDA customization_summary, serverns 422 VID färgfältet och snippetarna tecken för tecken ur servern. Vy-spec specs/admin/views/inbaddning.md, partnerguide docs/engineering/integration-api/widgets.md, bevis node tools/gate/dpubapi-m11-e2e.mjs

    ✅ a95566cc.m-11 t-2

Public API

F14.01
Shipped
How it works
  • F14.01.01 Planned

    RESTful API with OpenAPI/Swagger documentation — GET /api/info discovery endpoint, enriched OpenAPI metadata (contact, license, terms, tags), Swagger UI at /docs, ReDoc at /redoc

    ⊘ byggt i den nuvarande stacken av F1-1/F1-8 (/openapi.json, /reference); legacy-raden beskriver FastAPI-Swagger som inte finns
  • F14.01.02 Planned

    API versioning — X-API-Version response header on all responses, /v1/ URL prefix transparency, X-API-Version-Deprecated header for mismatched versions

    ⊘ X-API-Version finns (F1-1); X-API-Version-Deprecated/Sunset ägs av a95566cc.m-2
  • F14.01.03 Shipped

    Rate limiting per client — X-RateLimit-Limit/X-RateLimit-Remaining/X-RateLimit-Reset response headers, per-IP sliding window, per-M2M-client configurable limits (1–10 000 req/min), abuse monitor with lockout

    ✅ a95566cc.m-1 för rate-limit per klient/tier + headers; *abuse monitor with lockout* har ingen ägare (ingen missbruksvakt finns i huset)
  • F14.01.04 Shipped

    M2M OAuth2 client credentials authentication — RFC 6749 §4.4 compliant POST /auth/m2m/token, ES512 JWT, SHA-256 secret hashing, IP CIDR allowlist, secret rotation, admin CRUD

    ✅ a95566cc.m-1 — granten, hashningen, allowlisten och rotationen; se F14.00.03/.04
  • F14.01.05 Planned

    Public endpoints (rankings, results, calendar, venue directory) — GET /public/rankings, /public/rankings/{id}, /public/results, /public/results/{competition_id}, /public/venues, /public/venues/{id} with cursor pagination, filters, and search

    ⊘ D-RANK/D-COMP/D-VENUE äger datan; den publika läsytan har ingen egen D-PUBAPI-leverans ännu
  • F14.01.06 Planned

    API developer portal — POST /api-tokens, scopade M2M-tokens, rate limiting

    ⊘ delvis: nyckel-self-service finns (F14.00.05) och portalens API-halva är byggd i a95566cc.m-7 t-1 (sandbox-familjen + de tre katalogprojektionerna GET /v1/developer/scope-catalog, …/webhooks/{event-types,policy}, …/deliveries/summary — samma kataloger som förbundsytans, byte-för-byte); PORTALENS SIDOR i web är BYGGDA i a95566cc.m-7 t-3 — de fem rutterna /developers, /developers/nycklar, /developers/sandlada, /developers/webhooks, /developers/referens under PLATTFORMS-chromen (§9b D-9, markören x-pl-devportal), som läser katalogerna ur SERVERN och aldrig bär en egen lista eller ett eget tal. Kvarstående luckor renderas MED ägare i ytan: arkivets kort *Tillgänglighet 99,96 %* som »—« med ägaren F1-8, fakturering BILL, data-produktkatalogen m-8, cursor-pagineringen F14.03.06. Vy-kontraktet specs/web/views/developers-portal.md; bevis node tools/gate/dpubapi-m7-e2e.mjs
  • F14.01.07 Shipped

    API key management — token-livscykel (create, revoke, validate), SHA-256-hash

    ✅ a95566cc.m-1 — se F14.00.02
  • F14.01.08 Planned

    API usage analytics and monitoring — ApiUsageRecord hourly buckets, GET /api-usage/summary, /api-usage/by-token, /api-usage/timeseries with per-endpoint breakdowns, latency tracking, and rate-limit hit counting

    ⊘ a95566cc.m-2 (usage-buckets, rollup-jobb, p50)
  • F14.01.09 Planned

    ERD drill-down explorer — three-tier /erd viewer (super-domain → sub-domain → entity) with breadcrumb, URL-state, fuzzy search, heatmap, BFS radius 1–2, cross-domain-bridge toggle; new JSON endpoints /erd/domains, /erd/domains/{id}, /erd/entities/{name}; project-configurable F01–F20 mapping via SuperDomainConfig

    ⊘ ingen ägare — ERD-utforskaren fanns bara i det rivna systemet
  • F14.01.10 Planned

    Service-account M2M-tokens with admin scopes — ServiceAccount-modell, ApiScope admin-scopes (tenants:write, federations:write, cms:write, admin_invitations:create, users:write, seed:run), /sys/service-accounts CRUD + token mint/revoke, 90-day default TTL, agent-driven prod-bootstrap utan WebAuthn-step-up

    ⊘ delvis: servicekontot som identitet + dess nycklar finns (F14.00.07); admin-scope-katalogen tenants:write/seed:run finns INTE — scope-katalogen är kod-deklarerad och läsande i m-1

Federation System Integration

F14.02
Planned

> **Greenfield-not (D-PUBAPI `a95566cc.m-6`, 2026-09) — TRUPPINLÄMNINGEN är byggd.**

How it works
  • F14.02.01 Shipped

    Data exchange with existing national federation systems — FederationIntegrationConfig CRUD, lifecycle (draft→active→paused→decommissioned), field mapping, sync state

    ✅ PL-F1402a
  • F14.02.02 Shipped

    File import service (CSV, XML, fixed-width) for legacy data — greenfield: /v1/federation/import-formats (receptet, validerat VID sparandet), POST /v1/federation/imports (RÅA bytes, mätt sha256/mime/size_bytes), :validate (torrkörningen som ett VERB) och :run (skrivpasset bakom fyra villkor). Legacy-radens POST /parse finns INTE: en parsning utan jobbrad lämnar inget spår efter sig

    byggt av D-PUBAPI m-9 (a95566cc-serien, federations-/legacy-importen)
  • F14.02.03 Shipped

    FIPJP data submission format support — FipjpSubmission CRUD, canonical envelope, payload validation per type, lifecycle (draft→submitted→accepted/rejected)

    ✅ PL-F1402a
  • F14.02.04 Shipped

    Continental confederation data exchange — ContinentalExchangeSession CRUD, lifecycle (initiated→in_progress→completed/failed/cancelled), participant tracking

    ✅ PL-F1402a
  • F14.02.05 Shipped

    Bi-directional sync for federations with existing systems — BidirectionalSyncSession CRUD, lifecycle (pending→pulling→pushing→completed/resolving_conflicts), conflict detection/resolution, per-direction statistics

    ✅ PL-F1402b
  • F14.02.06 Shipped

    Migration tools for legacy system data import — MigrationJob CRUD, lifecycle (draft→validating→validated→running→completed), batch processing, dry-run, rollback

    ✅ PL-F1402b
  • F14.02.07 Shipped

    Import validation and error reporting — greenfield: regelmotorn med de fem regeltyperna (required → type → format → range → uniqueness, stannar vid första felet per fält), rapporten som AGGREGAT + sample på jobbets detalj, felmängden …/errors (serverfiltrerad, cursor över hela sorteringen) och …/errors.csv (UTF-8 med BOM, åtta kolumner)

    byggt av D-PUBAPI m-9 (a95566cc-serien, federations-/legacy-importen)

Webhooks & Events

F14.03
Shipped
How it works
  • F14.03.01 Shipped

    Webhook configuration (outbound) — prenumerations-CRUD på POST /v1/webhooks (förbundet) och POST /v1/developer/webhooks (utvecklaren), :pause/:resume/:enable

    byggt av a95566cc.m-3
  • F14.03.02 Shipped

    Event types — competition.created/completed, result.published, license.issued/transferred, ranking.updated, sanction.created som SLUTEN kod-katalog (api/internal/webhook/catalog.go), serverad av GET /v1/webhooks/event-types

    byggt av a95566cc.m-3
  • F14.03.03 Planned

    ~~Retry med exponential backoff (max 5 försök, 10s×n²)~~ — LEGACY-formeln gäller inte. Den byggda trappan är F14.03.09:s: max 8 försök, bas 30 s, kapad vid 1 h. Bokfört val (webhook.MaxAttempts/BaseDelay med källan vid raden)

    LEGACY — ersatt av F14.03.09
  • F14.03.04 Shipped

    HMAC-SHA256-signering + :rotate-secret med 24 h överlappande dubbelsignering; hemligheten FÖRSEGLAD i databasen och läsbar exakt en gång

    byggt av a95566cc.m-3
  • F14.03.05 Shipped

    Petanque-specifik händelsekatalog (7 prenumererbara typer + den syntetiska test.ping)

    byggt av a95566cc.m-3
  • F14.03.06 Shipped

    Delivery log per prenumeration + :test-endpoint (5/min) + manuell :replay/:replay-dlq; KPI-summan på GET /v1/webhooks/deliveries/summary

    byggt av a95566cc.m-3

Third-Party Integrations

F14.04
Planned
How it works
  • F14.04.01 Shipped

    Payment gateway integration (Stripe, PayPal, Swish, iDEAL, etc.) — PaymentGatewayIntegration CRUD, lifecycle (draft→active→paused→decommissioned), key-vault credential refs, multi-currency, sandbox mode, usage tracking, validation

    ✅ PL-F1404a
  • F14.04.02 Shipped

    Calendar integration (Google Calendar, Outlook, iCal) — CalendarIntegration CRUD, lifecycle, OAuth/API-key refs, sync direction (push/pull/bidirectional), sync state tracking, event type filtering

    ✅ PL-F1404a
  • F14.04.03 Shipped

    Social media API integration (Facebook, Instagram, X) — SocialMediaIntegration CRUD, lifecycle, OAuth refs, page/account management, publish/analytics/moderation capabilities, auto-publish events

    ✅ PL-F1404a
  • F14.04.04 Shipped

    Video streaming platform integration (YouTube, Twitch) — StreamingIntegration CRUD, lifecycle, API/stream-key refs, channel management, RTMP URL, DVR/chat/auto-record config

    ✅ PL-F1404a
  • F14.04.05 Shipped

    Mapping/geolocation services (Google Maps, Mapbox) — MappingIntegration CRUD, lifecycle, API-key refs, geocoding/directions/static-maps/places-search toggles, domain allowlist, usage budget

    ✅ PL-F1404a
  • F14.04.06 Shipped

    WADA/ADAMS integration for anti-doping — WadaAdamsIntegration CRUD, lifecycle (draft→active→paused→decommissioned), ADAMS API/signing-key refs, organization/sport codes, athlete pool management, whereabouts sync, TUE management, test result tracking, notification relay

    ✅ PL-F1404b
  • F14.04.07 Shipped

    Insurance provider API integration — InsuranceIntegration CRUD, lifecycle, API/OAuth credential refs, broker/policy group IDs, coverage types, auto-enrollment, claims submission, premium calculation, certificate generation, sandbox mode

    ✅ PL-F1404b
  • F14.04.08 Shipped

    Government sports registry integration (per country) — GovSportsRegistryIntegration CRUD, lifecycle, API/signing-certificate refs, federation code, country code (auto-uppercased), membership reporting, grant applications, facility registration, event reporting, compliance tracking, reporting schedule

    ✅ PL-F1404b
  • F14.04.09 Shipped

    Accounting software integration (Fortnox, Xero, QuickBooks) — AccountingIntegration CRUD, lifecycle, OAuth/API-key refs, company ID, fiscal year config, sync direction (push/pull/bidirectional), chart of accounts mapping, invoice/payment/expense sync, VAT reporting, sandbox mode

    ✅ PL-F1404b

Data Export & Reporting

F14.05
Shipped

> **Raderna nedan beskriver det RIVNA PL-F1405-systemet.** Bulk-exporten är ombyggd rent i

How it works
  • F14.05.01 Shipped

    Bulk data export (CSV, JSON, Excel) — ExportJob CRUD, CSV/JSON/Excel format, configurable filters & columns, download lifecycle

    ✅ a95566cc.m-10 — byggd rent i Go/Postgres; se F14.00.12 (raden beskriver det RIVNA PL-F1405-systemet)
  • F14.05.02 Shipped

    Scheduled report generation and delivery — ScheduledExportJob CRUD, 6 frekvenser, pause/resume/trigger, webhook + e-post-leverans

    ✅ a95566cc.m-10 — se F14.00.14; bokförd avvikelse: kanalen är en PRENUMERATION, aldrig en URL i schemat, och brevet bär LÄNKEN, aldrig en bilaga
  • F14.05.03 Shipped

    Custom export templates — ExportTemplate CRUD, kolumnmappning med transform, delad/personlig, delimiter/encoding-konfiguration

    ✅ a95566cc.m-10 — se F14.00.13
  • F14.05.04 Planned

    Competition result export (federation-specific formats) — CompetitionExportJob, SBP CSV, FFPJP XML, DPV CSV, FIPJP JSON, generic CSV

    ⊘ delvis a95566cc.m-10 — fipjp_json (husets EGET petanque-life-v1-kuvert) och generic_csv (mallstyrd) är byggda (F14.00.16); sbp_csv · ffpjp_xml · dpv_csv byggs INTE: mottagarnas filscheman är okända i huset, och ett påhittat schema importeras TYST hos mottagaren. De står SYNLIGT i katalogen med sitt skäl och en väg som finns (422 competition_format_unavailable + use_instead: generic_csv)
  • F14.05.05 Shipped

    GDPR data portability export — GdprPortabilityExport, Art. 20, JSON/CSV, 48h-utgång, dubblettskydd, nedladdningsspårning

    ✅ PL-F1405
  • F14.05.06 Planned

    Open data feeds (public statistics, rankings) — OpenDataFeed CRUD, JSON/CSV/RSS/Atom, slug-baserad åtkomst, caching, accessräknare

    ⊘ ägarbeslut — de publika, oautentiserade läsytorna (rankings, kalender, resultat) och D-COMM:s syndikeringsflöden ÄR husets öppna data (visionens scope-tillägg 2026-07-09: *»open-data har redan ägare«*). En förvaltningsyta för förbundets EGNA flöden är ett beslut, inte en glömd flik; fliken *Öppna data* på /dataexport står ⊘ med den ägaren

Embedding & Widgets

F14.06
Shipped

> **Raderna nedan beskriver det RIVNA PL-F1406-systemet.** De inbäddningsbara widgetarna är

How it works
  • F14.06.01 Shipped

    Embeddable results widget for federation/club websites — WidgetConfig (type: results), GET /public/widgets/{token} returns published CompetitionResult data with embed-friendly headers, tenant-scoped, configurable columns (balls, club)

    ✅ a95566cc.m-11 — byggd rent i Go/Postgres; se F14.00.19 (raden beskriver det RIVNA PL-F1406-systemet)
  • F14.06.02 Shipped

    Embeddable calendar widget — WidgetConfig (type: calendar), queries CalendarEvent with date range, event type filter, federation/club filter, configurable months ahead

    ✅ a95566cc.m-11 — se F14.00.19/.21; källan är kalenderdomänens EGEN publika söm
  • F14.06.03 Shipped

    Embeddable ranking widget — WidgetConfig (type: ranking), queries RankingEntry by config/dimension/category, show/hide club and rank change columns

    ✅ a95566cc.m-11 — se F14.00.21; bokförd avvikelse: källan är en PUBLIK, aktiv D-RANK-preset (preset_slug), och en icke-publik preset ger ett ärligt tomläge preset_not_public — aldrig en rad
  • F14.06.04 Shipped

    Embeddable live score widget — WidgetConfig (type: live_score), queries Match for in_progress/scheduled matches, mène detail, court assignment, auto-refresh config

    ✅ a95566cc.m-11 — se F14.00.19; auto_refresh_seconds 5—60, pollen armeras EN gång per montering
  • F14.06.05 Shipped

    Widget customization (colors, branding) — WidgetCustomization with full color palette (8 colors), branding (logo, powered-by, custom footer), theme (light/dark/custom), size, locale, border radius, font family, max items, custom CSS

    ✅ a95566cc.m-11 — se F14.00.21; bokförd skärpning: kontrasten DÖMS av servern (WCAG 2.2 AA, 4,5:1) med den uppmätta kvoten i svaret, och custom_css avvisas — aldrig strippas tyst
  • F14.06.06 Shipped

    Widget embed code generator — POST /widgets/{id}/embed-code and GET /public/widgets/{token}/embed-code, generates iframe snippet (sandbox, lazy-load, referrerpolicy), JavaScript snippet, and direct URL with configurable dimensions

    ✅ a95566cc.m-11 — se F14.00.21; bokförd avvikelse: generatorn är GET /v1/widgets/{id}/embed-code (en LÄSNING, inte en POST) och den publika …/embed-code finns INTE — en anonym yta ska inte generera inbäddningskod åt någon annans widget

Stripe Deep Integration

F14.07
Planned
How it works
  • F14.07.01 Shipped

    Stripe Payment Intents — StripePaymentIntent-samling tenant-scopad med stripe_payment_intent_id/stripe_client_secret/invoice_id/payment_id/amount/currency/status (requires_payment_method/requires_confirmation/requires_action/processing/succeeded/canceled/requires_capture)/payment_method_types/capture_method (automatic/manual)/metadata (StripePaymentIntentMetadata invoice_id/debtor_id/debtor_type/fee_category/season_id/custom)/connected_account_id/application_fee_amount/requires_action/description/stripe_customer_id; CRUD /stripe/payment-intents/ med filtrering status/invoice_id, confirm/capture/cancel/sync-endpoints

    ✅ PL-F1407
  • F14.07.02 Shipped

    Stripe Connect — StripeTenantConnectAccount-samling tenant-scopad med stripe_account_id/account_type (standard/express/custom)/status (pending/onboarding/active/restricted/disabled)/entity_type (federation/club/org_node)/entity_id/country/default_currency/display_name/onboarding (StripeConnectOnboarding requirements_due/payouts_enabled/charges_enabled/details_submitted)/platform_fee_percent; CRUD /stripe/connect/ med filtrering status/entity_type, account-link/refresh/disable-endpoints

    ✅ PL-F1407
  • F14.07.03 Shipped

    Stripe Webhooks — StripeWebhookEvent-samling tenant-scopad med stripe_event_id/event_type/status (received/verified/failed_verification/processed/processing_failed)/signature_valid/idempotency_key/payload/processing_error; POST /stripe/webhooks/ med signaturverifiering mot STRIPE_WEBHOOK_SECRET, idempotens-kontroll, dispatch till handlers (payment_intent.succeeded/failed/canceled/requires_action, charge.refunded, refund.updated, account.updated); GET /stripe/webhooks/events för audit-loggning

    ✅ PL-F1407
  • F14.07.04 Shipped

    Stripe SCA / 3D Secure — StripeScaChallenge-samling tenant-scopad med stripe_payment_intent_id/status (not_required/required/initiated/succeeded/failed)/three_ds_version/authentication_flow (challenge/frictionless)/failure_reason/initiated_at/completed_at; CRUD /stripe/sca/, POST /stripe/sca/{stripe_pi_id}/complete med success/failure_reason

    ✅ PL-F1407
  • F14.07.05 Shipped

    Stripe Refunds — StripeRefund-samling tenant-scopad med stripe_refund_id/stripe_payment_intent_id/invoice_id/refund_type (full/partial)/amount/currency/status (pending/succeeded/failed/canceled/requires_action)/reason (duplicate/fraudulent/requested_by_customer)/description; CRUD /stripe/refunds/ med filtrering status/invoice_id/payment_intent_id, sync-endpoint

    ✅ PL-F1407
  • F14.07.06 Shipped

    Stripe Tax — StripeTaxConfig-samling tenant-scopad med country/tax_behavior (inclusive/exclusive)/tax_code/tax_id/tax_id_type/automatic_tax_enabled/tax_rates[StripeTaxRate display_name/percentage/inclusive/country/tax_type/stripe_tax_rate_id]/tax_registrations[]/head_office_address/status (active/inactive/deleted); CRUD /stripe/tax/configs, registrations/sync-rates/calculate-endpoints med per-tenant momsberäkning (SE 25% exclusive, FR 20% inclusive, DE 19% exclusive)

    ✅ PL-F1407

PayPal Deep Integration

F14.08
Planned
How it works
  • F14.08.01 Shipped

    PayPal Checkout — PayPalOrder-samling tenant-scopad med paypal_order_id/intent (capture/authorize)/status (created/saved/approved/voided/completed/payer_action_required)/invoice_id/payment_id/amount/currency/purchase_units[PayPalPurchaseUnit]/payer_email/payer_id/capture_id/authorization_id/approval_url/metadata (PayPalOrderMetadata invoice_id/debtor_id/debtor_type/fee_category/season_id/custom)/brand_name/sandbox/express_profile_id; CRUD /paypal/orders/ med filtrering status/invoice_id/payer_id, capture/void/sync-endpoints

    ✅ PL-F1408
  • F14.08.02 Shipped

    PayPal IPN/Webhooks — PayPalWebhookEvent-samling tenant-scopad med paypal_event_id/event_type/resource_type/status (received/verified/failed_verification/processed/processing_failed)/signature_valid/idempotency_key/related_resource_id/related_order_id/webhook_id/processing_error; POST /paypal/webhooks/ med signaturverifiering via PayPal Notifications API, idempotens-kontroll, dispatch till handlers (CHECKOUT.ORDER.APPROVED/COMPLETED/DECLINED, PAYMENT.CAPTURE.COMPLETED/DENIED/REFUNDED/REVERSED/PENDING); GET /paypal/webhooks/events för audit-loggning

    ✅ PL-F1408
  • F14.08.03 Shipped

    PayPal Refunds — PayPalRefund-samling tenant-scopad med paypal_refund_id/paypal_capture_id/paypal_order_id/order_doc_id/invoice_id/refund_type (full/partial)/amount/currency/status (pending/completed/failed/cancelled)/reason/note_to_payer/seller_payable_breakdown; CRUD /paypal/refunds/ med filtrering status/capture_id/order_id/invoice_id, sync-endpoint

    ✅ PL-F1408
  • F14.08.04 Shipped

    PayPal Express för one-click — PayPalExpressProfile-samling tenant-scopad med user_id/paypal_payer_id/payer_email/payment_token (vault token)/consent_status (pending/active/revoked/expired)/display_name/preferred/last_used_at; CRUD /paypal/express/profiles med activate/revoke/set-preferred-endpoints, integration med PayPal Vault API för sparade betalningskällor

    ✅ PL-F1408

Local Payment Methods

F14.09
Planned
How it works
  • F14.09.01 Shipped

    Swish QR-betalningar (Sverige) — SwishPaymentRequest-samling tenant-scopad med swish_instruction_uuid indexed/payee_alias/payer_alias/amount Decimal/currency SEK/message (max 50)/status (created/paid/declined/error/cancelled)/qr_code_data base64/qr_format/callback_url/invoice_id/payment_id/payment_reference/payer_payment_reference/error_code/error_message/paid_at/metadata (SwishPaymentMetadata invoice_id/debtor_id/debtor_type/fee_category/season_id/custom); CRUD /swish/payments/ med filtrering status/invoice_id, cancel/sync-endpoints; valutavalidering (enbart SEK); QR-kodgenerering vid skapande

    ✅ PL-F1409a
  • F14.09.02 Shipped

    Swish webhook callbacks — SwishCallbackEvent-samling tenant-scopad med swish_instruction_uuid indexed/event_status (PAID/DECLINED/ERROR/CANCELLED)/callback_identifier indexed för idempotens/status (received/verified/processed/processing_failed)/payload_summary saniterad/processing_error/payer_alias/payment_reference/amount/date_paid; POST /swish/callbacks/ tar emot Swish-callbacks med idempotens-kontroll, dispatch till handlers som uppdaterar SwishPaymentRequest och skapar Payment+Receipt vid PAID; GET /swish/callbacks/events för audit-loggning

    ✅ PL-F1409a
  • F14.09.03 Shipped

    iDEAL (Nederländerna) — IDealPayment-samling tenant-scopad med ideal_transaction_id indexed/provider (stripe/mollie)/provider_payment_id/bank_bic/bank_name/amount Decimal/currency EUR/status (created/pending/succeeded/failed/expired/canceled)/invoice_id/payment_id/redirect_url/return_url/webhook_url/description/metadata (IDealPaymentMetadata)/succeeded_at/failed_at/error_code/error_message; CRUD /ideal/payments/ med filtrering status/invoice_id, sync-endpoint, webhook-endpoint; valutavalidering (enbart EUR); skapar Payment+Receipt vid succeeded

    ✅ PL-F1409a
  • F14.09.04 Shipped

    Bancontact (Belgien) — BancontactPayment-samling tenant-scopad med bancontact_transaction_id indexed/provider (stripe/mollie)/provider_payment_id/cardholder_name/preferred_language (nl/fr/de/en)/amount Decimal/currency EUR/status (created/pending/authorized/succeeded/failed/expired/canceled)/invoice_id/payment_id/redirect_url/return_url/description/metadata (BancontactPaymentMetadata)/succeeded_at/failed_at/error_code/error_message; CRUD /bancontact/payments/ med filtrering status/invoice_id, sync-endpoint, webhook-endpoint; valutavalidering (enbart EUR); skapar Payment+Receipt vid succeeded

    ✅ PL-F1409a
  • F14.09.05 Shipped

    Bizum (Spanien) — BizumPayment-samling tenant-scopad med bizum_transaction_id indexed/provider (stripe/redsys)/provider_payment_id/payer_phone/amount Decimal/currency EUR/status (created/pending/paid/failed/cancelled/timeout)/qr_code_data base64/qr_format/invoice_id/payment_id/redirect_url/return_url/description/metadata (BizumPaymentMetadata)/paid_at/failed_at/error_code/error_message; CRUD /bizum/payments/ med filtrering status/invoice_id, sync-endpoint, webhook-endpoint; valutavalidering (enbart EUR); QR-kodgenerering; skapar Payment+Receipt vid paid

    ✅ PL-F1409b
  • F14.09.06 Shipped

    SEPA Direct Debit (EUR-länder) — SepaDirectDebitPayment-samling tenant-scopad med sepa_transaction_id indexed/provider (stripe/mollie)/provider_payment_id/mandate_id indexed/mandate_status (pending/active/revoked/expired)/debtor_iban/debtor_name/creditor_id/amount Decimal/currency EUR/status (pending/authorized/processing/succeeded/failed/reversed/cancelled)/sequence_type (OOFF/RCUR/FRST/FNAL)/invoice_id/payment_id/description (max 140)/return_url/redirect_url/return_code (R01-R99)/metadata (SepaDirectDebitMetadata)/succeeded_at/failed_at/error_code/error_message; CRUD /sepa-direct-debit/payments/ med filtrering status/invoice_id/mandate_id, sync-endpoint, webhook-endpoint; mandathantering; SEPA-returkoder; valutavalidering (enbart EUR); skapar Payment+Receipt vid succeeded

    ✅ PL-F1409b
  • F14.09.07 Shipped

    Klarna BNPL (EU) — KlarnaPayment-samling tenant-scopad med klarna_order_id indexed/provider (klarna/stripe)/provider_payment_id/klarna_session_id/purchase_country (18 länder)/purchase_language/amount Decimal/currency (EUR/SEK/NOK/DKK/GBP/USD/CHF/PLN/CZK)/status (created/authorized/captured/failed/cancelled/expired)/payment_type (pay_later/pay_over_time/direct_debit/direct_bank_transfer)/installment_count (2–36)/invoice_id/payment_id/redirect_url/return_url/description/customer_email/metadata (KlarnaPaymentMetadata)/authorized_at/captured_at/failed_at/error_code/error_message; CRUD /klarna/payments/ med filtrering status/invoice_id/payment_type, capture-endpoint, sync-endpoint, webhook-endpoint; lands- och valutavalidering; tvåstegsflöde (authorize→capture); skapar Payment+Receipt vid captured

    ✅ PL-F1409b

Bokföringsintegrationer

F14.10
Planned
How it works
  • F14.10.01 Shipped

    Fortnox API (Sverige) — AccountingProviderConfig (provider=fortnox) med FortnoxConfig (client_id_ref/client_secret_ref/access_token_ref/refresh_token_ref/company_id/default_account_plan BAS2024/auto_create_customers/auto_bookkeep_invoices); AccountingSyncJob för batch-push av fakturor/betalningar/kunder till Fortnox API med idempotent AccountingSyncMapping, hashbaserad ändringsdetektering, dry-run-stöd; AccountingWebhookEvent med HMAC-SHA256-signaturverifiering för Fortnox webhooks

    ✅ PL-F1410
  • F14.10.02 Shipped

    Xero API (internationell) — AccountingProviderConfig (provider=xero) med XeroConfig (client_id_ref/client_secret_ref/access_token_ref/refresh_token_ref/xero_tenant_id/tracking_category_id/auto_create_contacts/branding_theme_id); faktura/betalning/kontakt-sync till Xero REST API, OAuth2-tokenhantering, webhook-mottagning med idempotens

    ✅ PL-F1410
  • F14.10.03 Shipped

    Visma eEkonomi (Sverige) — AccountingProviderConfig (provider=visma) med VismaConfig (client_id_ref/client_secret_ref/access_token_ref/refresh_token_ref/company_id/fiscal_year_id/auto_create_customers); faktura/betalning/kund-sync till Visma eAccountingAPI

    ✅ PL-F1410
  • F14.10.04 Shipped

    QuickBooks (US/UK) — AccountingProviderConfig (provider=quickbooks) med QuickBooksConfig (client_id_ref/client_secret_ref/access_token_ref/refresh_token_ref/realm_id/minor_version/sandbox_mode/auto_create_customers); faktura/betalning/kund-sync till QuickBooks Online API

    ✅ PL-F1410
  • F14.10.05 Shipped

    SIE4-fil-export (svensk standard) — SIE4Export med livscykel (pending→generating→completed/failed), #FLAGGA 0/#PROGRAM/#FORMAT PC8/#GEN/#SIETYP 4/#FNR/#FNAMN/#RAR/#KONTO/#IB/#UB/#VER/#TRANS; konfigurerbar räkenskapsår, datumfilter, öppnings-/stängningssaldon, periodbalans; POST /accounting/sie4-exports/ genererar och returnerar metadata, GET .../download returnerar filinnehåll

    ✅ PL-F1410
  • F14.10.06 Shipped

    Per-tenant kontoplansmappning — ProviderAccountMapping med livscykel (draft→active→archived), AccountMappingRule (internal_category/internal_account_number/provider_account_code/provider_account_name/vat_code/cost_centre), validering (dubbletter, numerisk kontroll för Fortnox), BAS2024-standardmappningar för 8 kategorier (licensavgifter/tävlingsavgifter/klubbavgifter/medlemsavgifter/sponsorintäkter/bidrag/resekostnader/förbrukningsinventarier), sync-to-provider

    ✅ PL-F1410

Kart- och geokod-integrationer

F14.11
Planned
How it works
  • F14.11.01 Shipped

    Google Maps embed för venue-sidor — MapEmbedConfig-samling tenant-scopad med venue_id/embed_type (google_maps_embed/google_maps_static/mapbox_gl/mapbox_static/openstreetmap)/style (MapEmbedStyle zoom/map_type/width/height/show_marker/marker_label/custom_style_url)/mapping_integration_id/show_nearby_clubs/nearby_radius_km/show_directions_link/show_street_view/custom_marker_icon_url; GET /geo/venues/{venue_id}/embed genererar embed-URL med adress, koordinater och directions-länk; GET /geo/venues/{venue_id}/embed-config + PATCH för konfigurationshantering

    ✅ PL-F1411
  • F14.11.02 Shipped

    Mapbox alternativ med vector tiles — Mapbox GL JS-konfiguration med style_url (mapbox://styles/mapbox/streets-v12), center, zoom, markers; generate_mapbox_embed_config() returnerar fullständig klientkonfiguration; generate_mapbox_static_url() för statiska kartbilder via Mapbox Static Images API; stöd för OpenStreetMap som gratis fallback utan API-nyckel

    ✅ PL-F1411
  • F14.11.03 Shipped

    Geocoding för venue-adresser — GeocodingResult-samling tenant-scopad med direction (forward/reverse)/provider (google_maps/mapbox/openstreetmap/here)/input_address/coordinates (GeoCoordinates lat/lng)/address (GeocodedAddress formatted_address/street/city/postal_code/country/country_code/region)/confidence 0.0–1.0/cached_at/expires_at/mapping_integration_id; POST /geo/geocode med cachning, provider-val och integration mot MappingIntegration

    ✅ PL-F1411
  • F14.11.04 Shipped

    Reverse geocoding för spelarposition — POST /geo/reverse-geocode med lat/lng input, cachning med ~100m bounding-box matchning, returnerar GeocodedAddress med strukturerad adress; stöd för Google Maps och Mapbox providers; tenant-scopad cachning med TTL

    ✅ PL-F1411
  • F14.11.05 Shipped

    Route-beräkning till tävlingsvenues — RouteCalculation-samling tenant-scopad med provider/travel_mode (driving/walking/cycling/transit)/origin (GeoCoordinates)/destination (GeoCoordinates)/venue_id/status (ok/not_found/zero_results/error)/summary (RouteSummary total_distance_m/total_duration_s/total_distance_km/total_duration_min)/steps[RouteStep]/polyline/cached_at/expires_at; POST /geo/route med haversine-baserad uppskattning, cachning med ~500m tolerans

    ✅ PL-F1411
  • F14.11.06 Shipped

    Klubb-finder med radius-sökning — GET /public/clubs/nearby publik endpoint utan autentisering med lat/lng/radius_km (0.5–500)/level/facilities (kommaseparerad)/skip/limit (1–100); bounding-box pre-filter på venue-koordinater sedan exakt haversine-avstånd; resultat sorterade efter avstånd (närmast först); ClubFinderResult med club_id/club_name/club_code/distance_km/location/address/city/facilities/level/venue_id/venue_name; cross-tenant som standard, tenant-scopad med valfri tenant_id-parameter

    ✅ PL-F1411

Anti-doping system-integration

F14.12
Planned
How it works
  • F14.12.01 Shipped

    WADA ADAMS export — AdamsIntegrationConfig-samling tenant-scopad med display_name/credentials (AdamsCredentialRefs api_key_ref/api_secret_ref/signing_key_ref/endpoint_url)/organisation_code/sport_code/enable_athlete_export/enable_whereabouts_sync/enable_test_result_import/enable_tue_sync/registered_testing_pool_ids/testing_pool_ids/sandbox_mode; CRUD /anti-doping/adams-configs/ med enable/disable-endpoints; AdamsExportJob-samling tenant-scopad med config_id/entity_type (athlete_profile/whereabouts/test_result/tue_application/sanction)/status (pending/exporting/completed/completed_with_errors/failed/cancelled)/dry_run/statistics (AdamsExportStatistics total/succeeded/failed/skipped)/results[AdamsExportResult]; CRUD /anti-doping/export-jobs/ med run/cancel-endpoints; hashbaserad ändringsdetektering för idempotent export

    ✅ PL-F1412
  • F14.12.02 Shipped

    Whereabouts upload — WhereaboutsRecord-samling tenant-scopad med player_id/adams_athlete_id/quarter_year/quarter_number/entries[WhereaboutsEntry slot_date/slot_type (overnight/training/competition/other/sixty_minute)/start_time/end_time/address/city/country_code]/status (draft/submitted/confirmed/rejected/expired/cancelled)/submitted_at/confirmed_at/rejected_reason/adams_submission_id/sync_hash; CRUD /anti-doping/whereabouts/ med submit/confirm/reject-livscykel; tidsvalidering HH:MM, auto-uppercase country_code

    ✅ PL-F1412
  • F14.12.03 Shipped

    Test result import — TestResultImport-samling tenant-scopad med player_id/adams_test_id/source_provider (NadoProvider)/source_reference/detail (TestResultDetail sample_code/sample_type/collection_date/lab_name/lab_code/substances_detected/result_code/b_sample_requested/b_sample_result)/test_type/competition_id/status (received/validated/processed/failed/rejected)/linked_doping_test_id/idempotency_key; CRUD /anti-doping/test-results/ med validate/process-livscykel; process skapar DopingTest-record med korrekt resultatmappning (negative/adverse→positive/atypical/pending); idempotens via idempotency_key

    ✅ PL-F1412
  • F14.12.04 Shipped

    TUE application sync — TueSyncRecord-samling tenant-scopad med tue_application_id/player_id/direction (push/pull)/status (pending/syncing/synced/failed/conflict)/adams_tue_id/adams_status/sync_hash/conflict_field/local_value/remote_value; CRUD /anti-doping/tue-syncs/ med execute-endpoint; push exporterar lokal TUE till ADAMS, pull hämtar ADAMS-beslut och uppdaterar lokalt; konfliktdetektering

    ✅ PL-F1412
  • F14.12.05 Shipped

    Per-nation anti-doping-byrå-koppling — NadoConfig-samling tenant-scopad med provider (rf_antidoping/afld/nada_de/ukad/usada/nadof/nada_at/wada/other)/country_code (auto-uppercase)/contact (NadoContactInfo organisation_name/website/email/phone/address/dco_contact_email/reporting_portal_url)/has_api/api_key_ref/api_endpoint_url/code_version/whereabouts_required/tue_committee_email/notify_on_adverse_finding/notify_on_whereabouts_failure; CRUD /anti-doping/nado-configs/ med enable/disable-endpoints; GET /defaults returnerar standardkonfigurationer för SE/FR/DE; AntiDopingWebhookEvent-samling med HMAC-SHA256-signaturverifiering per provider, idempotens-kontroll, dispatch till handlers (test_result.*/tue.*/whereabouts.*); POST /anti-doping/webhooks/{provider} + GET /anti-doping/webhooks/events audit-logg

    ✅ PL-F1412

Kommunikationsintegrationer

F14.13
Planned
How it works
  • F14.13.01 Shipped

    SendGrid transactional email — SendGridConfig-samling tenant-scopad med display_name/credentials (SendGridCredentialRefs api_key_ref/webhook_signing_key_ref)/from_email/from_name/reply_to_email/enable_open_tracking/enable_click_tracking/enable_unsubscribe_tracking/ip_pool_name/sandbox_mode/usage (UsageMetrics); CRUD /communication/sendgrid/configs/ med livscykel (draft→active→paused→error→decommissioned); EmailMessage-samling med config_id/provider/to[EmailRecipient]/subject/template_id/template_data/body_text/body_html/status/engagement (EmailEngagementMetrics)/bounce_type/idempotency_key; POST /communication/sendgrid/emails/ skickar via SendGrid v3 API

    ✅ PL-F1413
  • F14.13.02 Shipped

    ELKS SMS för svenska nummer — ElksConfig-samling tenant-scopad med display_name/credentials (ElksCredentialRefs api_username_ref/api_password_ref)/sender_id (max 11 tecken GSM)/default_country_code (+46)/dlr_callback_url/usage; SmsMessage-samling med direction (outbound/inbound)/from_number/to (SmsRecipient)/body (max 1600)/segments/cost_amount/cost_currency SEK/idempotency_key; POST /communication/elks/sms/ skickar via 46elks API

    ✅ PL-F1413
  • F14.13.03 Shipped

    Firebase Cloud Messaging för push — FcmConfig-samling tenant-scopad med credentials (FcmCredentialRefs service_account_json_ref/project_id)/default_ttl_seconds/default_priority/usage; PushNotification-samling med target (PushTarget device_token/platform/player_id)/topic/title/body/image_url/data/priority/ttl_seconds/collapse_key/badge_count/sound/click_action/idempotency_key; POST /communication/fcm/push/ skickar via FCM v1 API

    ✅ PL-F1413
  • F14.13.04 Shipped

    Twilio SMS som international fallback — TwilioConfig-samling tenant-scopad med credentials (TwilioCredentialRefs account_sid_ref/auth_token_ref/messaging_service_sid)/from_number E.164/status_callback_url/supported_countries[]/usage; SmsMessage (delad med ELKS) med provider=twilio; POST /communication/twilio/sms/ skickar via Twilio Messages API

    ✅ PL-F1413
  • F14.13.05 Shipped

    Mailgun som backup till SendGrid — MailgunConfig-samling tenant-scopad med credentials (MailgunCredentialRefs api_key_ref/webhook_signing_key_ref/domain/region eu

    us)/from_email/from_name/enable_tracking/enable_click_tracking/test_mode/usage; EmailMessage (delad med SendGrid) med provider=mailgun; POST /communication/mailgun/emails/ skickar via Mailgun v3 API | ✅ PL-F1413
  • F14.13.06 Shipped

    WhatsApp Business API för notiser — WhatsAppConfig-samling tenant-scopad med credentials (WhatsAppCredentialRefs access_token_ref/phone_number_id/business_account_id/webhook_verify_token_ref)/display_phone_number/business_name/default_language_code BCP 47/usage; WhatsAppMessage-samling med to (WhatsAppRecipient)/message_type (template/text)/template_name/template_language/template_parameters[]/body_text/media_url/read_at/idempotency_key; POST /communication/whatsapp/messages/template och /text skickar via WhatsApp Cloud API v18.0; CommunicationWebhookEvent med signaturverifiering (HMAC-SHA256/SHA1), idempotens-kontroll, dispatch till email/sms/whatsapp-handlers

    ✅ PL-F1413

Streaming & Video Integrations

F14.14
Planned
How it works
  • F14.14.01 Shipped

    YouTube Live embed — YouTubeLiveEmbed-samling tenant-scopad med name/channel_id/video_id/api_key_ref/privacy (public/unlisted/private)/player_params (YouTubePlayerParams autoplay/mute/controls/loop/modest_branding/rel/fs/cc_load_policy)/embed_width/embed_height/responsive/allowed_domains/competition_id/live_chat_embed/enabled; CRUD /youtube-embeds/ med filtrering enabled/competition_id; GET /{id}/embed genererar embed-URL och iframe-HTML med responsiv 16:9 container; GET /{id}/validate validerar konfiguration (video_id/channel_id-format); live chat iframe-URL vid live_chat_embed=true

    ✅ PL-F1414
  • F14.14.02 Shipped

    Twitch embed — TwitchEmbed-samling tenant-scopad med name/channel_name/video_id/collection_id/layout (video/video_with_chat)/player_params (TwitchPlayerParams autoplay/muted/allow_fullscreen/time)/parent_domains (obligatorisk)/embed_width/embed_height/responsive/competition_id/theme (dark/light)/enabled; CRUD /twitch-embeds/ med filtrering enabled/competition_id; GET /{id}/embed genererar embed-URL med parent-domain-säkerhet; GET /{id}/validate validerar channel_name-format och parent_domains; chat-embed-URL vid layout=video_with_chat

    ✅ PL-F1414
  • F14.14.03 Shipped

    RTMP relay-konfiguration — RtmpRelayConfig-samling tenant-scopad med name/status (draft/active/paused/error/decommissioned)/ingest_protocol (rtmp/rtmps/srt)/ingest_url/ingest_key_ref/destinations[RtmpRelayDestination name/platform/rtmp_url/stream_key_ref/enabled/bitrate_kbps/resolution] (max 5)/max_bitrate_kbps/transcoding_enabled/recording_enabled/competition_id; CRUD /rtmp-relays/ med filtrering status/competition_id; livscykel activate/pause/decommission med statusvakter (409); URL-validering (rtmp://rtmps://srt://)

    ✅ PL-F1414
  • F14.14.04 Shipped

    Stream metadata API — StreamMetadata-samling tenant-scopad med title/stream_type (live/vod/clip)/status (scheduled/live/ended/processing/available/error/archived)/platform/platform_stream_id/platform_url/thumbnail_url/embed_url/competition_id/match_id/language/tags[]/scheduled_start_at/actual_start_at/ended_at/duration_seconds/viewer_stats (StreamViewerStats peak_concurrent/total_views/average_watch_time_s/unique_viewers)/is_featured/is_public; CRUD /stream-metadata/ med filtrering stream_type/status/platform/competition_id/is_featured/is_public; livscykel start/end/available/archive med statusvakter; viewer-stats endpoint med peak_concurrent max-beräkning

    ✅ PL-F1414
  • F14.14.05 Shipped

    Vimeo för on-demand replay — VimeoReplay-samling tenant-scopad med name/status (draft/uploading/transcoding/available/error/archived)/vimeo_video_id/vimeo_uri/api_token_ref/privacy (anybody/nobody/password/unlisted/disable)/password_ref/embed_responsive/embed_width/embed_height/embed_autoplay/embed_loop/embed_title/embed_byline/embed_portrait/embed_color/allowed_domains/competition_id/match_id/duration_seconds/file_size_bytes/download_enabled; CRUD /vimeo-replays/ med filtrering status/competition_id; livscykel available/archive; GET /{id}/embed genererar Vimeo embed-URL med parametrar; GET /{id}/validate kontrollerar video_id/api_token/password

    ✅ PL-F1414
  • F14.14.06 Shipped

    Cloudflare Stream för egen leverans — CloudflareStreamConfig-samling tenant-scopad med name/status (draft/ready/live_input_created/connected/disconnected/error/decommissioned)/mode (live/on_demand)/account_id_ref/api_token_ref/cf_stream_id/cf_live_input_id/rtmp_url/rtmp_key_ref/srt_url/webrtc_url/playback_hls_url/playback_dash_url/signed_url_config (SignedUrlConfig signing_key_ref/token_ttl_seconds/require_signed_urls)/allowed_origins[CloudflareStreamAllowedOrigin]/recording_enabled/require_signed_urls/max_duration_seconds/competition_id; CRUD /cloudflare-streams/ med filtrering status/mode/competition_id; livscykel activate/create-live-input/decommission; HMAC-SHA256 signed playback URL-generering med konfigurerbar TTL

    ✅ PL-F1414

DNS, SSL & CDN Integrations

F14.15
Planned

**Plattform-CMS-trafik (`*.web.petanque.life` + custom domains) routas via Caddy reverse proxy** på Azure VM `vm-petanque-proxy` (`20.238.51.13`) — hanterar TLS-termination för obegränsat antal CMS-sajter framför `swa-petanque-web`. On-demand TLS via Let's Encrypt HTTP-01, cert-persistens i Docker-volym `caddy_data`. Cert-utfärdande gateas av `GET /public/domains/cert-allowed?domain=<host>` (plattforms-API:t) som returnerar 200 om hostname matchar aktiv `CmsSite.subdomain`/`CmsSite.domain` eller verifierad `CmsCustomDomain`. Federationer pekar sin egen domän mot CNAME-target `proxy.web.petanque.life`. Se `docs/engineering/architecture/05a-dns-and-tls.md` och `specs/infrastructure/caddy-proxy.md`.

How it works
  • F14.15.01 Shipped

    ACME/Let's Encrypt certificate management — AcmeCertificate-samling tenant-scopad med automatisk certifikatutfärdande och förnyelse; för CMS-trafik: Caddy-baserad on-demand TLS via HTTP-01 challenge på vm-petanque-proxy med cert-persistens i Docker-volym (PL-T232)

    ✅ PL-F1415 + PL-T232
  • F14.15.02 Shipped

    Cloudflare DNS zone management — CloudflareDnsZone-samling tenant-scopad med zone CRUD och DNS-posthantering

    ✅ PL-F1415
  • F14.15.03 Shipped

    Cloudflare DNS record management — CloudflareDnsRecord-samling tenant-scopad med A/AAAA/CNAME/MX/TXT-poster

    ✅ PL-F1415
  • F14.15.04 Shipped

    Domain verification — DomainVerification-samling tenant-scopad med TXT/CNAME-verifieringsmetoder, WildcardCertificate för wildcard-certifikat

    ✅ PL-F1415
  • F14.15.05 Shipped

    Cloudflare Workers för edge computing — CloudflareWorkerDeployment-samling tenant-scopad med worker-konfiguration och deployment-hantering

    ✅ PL-F1415
  • F14.15.06 Shipped

    Caddy reverse proxy för CMS-trafik — vm-petanque-proxy Azure VM (B1s, statisk IP 20.238.51.13) kör Caddy 2.x i Docker; on-demand TLS via Let's Encrypt HTTP-01; cert-cache i volym caddy_data; reverse-proxy med header_up Host {host} till swa-petanque-web; gateas av /public/domains/cert-allowed-endpoint mot abuse; stabilt CNAME-target proxy.web.petanque.life för federationers egna domäner; ersätter Cloudflare for SaaS (PL-T046) som vilande alternativ (PL-T232)

    ✅ PL-T232
  • F14.15.07 Shipped

    Loopia DNS API-integration för auto-provisionering av plattform-subdomäner — services/sys/loopia_dns (XML-RPC mot https://api.loopia.se/RPCSERV) hookas in i POST/PATCH/DELETE /cms/sites/ så A-record <slug>.web.petanque.life → 20.238.51.13 skapas, byts eller tas bort automatiskt vid CmsSite-livscykelhändelser; dns_provisioning_status (pending/active/failed/disabled) + dns_provisioning_error + dns_provisioned_at på CmsSite för observability; POST /cms/sites/{id}/repair-dns för idempotent retry; reserverade slugs (proxy, _acme-challenge, test) blockerade; transient API-fel rullar inte tillbaka CmsSite-creation (PL-T235)

    ✅ PL-T235

Analytics & Tracking Integrations

F14.16
Planned

## F14.01 (additions) — PL-T215

How it works
  • F14.16.01 Shipped

    Plausible analytics (privacy-respecting) — PlausibleConfig-samling tenant-scopad med display_name/credentials (PlausibleCredentialRefs api_key_ref)/site_id/instance_url (cloud eller self-hosted)/enable_custom_events/enable_revenue_tracking/allowed_domains/usage (AnalyticsUsageMetrics); CRUD /analytics/plausible/configs/ med livscykel (draft→active→paused→error→decommissioned); AnalyticsEvent-samling med config_id/provider/event_name/event_properties/user_id/anonymous_id/page_url/referrer/user_agent/idempotency_key; POST /analytics/plausible/events/ skickar via Plausible Events API; GDPR-kompatibel utan cookies

    ✅ PL-F1416
  • F14.16.02 Shipped

    Umami analytics som självhostat alternativ — UmamiConfig-samling tenant-scopad med display_name/credentials (UmamiCredentialRefs api_key_ref/username_ref/password_ref)/instance_url/website_id/share_url/enable_custom_events/track_outbound_links/usage; CRUD /analytics/umami/configs/ med livscykel; POST /analytics/umami/events/ skickar via Umami Collect API; privacy-fokuserad, cookiefri

    ✅ PL-F1416
  • F14.16.03 Shipped

    Google Analytics 4 (opt-in per tenant) — GA4Config-samling tenant-scopad med display_name/credentials (GA4CredentialRefs measurement_id/api_secret_ref/service_account_json_ref)/property_id/data_stream_id/require_cookie_consent (default true)/anonymize_ip/enable_enhanced_measurement/enable_ecommerce/debug_mode/usage; CRUD /analytics/ga4/configs/ med livscykel; POST /analytics/ga4/events/ skickar via GA4 Measurement Protocol med client_id; kräver cookie-samtycke (analytics-kategori) innan spårning aktiveras

    ✅ PL-F1416
  • F14.16.04 Shipped

    Per-tenant cookie consent — CookieConsentConfig-samling tenant-scopad med display_name/status/banner (ConsentBannerConfig position/style/primary_color/background_color/text_color/show_reject_all/show_preferences)/categories (necessary/functional/analytics/marketing med ConsentCategoryConfig enabled/required/default_accepted/display_name/description/cookie_names)/privacy_policy_url/cookie_policy_url/consent_expiry_days (1–730)/geo_targeting_enabled/respect_do_not_track; CRUD /analytics/cookie-consent/configs/ med PATCH-uppdatering; integrerar med befintlig CookieConsentRecord (privacy.py) för individuella samtyckesbeslut

    ✅ PL-F1416
  • F14.16.05 Shipped

    PostHog event tracking integration for product analytics, feature flags, and funnel analysis with per-tenant configuration

    ✅ PL-F1416
  • F14.16.06 Shipped

    API usage analytics aggregation per developer/tier — RateLimitWindow flushes till ApiUsageRecord-buckets; admin /admin/api/usage-vy med stacked area chart per tier, drilldown per utvecklare

    ✅ PL-T215
  • F14.16.07 Shipped

    Per-record provenance metadata — _meta.dataset_version + _meta.provenance_uri + field_provenance på alla data-product-svar för spårning av källdataset och version

    ✅ PL-T215
  • F14.01.10 Shipped

    Developer portal self-service — POST /developer/keys, GET/DELETE /developer/keys/{id}, GET /developer/keys/{id}/usage med 256-bit-key + SHA-256-hash; X-Developer-Id-bootstrap-header för första key-issuance

    ✅ delvis a95566cc.m-1 (nyckel-CRUD, se F14.00.05 — klienten ensureas ur SESSIONEN, X-Developer-Id-bootstrapen finns INTE och kommer inte); …/usage ⊘ a95566cc.m-2, portalens UI ✅ a95566cc.m-7 t-3 (web /developers/nycklar)
  • F14.01.11 Shipped

    Sandbox-tenant provisioning — POST /developer/sandbox med 4 seed-templates (minimal, national_federation, club, competition_in_progress), separat PostgreSQL-databas, 30-dagars auto-expiry, 10× rate-limit

    ✅ a95566cc.m-7 (POST|GET /v1/developer/sandbox, …/templates, …/{id}:extend, …:reset, DELETE …): en RIKTIG tenant (tenant_type='sandbox', server-myntad kod sbx-<16 hex>, land XS) född genom husets ENDA defaults-väg, med de fyra mallarna byggda av de ägande domänernas EGNA sömmar och ett serverat manifest med ärliga omits[]; 30 dagars frist (block om 30, tak 120, varning 7) genom svepet developer_sandbox_expiry_tick; m-1:s ×10-budget genom is_sandbox + X-Petanque-Environment: sandbox. TRE legacy-löften ERSATTA (spec §9b): »separat PostgreSQL-databas« ⇒ tenant-isolation (arkitekturen har EN Postgres) · »raderas 1 dygn efter expiry« ⇒ stängning (klient återkallad + tenant arkiverad; huset har ingen tenant-hard-delete) · 429 vid kvot ⇒ 409 sandbox_quota_exceeded med {tier, limit, used}. Kontraktet: specs/api/endpoints/developer-sandbox.md §Greenfield. Portalens YTA (web /developers/sandlada) är BYGGD i a95566cc.m-7 t-3: mallarna med sina SERVERADE manifest och luckornas ägare cell för cell, beståndet med frist/dagräknare, :extend/:reset/DELETE och serverns 409 sandbox_quota_exceeded renderat VID åtgärden (aldrig en förhandsutgråad knapp). Operatörens motsvarighet är sys-panelen *Sandbox-tenanter* (/utvecklarplattform?flik=utvecklare) — en ren LÄSNING utan en enda mutationsknapp, där mockupens databaskolumn är ersatt av Tenant (§9b D-3) och *Provision sandbox (operator override)* står som ⊘ med skäl och pekar på den väg som FAKTISKT finns (impersonation med samtycke, D-SYS m-5) — §9b D-6
  • F14.01.12 Shipped

    OAuth 2.0 client-credentials grant — POST /v1/oauth/token med scope-baserad authorization (api:read, webhooks:write, data:integrity etc.); 3600s opaque token-livslängd; key-id-blacklist vid revoke

    ✅ a95566cc.m-1 — granten och key-id-blacklisten; tokenen är kortlivad och signerad (bokförd avvikelse mot legacys 3600 s opaka token)
  • F14.01.13 Planned

    Public OpenAPI surface — GET /v1/openapi.json filtrerat till canonical tags (CANONICAL_DOMAINS frozenset i domains.py)

    ⊘ a95566cc.m-2 (GET /public/openapi.json, den filtrerade projektionen)
  • F14.01.14 Planned

    API-versionering policy + middleware — /v{N} URL-prefix, X-API-Version/X-API-Version-Deprecated/Sunset headers, route-aware aliasing (explicit /v1/X-routes passerar genom oförändrade)

    ⊘ a95566cc.m-2 (versionslivscykeln)
  • F14.01.15 Shipped

    Sliding-window rate-limit per client + tier — Redis sorted-set per (client_id, bucket); per-endpoint-buckets (default, webhook_management, data_product_query, oauth_token); fail-open vid Redis-utfall

    ✅ a95566cc.m-1 — per klient/tier, in-memory sliding window per instans (Redis är avvecklad, arkitektur §3)
  • F14.01.16 Planned

    Legacy federation field-mapping — nationsprofilkatalogen GET /v1/federation/import-nation-profiles (SBF · NBoF · FFPJP ifyllda ur legacy-federation-mapping.md; FBP · FIB · FEP available: false med skäl och TOM mappning) + förbundets EGNA recept (/v1/federation/import-formats, mappning per kolumn med sluten transformmängd) och fältmappnings-editorn i admin /dataexport. Legacy-radens tenant.field_mapping_overrides ERSATT: mappningen är en TENANT-ÄGD rad, inte en override i tenant-konfigurationen — profilen KOPIERAS vid sparandet och läses aldrig igen. FIPJP-/CEP-formatet ligger kvar hos truppinlämningen (F14.02.03/.04)

    byggt av D-PUBAPI m-9 (a95566cc-serien, federations-/legacy-importen)
  • F14.03.07 Shipped

    Signed payload v2 — kanonisk "{timestamp}.{råa body-bytes}" HMAC-SHA256 (Stripe-formen), 5 min replay-fönster, headerfamiljen X-Petanque-Signature/-Timestamp/-Event-Id/-Delivery/-Attempt (+ -Replay-Of, -Environment) genom husets ENDA header-writer

    byggt av a95566cc.m-3
  • F14.03.08 Shipped

    Self-service CRUD + debugging — /v1/developer/webhooks*, leveransloggen med per-försök-status, :test, :replay med X-Petanque-Replay-Of

    byggt av a95566cc.m-3
  • F14.03.09 Shipped

    DLQ + auto-disable — 8 försök (backoff bas 30 s, kapad 1 h) ⇒ dlq; prenumerationen auto-avstängs efter 24 h med 100 % fel (disabled_reason='too_many_failures') av webhook_health_sweep, med audit (systemaktör) + in_app-notis. Ingen självläkning — :enable är en människas handling

    byggt av a95566cc.m-3
  • F14.03.10 Shipped

    Sandbox-säker routning — en sandbox-klient når bara PL_WEBHOOK_SANDBOX_TARGET_ALLOWLIST (default webhook.site + loopback i local/test); prövat vid BÅDE registrering (403 webhook_target_not_allowed med allowlisten i detail) och sändning; leveransen bär X-Petanque-Environment: sandbox

    byggt av a95566cc.m-3
  • F14.03.11 Planned

    ed25519-overlay — ed25519:<kid>=<hex> som tillägg till HMAC på integritetstyper (sanction.created); publik nyckel via GET /v1/integrity/public-key (ETag/304, 404 fail-closed) och roterade föregångare i previous[]. ⊘ Kvartalsvis AUTOMATISK rotation är INTE byggd — rotationen är en manuell driftåtgärd, runbooken §2. Ägare: D-PUBAPI (senare milstolpe)

    byggt av a95566cc.m-3 (rotationsautomatiken ⊘)
  • F14.04.10 Shipped

    Insurance risk-feed (aggregerad) — GET /v1/insurance/snapshots/{period} med månads-/kvartalssnapshots; competitions/venues/incidents-aggregat per region (NUTS-2), surface, capacity-band; väderdata per outdoor-event-hours; inga PII

    ✅ PL-T215
  • F14.05.07 Shipped

    GraphQL analytics-endpoint — POST /v1/analytics/graphql query-only med complexity-limit (count("{")*10 + count("(")*2, default 1000); per-tier-tak; field-level scope-gating

    ✅ PL-T215
  • F14.05.08 Shipped

    Research cohort query — POST /v1/research/cohorts/{id}/query med pseudonymized k=5-anonymity, consent-version per record, ethics-committee-approval-flow

    ✅ PL-T215
  • F14.05.09 Shipped

    Integrity event stream (SSE) — GET /v1/integrity/events/{event_id}/stream med Last-Event-ID-reconnect, p50<250ms latency-SLA, 15s heartbeat

    ✅ PL-T215
  • F14.05.10 Shipped

    Sanctions-list för betting-operatörer — GET /v1/integrity/sanctions med since/jurisdiction-filter, player_pseudo_id, ed25519-signerat _meta

    ✅ PL-T215

Data Product Subscriptions [DONE] — PL-T215

F14.17
Planned

> **Greenfield-not (D-PUBAPI `a95566cc.m-8`, 2026-09) — DATATORGET är byggt.** Legacy-taggen

  • F14.17.01 Shipped

    Self-service-applicering — POST /developer/data-products/subscriptions med per-product required fields (regulator-jurisdiction för integrity, ethics-committee-approval för research); pending_review-default

    ✅ a95566cc.m-8 (POST /v1/developer/data-products/subscriptions): ansökan skapar F1-6-ärendet på plattforms-sentinel-tenanten, aldrig en åtkomst. Fältmängden är PRODUKTENS — integrity kräver regulator_jurisdiction ur en SLUTEN lista om sex myndigheter, research institution + ansvarig forskare + etikprövningsreferens; use_case ≥ 40 tecken. Läget HÄRLEDS vid läsning (raden har ingen status-kolumn) och dubblettskyddet är DB-invarianten dps_live_uq, inte ett if
  • F14.17.02 Shipped

    Admin review-queue — GET /admin/applications med tabbar för status, side-drawer-detaljvy, FIFO-sortering, internal-notes (admin-only); POST .../approve

    reject|revoke med audit-trail | ✅ a95566cc.m-8 (GET /v1/sys/data-products/subscriptions[/{id}], POST …/{id}:revoke): granskningen fattas på F1-6:s GENERISKA steg-rutt — m-8 bygger ingen egen beslutsväg — bakom sys.data_product.review (sys_security ensam; sys_support LÄSER, deny-by-default bevisas mot en riktig inloggning). internal_note lämnar aldrig utvecklarens projektion. Legacys admin-yta är superseded (admin-data-product-applications.md)
  • F14.17.03 Shipped

    Tier-scopade subscriptions — 4 data products × 4 tiers (free/standard/partner/enterprise) med scope-injection vid approve (scopes_granted adderas till DeveloperApiKey.allowed_scopes)

    ✅ a95566cc.m-8: godkännandet injicerar produktens scopes på klienten OCH på varje levande nyckel (audit api_client.scopes_injected), och ensurear klientens pseudonym-salt en gång. Grinden är requireDataProduct i den pinnade ordningen M2M-only (401) → tokenens scope (403 insufficient_scope med required_scopes + apply_url — nekandet PEKAR PÅ DÖRREN) → det LEVANDE avtalet, med is_sandbox = false och valid_through som villkor i själva FRÅGAN. Scopen heter data:* (m-1:s slutna katalog, SelfService: false)
  • F14.17.04 Shipped

    Subscription-lifecycle — pending_review → approved → revoked

    expired; auto-expiry vid valid_through; revoke med future effective_at för compliance grace period | ✅ a95566cc.m-8: hela livscykeln pending_review → approved → rejected|withdrawn|revoked|expired HÄRLEDD, med svepet data_product_subscription_tick (dygnskadens) som verkställer den framtida fristen, skriver expired och varnar 30/7 dygn — högst EN notis per rad och körning, single-fire som DB-invariant på data_product_notice, och utfallet MÄTT (dispatched_at XOR skipped_reason). Svepet är BOKFÖRINGEN: åtkomsten dör vid ANROPET, inte vid vågen
  • F14.17.05 Shipped

    API version lifecycle management — admin /api/versions-vy med experimental → stable → deprecated → sunset transitions; minst 12 mån deprecation-fönster; force-sunset kräver typed confirmation

    ✅ a95566cc.m-2 (versionslivscykeln, GET /v1/api-versions + sys-ytan) — se F14.01
  • F14.17.06 Shipped

    De fyra läsrutterna — GET /v1/data/rankings|results|integrity/sanctions|research/cohorts + POST …/cohorts/{key}:query. Varje svar är {data, page, _meta} med keyset-paginering (page_size ≤ 500, opak next_cursor bunden till sina filter; ett offset mot en levande källa hade tyst hoppat över rader) och Cache-Control: private, no-store + stark ETag ⇒ 304. ?since är inkrementell synk på den precision databasen LAGRAR (RFC 3339 med bråkdel — en sekundtrunkerad stämpel gör »vad är nytt sedan sist« evigt trasig). Ingenting lämnar huset som förbundet inte redan publicerat: bara publika presets, bara publicerade TENANT/GLOBAL-resultat, bara FIPJP-registrets cross-tenant-publicerade rader (BR07.04 — aldrig active_sanction), aldrig en sandbox-tenant. En NAMNGIVEN preset= RESOLVAS (publik ∧ aktiv ∧ icke-raderad ∧ icke-sandbox) och ger annars 404 med en byte-identisk kropp för privat, raderad, inaktiv, sandbox och okänd — en tom 200 hade läst som »förbundet har inga publika presets«, och en skillnad mellan fallen hade varit ett existensorakel

    ✅ a95566cc.m-8
  • F14.17.07 Shipped

    PII-friheten är MÄTT, inte lovad — varje subjekt bärs av pl-ps_<40 hex> = HMAC-SHA256(klientens salt, uuid): stabil per klient över produkterna, olik mellan klienter, aldrig inverterbar (saltet lämnar aldrig processen). Acceptanssviten går REKURSIVT genom varje svar och faller på en förbjuden nyckel ELLER ett husets uuid utanför de tillåtna handtagen. Ett saknat salt UTELÄMNAR fältet — aldrig en tom pseudonym, som hade varit samma värde för varje människa

    ✅ a95566cc.m-8
  • F14.17.08 Shipped

    Provenance är MÄTT, aldrig skriven — _meta bär dataset_version (vattenmärke ur datans EGNA tidsstämplar; en tom sida ⇒ #empty, aldrig ett räknat löpnummer), provenance_uri, source_state ∈ {measured, register_unavailable, empty} (utan FIPJP-registret svarar feeden 200 med register_unavailable — aldrig en tystnad som läses som »inga avstängningar finns«), en KOD-deklarerad field_provenance där VARJE fält i data[] har en rad — per fält, inte per fråga: kohortens sources är unionen av allt frågan läser, men ursprungsraden för ett mått namnger de tabeller precis det måttet mättes ur (matches_played mäts ur D-COMP:s färdigspelade matcher i publicerade tävlingar, aldrig ur rankingens counted_results) — subscription, terms och — bara på integrity — en ed25519-signatur vars recept står körbart i Go/Node/Python. Utan nyckel: signature: null + signature_state: "unavailable"; en fejkad signatur är värre än ingen. Två läsningar utan skrivning emellan ⇒ byte-identiskt _meta

    ✅ a95566cc.m-8
  • F14.17.09 Shipped

    K-anonyma kohorter — en kohort är en DEKLARERAD aggregatfråga (dimensioner, mått, k_floor, max_cells, källor i den serverade katalogen), aldrig fri SQL: deny-by-default i två led gör att gender, postal_code och varje annat fritt fält per konstruktion inte kan nå SQL:en (422 med fältpekare). Varje grupp med n < 5 är suppressed: true med varje mått null, aldrig 0 (en nolla läses som ett mätvärde) och n nollas med dem. Inga poster på individnivå — legacys pseudo_id-rader kräver ett consent-scope ingen söm i huset frågar, och ett dataset som PÅSTOD samtycke vore fabricerad data

    ✅ a95566cc.m-8