Files
shihaam 2f5659f3ff
Build and Push Docker Images / Build and Push Docker Images (push) Failing after 8s
document the ui
2026-08-02 18:44:46 +05:00

87 lines
5.7 KiB
Markdown

# Architecture
## What the app is
SAR Link Portal — a customer + admin portal for an ISP. Users register (verified against the national identity registry), add network devices, and pay for device subscriptions either by bank transfer (MIB) or from a prepaid wallet they top up. Admins verify users, manage devices/payments/topups, and credit wallets.
## Stack (current)
- **Next.js 15** (App Router, React 19), TypeScript.
- **Tailwind CSS v4** (CSS-first, no config file) + **shadcn/ui** (`new-york`, neutral) + Radix + **lucide** icons.
- **Jotai** (global UI state) + **React Query** (mounted, not yet used).
- **react-hook-form** + **zod** (forms/validation), **nuqs** (URL query state), **sonner** (toasts), **next-themes**, **motion** (animation).
- **Auth:** mid-migration — old **next-auth** (JWT session) → new **localStorage token** (`lib/auth-store.ts`) + axios **api-client** (`lib/api-client.ts`).
## Folder map
```
app/
(auth)/auth/{signin,signup,verify-otp,verify-otp-registration}/ # public auth pages
(dashboard)/{devices,payments,top-ups,wallet,users,...}/ # authed app (user + admin)
api/{auth/[...nextauth],check-devices}/ # frontend API routes (being removed)
layout.tsx page.tsx globals.css auth.ts
actions/ # server actions: auth-actions, payment, user-actions, (omada, ninja = dead)
queries/ # server data fetchers: authentication, devices, islands, users, wallet
components/ # feature components + components/ui (shadcn primitives)
lib/ # auth-store, api-client, atoms, backend-types, schemas, person, utils
utils/ # tryCatch, axios-client (dead), axiosInstance (dead)
providers/ # QueryProvider, theme, (AuthProvider = next-auth, being removed)
hooks/ middleware.ts(removed)
docs/ # this documentation
deploy/ # (superseded — real prod is .build/prod/, see below)
```
## Current architecture (BFF — what's being replaced)
```
Browser ──(RSC + Server Actions)──▶ Next.js server ──(fetch + Token)──▶ Django API
```
The Next.js server sits between the browser and Django:
- Server components + server actions read the token via `getServerSession` and call Django server-side over `SARLINK_API_BASE_URL`.
- Public origin `/api/*` = Next.js's own routes (NextAuth); Django's `/api` is reached only internally.
- Deployed as a Node container behind nginx (`.build/prod/`).
## Target architecture (static + nginx, direct-to-API)
```
Browser ──(static HTML/JS from nginx)
├─ API_URL calls (/api, /callback, /auth/*) ─▶ nginx ─▶ Django
└─ everything else ─▶ nginx serves the static build
```
Goals set by the project owner:
- **No Node/Bun in production** — ship a static build served by nginx.
- **Configurable API base:** `API_URL=http://localhost:8000` in dev, `API_URL=https://portal.sarlink.net/api` (nginx → backend) in prod.
- Browser calls the Django API **directly** (same-origin in prod via nginx; cross-origin in dev with CORS).
Two ways to get there (under discussion):
1. **Next.js static export** (`output: "export"`) — keeps Next; fights the framework (no server actions, `searchParams` needs Suspense, dynamic routes need query-params, middleware gone). Foundation already built: `lib/auth-store.ts`, `lib/api-client.ts`, `components/auth/route-guard.tsx`, config flip, dev `rewrites()` proxy. See `../STATIC_MIGRATION_PLAN.md`.
2. **Vite + React SPA (recommended)** — natural fit for a static client app with a configurable `API_URL` (`import.meta.env.VITE_API_URL`). A **port, not a rewrite**: all components, shadcn, react-query, jotai, zod transfer 1:1; only the shell (routing, `next/link`, `next/font`, `next/image`, layouts) changes. TanStack Router or React Router for routing.
Either way the **auth/data plumbing already written is reusable**: token in localStorage, `Authorization: Token` interceptor, client route guard, React Query for reads/mutations.
## Auth model (target)
1. Login: `POST {API}/callback/auth/ { token: pin }``{ token, user, expiry }`.
2. Store token + user in localStorage (`setAuth`).
3. Attach `Authorization: Token <token>` on every request (axios interceptor).
4. `RouteGuard` gates authed pages; `401``clearAuth()` + redirect to signin.
5. Admin gating from `user.is_admin` / `user.user_permissions`.
## Production deployment (where nginx lives)
The real prod stack is **`.build/prod/`** (repo root), not `frontend/deploy/`:
- `compose.yml` — postgres + backend (Django/gunicorn) + frontend + **nginx** (single entrypoint, `:8080→80`).
- `nginx.conf` — reverse proxy. **Currently built for the BFF model** (`/` → Next Node server; `/api` NOT proxied to Django). For the static migration this must change to: serve the static build + proxy `/api`, `/callback`, `/auth/{login,logout,mobile}` to Django; the separate Node `frontend` service goes away.
- `frontend.Dockerfile` — currently `output:"standalone"` + `node server.js`; becomes a static build folded into the nginx image.
See [api-endpoints.md](./api-endpoints.md) for exact paths and the `/auth/*` frontend-vs-backend collision that the nginx config must handle.
## Known issues / cleanup
- **Mid-migration auth:** dashboard pages/actions/queries still use `getServerSession`; they must move to the client token store (or be removed in the SPA port).
- **Stale wallet balance:** header balance comes from the login `userAtom` snapshot; not refreshed after topups/payments until re-login.
- **Dead code:** Omada, Invoice Ninja, `/auth/login/`, `/islands/`, `/inventory/`, `backendMobileLogin`, `app/api/check-devices`, `utils/axios-client.ts`, `utils/axiosInstance.ts`.
- **person-verify** is called directly from the frontend; planned to route through the backend.