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

Commercial & Marketplace

122 features · 15 subsystems

E-commerce, equipment management, sponsorship marketplace, and commercial activities around petanque.

Equipment Catalog

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

    Boule product catalog (manufacturer, model, weight, diameter, hardness, striation)

    ✅ PL-F1101a
  • F11.01.02 Shipped

    Equipment homologation status (FIPJP approved)

    ✅ PL-F1101a
  • F11.01.03 Shipped

    Product reviews and ratings

    ✅ PL-F1101a
  • F11.01.04 Shipped

    Equipment comparison tool

    ✅ PL-F1101a
  • F11.01.05 Shipped

    Accessories catalog (bags, cochonnets, measuring tools, towels)

    ✅ PL-F1101b
  • F11.01.06 Shipped

    Apparel catalog (team wear, federation merchandise)

    ✅ PL-F1101b
  • F11.01.07 Shipped

    New product announcements

    ✅ PL-F1101b

Marketplace

F11.02
Shipped
How it works
  • F11.02.01 Shipped

    Federation/club online shop — PL-F1102a

    ✅ PL-F1102a
  • F11.02.02 Shipped

    Second-hand boule marketplace (player to player) — PL-F1102a

    ✅ PL-F1102a
  • F11.02.03 Shipped

    Classified ads for equipment — PL-F1102a

    ✅ PL-F1102a
  • F11.02.04 Shipped

    Manufacturer/retailer directory — PL-F1102a

    ✅ PL-F1102a
  • F11.02.05 Shipped

    Bulk order management (club team equipment) — PL-F1102b

    ✅ PL-F1102b
  • F11.02.06 Shipped

    Payment processing for marketplace — PL-F1102b

    ✅ PL-F1102b
  • F11.02.07 Shipped

    Shipping and delivery tracking — PL-F1102b

    ✅ PL-F1102b
  • F11.02.08 Shipped

    Cost price tracking and margin report per shop — PL-T075

    ✅ PL-T075

Sponsor Management

F11.03
Shipped

> **Impression-källa från D-SCORE (m-4).** Den digitala scoreboarden (**D-SCORE**) äger en

How it works
  • F11.03.01 Shipped

    Sponsorship opportunity listing (competitions, federations, players) — PL-F1103

    ✅ PL-F1103
  • F11.03.02 Shipped

    Sponsor profile pages — PL-F1103

    ✅ PL-F1103
  • F11.03.03 Shipped

    Banner/ad placement management on platform — PL-F1103

    ✅ PL-F1103
  • F11.03.04 Shipped

    Sponsor visibility reporting (impressions, clicks) — PL-F1103

    ✅ PL-F1103
  • F11.03.05 Shipped

    Sponsorship package builder — PL-F1103

    ✅ PL-F1103
  • F11.03.06 Shipped

    Sponsor-federation matching — PL-F1103

    ✅ PL-F1103
  • F11.03.07 Shipped

    Pre-aggregated visibility rollup — SponsorVisibilityMetric keyed by (tenant, sponsor, campaign, placement_key, audience_segment, bucket_period, bucket_start). Tracks impressions, unique_viewers, clicks, conversions, viewable_seconds. Hour/day/week/month buckets. Idempotent upsert on the unique key.

    ✅ PL-T221
  • F11.03.08 Shipped

    Visibility report endpoint — GET /sponsors/{id}/visibility-analytics returns time-series + totals (with pre-computed CTR%/CVR%) + optional breakdown (placement / surface / segment / campaign). 13-month max query range. Filters: placement_surface[], audience_segment[], campaign_id.

    ✅ PL-T221
  • F11.03.09 Shipped

    Top placements endpoint — GET /sponsors/{id}/visibility-analytics/placements?metric=impressions\

    clicks|conversions|ctr|cvr&limit=10. | ✅ PL-T221
  • F11.03.10 Shipped

    CSV export for bookkeeping — GET /sponsors/{id}/visibility-analytics/export.csv. Filename normalised to alfanumeric+-_, max 80 chars, sponsor-id fallback. Columns: bucket_start, bucket_period, placement_key, placement_surface, audience_segment, campaign_id, impressions, unique_viewers, clicks, conversions, viewable_seconds.

    ✅ PL-T221
  • F11.03.11 Shipped

    Rollup job compute_sponsor_visibility_rollup (the job scheduler) — hourly for bucket=hour, nightly for bucket=day, Sunday 02:00 UTC for bucket=week, first-of-month 03:00 UTC for bucket=month. Backfill via tools/backfill_sponsor_visibility.py reuses the same upsert path.

    ✅ PL-T221
  • F11.03.12 Shipped

    Sponsor analytics admin view — /(dashboard)/sponsors/{id}/analytics with 6 summary tiles, ASCII-bar time-series chart, sortable breakdown table, top-N placements section, CSV-export button. Sponsors landing (/(dashboard)/sponsors) is a sponsor-id input bridge until F11.03's sponsor-list admin lands.

    ✅ PL-T221
  • F11.03.13 Shipped

    sponsor:analytics:read capability gate — federation admins see all sponsors in tenant; sponsor accounts will resource-scope to own sponsor-id once F11.03's account model finalises. Capability-deny logged to AuditLog with action=capability.deny.

    ✅ PL-T221

Equipment Homologation

F11.04
Shipped
How it works
  • F11.04.01 Shipped

    Homologation application workflow (manufacturer submits) — PL-F1104

    ✅ PL-F1104
  • F11.04.02 Shipped

    Testing and certification tracking — PL-F1104

    ✅ PL-F1104
  • F11.04.03 Shipped

    Approved equipment registry (public) — PL-F1104

    ✅ PL-F1104
  • F11.04.04 Shipped

    Homologation expiry and renewal — PL-F1104

    ✅ PL-F1104
  • F11.04.05 Shipped

    Equipment inspection at competitions (serial number check) — PL-F1104

    ✅ PL-F1104

Boule Bars & Playing Venues

F11.05
Shipped
How it works
  • F11.05.01 Shipped

    Boule bar registry with map display and proximity search — PL-F1105

    ✅ PL-F1105
  • F11.05.02 Shipped

    Events and recurring activities at boule bars — PL-F1105

    ✅ PL-F1105
  • F11.05.03 Shipped

    Opening hours and court information — PL-F1105

    ✅ PL-F1105
  • F11.05.04 Shipped

    Equipment rental availability — PL-F1105

    ✅ PL-F1105
  • F11.05.05 Shipped

    Verified and featured venue badges — PL-F1105

    ✅ PL-F1105

Marketplace Seller Dashboard

F11.06
Shipped
How it works
  • F11.06.01 Shipped

    Seller onboarding with KYC verification — PL-F1106a

    ✅ PL-F1106a
  • F11.06.02 Shipped

    Product inventory with variants — PL-F1106a

    ✅ PL-F1106a
  • F11.06.03 Shipped

    Order management (seller perspective) — PL-F1106a

    ✅ PL-F1106a
  • F11.06.04 Shipped

    Stripe Connect payouts — PL-F1106a

    ✅ PL-F1106a
  • F11.06.05 Shipped

    Reviews and ratings — PL-F1106b

    ✅ PL-F1106b
  • F11.06.06 Shipped

    Return and refund management — PL-F1106b

    ✅ PL-F1106b
  • F11.06.07 Shipped

    Inventory tracking per product — PL-F1106b

    ✅ PL-F1106b

Marketplace Commission Motor

F11.07
Shipped
How it works
  • F11.07.01 Shipped

    Stripe Connect Express seller account onboarding — PL-T032

    ✅ PL-T032
  • F11.07.02 Shipped

    Commission listing with i18n, stock tracking, categories — PL-T032

    ✅ PL-T032
  • F11.07.03 Shipped

    5% platform commission on marketplace transactions — PL-T032

    ✅ PL-T032
  • F11.07.04 Shipped

    Transparent commission breakdown display — PL-T032

    ✅ PL-T032
  • F11.07.05 Shipped

    Atomic stock decrement with race-condition protection — PL-T032

    ✅ PL-T032
  • F11.07.06 Shipped

    Proportional commission reversal on refunds — PL-T032

    ✅ PL-T032
  • F11.07.07 Shipped

    Monthly seller payout job (idempotent) — PL-T032

    ✅ PL-T032
  • F11.07.08 Shipped

    Commission accounting job (monthly financial report) — PL-T032

    ✅ PL-T032
  • F11.07.09 Shipped

    Admin commission report and manual refund endpoints — PL-T032

    ✅ PL-T032

Brand Pages

F11.08
Shipped

**Marketplace seller landing pages with multi-language content, hero/about/products/awards sections, public slug, optional facility-supplier listing.**

  • F11.08.01 Shipped

    Multi-language brand page (name, hero, about, awards) — PL-T214

    ✅ PL-T214
  • F11.08.02 Shipped

    Featured products grid with cap (≤6) — PL-T214

    ✅ PL-T214
  • F11.08.03 Shipped

    Public slug (unique per tenant) + canonical CMS bridge export — PL-T214

    ✅ PL-T214
  • F11.08.04 Shipped

    Facility-supplier opt-in directory listing — PL-T214

    ✅ PL-T214
  • F11.08.05 Shipped

    Audit trail with publish/unpublish events — PL-T214

    ✅ PL-T214

Product Bundles & Cross-Sell Engine

F11.09
Shipped

**Anchor + accessory bundle authoring with cross-sell triggers; checkout `<BundleSuggest>` returns up to three matching bundles.**

  • F11.09.01 Shipped

    Bundle authoring (anchor line required) — PL-T214

    ✅ PL-T214
  • F11.09.02 Shipped

    Pricing strategies: fixed / percent_off / sum_minus_amount — PL-T214

    ✅ PL-T214
  • F11.09.03 Shipped

    Cross-sell trigger by anchor product + min_cart — PL-T214

    ✅ PL-T214
  • F11.09.04 Shipped

    /preview endpoint returning ≤3 active bundles for cart — PL-T214

    ✅ PL-T214
  • F11.09.05 Shipped

    Validity windows (valid_from/valid_to) honoured — PL-T214

    ✅ PL-T214

Bulk Order Quotes & Split-Payment

F11.10
Shipped

**Multi-stage RFQ for clubs: draft → submit → price → split (per_roster_entry / one_payer / percent_split) → Stripe Connect webhook drives PAID; freight consolidation links sibling quotes.**

  • F11.10.01 Shipped

    Quote lifecycle (draft → submit → price → split → paid) — PL-T214

    ✅ PL-T214
  • F11.10.02 Shipped

    Roster-based per-payer payment split — PL-T214

    ✅ PL-T214
  • F11.10.03 Shipped

    One-payer + percent split modes — PL-T214

    ✅ PL-T214
  • F11.10.04 Shipped

    Stripe Connect webhook routes share-level events — PL-T214

    ✅ PL-T214
  • F11.10.05 Shipped

    48h split reminder cron stamps audit — PL-T214

    ✅ PL-T214
  • F11.10.06 Shipped

    Freight consolidation links sibling quote IDs — PL-T214

    ✅ PL-T214

Lead Generation

F11.11
Shipped

**Public + admin lead pipeline for facility construction, lighting, surface and consulting projects; rate-limited captcha-gated public form, anti-spam scoring, geo-nearest routing fallback to manual.**

  • F11.11.01 Shipped

    Public lead form (/public/leads, captcha-gated) — PL-T214

    ✅ PL-T214
  • F11.11.02 Shipped

    Per-IP rate limit (3/h, 429 + Retry-After) — PL-T214

    ✅ PL-T214
  • F11.11.03 Shipped

    Anti-spam scoring (5+ duplicate emails ⇒ status=spam) — PL-T214

    ✅ PL-T214
  • F11.11.04 Shipped

    Geo-nearest routing with manual fallback — PL-T214

    ✅ PL-T214
  • F11.11.05 Shipped

    Status graph enforcement (NEW → ROUTED only) — PL-T214

    ✅ PL-T214
  • F11.11.06 Shipped

    Lead routing tick (5 min) — PL-T214

    ✅ PL-T214

