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

Venues & Facilities

118 features · 12 subsystems

Management of boulodromes, courts, and facilities. Covers venue registration, court booking, maintenance, and homologation.

Venue Registry

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

    Venue/boulodrome registration (name, address, GPS coordinates)

    ✅ PL-F0701a
  • F07.01.02 Shipped

    Venue profile (photos, description, capacity, amenities)

    ✅ PL-F0701a
  • F07.01.03 Shipped

    Court inventory per venue (number, type, surface, indoor/outdoor, lighting)

    ✅ PL-F0701a
  • F07.01.04 Shipped

    Venue ownership/management (club_id reference)

    ✅ PL-F0701a
  • F07.01.05 Shipped

    Venue search/directory (by location, capacity, facilities)

    ✅ PL-F0701a
  • F07.01.06 Shipped

    Map-based venue finder with geo-search (lat/lng/radius via Haversine)

    ✅ PL-F0701b
  • F07.01.07 Shipped

    Venue rating and reviews

    ✅ PL-F0701b
  • F07.01.08 Shipped

    Venue accessibility information (wheelchair, parking, toilets, hearing loop)

    ✅ PL-F0701b
  • F07.01.09 Shipped

    Opening hours management

    ✅ PL-F0701b
  • F07.01.10 Shipped

    Venue contact (phone, email, website) — social media links via separate feature

    ✅ PL-F0701b
  • F07.01.11 Shipped

    Venue archive lifecycle (status='archived' + archived_at, re-activation clears it): blocks new bookings/series/allocations (409 venue_not_active), invisible on every public surface, visible in the admin list only via ?status=archived. Distinct from soft delete.

    ✅ D-VENUE c03bd31a.m-1 (api/db/migrations/00121_dvenue_m1_delta.sql, api/internal/http/venues.go)

Court Management

F07.02
Planned
How it works
  • F07.02.01 Shipped

    Court numbering and configuration

    ✅ PL-F0702
  • F07.02.02 Shipped

    Court dimensions and surface type tracking

    ✅ PL-F0702
  • F07.02.03 Shipped

    Court status (real-time via bookings, allocations, and maintenance — /venues/{id}/courts/status)

    ✅ PL-F0702
  • F07.02.04 Shipped

    Court allocation during competitions (allocate/confirm/release courts per competition session)

    ✅ PL-F0702
  • F07.02.05 Shipped

    Court condition reporting (file reports with severity, category, images; resolve and link to maintenance)

    ✅ PL-F0702
  • F07.02.06 Shipped

    Maintenance scheduling and logging (full lifecycle: scheduled → in_progress → completed, cost tracking)

    ✅ PL-F0702
  • F07.02.07 Shipped

    Court lifecycle — retire a court (courts.status = active\

    retired, PATCH /v1/venues/{id}/courts/{number}). A retired court refuses new bookings/walk-ins/self-bookings/allocations/new series (409 court_retired), is skipped by the recurring expansion, is omitted from public availability and shows as its own state on the admin board; retiring a court with future non-cancelled bookings is refused (409 court_has_future_bookings). "Delete court" is expressed as retire — existing bookings are never orphaned. | ✅ D-VENUE c03bd31a.m-1 (backend: api/db/migrations/00121_dvenue_m1_delta.sql, api/internal/http/venues.go, api/internal/http/bookings.go)
  • F07.02.08 Shipped

    Allocation actor stamp (court_allocations.allocated_by, server-side from the authenticated actor, never client-settable)

    ✅ D-VENUE c03bd31a.m-1
  • F07.02.09 Shipped

    Condition-report resolution stamps (court_condition_reports.resolved_by + the now-exposed resolved_at, both stamped server-side from the authenticated actor on resolve, both nulled on re-open — a resolved_by in the request body is ignored by construction, no-idor)

    ✅ D-VENUE c03bd31a.m-2 (backend: api/db/migrations/00122_dvenue_m2_delta.sql, api/internal/http/maintenance_reviews.go)
  • F07.02.10 Shipped

    Completion side-effect: a maintenance record transitioning to completed resolves its linked UNRESOLVED condition reports in the SAME transaction (stamped with the completing actor, one audit row per report; already-resolved reports untouched; cancelled resolves none). The response carries auto_resolved_report_ids.

    ✅ D-VENUE c03bd31a.m-2 (backend)
  • F07.02.11 Shipped

    Condition-report photo path — POST /v1/venues/{id}/condition-report-photos (multipart photo, ≤ 5 MB, PNG/JPEG/WebP magic-byte-validated → 413 photo_too_large / 415 unsupported_media_type) returning a served URL that lands in the report's images[], plus the capability-gated GET …/condition-report-photos/{pid} byte serve

    ✅ D-VENUE c03bd31a.m-2 (backend: api/internal/http/maintenance_photos.go)

Booking System

