Skip to content

TODO

Frontend

Dashboard

  • On the map I'd like to be able to right click and have an option to create a location (storage or delivery) at the point selected.
  • The location editor now opens with the clicked coordinates prefilled.
  • Clicking an existing zone now opens the popup with an Edit button that launches the location editor.
  • When deleting a location, do we consider cascading it to remove history records where a tracker entered the zone?

Campaign Management

  • The Open locations button at the top of the page is unnecessary. Removed from the admin app's Campaign Management page (tracker-admin-svelte/.../clients/+page.svelte) -- it duplicated the "Open locations" icon already on each campaign/child-run card.

Unified CRUD

  • On the campaign management page the interface does not work well on mobile.
  • I think the mobile display should stack as rows not columns, so each selection fills beneath the next.
  • On selecting a client the mobile interface should jump to brand, on selecting a brand jump to campaign. Fixed all three together: the Clients/Brands/Campaigns/Child runs columns were a fixed-height side-by-side row, which just doesn't fit four columns on a phone. Built a shared EntityColumnGroup component (both apps' campaign management pages now use it, replacing four hand-written EntityColumns each) that keeps the side-by-side layout at the lg breakpoint and up, and below it stacks the columns as full-width rows, each with its own capped height and internal scroll. Selecting an item smooth-scrolls the next column into view (mobile only -- on desktop everything's already visible side by side).

Tracker Cards

  • The tooltips on mobile flow off screen to the left for cards that are in the left column. Can the tooltips be aligned to the right for left hand cards? Fixed by flipping the status tooltip outward on compact card grids, while leaving the wider layouts unchanged.
  • Trying to scroll in mobile causes the drag/drop trigger and the wheel appears. Is there anything to be done to make scrolling better? Fixed by allowing vertical touch panning on move-enabled cards/rows and only starting the radial drag wheel from mouse input.

Admin Panel

Users

  • The user invite gets sent out with the link to the admin panel.
  • The invite should have the frontend link, unless they are an admin, then it should have both. Fixed: the invite link was derived from whichever app's origin submitted the create-user request (always the admin panel, since that's the only place POST /users is called from), not the invited user's own role. Now role-based — ADMIN_URL/FRONTEND_URL are both real settings, and the email includes the admin panel link only when "admin" is in the new user's roles.
  • The user cards should behave like tracker cards. The edit/delete only appears on hover. Fixed in the shared EntityCard component (also used by clients and campaign management), so all three pick up the same hover-reveal behaviour as TrackerCard.
  • User cards could take up less space. Two columns, unless mobile? Added an opt-in columns prop to EntityColumn (default stays 1, so clients/campaign management are unaffected) and set it to 2 on the Users page; falls back to a single column below the sm breakpoint.
  • Cards could show the clients they have access to instead of just "1 client" Now lists the actual client names (comma-separated, capped at 3 with "+N more"), resolved from the clients already loaded for the editor modal.
  • Add a filter to show users with specific client access. Added a "Client access" dropdown next to the Role filter. Along the way, found that User.client_list/User.roles used the generic sqlalchemy.ARRAY type instead of the Postgres-specific one, so .contains() raised NotImplementedError at query time -- this was already broken for the pre-existing Role filter too, just never exercised by a test. Fixed the column type (no migration needed -- the actual DB column was always a real Postgres array; this was a Python-level type annotation bug). Admins match every client filter since they implicitly have access to all clients.
  • Check that no password reset email is sent unless the user is using local auth.

Authentication

better-auth

  • Did we over engineer our own auth? Would be better using https://better-auth.com/docs/concepts/oauth Discussed and rejected. The current JWT + OIDC provider-registry setup (app/core/oidc.py) is a fairly standard size for what it does, not over-engineered. better-auth is TypeScript-only (expects a Node/Bun/Deno backend with Drizzle/Prisma/Kysely) -- this app's auth lives in the Python/FastAPI backend, so adopting it would mean standing up a separate Node auth microservice or rewriting auth in TypeScript, not a drop-in swap.
  • Would it give us scope for other auths facebook/github? Not a reason to switch -- GitHub/Facebook fit the existing _PROVIDERS-dict pattern already used for Google/Microsoft (with per-provider quirks, e.g. GitHub isn't strictly OIDC-compliant so it needs a token-exchange/userinfo step instead of JWKS validation). A scoped addition to the current architecture, not a reason to migrate.

Backend API

Alembic

  • Can we merge the alembic migrations so we don't have branches? Linearized both branch points (alembic heads was already a single head -- the "branches" were two already-resolved fork/merge pairs inside the history, not a live problem). Checked every environment's current stamped revision first (local dev and staging both at head; production intentionally 11 migrations behind, on 46408209ddfd, well before either fork) to confirm nothing was stamped at a revision being removed. Reordered the two branch pairs by creation date, repointed down_revisions to chain them sequentially instead of merging, and deleted the now-unneeded pure no-op merge revision (ab12cd34ef56; the other merge point, e3f1a2b4c5d6, had real schema changes so it was kept, just with a single down_revision instead of a tuple). Verified by building a completely fresh database through the whole chain from scratch -- all 36 revisions apply cleanly in the new linear order, ending at the same head (d0e1f2a3b4c5) as before.
  • Once we get staging, and production to the current head we should flatten the migrations using alembic revision --autogenerate -m "Schema Baseline"

Schema Improvement Notes

  • Several geography-backed tables currently expose both legacy and modern GIST index names on the same column. If backward compatibility is no longer required, consider keeping one canonical index per table.
  • If OAuth sign-in becomes the dominant login path, adding an index on users.auth_provider or users.provider_subject_id may help lookup-heavy auth flows.
  • Short-lived tables such as password_reset_tokens may benefit from an explicit retention or cleanup policy being documented alongside the schema.

Documentation

Usage Guide

  • The user guide needs to be updated to cover the new design and move to the unified crud in Campaign Management Added a "Managing Clients, Brands, and Campaigns" section covering the drill-down interaction, hover-to-reveal edit/delete, mobile behavior, child runs, and per-run tracker management. Cross-linked from "Setup — Required Order".

Remove Stale Documents

  • We need to do a review of documentation and remove cruft relating to the previous React version and any other outdated materials. Rewrote the Admin Panel (8 files) and Front End (7 files) sections wholesale -- both described the deleted React/react-admin apps as current, with dead paths and code samples. Fixed scattered stale mentions in docs/index.md, reference/system-architecture.md, and several guides/services docs. Left legitimate historical/migration docs (the Svelte migration assessments, the cutover TODO) untouched -- they're supposed to talk about the old React app for comparison.
  • The documentation requires a restructure as the top level menu contains too many items and it looks disorganised. Root cause: mkdocs-awesome-pages-plugin defaults to reading .pages files, but every nav file in this repo is named .nav.yml and the plugin was never told to look for that instead -- so none of the curated navigation was ever actually being read, and mkdocs was silently falling back to a flat alphabetical dump of all ~90 pages. Fixed the plugin config (one line), fixed the "*" wildcard token (should be "..." for this plugin version), fixed a broken nested-path reference and a dead redoc link, and moved/removed the handful of stray top-level directories that had no real content (an empty dir, a confusingly-duplicate database/, asset-only dirs). Verified by building the full site and confirming the rendered nav matches the curated structure.