Sponsor Activation

F11.12
Shipped

**Schedules and ROI snapshots for overlay/signage/athlete-partnership/digital-campaign activations. Slot overlap detection, signage date validity, deterministic CTR computation.**

  • F11.12.01 Shipped

    Overlay schedule with slot overlap detection (409) — PL-T214

    ✅ PL-T214
  • F11.12.02 Shipped

    Signage booking with install/take-down date validation — PL-T214

    ✅ PL-T214
  • F11.12.03 Shipped

    Athlete partnership + digital campaign payloads — PL-T214

    ✅ PL-T214
  • F11.12.04 Shipped

    ROI snapshot (impressions, CTR, broadcast minutes, mentions) — PL-T214

    ✅ PL-T214
  • F11.12.05 Shipped

    Daily ROI refresh tick (live + last 7d completed) — PL-T214

    ✅ PL-T214

Demand Forecasting

F11.13
Shipped

**Deterministic linear coefficient model — no ML — over 6 product categories. Buckets per (week × category), confidence band by signal coverage, version-stamped algorithm. Weekly tick regenerates per tenant.**

  • F11.13.01 Shipped

    Deterministic per-category coefficient model — PL-T214

    ✅ PL-T214
  • F11.13.02 Shipped

    Weekly + monthly granularity — PL-T214

    ✅ PL-T214
  • F11.13.03 Shipped

    Confidence band (low/medium/high) — PL-T214

    ✅ PL-T214
  • F11.13.04 Shipped

    Baseline-used audit when signals are zero — PL-T214

    ✅ PL-T214
  • F11.13.05 Shipped

    Weekly regeneration tick (Monday 04:00 UTC) — PL-T214

    ✅ PL-T214

Public Homologation Database

F11.14
Shipped

**Searchable public mirror of FIPJP-homologated boules, derived from F11.04. Cache-Control + sha256-derived QR token + revoke-with-reason audit trail. Hourly sync tick.**

  • F11.14.01 Shipped

    Public list with category/manufacturer/valid_on filters — PL-T214

    ✅ PL-T214
  • F11.14.02 Shipped

    Public detail page with QR token (sha256 of certificate_id) — PL-T214

    ✅ PL-T214
  • F11.14.03 Shipped

    Admin publish + revoke (with reason + audit) — PL-T214

    ✅ PL-T214
  • F11.14.04 Shipped

    Cache-Control max-age=3600 — PL-T214

    ✅ PL-T214
  • F11.14.05 Shipped

    Hourly sync tick refreshes last_synced_at — PL-T214

    ✅ PL-T214

Uthyrning av poängtavle-kit (D-EQUIP)

F11.15
Planned

> **PL:s ANDRA intäktsström** (vid sidan av SaaS-abonnemanget). PL äger hårdvaran och är

  • F11.15.01 Shipped

    Kit-katalog (publik) — mallarna Trial (8) / Silver (32) / Gold (64) / Platinum (128) med baspris, deposition per tavla, frakt inrikes/EU, försäkring i baspunkter; belopp som heltal i minsta enhet + ISO 4217. GET /v1/equipment/kits[/{id}] är publik (den publika hyr-sidan har ingen session) och bär inga interna fält; POST/PATCH/DELETE kräver equip:admin och DELETE är soft (is_active=false — katalogen är historik för varje bokning) — a4875234.m-1.t-2

    ✅ a4875234.m-1.t-2
  • F11.15.02 Shipped

    Tillgänglighet med frakt-buffert — GET /v1/equipment/kits/{id}/availability?from=&to= räknar instanser som är lediga HELA det buffert-utökade fönstret (72 h före + 72 h efter event-perioden). Bufferten bor på EN plats (equipment.ReservedPeriod) och används av både räkningen och reservationen, så ett kit som räknas ledigt aldrig kan avvisas av insertet; from >= to → 400 — a4875234.m-1.t-2

    ✅ a4875234.m-1.t-2
  • F11.15.03 Shipped

    Lager av fysiska instanser — scoreboard_kit_instance (serienr, in_stock\

    rented|maintenance|retired) med CRUD för equip:admin, inventarie-tidslinje per instans (newest-first, paginerad) och guards: dubblett-serienummer → 409, lagerväxling på instans med pågående uthyrning → 409 invalid_transition, rented sätts/nollas ENBART av hyr-FSM:en — a4875234.m-1.t-2 | ✅ a4875234.m-1.t-2
  • F11.15.04 Shipped

    Atomisk reservation — databasen arbitrerar — POST /v1/equipment/rentals väljer instans server-side och INSERT:ar per kandidat; EXCLUDE USING gist (kit_instance_id, period) (migration 00157) avgör (23P01 → nästa kandidat, tömd pool → 409 kit_unavailable). Ingen förkontroll: två samtidiga överlappande bokningar mot en enda ledig instans ger exakt ett 201 och ett 409. Idempotency-Key är obligatorisk (utan → 400 idempotency_key_required; samma nyckel+body → replay; annan body → 409 idempotency_conflict) — a4875234.m-1.t-2

    ✅ a4875234.m-1.t-2
  • F11.15.05 Shipped

    Hyr-FSM — booking → shipping → in_use → returning → returned → closed (+ cancel enbart från booking, som FRIAR perioden). Aktörsmatris per kant (PL packar/inspekterar/stänger, hyresgästen kvitterar/returnerar), If-Match obligatorisk även på POST-stegen (428/412), otillåten kant → 409 invalid_transition utan sidoeffekt, EXAKT en inventarie-händelse + audit-rad per övergång i samma transaktion, instansen rented/in_stock följer FSM:en — a4875234.m-1.t-2

    ✅ a4875234.m-1.t-2
  • F11.15.06 Shipped

    PL-driftens vyer — GET /v1/equipment/inventory/dashboard (per mall: antal per lagerstatus + per instans dess AKTUELLA och NÄSTA uthyrning — verkliga rader) och GET /v1/equipment/bookings/queue (to_pack + expected_returns) — a4875234.m-1.t-2

    ✅ a4875234.m-1.t-2
  • F11.15.07 Shipped

    AuthZ/tenancy — equip:admin (PL-drift, räknas ENDAST i plattforms-tenanten — samma roll i ett förbund öppnar ingenting), equip:rent (hyresgästen över sina egna). Skopet injiceras server-side: annan tenants uthyrning är 404 (anti-enumeration), fel capability på egen resurs är 403, och en hyresgäst kan inte filtrera fram en främmande rad. §5b-bracket-filter ur whitelist (okänt fält/operator → 400) — a4875234.m-1.t-2

    ✅ a4875234.m-1.t-2
  • F11.15.08 Shipped

    Kontrakt + fixtur — 17 vägar i api/openapi/openapi.json (taggen equipment-rental, delade Problem-/PageMeta-scheman, Idempotency-/ETag-metadata) → genererad typad TS-klient; api seed-equipment ger kit-katalog, fem lagerinstanser med stabila serienummer, PL:s eget merchant-konto och en demo-bokning med betald fall 1-kedja på PL:s tenant-noll — a4875234.m-1.t-1/t-2 + a4875234.m-2.t-1/t-2

    ✅ a4875234.m-2
  • F11.15.09 Shipped

    Betalning som PL-merchant (fall 1) — kort-vägen skapar server-side en F1-11 payments-rad i PL:s tenant-noll mot PL:s EGET merchant-konto (subject_type='equipment_rental'; ingen PAY-2-resolve, ingen connected account, inga splits, ingen plattformsavgift) och returnerar checkout_url; idempotent replay ger samma bokning, samma URL och EN betalrad. Faktura-vägen ställer ut en NET-30-faktura (payment_status='INVOICED', invoice_due_at ≈ +30 dygn, GET …/invoice). Statusen speglas av F1-11:s centrala webhook (payment_intent.succeeded/invoice.paid ⇒ PAID, charge.refunded ⇒ REFUNDED, invoice.payment_failed lämnar uthyrningen INVOICED) — D-EQUIP exponerar ingen egen mottagare — a4875234.m-2.t-2

    ✅ a4875234.m-2.t-2
  • F11.15.10 Shipped

    Moms + RevenueEvent till tenant-noll — billing_address är obligatorisk och momsen (svensk standardsats, rate_bps 2500) låses i pricing_breakdown.vat_lines vid create; total_amount_minor är moms-inklusive (Silver + inrikes frakt: 1 320 000 netto + 330 000 moms = 1 650 000 öre) och räknas aldrig om vid läsning; icke-svensk adress ⇒ ärligt 422. Vid lyckad betalning emitteras exakt ett RevenueEvent (tenant_id = PL:s tenant-noll, source_type='equipment_rental', income_account_hint='3040', prislåsets vat_lines, nyckel revenue:equipment_rental:<payment_id>) — aldrig mot hyresgästens böcker, aldrig en skrivning i BILL:s tabeller — a4875234.m-2.t-2

    ✅ a4875234.m-2.t-2
  • F11.15.11 Shipped

    Packgrind + dunning (F1-7) — confirm-shipment kräver PAID eller INVOICED (annars 409 payment_pending), samma predikat som bokningsköns to_pack; api run-job equipment_invoice_dunning (även registrerat i workern) stämplar invoice_dunning_at + en audit-rad för förfallna/studsade NET-30-fakturor, idempotent inom ett 7-dygnsfönster och rör aldrig en betald bokning — a4875234.m-2.t-2

    ✅ a4875234.m-2.t-2
  • F11.15.12 Shipped

    Custody — förvaringskedjan inom en tenant — brädregistret (<instansens serial_no>-B<nnn>) med denormaliserad current-rad + append-only historik. Custodian redovisas som PARET (tenant_id, org_node_id) plus härlett custodian_kind (platform_warehouse\

    tenant_root|org_node); permanent_owner är alltid PL. Tre flyttkommandon (POST /v1/equipment/custody/transfer, …/bulk-transfer max 500 serier, POST /v1/equipment/kits/{kit_id}/transfer-custody) — alla med obligatorisk Idempotency-Key, närvarande (nullbar) from_org_node_id-förväntan (fel förväntan → 409 custody_conflict), valfritt men respekterat If-Match, och N events + N current-uppdateringar + EN audit-rad i EN transaktion (mängd-satser: 128 tavlor < 2 s). Fast-track = reason='fast-track' — a4875234.m-3.t-1/t-2 | ✅ a4875234.m-3
  • F11.15.13 Shipped

    QR-handover + cross-tenant-spärr + PL-override — engångs-token (sex siffror + qr_payload, 7 dygn) skapas av avsändaren och löses in av mottagaren; svaret ÄR kvittot (event_ids[] + tavlornas nya förvaring), accept + materialisering i EN transaktion. Prövningsordning: okänd kod → 404, utgången mot klockan → 409 handover_token_expired, redan inlöst → 409 handover_token_used. F1-7-ticken equipment_handover_token_expiry är hygien (idempotent, ingen audit-storm), aldrig grinden. Flytt/token mot en annan tenants nod → 409 cross_tenant_custody_forbidden (dubbel spärr: applikation + composite-FK:er i migration 00159) — tavlan måste via PL:s lager. POST /v1/equipment/custody/force-return (equip:admin i tenant-noll) tvångs-returnerar EN tavla med override-event + EN audit-rad, rör inte hyr-FSM:en och är idempotent — a4875234.m-3.t-2

    ✅ a4875234.m-3.t-2
  • F11.15.14 Shipped

    Custody vävd i hyr-FSM:en + läsvyerna — confirm-receipt levererar hela kitet till hyresgästens rotnivå (ett delivery-event per tavla, rental_id satt) och inspection returnerar de tavlor som faktiskt kom tillbaka; valfri body {"missing_serials":[…]} lämnar de saknade helt orörda (förlustspåret "senaste custodian utan retur-event"), okänd serie → 422 utan skrivningar, return rör ingen custody. Läsningarna: GET /v1/equipment/custody/{serial}/history (newest-first — PL ser HELA kedjan, hyresgästen bara sin egen tenants events, filtrerat server-side), GET /v1/org-nodes/{id}/scoreboards och GET /v1/equipment/rentals/{id}/distribution (summan = instansens board_count). Nodradering som krockar med custody → 409 (aldrig 500). Seeden ger en levererad demo-uthyrning + en accepterad och en öppen överlämning — a4875234.m-3.t-2

    ✅ a4875234.m-3.t-2
  • F11.15.15 Planned

    Ärlig m-3-gräns (inget fabricerat) — ingen SSE-ström, damage_pending fortfarande onåbar, inget skadeärende och ingen cancelled-yta på överlämnings-token (D-10). Custody-mandatet prövas i tenant-scope, inte per nod (D-12). Depositionen levereras av m-4 t-1 (F11.15.16); frakt/spårning, skada + F1-6-bestridning = m-4 t-2; UI = m-5–m-7

    ⏳ m-4–m-7
  • F11.15.16 Shipped

    Deposition — säkerheten för PL:s hårdvara (manual capture, fall 1) — EN rad per uthyrning (unique (rental_id), migration 00160): den FÖDS vid bokningen med sparad betalmetod (SetupIntent, PL som merchant — create-svaret bär deposit_setup_client_secret, för BÅDA betalsätten) och auktoriseras vid confirm-shipment som en F1-11-betalning med capture_method=manual i PL:s tenant-noll mot PL:s eget merchant-konto (subject_type='equipment_deposit', inga splits, ingen application_fee, ingen egen webhook-mottagare). Utan användbar metod: 409 deposit_method_missing utan statusövergång. Strategin väljs ur kalendern (planerat håll ≤ 6 dygn ⇒ auth_hold, annars charge_and_refund — Stripe håller en auktorisation i högst 7 dygn; konstanterna bor på EN plats). Livscykel held → captured\

    released|refunded (en gång; annars 409 deposit_state_invalid) via GET/POST /v1/equipment/rentals/{id}/deposit[/capture|release|refund] (equip:admin, obligatorisk Idempotency-Key, belopp > kvarvarande ⇒ 422; hyresgästens projektion bär aldrig PL:s betalnings-id:n). En skadefri inspection släpper säkerheten efter commit, och F1-7-svepet api run-job equipment_deposit_sweep är det durabla nätet (strategiväxling före auth-utgång + release av strandad held) — a4875234.m-4.t-1 | ✅ a4875234.m-4.t-1 · specs/api/endpoints/equipment-risk.md
  • F11.15.17 Shipped

    Frakt & spårning (carrier-neutral) — försändelsen FÖDS UR FSM:en: confirm-shipment skapar outbound och return-steget skapar return, i SAMMA transaktion som statusövergången, högst EN rad per riktning (unique (rental_id, direction)). PL:s etikettyta POST /v1/equipment/rentals/{id}/shipments upsertar på riktningen (201 skapad / 200 påfylld, obligatorisk Idempotency-Key); GET …/shipments är self-guardad med skopberoende projektion (hyresgästen ser aldrig label_ref/last_event_key/tracking_polled_at) och GET /v1/equipment/shipments/{id}/tracking bär EXAKT hyresgäst-fältmängden med ETag + Cache-Control: private, max-age=15 (polling — SSE är m-7). Jobbet api run-job equipment_tracking_poll frågar den leverantörsneutrala CarrierTracker-porten, appenderar BARA nya händelser (dedup), är batch-takat och fäller inte hela vågen på ETT carrier-fel; lokalt/test kör den deterministiska fake-carriern (riktiga PostNord-/DHL-adaptrar är go-live-arbete) — a4875234.m-4.t-2

    ✅ a4875234.m-4.t-2 · specs/api/endpoints/equipment-risk.md
  • F11.15.18 Shipped

    Skade-kanten + skaderapport med HÄRLETT ansvar — inspection-kroppens damage_found: true (eller en icke-tom missing_serials) väljer kanten returning → damage_pending: depositionen ligger kvar held, inventarie-händelsen är returned_with_damage och custody-vävningen körs oförändrat på båda utfallen; close från damage_pending kräver att varje ärende är avräknat (annars 409 damage_unresolved). POST /v1/equipment/rentals/{id}/damage-report (equip:admin, If-Match, Idempotency-Key) härleder ansvarig custodian ur kedjan (senaste händelsen som inte är en retur; lika ⇒ noden, olika ⇒ hyresgästens rotnivå + per-serie-karta i responsible_detail) — en klient-angiven ansvarig tas ALDRIG emot, och paret är composite-FK-säkrat mot en annan tenant. Foto-bevisen är klient-angivna referenser: max 20, https:// (aldrig http://). Läsningarna GET …/rentals/{id}/damage-reports, GET /v1/equipment/damage-reports[?status[in]=…&rental_id[eq]=…&created_at[gte]=…] (cursor-paginerad, skop server-side) och GET …/damage-reports/{id} (ETag) — a4875234.m-4.t-2

    ✅ a4875234.m-4.t-2 · specs/api/endpoints/equipment-risk.md
  • F11.15.19 Shipped

    Debitering mot depositionen + RevenueEvent (PL-intäkt) — POST /v1/equipment/damage-reports/{id}/charge har TOM kropp (beloppet ÄR cost_assessed_minor): min(kostnad, kvarvarande deposition) fångas ur säkerheten (partiell capture för auth_hold, ren bokföring för charge_and_refund) och ETT eventuellt överskott blir EN extra fall 1-betalning (subject_type='equipment_damage', kort ⇒ off-session, faktura ⇒ NET-30). Replay på samma nyckel ⇒ samma svar och ingen andra capture; en andra debitering ⇒ 409 deposit_state_invalid. F1-11:s centrala OnSuccess-hook emitterar EXAKT ETT RevenueEvent per betalning (revenue:equipment_damage:<payment_id>, tenant_id = tenant-noll, source_type='equipment_damage', income_account_hint='3040', tomma vat_lines — momsen på skadeersättning är BILL:s beslut och gissas inte); summan över rapportens betalningar = charged_minor, eftersom den kapade depositionen ÄR intäkt, och hyresgästens tenant får aldrig ett event — a4875234.m-4.t-2

    ✅ a4875234.m-4.t-2 · specs/api/endpoints/equipment-risk.md
  • F11.15.20 Shipped

    Bestridning som F1-6-approval (14 dygn) + påminnelser — POST /v1/equipment/damage-reports/{id}/dispute (hyresgästens equip:rent) skapar och submittar begäran (request_type='damage_dispute', seedad policy med EN sekventiell steg-rad i PL:s tenant-noll) i ETT anrop ⇒ rapporten blir disputed; efter fönstret 409 dispute_window_closed, andra försöket 409 dispute_exists, annan tenant 404. Fasaden POST …/dispute/steps/{seq}/approve\

    reject (equip:admin) är en TUNN PROXY till samma approval.Engine med stegets egen capability-grind. Semantiken står utskriven: approve = bestridningen BIFALLS ⇒ hyresgästen får rätt ⇒ pengarna reverseras (avsikten verkställs av equipment_deposit_sweep — provider-anrop får aldrig ligga i beslutets transaktion), reject = debiteringen står fast (rationale obligatorisk). D-EQUIP äger INGEN egen tvist-FSM. api run-job equipment_return_reminder stämplar retur- och inspektions-påminnelser (ett event + en audit-rad per uthyrning, idempotent inom 7 dygn) — kanalerna ägs av D-COMM/D-PUSH — a4875234.m-4.t-2 | ✅ a4875234.m-4.t-2 · specs/api/endpoints/equipment-risk.md
  • F11.15.21 Planned

    Ärlig m-4-gräns (inget fabricerat) — inga riktiga carrier-integrationer (porten finns, adaptern är fake-carriern), ingen SSE-ström (spårningen är polling med ETag — m-7), ingen media-uppladdning (foton är https://-referenser), ingen moms på skadeersättning (vat_lines: [] — BILL:s beslut), ingen fri PL-satt delreversering och ingen egen webhook-mottagare/tvist-FSM. Frontend-ytorna (hyresgästens spårnings-/skadevy, PL:s skadeärende-konsol) är m-5–m-7

    ⏳ m-5–m-7
  • F11.15.22 Shipped

    Hyresgästens uthyrningsyta i admin (/utrustning) — NAV-posten admin-nav-utrustning (capability: 'equip:rent', gruppen *Verksamhet*) med deny-by-default: utan mandatet renderas varken navpost eller innehåll (aldrig utgråat, och ingen datahämtning i nekat läge). Checkout-steppern (/utrustning/boka, fem steg: kit → period & tillgänglighet → leverans & fakturaadress → betalsätt → summering) listar katalogens aktiva mallar, tar djuplänken ?kit=<slug>, visar available_count/total_count för fönstret och — vid 0 lediga — ett ärligt upptaget-läge plus framåt-sondering (högst 60 dagar, samma publika endpoint). Create går med Idempotency-Key och kontraktets exakta fält (shipping_zone ur formuläret, aldrig härledd ur adressen), och 201-svaret renderas som serverns prisbild: pricing_breakdown (hyra/frakt/försäkring/vat_lines), total_amount_minor och den informativa depositionsraden — ytan summerar aldrig själv. Kort-vägen visar checkout_url och kan återuppta betalningen som ett idempotent återspel av SAMMA nyckel (samma URL, EN betalrad; utanför minnet ett ärligt läge i stället för en knapp som myntar en andra betalning — nyckeln lever i minnet, aldrig i webblagring). Mina bokningar har server-sidiga segment (*Aktuella · Kommande · Historiska* = bracket-frågor), och bokningsdetaljen visar FSM:ens byggda statusnamn, sidolägena damage_pending/cancelled särredovisade, depositionspanelen ur GET …/deposit (status, belopp, capture_strategy i klarspråk, eller det ärliga "ingen deposition ännu"), fakturapanelen (pdf_url/hosted_url) och hyresgästens tre steg kvittera · returnera · avboka med If-Match + bekräftelsedialog. Felen renderas som annonserade rutor med problemets code i klartext (kit_unavailable, invalid_transition, stale_version, 422 vid fältet, 404 utan existens-läcka) — a4875234.m-5.t-1

    ✅ a4875234.m-5.t-1 · specs/admin/views/utrustning.md
  • F11.15.23 Shipped

    Publik kit-katalog på webben (/poangtavlor) — SSR-route (force-dynamic) som svarar utan session: funktionssektion (hero, teknisk specifikation ur husets egen enhetskälla, användningsfall), kit-kort ur GET /v1/equipment/kits med belopp renderade ur *_minor + currency, SEO-metadata (titel/beskrivning/canonical/Open Graph) och JSON-LD Product vars pris är exakt katalogens base_price_minor (ingen statisk availability — den är per datumfönster). En klient-ö ger datumfönstret (default: nästkommande helg) och läser GET …/availability per mall; indikatorn är mätbar: 0 ⇒ Fullbokat, 1 ⇒ Få kvar, ≥2 ⇒ Tillgängligt, total_count = 0 ⇒ "Offert — kontakta oss" — alltid ikon + text, aldrig färg ensam. CTA:n djuplänkar till hyresgästens admin (<admin>/utrustning/boka?kit=<slug>; bokningen är autentiserad). Ärliga tillstånd: svarar katalog-API:t inte visas ett felläge med kontakt-CTA utan priser och utan indikatorer (mockupens "static price fallback" är en bokförd avvikelse — hårdkodade priser i en live-yta är förbjudna), tom katalog ⇒ ärligt tomläge, laddläge per skeletonmönstret — a4875234.m-5.t-2

    ✅ a4875234.m-5.t-2 · specs/web/views/poangtavlor.md
  • F11.15.24 Planned

    Ärlig m-5-gräns (inget fabricerat) — hyresgästens spårnings-, skade-/bestridnings- och custody-/distributionsvy byggs i m-6; PL:s systemägar-vyer (lager-dashboard, bokningskö, skadeärenden, intäkts-/beläggningsrapport, custody-override) i m-7; inget publikt bokningsflöde eller publikt kvitto på webben (ytbeslut — det kräver ett eget mockup-/kontrakts-delta, ingen attrapp byggs under tiden); ingen provider-SDK för depositionens SetupIntent i UI:t (deposit_setup_client_secret renderas aldrig — hemligheten når inte ytan) och ingen förlängningsdags-rad (prismotorn har ingen sådan prissättning). PL:s driftsteg (confirm-shipment, inspection, close) finns inte på hyresgästens yta — och därför bevisas kvittera/returnera i L4-drivrutinen som request-bevis (POST …/return med If-Match) i stället för en genomförd övergång: ingen seedad dev-login-identitet bär equip:admin, och att driva seedens in_use-fixtur vidare hade gjort körningen icke-omkörbar (redovisat i drivrutinens huvud, aldrig ett tyst grönt)

    ⏳ m-6–m-7
  • F11.15.25 Shipped

    Hyresgästens spårnings- och skadeärendevy i admin (m-6) — bokningsdetaljens fraktpanel visar BÅDA riktningarnas försändelser med carrier/tracking_no/status (ikon + text) och varje spårningshändelses egna fält ur GET /v1/equipment/shipments/{id}/tracking; färskheten är polling med If-None-Match (dokumenterat intervall, stopp när fliken är dold, noll /stream-anslutningar — SSE är m-7), och PL-interna fält (label_ref, last_event_key, tracking_polled_at) finns aldrig i hyresgästens DOM. Skadeärende-listan /utrustning/skadearenden filtrerar som serverfrågor (status[in]) och detaljen visar foto-bevisen, ansvarig orgnod med namn (NULL ⇒ rotnivå-klartext), charged_minor/reversed_minor som serverns tal och 14-dygnsfönstret renderat ur dispute_deadline_at; bestrid-formuläret skickar motivering + belopp i minsta enhet + motbevis genom medie-sömmen och renderar serverns 422 vid fältet respektive 409 dispute_exists annonserat — a4875234.m-6.t-1

    ✅ a4875234.m-6.t-1 · specs/admin/views/utrustning.md
  • F11.15.26 Shipped

    Kit-distribution & custody i admin (/utrustning/distribution, m-6) — EGEN route med EGEN gate på equip:custody (oberoende av equip:rent, NAV-posten admin-nav-kit-distribution): en distrikts-/klubbadmin når ytan utan boknings-mandat, och utan custody-mandat finns varken navpost eller innehåll (ingen datahämtning i nekat läge). Nodvyn läser tenantens org-träd → GET /v1/org-nodes/{id}/scoreboards; skapa-flödet (frånnod → serieurval → mottagarnod → valfri anledning/foto genom medie-sömmen, aktiv foto-uppmaning över 5 valda tavlor) skapar överlämningen och visar den 6-siffriga koden med en LOKALT ritad QR (qrcode-generator, <svg> vars tillgängliga namn läser upp koden — ingen serverbild, ingen extern QR-tjänst, noll bildhämtningar) + expires_at. Överlämningslistan är en serverfråga, och ta emot-reservvägen i admin löser in koden mot samma endpoint som appen och renderar kvittot ur svaret. Bokningsdetaljens fördelningspanel grupperar per custodian (custodian_kind) med summan = serverns board_count, och varje serie länkar till den läs-endast förvaringskedjan (nyast först, cursor-paginerad, markering för event via bekräftad överlämning). Felen i klarspråk med sin kod (handover_token_expired/handover_token_used/cross_tenant_custody_forbidden/custody_conflict) och 404 som "Koden finns inte" — identiskt för okänd kod och för en kod i ett annat förbund (anti-enumeration). Ingen force-return-affordance (PL-override är m-7) — a4875234.m-6.t-2

    ✅ a4875234.m-6.t-2 · specs/admin/views/utrustning.md
  • F11.15.27 Shipped

    QR-handover i appen (/kit-overlamning, m-6) — mottagarens fältyta, buren av RequireCapability('equip:custody') med ärlig fallback som nämner behörigheten, nådd ur inställningarnas länklista (posten renderas bara med mandatet). Manuell 6-siffrig inmatning är den byggda huvudvägen (≥ 48 px, tillgängligt namn) och QR-fångsten är ett påbyggnadslager genom den byggda adaptern QrCaptureView, vars payload matar EXAKT samma ingång; adapterns tre ärliga tillstånd (granted|denied|unavailable) visas alltid i klartext, och eftersom repot medvetet saknar kameraberoende (A-4) är unavailable det e2e-bevisade läget i CI. Kvittot är accept-svaret (serier, från/till-nod, event_ids-antal, accepted_at — aldrig klientens eget urval), och fast-track flyttar EN tavla med reason='fast-track' mot en närvarande frånnods-förväntan (fel förväntan ⇒ 409 custody_conflict annonserat med hänvisning till innehavslistan). Online-only ärligt: utan nät sägs rakt ut att ingenting har köats — ingen offline-kö, ingen ny lokal lagring, koden lagras aldrig — a4875234.m-6.t-2

    ✅ a4875234.m-6.t-2 · specs/app/views/kit-overlamning.md
  • F11.15.28 Planned

    Ärlig m-6-gräns (inget fabricerat) — ingen SSE-ström (färskheten är polling med ETag; strömmen + PL:s live-drift är m-7), ingen generisk F1-6-approval-yta (bestridningen projiceras på skaderapporten — begäran lever i PL:s tenant-noll), ingen fotobilaga i appen (foto-åtagandet ligger i admin, där medie-sömmen finns), inget kameraberoende (fångstadaptern använder plattformens egna sömmar), ingen offline-kö för custody (serverns klockprövning mot expires_at är kontraktet) och ingen force-return/lager-/bokningskö-/intäktsvy — PL:s systemägar-ytor är m-7. PL-driftens steg (confirm-shipment, POST …/shipments, damage-report, charge) kräver equip:admin i plattforms-tenanten och bärs av ingen dev-login-identitet: L4-drivrutinerna mäter det gapet och redovisar det med ⊘ i loggen i stället för att gissa (ett färskt skadeflöde och ett NYTT spårningsnummer kan därför inte drivas utan en ny seed/identitet, vilket m-6 uttryckligen förbjuder)

    ⏳ m-7
  • F11.15.29 Shipped

    PL-driftens API-/seed-delta (m-7 t-1) — GET /v1/equipment/rentals/stream (equip:admin, SSE per husets prövade mönster: mandatet prövas FÖRE stream-headern, snapshot-först, heartbeat som SSE-kommentar, ?mode=snapshot ger SAMMA payload som JSON; FRYST vokabulär snapshot|rental|damage_report, ramar bara på ÄNDRING — ingen ny event-tabell, inget nytt jobb), GET /v1/equipment/reports/utilization (server-beräknad serie per kit-mall × kalendermånad: hyresintäkt ur PAID-uthyrningar periodiserade på lower(period), särredovisad skadeintäkt, occupancy_bps som heltal i baspunkter med underhållsdagar ur nämnaren, antal bokningar — drift-nyckeltal, INTE bokföring), namn-berikning av PL-projektionerna (renter_tenant_name, responsible_org_node_name, custody-kedjans from/to_org_node_name — hyresgästens projektion är oförändrad) och driftidentiteten equip-drift-seed@demo.petanque.life i seed-equipment (medlemskap i plattforms-tenanten + platform_equipment_admin + en befintlig media:manage-bärare; mallen breddas ALDRIG — den är testpinnad SMAL) — a4875234.m-7.t-1

    ✅ a4875234.m-7.t-1 · specs/api/endpoints/equipment-rental.md
  • F11.15.30 Shipped

    PL:s driftyta i admin (/uthyrningsdrift, m-7 t-2) — NAV-posten admin-nav-uthyrningsdrift (capability: 'equip:admin', gruppen *Verksamhet*) i ett EGET träd skilt från hyresgästens /utrustning, deny-by-default med ärligt nekat-läge utan datafetch. Lager-dashboarden: status-räkningar och instansrader ur GET …/inventory/dashboard, härledd plats (lagerstatus × uthyrningens FSM-läge ⇒ PL:s lager / i transit / hos {hyresgästens NAMN} / retur på väg / verkstad / utrangerad — datamodellen har ingen plats-kolumn), aktuell/nästa bokning med NAMN, instans-drift in_stock ↔ maintenance/→ retired med If-Match (409 invalid_transition, 412 stale_version annonserade), inventarie-tidslinjen och beläggnings-heatmapen renderad ur rapport-endpointens serie med talet i varje cell (färg aldrig enda signalen). Bokningskön: *Att packa* + *Väntade returer* hållna färska av SSE-strömmen genom transportens requestEventStream med synligt anslutningsläge och ärlig ?mode=snapshot-fallback (aldrig new EventSource, aldrig attrapp-"live"), per-rental-kort med hyresgäst-namn/betalmärke/depositions-LÄGE, och driftstegen packa · registrera frakt · inspektera (skadefri ⇒ returned + serverns depositions-släpp, skada/saknade ⇒ damage_pending) · stäng (409 damage_unresolved) · avboka. Skadeärende-inkorgen: §5b-statusfilter som serverfrågor, utestående kostnad ur serverns tal, detalj med foton, ansvarig orgnod med namn (NULL ⇒ rotnivå-klartexten), charged_minor/reversed_minor och PL-fälten charge_payment_id/dispute_request_id, skapa-rapport med foton genom medie-sömmen (grant → uppladdning → commit), charge med klartext före/efter (tom kropp, mekanisk fördelning) och bestridningsbeslutet med UTSKRIVEN semantik (*"Bifall bestridningen (pengarna går tillbaka till hyresgästen)"* / *"Avslå (debiteringen står fast)"*) där återbetalningen aldrig utlovas innan equipment_deposit_sweep verkställt den. Rapporten: månads-/årsintäkt per kit-typ, särredovisad skadeintäkt, beläggningsgrad, antal bokningar, årsval och ärligt tomläge — ingen fabricerad "Mål"-rad. Custody-överriden: seriesök → HELA kedjan över tenant-gränsen med nodNAMN (läs-endast, append-only), force-return med obligatorisk reason_note + bekräftelsesteg och ärligt idempotens-kvitto (*"ingenting utfördes"*) — ingen generell custody-flytt för PL (D-15) — a4875234.m-7.t-2

    ✅ a4875234.m-7.t-2 · specs/admin/views/uthyrningsdrift.md
  • F11.15.31 Shipped

    Ärlig m-7-gräns (inget fabricerat) — och D-EQUIP:s stängning — driftytan myntar inga egna depositions-åtgärder (capture/release/refund ägs av charge-flödet, inspektionen och svepet), gör ingen kit-katalog-redaktion i UI, har ingen export/print/BI ur rapporten, ingen BILL-/bokföringsyta (verifikat, konton, moms och SIE ägs av BILL i tenant-noll-böckerna) och ingen generell custody-flytt. web/, sys/, app/ och www/ rörs inte. Kvarvarande kandidater för ett senare härdnings-svep/ägarbeslut: appens fast-track-namnfallback (m-6 increment §5.5), export/print och kit-katalog-redaktion. m-6:s bokförda ⊘-gap är STÄNGT: bestridningens happy path (bifall ⇒ svep ⇒ reversed_minor > 0) är maskinbevisad i L4-drivrutinen tools/gate/dequip-m7-admin-e2e.mjs (descriptor 920-dequip-m7-admin.mjs) — a4875234.m-7.t-2

    ✅ a4875234.m-7.t-2