F07.03
Planned
How it works
  • F07.03.01 Shipped

    Court reservation (time slot per court with overlap detection + allocation cross-check)

    ✅ PL-F0703a
  • F07.03.02 Shipped

    Booking calendar with availability view (public endpoint, includes allocations)

    ✅ PL-F0703a
  • F07.03.03 Shipped

    Recurring bookings (weekly/biweekly/monthly series with conflict-aware expansion)

    ✅ PL-F0703a
  • F07.03.04 Shipped

    Competition court blocking (allocations block regular bookings and recurring series)

    ✅ PL-F0703a
  • F07.03.05 Shipped

    Booking payment integration (fee, currency, payment_status, invoice_id; auto-confirm on payment)

    ✅ PL-F0703b
  • F07.03.06 Shipped

    Booking confirmation (confirmed_at timestamp, explicit /confirm endpoint for pending bookings)

    ✅ PL-F0703b
  • F07.03.07 Shipped

    Walk-in vs. reservation management (booking_type: reservation\

    walk_in, /walk-in endpoint, filter by type) | ✅ PL-F0703b
  • F07.03.08 Shipped

    Cancellation (DELETE + POST /cancel with reason, cancelled_at, cancelled_by, cancellation_reason)

    ✅ PL-F0703b
  • F07.03.09 Shipped

    Player self-service booking (POST /v1/venues/{id}/bookings/self, capability self.venues.bookings.write on the player role): booked_by = the caller, booking_type=reservation, source=app, guest tariff from court_pricing, all staff guards apply

    ✅ D-VENUE c03bd31a.m-1 (api/internal/http/bookings.go)
  • F07.03.10 Shipped

    Player self-service cancellation of one's OWN booking (someone else's → 404; no force escape past the deadline — force stays staff-only)

    ✅ D-VENUE c03bd31a.m-1
  • F07.03.11 Shipped

    Idempotent booking creation (Idempotency-Key on booking / walk-in / self-booking / allocation POSTs — replay returns the same resource with Idempotency-Replayed: true, exactly one row)

    ✅ D-VENUE c03bd31a.m-1 (F1-5 primitive)

Homologation

F07.04
Planned

### Restricted-facility access (F22.04.20–22, delivered here by D-VENUE m-3)

