Three-tab shell with header
DoneSocials, Navigate and Schedule tabs with the logo on the left of the header and your avatar on the right, which opens Profile.
ios/FindMyETH/Shell/MainTabView.swiftweb/src/components/Shell.tsx
main is the branch the team agreed on for FindMyETH, Team HELPS' ETH Zurich campus app from VISCon Hackathon 2026: a native iOS app, a web app with an admin console, and a FastAPI backend. This page lists every feature on origin/main at commit 685635f (2026-10-10 16:53 UTC), checked against the code and against docs/TODO.md and docs/DEVIATIONS.md.
The iOS app was written on Linux. At this commit docs/BUILD-IOS.md still says it has never been compiled, and the TestFlight pipeline was still being brought up, so iOS rows describe code on main, not behaviour checked on a phone.
| Platform | Done | Partial | Planned / stub | Total |
|---|---|---|---|---|
| iOS | 71 | 6 | 8 | 85 |
| Web | 71 | 7 | 5 | 83 |
| Server | 47 | 6 | 5 | 58 |
Your week of lectures, with a way to walk to each one.
Month and day header like iOS Calendar, Mon to Fri tiles, a timeline with the next event highlighted and a sheet on tap.
ios/FindMyETH/Schedule/ScheduleView.swiftios/FindMyETH/Schedule/ScheduleCalendar.swiftweb/src/screens/schedule/Schedule.tsxSearch the VVZ catalogue by number, title or lecturer and add courses to your schedule.
ios/FindMyETH/Schedule/CourseSearchView.swiftserver/app/routers/schedule.pyserver/app/services/vvz.pyImport a .ics export (file picker on iOS, upload on web); the server parses it into your courses.
ios/FindMyETH/Schedule/ScheduleView.swiftserver/app/routers/schedule.pyiOS reads course numbers from a timetable screenshot with Vision on the phone and lets you review them; the web uploads the image to server-side tesseract.
ios/FindMyETH/Schedule/ScheduleOCR.swiftweb/src/screens/schedule/Schedule.tsxserver/app/routers/schedule.pyVVZ has no timeslots for 2026W, so weekly lecture times and rooms are derived from ETH roominfo bookings.
server/app/services/roominfo.pyserver/app/services/vvz.pyYour own data, kept on your phone where possible.
Avatar, display name, department and semester with an edit sheet.
ios/FindMyETH/Profile/ProfileView.swiftios/FindMyETH/Profile/EditProfileView.swiftweb/src/screens/profile/Profile.tsxYour positions and friend sightings are logged on the device for 60 days and never uploaded; you can delete them from Profile.
ios/FindMyETH/Profile/PresenceLog.swiftweb/src/lib/history.tsHours on campus this week with a bar chart, most visited building and room, longest day, weekday streak and a friends ranking.
ios/FindMyETH/Profile/PresenceStats.swiftweb/src/screens/profile/Profile.tsxVegetarian, vegan, allergens and a price cap, used as hard constraints in Socials.
ios/FindMyETH/Profile/ProfileView.swiftweb/src/screens/profile/Profile.tsxLight, Dark or System, applied across the app.
ios/FindMyETH/Design/Theme.swiftweb/src/lib/theme.tsiOS settings for Apple or HELPS map, on-device or server routing, and step-free routes by default.
ios/FindMyETH/Profile/ProfileView.swiftios/FindMyETH/App/AppModel.swiftEnglish or Deutsch and a notifications switch are stored, but the language does not change the UI yet.
ios/FindMyETH/Profile/ProfileView.swiftweb/src/screens/profile/Profile.tsxApp version, open-source licences and credits, and log out.
ios/FindMyETH/Profile/ProfileView.swiftweb/src/screens/profile/Profile.tsxHow friends see you.
Flat 2D vector character with skin, hair, outfit and accessory, saved in your profile.
ios/FindMyETH/Avatar/AvatarBuilderView.swiftios/FindMyETH/Avatar/AvatarSpec.swiftweb/src/screens/onboarding/AvatarBuilder.tsxPick a preset character or upload a photo, which is shown round and not animated.
ios/FindMyETH/Avatar/AvatarView.swiftweb/src/components/Avatar.tsxserver/app/routers/social.pyAvatars animate and switch pose by room type (eating, lecture, studying, walking); map markers do not show photos or animation yet.
ios/FindMyETH/Avatar/AvatarView.swiftios/FindMyETH/Avatar/AvatarSpec.swiftChoose whether other students can find you by name in user search.
web/src/screens/profile/Profile.tsxserver/app/routers/social.pyLocation sharing where the server only ever sees ciphertext.
Positions are sealed with HPKE (X25519, ChaCha20-Poly1305) for each recipient device, keys are Ed25519-signed, and the server keeps only the last ciphertext for 15 minutes.
ios/FindMyETH/FindMy/FindMyCrypto.swiftios/FindMyETH/FindMy/FindMyService.swiftweb/src/lib/crypto.tsserver/app/routers/findmy.pySend immediately after moving more than 3 m or changing floor, every 5 s while moving and every 30 s while still; same rules on iOS and web.
ios/FindMyETH/FindMy/FindMySendPolicy.swiftweb/src/lib/findmy.tsToggle sharing for whole groups or single friends; off by default.
ios/FindMyETH/Profile/ProfileView.swiftweb/src/screens/profile/Profile.tsxOne button stops sharing and deletes every blob you have on the server.
ios/FindMyETH/FindMy/FindMyService.swiftweb/src/lib/findmy.tsserver/app/routers/findmy.pyAn encrypted "arrived" event shows "Sam arrived on campus" as a local notification on iOS or a toast and browser notification on web.
ios/FindMyETH/FindMy/FindMyService.swiftweb/src/components/Shell.tsxCentrifugo JWT from /api/realtime/token with food, user-limited find-my, occupancy and bundle channels; live share lands in about a second.
server/app/realtime.pyios/FindMyETH/Networking/RealtimeClient.swiftweb/src/lib/realtime.tsA Notification Service Extension to decrypt find-my pushes when the app is closed.
docs/DEVIATIONS.mdIndoor position from ETH Bluetooth beacons, plus walks that make it better.
Swift package that loads the HG beacon bundle (33 MB with the lookup table) and runs the same grid filter as the HGScan Python model.
ios/Packages/ETHPositioning/Sources/ETHPositioning/Core/PositioningEngine.swiftios/Packages/ETHPositioning/Sources/ETHPositioning/Core/LocalizerBundle.swiftiBeacon ranging at about 1 Hz for the ETH UUID, with barometer and pedometer hints.
ios/Packages/ETHPositioning/Sources/ETHPositioning/Device/BeaconScanner.swiftios/Packages/ETHPositioning/Sources/ETHPositioning/Device/MotionHints.swiftStep-based dead reckoning, floor hysteresis with barometer, Kalman smoothing and GPS gating; the Swift and TypeScript versions agree to 2e-14 m on a shared fixture.
ios/Packages/ETHPositioning/Sources/ETHPositioning/Core/Fusion.swiftpackages/positioning-ts/src/fusion.tsSwift and TypeScript tests replay a recorded HG walk against expected Python output.
ios/Packages/ETHPositioning/Tests/ETHPositioningTests/ParityTests.swiftpackages/positioning-ts/test/parity.test.tsThe app uses a BLE estimate younger than 10 s and falls back to GPS, switching bundles when you enter another building.
ios/FindMyETH/Location/LocationService.swiftios/Packages/ETHPositioning/Sources/ETHPositioning/Device/PositionProvider.swiftFeed LocationService through FusionEngine and add a .fused source; the Swift engine is ready, the app does not use it yet.
ios/FindMyETH/Location/LocationService.swiftdocs/POSITIONING-FUSION.mdAndroid Chrome scans beacons with requestLEScan (behind a Chrome flag, feature-detected with an explanation) and runs the fused engine in the browser.
packages/positioning-ts/src/webbluetooth.tsweb/src/lib/location.tsAsk DeviceMotionEvent.requestPermission() from a tap; until then Safari gives the web app no steps or heading.
web/src/lib/location.tsdocs/TODO.mdRecords BLE, motion and GPS streams in the v1 chunk format for contribution walks.
ios/Packages/ETHPositioning/Sources/ETHPositioning/Device/SensorRecorder.swiftSurvey CAB and other buildings, an accuracy circle and floor badge on the blue dot, and an "approximate" mode elsewhere.
docs/TODO.mdThe server plans a mission; you walk it with a heading-up strip map, rooms left and right, a lane diagram, a distance countdown and a haptic at each checkpoint.
ios/FindMyETH/Contribute/MissionScreen.swiftios/FindMyETH/Contribute/LaneDiagramView.swiftweb/src/screens/profile/ImproveAccuracy.tsxserver/app/hgscan/planner.pyReport a blocked corridor with a reason and get a new mission; reports reach the admin walkability queue.
ios/FindMyETH/Contribute/BlockedSheet.swiftserver/app/routers/contribute.pyOptional headless ARKit session records camera poses (and LiDAR wall distances) during a walk, never images.
ios/FindMyETH/Sensors/ARAssistTracker.swiftGzipped chunks upload during the walk; afterwards you see usable metres and a weekly and all-time contributor leaderboard.
ios/FindMyETH/Contribute/ChunkUploader.swiftios/FindMyETH/Contribute/ContributeSummaryView.swiftserver/app/routers/contribute.pyFirst launch.
Welcome, log in with your team account, two opt-ins (location sharing, arrival notifications) and the avatar step; shown once per account.
ios/FindMyETH/Onboarding/OnboardingView.swiftweb/src/screens/onboarding/Onboarding.tsxserver/migrations/003_onboarded.sqlLagoon Classic by default, and a hidden parchment-and-ink theme.
Tint #337691, neutral surfaces, light and dark sets, round controls, 16 px cards and soft shadows on both platforms.
ios/FindMyETH/Design/Tokens.swiftweb/src/styles/tokens.cssPlus Jakarta Sans titles over system body text, and the FindMyETH map-pin logo.
ios/FindMyETH/Design/Typography.swiftios/FindMyETH/Design/Logo.swiftweb/src/components/Logo.tsxSaying "I solemnly swear that I am up to no good" into search turns the mode on and "Mischief managed" turns it off; the choice is remembered.
ios/FindMyETH/Design/Theme.swiftweb/src/lib/marauder.tsA second token set in parchment and ink for light, and a candlelit dark variant.
ios/FindMyETH/Design/Theme.swiftweb/src/styles/marauder.cssParchment land, ink-outlined buildings and calligraphy building names (IM Fell English on web, Noto Sans Italic labels on iOS).
web/src/map/parchment.tsios/FindMyETH/Navigate/MapLibreStyle.swiftRoutes are drawn as footsteps and friends as footprints with a name ribbon instead of avatars.
ios/FindMyETH/Design/Marauder.swiftweb/src/map/MapView.tsxThe map inks in from your position when opened and bottom sheets unfold like paper.
ios/FindMyETH/Design/Marauder.swiftweb/src/styles/marauder.cssParchment grain, ink-blot loader, quill stroke under the active tab, ink flourish dividers, torn-paper tags, wax seal and ink-stamp buttons.
ios/FindMyETH/Design/Marauder.swiftweb/src/styles/marauder.cssA non-voice gesture to wake the map and hand-drawn ink icons.
docs/TODO.mdThe same app in the browser, plus the operator console at /admin.
Web manifest, home-screen icons and a hand-written service worker with an offline shell; it never caches /api or /rt.
web/public/manifest.webmanifestweb/public/sw.jsweb/vite.config.tsHeadline numbers and suggested actions; applying an action is a server stub (404).
web/src/admin/Overview.tsxList graph edges by status, confidence and popularity and approve or block them in bulk; approvals made before the latest graph rebuild are orphaned.
web/src/admin/Walkability.tsxDraw new edges and stair or lift connectors on a floor; splitting an edge returns 501.
web/src/admin/PathBuilder.tsxCreate, edit and delete the missions contributors walk.
web/src/admin/Missions.tsxFilter contribution sessions, replay them on the map and accept, exclude, trim or reprocess.
web/src/admin/Sessions.tsxSee surveyed coverage, steer where missions go and message contributors.
web/src/admin/Coverage.tsxList and compare localizer builds and publish one; the publish gate is not yet enforced by the manifest.
web/src/admin/Builds.tsxBeacon inventory, users and their registered devices.
web/src/admin/Beacons.tsxweb/src/admin/Misc.tsxSearchable log of admin actions by actor and kind.
web/src/admin/Misc.tsxHide or correct dishes from the cookpit feed.
web/src/admin/Misc.tsxHealth of each source with run and refresh buttons; the page does not yet show the new stale, failures and next-run fields.
web/src/admin/Misc.tsxserver/app/services/sources.pyFeature flags and a demo date that makes menus and bookings behave as on that day.
web/src/admin/Misc.tsxserver/app/clock.pyFastAPI on Postgres/PostGIS with workers that pull ETH data.
Password accounts (scrypt, login, logout, change password), username mode for demos and trusted proxy headers; team accounts become admins.
server/app/auth.pyserver/app/routers/social.pyA CLI creates team and judge accounts from a file kept outside git and makes judges friends with the team.
server/app/accounts.pyserver/migrations/002_accounts.sqlAUTH_MODE=oidc exists but returns 501; ETH single sign-on is not implemented.
server/app/auth.pyFriends, invites, groups, photos, canteens, dishes, food sessions, courses, .ics and OCR endpoints.
server/app/routers/social.pyserver/app/routers/food.pyserver/app/routers/schedule.pyMeilisearch index of rooms, buildings, POIs, canteens, courses and lecturers, rebuilt and swapped atomically, with an in-process fallback scorer.
server/app/services/search.pyBands per room from today's bookings, recomputed every 60 s by the worker and published on change.
server/app/services/occupancy.pyserver/app/routers/places.pyThe ingest endpoint and aggregation are built and tested, but no Wi-Fi data is posted yet.
server/app/routers/places.pydocs/DATA-SOURCES.mdScheduler with per-source backoff for cookpit menus, the VVZ dump mirror and roominfo bookings, falling back from live to cache to seed.
server/app/workers/__main__.pyserver/app/services/sources_jobs.pyserver/app/services/cookpit.pyBundled menus, rooms, bookings, courses and the HG survey venue so the stack runs without network.
server/seed/server/app/seed.pyContent-hashed URLs for venue files, search.sqlite and localizer bundles, with a realtime notice when a new manifest is out.
server/app/routers/places.pyserver/app/venue.pyMission planning with the vendored HGScan planner, gzip chunk ingest, finish processing, blocked reports and leaderboard.
server/app/routers/contribute.pyserver/app/services/survey.pyEndpoints behind every admin page, including graph edits, session review, builds and flags.
server/app/routers/admin.pyTurns ETH map data into floor GeoJSON, routing graphs with reconstructed floor links, search.sqlite and beacon bundles.
tools/venue-build/venue_build/graph.pytools/venue-build/venue_build/search.pytools/venue-build/venue_build/localizer.pyOptional compose profile for streaming occupancy; the Python worker aggregator is what runs by default.
deploy/risingwave/001_occupancy.sqlpytest coverage for auth, food flow, find-my, routing, contribute, admin, sources, scoring and places.
server/tests/How the stack ships to staging and the app to TestFlight.
Gateway, api, worker, PostGIS, NATS, Centrifugo and Meilisearch, with RisingWave as an optional profile.
deploy/compose.yamldeploy/Dockerfile.apiOne public port serving the web, /admin, /api, /rt and hashed /venue and /bundles files, with basic auth on staging and no-cache for sw.js.
deploy/CaddyfilePushing a vX.Y.Z tag runs a self-hosted job that syncs the code to staging and rolls the stack.
.github/workflows/release.ymldeploy/scripts/deploy-on-host.shThe same tag can archive, cloud-sign and upload the iOS app; it sits behind TESTFLIGHT_ENABLED and was still being debugged at this commit.
ios/scripts/testflight.sh.github/workflows/release.ymlproject.yml is the source of truth and make-project.sh generates the Xcode project.
ios/project.ymlios/make-project.shTypecheck, lint, build and run server, TypeScript and Swift tests on every PR.
docs/TODO.mdChoose the access mode and promote a staged tag to the hackathon production VM.
docs/TODO.mdNo feature matches these filters.
Socials & food picker11
Groups of friends swipe on today's dishes and get one place to eat.
Groups
DoneGroup cards with "+ New group" and an editor to rename, add or remove members.
ios/FindMyETH/Socials/SocialsView.swiftios/FindMyETH/Socials/GroupEditorView.swiftweb/src/screens/socials/Groups.tsxserver/app/routers/social.pyAdd friends by QR, link or username
DoneA real QR code, a share sheet invite link (ShareLink, Web Share or copy) and search by exact handle or discoverable users.
ios/FindMyETH/Socials/FriendQRViews.swiftweb/src/screens/socials/GroupEditor.tsxSolo mode
DoneEvery user has a private "Just me" group, so you can use the picker alone.
server/app/routers/food.pySwipe deck
DoneDish photo on half the screen, name and price, canteen below, veg, vegan and price filter chips, swipe gestures plus two buttons.
ios/FindMyETH/Socials/FoodSwipeDeckView.swiftweb/src/screens/socials/Swipe.tsxReal dish photos with credit
DonePhotos come from the ETH cookpit feed with a "Dish photos © ETH Zürich Gastronomie" credit and an icon placeholder when a dish has none.
ios/FindMyETH/Socials/FoodSwipeDeckView.swiftweb/src/screens/socials/Swipe.tsxHard constraints and scoring
DoneVegetarian, vegan, allergens, price cap and "still serving later today" filter dishes before the group score picks a match or compromise.
server/app/services/food_scoring.pyserver/app/routers/food.pyRecommendation screen
DoneTop pick plus two runner-ups with photo, walk time, price, opening hours, member avatars with yes markers and Guide me there.
ios/FindMyETH/Socials/FoodRecommendationView.swiftweb/src/screens/socials/Recommendation.tsxLive session updates
DoneJoins, progress, new recommendations and closing are pushed over Centrifugo, so the result changes while friends are still swiping.
ios/FindMyETH/Socials/FoodSessionModel.swiftweb/src/lib/food.tsserver/app/realtime.pyDecide now and restart
DoneThe starter can close the vote early; anyone can swipe again or change group from the restart panel.
ios/FindMyETH/Socials/FoodRecommendationView.swiftweb/src/screens/socials/Recommendation.tsxMatch celebration
DoneConfetti when the group agrees, and a wax seal on the top pick in Marauder mode.
ios/FindMyETH/Design/Confetti.swiftweb/src/screens/socials/Recommendation.tsxPrivate food channels
Planned / stubRestrict food session channels with Centrifugo channel tokens; today anyone who knows a session id can subscribe.
docs/TODO.md