# Kraków bez barier A PWA that tells wheelchair users and parents with strollers whether a place or route in Kraków fits **their** limits, and shows how we know: every fact carries a source, a date and a reliability level. Missing data is never shown as "accessible". Prototype for the "Kraków bez barier" hackathon challenge. Demo area: Old Town, Kazimierz, Wawel. ## Run ```bash pnpm install pnpm dev # or: pnpm build && pnpm preview pnpm test # unit tests (parsing, verdicts, routing, reach, moderation) pnpm smoke # end-to-end flows against `pnpm preview` on :4173 pnpm a11y # axe-core WCAG 2.2 AA scan of every main view pnpm data:build # re-fetch OSM + ZTP data into public/data/kk-snapshot.json ``` Demo sign-in has no passwords: pick **Anna** (wheelchair), **Piotr** (stroller) or **Maria** (city official, unlocks the City panel). Everything is stored in the browser, per account. ## What it does | For residents and visitors | For city staff (role "Pracownik urzędu") | | --- | --- | | Guided profile: persona, equipment presets, limits with plain-language hints and tooltips, live preview of how many places fit | Data-quality KPIs computed from open sources, no database kept by the city | | Fit report per place (entrance, steps, ramp/lift, width, surface, toilet, benches, baby changing) | Gaps by place type; operator-feed gap for transit stops | | Step-free routing that avoids steps, high kerbs, steep and narrow sections, optionally cobbles; text route and barrier list | "Fix first" ranking of crossings with high or unknown kerb height, weighted by places served | | Barrier-free reach: what you can get to in 5/10/15 min | Report moderation queue: approve → "verified by the city office" | | Printable access card per place | Anonymous demand signals: where people look but data is missing | | Report a correction (kept apart from OSM data, marked unverified) | CSV / GeoJSON export of the computed data | | Saved places, text size, high contrast, reduced motion, PL/EN | | ## Routes, guidance and evidence - **Route options:** the shortest path comes first (difficulties counted, not avoided), then variants that trade extra distance for fewer difficulties. Each shows distance, time, overhead vs shortest, and counts of barriers / cautions / unknown points; the best one is flagged "Recommended" and others are drawn faintly on the map. - **Guide me:** live GPS guidance with turn prompts and barrier warnings at the top (optional voice, screen kept awake, off-route re-routing). "Simulate GPS" walks the route for demos. Or hand the route to Google Maps / Apple Maps: waypoints along our route keep their path close to ours, but those apps do not know the user's limits. - **Map layers:** street map or satellite (Esri World Imagery; check its terms before production use). - **Report evidence:** photo (EXIF stripped, downscaled), slope measured with the phone's tilt sensors, kerb height measured on the photo against a reference object (card / A4 / ruler), or typed in. **LiDAR is not reachable from a web app** (no LiDAR or WebXR on iOS Safari); `Measurement.method = 'lidar'` is reserved for a native iOS companion. - **Automatic first look:** on-device CLIP zero-shot (free, private, no API key) labels the photo; rules combine it with the claim and measurement into validity, consistency, severity and a triage lane (fast-track / review / likely reject). It only orders the city queue. If the model cannot load the app says "No Credits left". Hosted free vision APIs need a key (Pollinations anonymous is text-only), so none are wired in. ## Data and honesty rules - **OpenStreetMap** (ODbL) via Overpass: places, steps, ramps, kerbs, surfaces, benches, toilets. - **ZTP Kraków GTFS** (`stops.txt`, `wheelchair_boarding`): 82 stops in the area. The operator's field says "no information" for **all** of them; OSM contributors describe 44. The app shows both and the City panel points at the gap. Licence of the ZTP feed must be confirmed at otwartedane.um.krakow.pl before reuse. - Reliability levels: `verified` (survey date ≤ 24 months, or approved by the city office) · `mapped` (OSM edit ≤ 24 months) · `stale` (older) · `inferred` (from nearby objects) · `user` (unverified report) · `none`. The date shown is the last OSM edit of the object unless a survey date exists, so we never call edit-date data "confirmed". - Absence of data → "No data". User report vs OSM disagreement → "Conflicting data" with both sides shown. Refresh failure → last snapshot date plus a warning (demo switch in *Data → Demo controls*). - Four fictional places and three sample reports are labelled **DEMO** and can be hidden in Settings. ## Architecture ``` scripts/build-data.mjs adapters: Overpass (OSM) + GTFS (ZTP) → public/data/kk-snapshot.json src/lib/osm.ts tag interpretation (surface, incline, width, kerb) src/lib/assess.ts fact model {status, source, confidence, date} + verdict per profile src/lib/route.ts A* over the pedestrian graph, profile-aware penalties src/lib/reach.ts time-limited Dijkstra for barrier-free reach src/lib/civic.ts city-panel aggregates, hotspot ranking, export src/components/* USWDS 3 UI; MapView = MapLibre GL (raster OSM tiles) ``` Acquisition and presentation are separate: a new source is a new adapter producing the same fact shape; a new city is a bounding box in `build-data.mjs` plus its adapters. Configuration lives in code constants today; moving it to a per-city JSON is the first scaling step. ## Business model and go-live (proposal) - Free for residents. Revenue from B2B: venue accessibility widget/report for hotels, event organisers and property managers; accessibility API for booking and travel apps; roll-out package for other cities. - Owner of the product: the operating entity (not UMK). Costs: static hosting, scheduled Overpass/GTFS pulls, report moderation. - Month-one launch: host static build + nightly data job; real SSO for staff; server-side reports with rate limiting and two-person confirmation before pushing to OSM; replace OSM tile server with a paid or self-hosted tile provider; confirm every dataset licence. ## Privacy and security No accounts on a server, no analytics, no health questions — only barrier preferences. Profile, saved places and reports are in `localStorage`. Geolocation (optional) never leaves the browser. HTTPS only. The demo sign-in is not security: it only selects a local profile and role. ## Accessibility status Target WCAG 2.2 AA. Automated: axe-core finds 0 violations on login, places, place detail, route, profile, City panel, data pages (`pnpm a11y`). Built in: full keyboard operation, focus management on view changes, information never by colour alone, tooltips dismissible with Esc, text size and contrast settings, text equivalents for map content. **Known limits:** choosing a place by clicking a map pin is not keyboard accessible (use the list); no manual screen-reader pass on every platform yet; high-contrast mode is basic. ## Known limitations Demo area only. Reports and moderation are local to one browser. Kerb height is known for only part of the crossings and entrance width is almost never mapped. Walking times are estimates. Routing ignores traffic lights and temporary obstacles. OSM tile servers are for demos only.