How it works
  • F07.04.01 Shipped

    Venue homologation request (for hosting official competitions)

    ✅ PL-F0704
  • F07.04.02 Shipped

    Inspection checklist (court dimensions, surface, lighting, facilities)

    ✅ PL-F0704
  • F07.04.03 Shipped

    Homologation certificate management

    ✅ PL-F0704
  • F07.04.04 Shipped

    Homologation level (club, regional, national, international)

    ✅ PL-F0704
  • F07.04.05 Shipped

    Renewal and re-inspection scheduling

    ✅ PL-F0704
  • F07.04.06 Shipped

    Venue requirement profiles per competition level — configurable per tenant: each competition level defines required venue capabilities (Sweden int.: centercourt 300+ seats, PA, catering, first aid; Sweden reg.: marked courts, scoring boards, secretariat). System auto-validates venue meets requirements when competition is assigned at approval time.

    ✅ PL-F0704
  • F07.04.07 Shipped

    Certificate PDF — GET /v1/venues/homologations/{hid}/certificate.pdf renders the real certificate (boulodrome, level, certificate number, issued/valid-until) as a printable PDF; a non-approved homologation is 409 homologation_not_approved.

    ✅ D-VENUE m-3
  • F07.04.08 Shipped

    Renewal reminder tick — the idempotent homologation_renewal_reminder_tick job stamps renewal_scheduled_at + an audit row on approved homologations whose certificate expires within 90 days (the data behind the admin renewal banner + renewals-due). No notification is sent — the channel is D-COMM's.

    ✅ D-VENUE m-3
  • F07.04.09 Shipped

    Renewal supersedes the previous certificate — approving a renewal expires every other approved homologation for the same (venue, level) inside the decision transaction (one audit row each), so exactly one approved certificate per level exists.

    ✅ D-VENUE m-3
  • F07.04.10 Shipped

    Certificate invariant on ALL decision paths — the F1-6 venue_homologation OnApprove hook refuses a cert-less approval (422 homologation_certificate_required, whole decision rolled back), including the generic Ärenden inbox approve.

    ✅ D-VENUE m-3
  • F22.04.20 Shipped

    Restricted-facility configuration — a venue inside a restrictive host organisation (military/school/civic/corporate/religious): host organisation, host-admin + security-officer allow-lists (displayed config), government-clearance flag + authority, access hours per weekday (UTC), manifest requirement, host-operations calendar reference (stored metadata only — no external iCal fetch in m-3). CRUD with ETag/If-Match + audit; /v1/venues/restricted-facilities.

    ✅ D-VENUE m-3
  • F22.04.21 Shipped

    Capability-gated approval chain via F1-6 (request_type=venue_access): host admin → security officer → conditional government clearance, per-step capability, 24h expiry (F1-6's own expiry tick), self-approval protection (403 approval_self_decision_denied). The LAST approval creates a real court_booking in the decision transaction; a host-operations clash rolls the whole decision back (409 host_operations_conflict). Decisions happen in the Ärenden inbox — the domain ships no decision facade.

    ✅ D-VENUE m-3
  • F22.04.22 Shipped

    Access log + per-facility audit view — append-only checkin/checkout/access_denied events with a SERVER-stamped actor (a body actor_id is ignored), only on an approved request; GET …/{rfid}/audit returns the requests newest-first with the chain's steps and the access log.

    ✅ D-VENUE m-3
  • F22.04.30 Planned

    Shared-facility mirroring across tenants (shared_facility_owner_tenant_id) — D-CHAIN/D-BRASSERIE, deliberately out of scope for D-VENUE m-3.

    ⛔ not here

Bar/Buvette Management

F07.05
Planned
How it works
  • F07.05.01 Shipped

    Buvette inventory management (CRUD, stock adjustments with audit trail, low-stock filter, SKU/barcode)

    ✅ PL-F0705
  • F07.05.02 Shipped

    Point-of-sale integration (transactions, multi-payment-method, line items, auto-stock-deduction, void/refund)

    ✅ PL-F0705
  • F07.05.03 Shipped

    Revenue tracking per event (event-scoped transactions, revenue summary with payment method breakdown)

    ✅ PL-F0705
  • F07.05.04 Shipped

    Volunteer shift scheduling for buvette (planned→confirmed→in_progress→completed lifecycle, check-in/out, auto-hours)

    ✅ PL-F0705
  • F07.05.05 Shipped

    License/permit tracking (alcohol license, food hygiene, fire safety, renewal, compliance check, expiry alerts)

    ✅ PL-F0705
  • F07.05.06 Shipped

    Z-report / dagsavslut (immutable daily close, cash reconciliation, payment method & VAT breakdown, archive PDF)

    ✅ PL-T077
  • F07.05.07 Shipped

    Automatic COGS booking (Cost of Goods Sold from inventory unit_cost, batch at Z-report close or realtime per transaction)

    ✅ PL-T077
  • F07.05.08 Shipped

    Stock adjustment accounting (waste/breakage/theft → expense accounts, consolidated at Z-report close)

    ✅ PL-T077

Court Booking & Occupancy

F07.06
Planned
How it works
  • F07.06.01 Shipped

    Per-court booking with calendar (per-court time slots, calendar view, date/court filtering, public availability endpoint)

    ✅ PL-F0706a
  • F07.06.02 Shipped

    Recurring bookings (weekly/biweekly/monthly series with conflict-aware expansion, cancel propagation)

    ✅ PL-F0706a
  • F07.06.03 Shipped

    Price per court and hour (court-specific pricing with default fallback, auto-calculation from venue config)

    ✅ PL-F0706a
  • F07.06.04 Shipped

    Member price vs guest price (booker_type: member\

    guest, differentiated rates, auto-applied pricing) | ✅ PL-F0706a
  • F07.06.05 Shipped

    Cancellation with deadline (venue cancellation policy, deadline enforcement, late fees, force cancel option)

    ✅ PL-F0706a
  • F07.06.06 Shipped

    No-show registration with cost (POST /no-show, fee from cancellation policy no_show_fee_percent, blocks if checked in)

    ✅ PL-F0706b
  • F07.06.07 Shipped

    QR code for court check-in (check_in_token per booking, GET /check-in-token, POST /check-in with token validation)

    ✅ PL-F0706b
  • F07.06.08 Shipped

    Real-time availability (GET /public/venues/{id}/real-time-availability — per-court, per-slot grid with configurable duration)

    ✅ PL-F0706b
  • F07.06.09 Shipped

    Lighting and heating per court (bookable) (court.heating field, amenity surcharges in pricing, validation against court capabilities)

    ✅ PL-F0706b
  • F07.06.10 Shipped

    Live court-status board (SSE, opt-in) — GET /v1/venues/{id}/courts/status/stream (operationId streamCourtStatus): snapshot event first, then status events carrying the whole freshly derived list whenever a booking/allocation/maintenance/court-retire mutation changes it, 15 s heartbeat and a ?mode=snapshot JSON fallback. Same derivation and same authz as the polling route (domain.venues.bookings.read, checked BEFORE the stream header); the polling route is unchanged.

    ✅ D-VENUE c03bd31a.m-2 (backend: api/internal/http/venue_status_live.go)

Venue Accessibility Metadata

F07.07
Planned

Structured accessibility profile attached to `Venue`. Feeds the

  • F07.07.01 Shipped

    AccessibilityFacilityMetadata sub-document (wheelchair entry/courts, parking, restroom, seating, step-free path, ramp, surface, assistance dog, guide assistance, multilingual notes)

    ✅ PL-T220 ✅ PL-T220
  • F07.07.02 Shipped

    Verification stamps (metadata_verified_at, metadata_verified_by) + admin edit flow + audit trail

    ✅ PL-T220 ✅ PL-T220
  • F07.07.03 Shipped

    Public accessibility detail view (/venues/{id}/accessibility) consumed by adapted-competition discovery

    ✅ PL-T220 ✅ PL-T220

Admin-yta: Anläggningar (admin, D-VENUE m-1)

F07.08

Den tenant-bundna operatörsytan för anläggningarna: `admin/app/anlaggningar/`

  • F07.08.01 Shipped

    Anläggningsregister (/anlaggningar) — server-side filter på status/typ/underlag/sök; default-listan döljer arkiverade, ?status=archived hittar dem; riktiga fält (härlett court_count, kapacitet, ägande OrgNod); registrera ny anläggning (POST /v1/venues med namn/typ/underlag/adress/position/kapacitet/ägande OrgNod → profilen öppnas direkt)

    ✅ D-VENUE c03bd31a.m-1 (t-2)
  • F07.08.02 Shipped

    Venue-profil (/anlaggningar/{id}) — grunddata, adress, position (läsvärde), kapacitet, beskrivning, ägande/kontakt, faciliteter, bilder, öppettider, avbokningspolicy; spara med ETag/If-Match och begriplig 412-återhämtning; arkivera/återaktivera + mjuk borttagning

    ✅ D-VENUE c03bd31a.m-1 (t-2)
  • F07.08.03 Shipped

    Baninventarie (/anlaggningar/{id}/banor) — [nr, namn, mått, underlag, inomhus, belysning, värme, status] + redigera bana (namn/mått/underlag/inomhus/belysning/värme via partiell PATCH …/courts/{number}) + ta ur drift / sätt i drift, med court_has_future_bookings-hindret i klartext

    ✅ D-VENUE c03bd31a.m-1 (t-2)
  • F07.08.04 Shipped

    Bokningskalender (per bana × timme, vald dag) — skapa bokning (bana/tid/taxa/tillval), walk-in (namn + telefon), återkommande serie + occurrence-lista, avbokning med synlig frist och sen-avgift och forcerad avbokning för personal; konfliktkoderna renderas som fältfel

    ✅ D-VENUE c03bd31a.m-1 (t-2)
  • F07.08.05 Shipped

    Beläggnings-/banstatusvy (/anlaggningar/{id}/bandrift) — serverns härledda status per bana vid vald tidpunkt (GET …/courts/status?at=), inkl. banor ur drift

    ✅ D-VENUE c03bd31a.m-1 (t-2)
  • F07.08.06 Shipped

    Allokeringsvy — lista/skapa/bekräfta/släppa/avbryta tävlingsallokeringar, tävlingen väljs vid namn ur GET /v1/competitions (id-fält bara som ärlig reserv för roller utan tävlingsbehörighet), tävlingsnamnet visas i tabellen, allocated_by synlig, konfliktvarning mot befintliga bokningar före submit + 409-rendering

    ✅ D-VENUE c03bd31a.m-1 (t-2)
  • F07.08.07 Shipped

    Banskick-fliken (/anlaggningar/{id}/bandrift) — felrapporter med server-side-filter (bana/allvarsgrad/kategori/löst), riktiga fält (bana, fel, kategori, allvarsgrad, rapportör, tidpunkt, foto), lös (visar resolved_at/resolved_by-stämpeln som servern satte), öppna igen, schemalägg underhåll ur rapporten (för-ifyller bana/titel/länk), synlig koppling rapport↔underhåll och ett äkta tomt-läge ("Inga olösta banskick-rapporter"); rapportformuläret bär alla kontraktsfält inkl. riktig fotouppladdning

    ✅ D-VENUE c03bd31a.m-2 (t-2)
  • F07.08.08 Shipped

    Underhålls-fliken — lista med filter (status/typ), kostnader renderade ur *_minor-heltal, schemaläggningsformulär (banor, typ, titel, beskrivning, datumfönster, ansvarig, estimerad kostnad + valuta, länka felrapport) och en stepper scheduled → in_progress → completed/cancelled där avslutssteget frågar efter faktisk kostnad och synliggör vilka länkade rapporter servern auto-löste (auto_resolved_report_ids); otillåten övergång renderas som fältfel (422)

    ✅ D-VENUE c03bd31a.m-2 (t-2)
  • F07.08.09 Shipped

    Banstatustavlan kompletterad — under_maintenance renderas med egen färgkod och text, och ett opt-in live-läge konsumerar SSE-strömmen GET …/courts/status/stream (snapshot först så tavlan aldrig är tom, synligt anslutningsläge, återanslutning med backoff + snapshot-polling under tappet); tidpunkt-väljaren (polling-läget) kvarstår oförändrad

    ✅ D-VENUE c03bd31a.m-2 (t-2)
  • F07.08.10 Shipped

    Underhållsfönster i bokningskalendern (/anlaggningar/{id}/banor) — ett schemalagt/pågående fönster visas som blockerad bana med den kanoniska maintenance-token (färg + text). Visualisering: API:t avvisar INTE en bokning i fönstret (milstolpens icke-mål 4)

    ✅ D-VENUE c03bd31a.m-2 (t-2)
  • F07.08.11 Shipped

    Tillgänglighetsformulär + ändringslogg (/anlaggningar/{id}) — hela AccessibilityProfile (rullstolsentré, tillgängliga banor, parkering, toalett, åskådarplatser, stegfri väg, ramp, para-vänlig yta, ledarhund, guideassistans) + flerspråkiga noter med locale-nycklar; sparas via PUT …/accessibility med If-Match (412 → begriplig återhämtning, 422 invalid_locale som fältfel), verifieringsstämpeln (metadata_verified_at/_by) syns efter sparning, och ändringsloggen läses ur den befintliga audit-ytan filtrerad på action=venue.accessibility.set + venue. Profilen matar den publika tillgänglighetsvyn och para-/anpassad discovery (BR32)

    ✅ D-VENUE c03bd31a.m-2 (t-2)

App-yta: Boka bana (`app`, D-VENUE m-1)

F07.09

Spelarens bokningsflöde i Expo/RN-appen på blueprint-routen **`/app/bokning`**

  • F07.09.01 Shipped

    Hitta bana — publik geo-katalog (GET /public/venues?lat&lng&radius) med enhetens position (expo-location, nekad position degraderar förklarat), fritextsök, radieval, avstånd ur API:ts distance_km, faciliteter och riktigt tomt-läge

    ✅ D-VENUE c03bd31a.m-1 (t-3)
  • F07.09.02 Shipped

    Boka bana — dag/bana/tidslucka ur EN availability-läsning per bana och dag (…/availability?date=) plus realtidsstatus (…/real-time-availability); tillval belysning/värme; skapande via självbetjänings-rutten POST …/bookings/self med Idempotency-Key (aldrig personalens POST …/bookings); konfliktkoderna (court_double_booked, court_retired, amenity_unavailable, venue_not_active) i klartext

    ✅ D-VENUE c03bd31a.m-1 (t-3)
  • F07.09.03 Shipped

    Mina bokningar — GET /v1/me/venue-bookings (kommande + tidigare) med bekräftelse-/betal-/no-show-/incheckningsstatus, avgift ur *_minor-heltal, synlig avbokningsfrist och egen avbokning (ingen force-utväg för spelaren, FR-B2)

    ✅ D-VENUE c03bd31a.m-1 (t-3)
  • F07.09.04 Shipped

    QR-incheckning offline — GET …/check-in-token cachas VID hämtningen (AsyncStorage: persistent på native, localStorage-backad på Expo Web) och ritas LOKALT som QR (qrcode-generator + react-native-svg); utan nät visas den cachade koden med ett ärligt offline-besked; incheckning via POST …/bookings/check-in

    ✅ D-VENUE c03bd31a.m-1 (t-3)
  • F07.09.05 Shipped

    Personal-walk-in (BR12) — namn + telefon på vald bana/tid via POST …/bookings/walk-in; ytan är capability-gated på domain.venues.bookings.write och är helt frånvarande för en aktör utan den (deny-by-default)

    ✅ D-VENUE c03bd31a.m-1 (t-3)
  • F07.09.06 Shipped

    Rating-läge — medelbetyg och antal omdömen ur GET /public/venues/{slug}/rating-summary, både på anläggningskortet i Hitta-fliken och i den valda anläggningens rubrikrad; en anläggning utan omdömen visar "Inga omdömen ännu", aldrig 0★

    ✅ D-VENUE c03bd31a.m-1 (t-3)
  • F07.09.07 Shipped

    Katalogfilter — chipen Inomhus (has_indoor), Belysning / Parkering / Servering (facilities) filtrerar via den publika katalogens EGNA parametrar, inte lokalt i klienten

    ✅ D-VENUE c03bd31a.m-1 (t-3)
  • F07.09.08 Shipped

    Registrera drop-in-resultat (prototypens sub-flik "Drop-in results") — se F07.12.2. Betalsteget ("Book & pay") levererades i m-4 (F07.11).

    ✅ D-VENUE c03bd31a.m-5 (t-2)
  • F07.09.09 Shipped

    Banskick-snabbrapport från banan (personaldelen av /app/bokning, spec-beslut B-3 — ingen egen blueprint-route): välj boulodrome + bana ur riktig API-data, kategori och allvarsgrad, titel/beskrivning, bifoga foto (multipart via den delade transportens requestMultipart → API-serverad URL i rapportens images[], aldrig en data-URL) och skicka via POST …/condition-reports. Ytan är capability-gated på domain.venues.maintenance.write och är helt frånvarande för en aktör utan den (deny-by-default); 409 court_unknown/403 renderas i klartext

    ✅ D-VENUE c03bd31a.m-2 (t-2)

Admin-yta: Homologering & skyddade anläggningar (admin, D-VENUE m-3)

F07.10

Två admin-ytor ovanpå m-3:s backend-delta (F07.04.07–10 + F22.04.20–22):

  • F07.10.01 Shipped

    Homologeringslista + statusflöde (/homologering) — statusremsan requested → submitted → under_review → approved · rejected · expired, listan med Boulodrome / Nivå / Status / Certifikat / Giltigt till och server-side nivå- och statusfilter (GET /v1/venues/homologations?level=&status=), expanderbar raddetalj (certifikatstämplar, förnyelsepåminnelse, checklista, kopplat ärende) och ett äkta tomt-läge ("Skapa kravprofiler per nivå först …")

    ✅ D-VENUE c03bd31a.m-3 (t-2)
  • F07.10.02 Shipped

    Förnyelse-banderoll ur GET …/renewals-due — anläggning, nivå, utgångsdatum och om FR-A1-ticken hunnit stämpla renewal_scheduled_at; banderollens "Förnya" startar förnyelseansökan

    ✅ D-VENUE c03bd31a.m-3 (t-2)
  • F07.10.03 Shipped

    Certifikat-PDF ur listan — radaktionen finns bara på en approved rad och laddar ner den RIKTIGA PDF:en (GET …/{hid}/certificate.pdf via requestBlob); 409 homologation_not_approved renderas som fel-kort i klartext

    ✅ D-VENUE c03bd31a.m-3 (t-2)
  • F07.10.04 Shipped

    Ansökan & inspektion — Boulodrome-väljare, nivå, "Återinspektion / förnyelse av"-väljare, kryssbar inspektionschecklista (sparas som inspection_checklist jsonb), certifikatfält med hjälptexten att de krävs vid godkännande, och "Skicka in för inspektion" (POST → ev. cert-PATCH → PATCH status=submitted, allt med Idempotency-Key/If-Match). 409 homologation_active_exists renderas som mockupens Error-kort i klartext

    ✅ D-VENUE c03bd31a.m-3 (t-2)
  • F07.10.05 Shipped

    Checklist-arv vid förnyelse (P-11/FR-A2) — "förnya" (radaktion eller banderoll) förifyller anläggning, nivå och checklistan KLIENT-side ur föregående homologerings inspection_checklist; ingen ny kolumn, ingen serverändring

    ✅ D-VENUE c03bd31a.m-3 (t-2)
  • F07.10.06 Shipped

    Kravprofil-editor per tävlingsnivå — nivåväljare, namn, aktiv-flagga, beskrivning och radeditor för requirement_key / validation_type (min_value\

    max_value|boolean|enum_set) / required_value med lägg till + ta bort rad; sparas med If-Match (412 stale_version i klartext) mot POST/PATCH /v1/venues/requirement-profiles, detaljläsningen via FR-A5-rutten | ✅ D-VENUE c03bd31a.m-3 (t-2)
  • F07.10.07 Shipped

    Auto-valideringsvy — POST /v1/venues/{id}/validate-requirements?competition_level= per vald anläggning + nivå: pass/fail per requirement_key med serverns BERÄKNADE värde och fail-förklaringen ("Faller på …"). Samma kontrakt D-COMP anropar vid tävlingstilldelning (SEAM-5) — vyn är konsument, inte en kopia av regeln

    ✅ D-VENUE c03bd31a.m-3 (t-2)
  • F07.10.08 Shipped

    Skyddade anläggningar: översikt (/anlaggningar/skyddade) — tabellen Anläggning / Typ (chip) / Sökande / Godkännandekedja / Status med en rad per åtkomstansökan (konfigurerad anläggning utan ansökningar visas ändå), kedje-förklaringen (host_admin → security_officer → ev. myndighetsklarering, självgodkännande-skydd, 24h-expiry) och ett äkta tomt-läge

    ✅ D-VENUE c03bd31a.m-3 (t-2)
  • F07.10.09 Shipped

    Facilitets-konfig — restriktionstyp, värdorganisation, host-admin- och säkerhetsansvarig-listor (lagrad konfig som dokumenterar vem som förväntas besluta, beslut B-4), myndighetsklarering på/av + myndighetsnamn, åtkomsttider per veckodag (lägg till/ta bort fönster), manifest-krav och kalender-referens; skapa (POST) + spara (PATCH med If-Match), 422-fältfel och 412 stale_version i klartext

    ✅ D-VENUE c03bd31a.m-3 (t-2)
  • F07.10.10 Shipped

    Åtkomstansökan — syfte, bana, datum + tidsfönster, deltagarantal och manifest-referens; POST …/requests med Idempotency-Key. 422 outside_access_hours och manifest-felet renderas som begriplig text (ingen rad skapas), och ansökan syns direkt i listan med F1-6-kedjans stegstatus

    ✅ D-VENUE c03bd31a.m-3 (t-2)
  • F07.10.11 Shipped

    Kedjevy + åtkomstlogg per ansökan — F1-6-stegen (steg, behörighet, beslutsläge) ur GET …/{rfid}/audit samt loggen Tid / Vem / Händelse där access_denied är markerad med både färg, ikon och text; checkin/checkout/access_denied loggas via POST …/access-log (aktören stämplas server-side) och bara på en godkänd ansökan (409 i klartext)

    ✅ D-VENUE c03bd31a.m-3 (t-2)
  • F07.10.12 Shipped

    Ärenden-etiketter (FR-C2) — venue_homologation/venue_access visas med svensk typ-etikett i inboxen och detaljvyn, och ett misslyckat beslut visar serverns egen detail (t.ex. 422 homologation_certificate_required) plus en domänhjälp med länk till rätt admin-yta i stället för ett tomt "okänt fel"

    ✅ D-VENUE c03bd31a.m-3 (t-2)

Venue-medlemskap, betalning & gästregister (admin + app, D-VENUE m-4)

F07.11

**Status:** LEVERERAD (milstolpe `c03bd31a.m-4`) — backend i task t-1, admin- och app-ytorna

  • F07.01.12 Shipped

    Publik katalog per tenant — GET /public/venues?tenant=<kod> avgränsar geo-katalogen till EN tenants venues (white-label-sajten visar bara sin egen federations/klubbs anläggningar). Okänd kod ⇒ tom lista, aldrig 404 och aldrig den ofiltrerade katalogen (ingen existens-läcka). Utan parametern är katalogen fortsatt cross-tenant (D-DISC).

    D-VENUE c03bd31a.m-5 (api/internal/http/venues.go, api/internal/store/venue.go)
  • F07.01.13 Shipped

    Publika ytor är active-only — katalogen och GET /public/venues/{slug} exkluderar nu closed, under_maintenance OCH archived (tidigare bara closed/archived resp. archived). Den authed admin-läsningen är oförändrad.

    D-VENUE c03bd31a.m-5
  • F07.01.14 Shipped

    Operatörssvar på recension — venue-admin publicerar ETT publikt svar per recension (PUT/DELETE /v1/venues/{id}/reviews/{rid}/response, capability domain.venues.reviews.respond, ETag/If-Match). Ett andra svar är omöjligt på datanivå (unique (tenant_id, review_id) ⇒ 409 review_response_exists, håller även under samtidighet). Svaret syns i publika …/reviews som response {body, responded_at}.

    D-VENUE c03bd31a.m-5 (api/internal/http/venue_review_response.go)
  • F07.01.15 Shipped

    Flaggning av recension — POST …/reviews/{rid}/flag {reason} (obligatoriskt skäl) markerar recensionen flagged_under_review publikt. Den döljs inte och rating-summary är oförändrad; flaggan köar recensionen för granskning i admin-listan (som bär flagged + flag_reason). Modererings-BESLUTET (vem avgör, SLA, ev. döljning) är ett senare initiativ.

    D-VENUE c03bd31a.m-5
  • F07.06.09 Shipped

    Casual-matchresultat (casual-results) — POST/GET /v1/venues/{id}/casual-results (capabilities self.venues.casual_results.write

    read, seedade på både player och federation_admin). En spelare eller on-site-personalen registrerar ett spelat drop-in-/house-league-resultat; registreringen emitterar §5d.2 match_completed (source_kind='casual', ranking_eligible=false) mot D-RANK — det casual-ELO-inflöde D-RANK uttryckligen väntat på. Endast deltagare med auth_identity_id bärs i eventet; ett resultat spelat enbart av anonyma walk-in-gäster (BR12) avvisas med 422 casual_result_no_eligible_player (ingen rad, inget event). win_margin härleds alltid server-side och reported_by tas ur token. | D-VENUE c03bd31a.m-5 (api/internal/http/venue_casual_results.go, api/internal/ranking/{sink,performance,ingest}.go)

Publik venue-katalog, drop-in-resultat & recensionsvy (web + app + admin, D-VENUE m-5)

F07.12

**Status:** LEVERERAD (milstolpe `c03bd31a.m-5`) — backend i task t-1 (avsnittet ovan),

  • F07.12.01 Shipped

    Katalog per tenant-sajt — sök (ort/anläggning), radieval, filter typ/storlek/faciliteter mappade mot katalogens EGNA parametrar (search,type,min_courts,min_capacity,facilities) plus tenant=<kod>: sajten visar bara sin egen federations/klubbs boulodromer. Filtren avgörs server-side; ett nollutfall ger ett handlingsbart tomtillstånd ("öka radien …").

    D-VENUE c03bd31a.m-5 (t-2)
  • F07.12.02 Shipped

    Position är valfri — "Använd min plats" (browser-geolocation) eller ort-sök. Avstånd (distance_km) renderas ENDAST när en position faktiskt angavs; utan position visas listan utan avståndspåstående.

    D-VENUE c03bd31a.m-5 (t-2)
  • F07.12.03 Shipped

    Betyg på katalogkortet — medelbetyg + antal ur GET /public/venues/{slug}/rating-summary, läst per renderad anläggning (tak på samtidiga anrop, samma mönster som appens Hitta-lista). Katalograden bär inget användbart rating_average; ett kort som läser den raden skulle påstå "Inga omdömen ännu" om en anläggning som HAR omdömen. Kan summeringen inte läsas visas INGEN betygstext — aldrig ett gissat betyg.

    D-VENUE c03bd31a.m-5 (t-2, granskning iter 1)
  • F07.12.04 Shipped

    Per-venue-sida — profil (namn, typ/yta/adress, beskrivning), öppettider ur opening_hours (bara publicerade dagar), facilitets-chips, antal bokningsbara banor (banor i drift; retired räknas inte), publik tillgänglighetsvy med verifieringsstämpel, rating-summering, recensioner med operatörens publika svar och diskret "under granskning"-markering för flaggade, samt "Boka bana"-CTA som djuplänkar till appens bokningsflöde med anläggningens slug.

    D-VENUE c03bd31a.m-5 (t-2)
  • F07.12.05 Shipped

    Ärliga tillstånd — 404 (anläggningen finns inte publikt: stängd/arkiverad/okänd slug) skiljs från ett läs-/serverfel, som får sitt eget felläge ("Kunde inte hämta anläggningen"). Tillgänglighet, omdömen och betyg degraderar var för sig till sina egna tomtillstånd i stället för att sänka sidan.

    D-VENUE c03bd31a.m-5 (t-2, granskning iter 1)
  • F07.12.06 Shipped

    Self-report av casual-resultat — registreringen skapar en riktig casual_match_result och emitterar §5d.2 match_completed (casual-ELO-inflödet). Spelarens EGEN kontoidentitet förifylls i lag A; medspelare/motståndare utan konto skrivs som fria namn och bär ingen ranking (BR12). win_margin skickas aldrig från klienten — servern härleder det.

    D-VENUE c03bd31a.m-5 (t-2)
  • F07.12.07 Shipped

    Egen identitet också i webb-sessionen — auth_identity_id tas ur JWT-claimen när den finns (native) och annars ur self-ytan GET /v1/me. Webb-/Expo-web-sessionen är cookie-baserad med TOM token, så en ren claim-läsning gav sub = null och gjorde formuläret obrukbart på webben.

    D-VENUE c03bd31a.m-5 (t-2, L4-fynd)
  • F07.12.08 Shipped

    Idempotens — nyckeln lever per formulär-session och byts först när en registrering FAKTISKT lyckats: dubbeltryck och omtag efter nätfel ger EN rad.

    D-VENUE c03bd31a.m-5 (t-2)
  • F07.12.09 Shipped

    Fel i klartext, inte som toast — 422 casual_result_no_eligible_player, 409 venue_not_active, 403 och valideringsfel renderas på svenska i formulärets egen felyta, med notisen om att bara deltagare med konto räknas i casual-ELO.

    D-VENUE c03bd31a.m-5 (t-2)
  • F07.12.10 Shipped

    Granskningskö — flaggade recensioner ligger överst, markerade "under granskning", med räknare och det INTERNA flaggskälet synligt för operatören (aldrig publikt). Ren list-härledning ur den authed läsningens flagged/flag_reason — inget nytt API.

    D-VENUE c03bd31a.m-5 (t-2)
  • F07.12.11 Shipped

    Svara publikt / redigera / ta bort — ETT svar per recension, med ETag under huven: PUT utan If-Match = skapa (409 review_response_exists när någon hann före), med If-Match = uppdatera (412 stale_version vid konkurrerande ändring). Båda felen i svensk klartext intill kontrollen som orsakade dem — och felrutan står kvar när vyn laddar om sig själv efter en 412.

    D-VENUE c03bd31a.m-5 (t-2; felrutans överlevnad är ett L4-fynd)
  • F07.12.12 Shipped

    Flagga med obligatoriskt skäl — utan skäl blir det ett fältfel, ingen flagga.

    D-VENUE c03bd31a.m-5 (t-2)
  • F07.12.13 Shipped

    Deny-by-default — utan domain.venues.reviews.respond renderas INGA mutationskontroller (läsaren ser omdömena), och API:t svarar 403 på ett direktförsök.

    D-VENUE c03bd31a.m-5 (t-2)