Skip to content

Repository files navigation

SoftTrack Mobile

The iOS & Android companion app for SoftTrack — a self-hostable issue tracker.

What this is

A mobile client that mirrors the full SoftTrack web feature set — boards, issues, cycles, reports, notifications, search, and administration — talking to the existing FastAPI backend of any SoftTrack instance. Sign-in takes three inputs: the server link (your instance URL), email, and password.

The design mockups and some issue text say "username". The API only ever resolves the OAuth2 username field against the email column (backend/lib_identity/identity.py), so the app asks for an email. Adding a username lookup would be a backend change.

Running it

You need a SoftTrack instance to point the app at. The quickest one is the reference stack:

cd ../soft-track && docker compose up --build

That serves the API on :8000 with a seeded demo account (demo@softtrack.dev / password123).

Then start the app:

npm install && npx expo start

Open it in Expo Go. At the login screen enter your machine's LAN address as the server link — http://192.168.x.x:8000, not localhost, which on a phone means the phone.

Layout

src/app/            expo-router routes — thin wrappers, no logic
  (auth)/           signed out: login, register
  (app)/            signed in: Home, Board, Search, Inbox, You
  invite/[token]    an invitation — readable either way, so guarded by neither
  [teamKey]         /ENG — sets the active team, then hands to Board
src/api/            HTTP client, instance URL, generated client
src/auth/           session store, auth context, deep-link capture
src/team/           team context, switcher, creation, invitations
src/board/          board and list views, filters, drag-to-move
src/issues/         priority and status metadata
src/offline/        connectivity, cache persistence, the mutation queue
src/ui/             design tokens, theme, primitives, navigation chrome
openapi/            the vendored API contract codegen reads

src/ mirrors the web app's frontend/src/ naming wherever the concept is the same, so moving between the two repos is uneventful.

The API client is generated

src/api/generated/ is Orval output — typed React Query hooks — built from openapi/openapi.json, a vendored copy of the schema the backend produces. Same config as the web app, so hook names match in both clients. Never edit it by hand:

npm run sync:openapi     # refresh the vendored schema
npm run generate:api     # regenerate the client

CI fails if the committed client does not match the committed schema, and a weekly job flags when the vendored schema falls behind the backend.

Theming

Tokens in src/ui/tokens.ts are transcribed from the web's frontend/src/index.css. Note the neutral ramp is inverted in dark mode, so the two palettes are built explicitly rather than derived. The stored key (softtrack.theme) and its contract — absent means "follow the system" — match the web exactly.

Checks

npm run lint && npm run typecheck && npm test

Two integration suites are opt-in because they need a live server. They drive the real client modules against it, and the onboarding one writes real rows (fresh accounts and team keys per run):

SOFTTRACK_LIVE_URL=http://localhost:8000 npm test

The live suites between them register a handful of real accounts per run, and registration is throttled per IP and charged even on success — so a few full runs in a row will eventually 429. The counter lives in the API process, so docker compose restart backend && docker compose up -d clears it without touching the database.

Note experiments.typedRoutes is a dev-time aid: the route union is written by expo start, not by expo export, so outside the dev server every path typechecks permissively. Paths built at runtime go through href() in src/ui/href.ts rather than being cast at each call site.

Planning

  • Work is tracked on the Mobile App project.
  • Design mockups live in docs/design/mobile/ — one SVG per feature issue, each showing the screen at three window size classes:
    • Phone — compact, <600dp: single pane, bottom navigation
    • Foldable (unfolded) — medium, 600–839dp: two panes split at the hinge
    • Tablet — expanded, ≥840dp: nav rail with persistent multi-panel layouts

The mockups reuse the web app's design tokens (brand #6342db, tinted neutrals, status/priority colors) from frontend/src/index.css in the main repo, so mobile and web share one visual language.

Status

Every tracked issue is implemented except push notifications, which have no backend to talk to. Sign in to any instance, register, accept invitations, manage teams, work a board, create and edit issues with sub-issues and links, comment in GitHub-flavored markdown, attach photos and files, search, run cycles, read the four reports, save views, administer a team or the whole instance, and keep working with no connection.

Known gaps, tracked rather than hidden:

  • Nothing has been seen on a device yet. The suites cover the logic, the mockup geometry and that the trees render, but no one has run this on hardware. The drag gesture in particular is unverified by touch, which is why every move is also reachable by tapping a card. The medium and expanded layouts would need a tablet or an Android emulator to check for real.
  • Invitation links cannot be true universal links. A https://your-instance/invite/… link can only open the app if that exact domain is declared in the build, which is impossible for arbitrary self-hosted hosts. softtrack://invite/<token> works, and falls back to asking you to sign in first, since a custom-scheme link carries no instance.
  • Push notifications are not built, because the API has no way to register a device. Issue #10 anticipated this ("requires a backend addition for device token registration + push delivery"). There is no /devices endpoint and nothing APNs- or FCM-shaped anywhere in the schema, so the in-app inbox and the unread badge are what ship; the badge polls once a minute while the app is in front rather than pretending to be pushed. Real push also needs a dev build and signing credentials, neither of which exists yet.
  • Member counts cost one request per team. TeamRead carries no count, so the teams list asks each team for its members. A member_count field upstream would remove the fan-out and help the web too.
  • Offline is verified as logic, not as behaviour. The queue, the conflict rule and the cache are covered by tests, but nobody has watched a phone lose signal, move a card and come back. That needs a device.
  • No aurora or glass blur yet. The web's translucent panels are approximated with opaque surfaces; backdrop-filter has no React Native equivalent and per-surface blur is expensive on Android.

About

SoftTrack mobile app — iOS & Android companion to soft-track/soft-track

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages