Skip to content

Repository files navigation

MobilityData Operations Admin

Internal admin UI for the Mobility Database Operations API (functions-python/operations_api in MobilityData/mobility-feed-api). It provides CRUD over every Operations API endpoint and is restricted to MobilityData staff signing in with their Google accounts.

Internal tool — not intended for the general public.

Stack

  • Next.js (App Router) + TypeScript + Yarn
  • MUI (Material UI) + @tanstack/react-query
  • openapi-typescript (types generated from the OpenAPI spec) + openapi-fetch (typed client)
  • Google Identity Services (GIS) for authentication
  • Jest + Testing Library for tests

The stack follows the MobilityData/mobilitydatabase-web pattern, with one deliberate difference: authentication uses GIS directly instead of Firebase (see below).

Authentication (how and why)

The Operations API accepts an Authorization: Bearer <token> where the token is a Google OAuth 2.0 access token whose audience equals the API's GOOGLE_CLIENT_ID (it validates the token against Google's tokeninfo endpoint). The API itself does not filter by email domain.

Therefore:

  • The app signs users in with GIS using NEXT_PUBLIC_GOOGLE_CLIENT_ID, which must be the same OAuth client as the API's GOOGLE_CLIENT_ID. GIS mints an access token under that client, so the audience matches by construction.
  • "MobilityData staff only" is enforced by configuring that OAuth client as Internal user type in the mobilitydata.org Google Workspace — only org members can obtain a token. The app additionally verifies the signed-in email ends in @mobilitydata.org and blocks anyone else client-side.
  • For local development against an API started with LOCAL_ENV=True, set NEXT_PUBLIC_LOCAL_ENV=true to skip real sign-in.
  • Guard rail: NEXT_PUBLIC_LOCAL_ENV is a NEXT_PUBLIC_ var, so its value is baked into the client bundle at build time — if it were ever true in a production build, every visitor would land in the app with no Google sign-in at all. next.config.js refuses to build or start when NEXT_PUBLIC_LOCAL_ENV=true and NODE_ENV=production are set together, so a misconfigured deploy fails loudly instead of shipping an unauthenticated app.

Getting started

# 1. Configure env
cp .env.rename_me .env.local   # then fill in the values

# 2. Install
yarn install

# 3. Generate the typed API client from the pinned OpenAPI spec
yarn generate:api-types

# 4. Run
yarn dev                       # http://localhost:3000

Environment variables

See .env.rename_me. Client-exposed vars must be prefixed with NEXT_PUBLIC_.

Variable Purpose
NEXT_PUBLIC_OPERATIONS_API_URL Base URL of the deployed Operations API
NEXT_PUBLIC_GOOGLE_CLIENT_ID OAuth client ID — must equal the API's GOOGLE_CLIENT_ID
NEXT_PUBLIC_LOCAL_ENV true to skip sign-in against a LOCAL_ENV=True API
NEXT_PUBLIC_ALLOWED_EMAIL_DOMAIN Allowed email domain (default mobilitydata.org)
OPERATIONS_SPEC_REF Build-time only: git ref of the spec to generate types from

Pointing a local instance at the deployed dev API

The Operations API sends no CORS headers and its auth middleware rejects an unauthenticated preflight, so a browser at http://localhost:3000 cannot call the dev Cloud Function cross-origin. Use the built-in same-origin dev proxy: the browser calls localhost:3000, and Next.js forwards /v1/operations/* to dev server-side (passing the Authorization: Bearer header through).

  1. Get the dev Cloud Function URL:

    gcloud functions describe operations-api --gen2 --region=northamerica-northeast1 \
      --project=mobility-feeds-dev --format='value(serviceConfig.uri)'
  2. In .env.local:

    NEXT_PUBLIC_LOCAL_ENV=false
    NEXT_PUBLIC_OPERATIONS_API_URL=            # empty → requests go through the proxy
    OPERATIONS_API_PROXY_TARGET=https://<dev-operations-api-url>
    NEXT_PUBLIC_GOOGLE_CLIENT_ID=59033768865-bbf5v4rkut7n7i59vi162a3snhh3r1gc.apps.googleusercontent.com
  3. One-time GCP setup: in the GCP Console, add http://localhost:3000 to the dev OAuth client's Authorized JavaScript origins (Google sign-in is rejected otherwise).

  4. yarn dev, sign in with your @mobilitydata.org account, and the app will read/write the dev database through the proxy.

Restart yarn dev after changing .env.local — Next.js reads env and next.config.js at startup.

For a real deployment (not localhost), the Operations API will need CORS added for the web app's origin, or the app must be served through an equivalent proxy.

API spec / codegen

The app is spec-first. yarn generate:api-types:

  1. Runs scripts/fetch-spec.mjs, which downloads docs/OperationsAPI.yaml from a pinned ref of MobilityData/mobility-feed-api (OPERATIONS_SPEC_REF) into spec/OperationsAPI.yaml.
  2. Runs openapi-typescript to regenerate src/lib/api/generated.ts.

To adopt a newer API contract, bump OPERATIONS_SPEC_REF and re-run the command. Never hand-edit src/lib/api/generated.ts.

Endpoint coverage

All 19 Operations API endpoints are exposed:

  • Feeds — list (search / status / type filters), GTFS & GTFS-RT detail, availability history, create & edit for both feed types.
  • Licenses — list, detail (with rules), match-a-URL tool, propagate tool (dry-run preview → confirmed apply).
  • Users — search, detail, per-user feature-flag editor.
  • Feature flags — list, create, edit, delete.

Project layout

src/
  app/                 # App Router pages (feeds, licenses, users, feature-flags)
  components/          # Shared UI + per-domain components
  lib/
    api/               # generated types, typed client, react-query hooks
    auth/              # GIS wrapper, AuthProvider, token store, config
  theme.ts
__tests__/             # Jest + Testing Library specs
scripts/fetch-spec.mjs # spec fetcher used by generate:api-types

Scripts

Command Description
yarn dev Run the dev server
yarn build / yarn start Production build / serve
yarn generate:api-types Fetch the spec and regenerate the typed client
yarn lint ESLint
yarn test Jest
yarn format Prettier

Deployment

Not configured yet. The app is a standard Next.js App Router project and can be deployed to Vercel or Firebase Hosting; add the environment variables above to the hosting provider. Ensure the deployed origin is added to the OAuth client's Authorized JavaScript origins.

Verifying end-to-end locally

  1. In mobility-feed-api, start the Operations API: scripts/api-operations-start.sh (listens on :8081 with LOCAL_ENV=True).
  2. Here, set NEXT_PUBLIC_OPERATIONS_API_URL=http://localhost:8081 and NEXT_PUBLIC_LOCAL_ENV=true, then yarn dev.
  3. Exercise each screen (feeds list/detail/availability/create/edit, licenses list/detail/match/propagate, users search/detail + flag editor, feature-flag CRUD).
  4. Real-auth check: point the app at a deployed dev API with a real NEXT_PUBLIC_GOOGLE_CLIENT_ID, sign in with a @mobilitydata.org account, and confirm a non-org account is blocked.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Used by

Contributors

Languages