Web admin (apps/web-admin)
The operator UI — a Next.js 16 (App Router) admin dashboard for managing
customers, devices, modules, and dashboard versions. It talks to the
API server through the generated
@signapps/api-client.
- Workspace:
apps/web-admin· package name:frontend - Output: Next.js
standaloneserver (.next/standalone/.../server.js)
Tech stack
| Concern | Choice |
|---|---|
| Framework | Next.js 16 (App Router), React 19 |
| UI | Tamagui (@signapps/ui), react-native-web |
| State / data | Redux Toolkit + RTK Query (@signapps/api-client) |
| Config | @signapps/next-config (createNextAppConfig) |
Usage
Run in dev
pnpm dev:fe # next dev (port 3000)
A predev hook runs scripts/ensure-api-client.mjs, which makes sure the
API client is generated from the API's OpenAPI spec before the dev server starts.
The app expects the API at NEXT_PUBLIC_API_URL (default
http://localhost:3001/api), so run pnpm dev:api alongside it.
Build
pnpm build:fe
Expands to:
node ./scripts/ensure-api-client.mjs \
&& next build \
&& node ./scripts/patch-standalone-deps.mjs
next.config.ts sets output: 'standalone' and transpilePackages for the
@signapps/* workspace packages. The result is a self-contained server in
.next/standalone/ plus .next/static/ and public/ assets.
Deploy
Built locally, then shipped over SSH (pnpm deploy:fe →
scripts/deploy-fe.mjs): it rsyncs/scp's .next/standalone/, .next/static/,
and public/ to the server and runs under PM2 (ecosystem.config.cjs,
port 3010). Deploy env vars: DEPLOY_HOST, DEPLOY_USER, APP_ROOT,
DEPLOY_FRONTEND_PATH, SSH_KEY_PATH, DEPLOY_PORT, and the build-time
NEXT_PUBLIC_API_URL.
NEXT_PUBLIC_* variables are baked in at next build, so NEXT_PUBLIC_API_URL
must be set before building for the target environment.
Structure
src/app/ App Router routes
/login public login
/dashboard/* protected: customers, devices, modules, versions, users, overview
src/features/ feature modules (customers, devices, modules, versions, users, overview)
src/middleware.ts cookie auth (admin_auth_token) → redirects to /login
Auth is cookie-based: login issues an admin_auth_token cookie; the middleware
guards /dashboard/* and redirects unauthenticated users to
/login?from=…. The API client attaches the token for authenticated requests.