Venues & Facilities
118 features · 12 subsystems
Management of boulodromes, courts, and facilities. Covers venue registration, court booking, maintenance, and homologation.
Venue Registry
F07.01- 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- 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- 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### 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- 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- 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.07Structured 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.08Den 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.09Spelarens 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.10Två 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)
No features match your filters.