110 lines
7.3 KiB
Markdown
110 lines
7.3 KiB
Markdown
# 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.
|