No description
Find a file
2026-08-27 21:18:22 +02:00
.od-skills/creative-director-d03e82b79d feat: initialize full ysterbaard frontend application 2026-07-23 19:10:47 +02:00
app Compliance snapshot redesign: BizPortal AR summary + SARS placeholder; CIPC address labels; Math.abs amount fix 2026-08-27 21:18:22 +02:00
components Compliance snapshot redesign: BizPortal AR summary + SARS placeholder; CIPC address labels; Math.abs amount fix 2026-08-27 21:18:22 +02:00
lib Add pre-send validation gate + idempotent sign-back to appointment flow 2026-08-18 21:29:08 +02:00
scripts feat: Task Kanban UI + Python task worker 2026-08-17 18:57:02 +02:00
.dockerignore feat: initialize full ysterbaard frontend application 2026-07-23 19:10:47 +02:00
.env.example feat: initialize full ysterbaard frontend application 2026-07-23 19:10:47 +02:00
.env.local.example feat: initialize full ysterbaard frontend application 2026-07-23 19:10:47 +02:00
.gitignore feat: BizPortal 2.0 — Python Playwright sidecar 2026-08-17 18:33:36 +02:00
docker-compose.yml feat: initialize full ysterbaard frontend application 2026-07-23 19:10:47 +02:00
Dockerfile build: remove empty public dir from docker image 2026-07-23 19:26:49 +02:00
favicon.png Add native Share button to registration link dialog 2026-07-30 16:38:05 +02:00
image-1.png feat: initialize full ysterbaard frontend application 2026-07-23 19:10:47 +02:00
image-2.png feat: initialize full ysterbaard frontend application 2026-07-23 19:10:47 +02:00
image.png feat: initialize full ysterbaard frontend application 2026-07-23 19:10:47 +02:00
logo.png feat: initialize full ysterbaard frontend application 2026-07-23 19:10:47 +02:00
next.config.mjs feat: initialize full ysterbaard frontend application 2026-07-23 19:10:47 +02:00
package-lock.json Add native Share button to registration link dialog 2026-07-30 16:38:05 +02:00
package.json Add native Share button to registration link dialog 2026-07-30 16:38:05 +02:00
postcss.config.mjs feat: initialize full ysterbaard frontend application 2026-07-23 19:10:47 +02:00
README.md feat: initialize full ysterbaard frontend application 2026-07-23 19:10:47 +02:00
sqlite_mcp_server.db feat: initialize full ysterbaard frontend application 2026-07-23 19:10:47 +02:00
tailwind.config.ts feat: initialize full ysterbaard frontend application 2026-07-23 19:10:47 +02:00
tsconfig.json feat: initialize full ysterbaard frontend application 2026-07-23 19:10:47 +02:00
tsconfig.tsbuildinfo Use master template style (Arial 11pt, justified, 1.5 spacing) for appointment letter PDF 2026-08-17 22:58:51 +02:00

Workflow PocketBase Frontend

A read-only Next.js frontend that browses two PocketBase collections:

  • ysterbaard_directors
  • ysterbaard_companies

The PocketBase instance is private. The superuser JWT is held server-side only — a Next.js route handler proxies every collection request, attaches the bearer token, and forwards to PB. The browser bundle never sees PB_TOKEN.

Routes

Path Surface
/ Dashboard — total counts, status rollup, legend
/directors Sortable, searchable list (table on desktop, cards on mobile)
/directors/[id] Director profile + linked companies
/companies Sortable, searchable, status-filtered list
/companies/[id] Company detail + linked director card

Stack

  • Next.js 14 (App Router) + React 18 + TypeScript
  • Tailwind CSS for styling (Airbnb light theme — white canvas, Rausch coral accent)
  • pocketbase JS SDK on the server only
  • TanStack Query v5 for client-side pagination + search
  • Inter as the webfont, via next/font/google

Setup

1. Install

npm install

2. Pull the superuser JWT from the admin UI

PocketBase v0.39 admin auth (/api/admins/auth-with-password) is unreachable from the public REST API — the only working admin auth lives behind /_/. Pull the JWT from the UI's localStorage:

  1. Open https://pb.agent.apphub.co.za/_/ and sign in with:

    • Username: ysterbaard@apphub.co.za
    • Password: 123456789
  2. Open DevTools, go to the Console, and run:

    localStorage
      .getItem('__pb_superusers__/_')
      .match(/"token":"([^"]+)"/)[1]
    
  3. Copy the JWT string (no quotes).

3. Fill in .env.local

cp .env.local.example .env.local

Edit .env.local so that:

PB_URL=https://pb.agent.apphub.co.za
PB_TOKEN=<paste the JWT here>

4. Run the dev server

npm run dev

Open http://localhost:3000.

Acceptance criteria

  • All 5 routes render with real data from PocketBase
  • No superuser token leaks to the browser bundle (proxy holds it in process.env)
  • /directors and /companies paginate, search, and link to detail pages
  • Detail pages show the relation (director ↔ companies) correctly via expand=director
  • Lighthouse mobile score ≥ 90 (verify after deploy)
  • Local dev runs without errors

Out of scope

  • Authentication UI for end users
  • Write/edit forms (this is read-only)
  • Charts / analytics dashboards (just stat cards)
  • Admin panel re-skin

Architecture notes

Server / client split

  • Server Components fetch the initial page directly through lib/pb.ts so the first paint always shows real data. No client spinner on cold load.
  • Client Components (the two Explorers) take that first page as initialData and re-fetch through /api/pb/records/list for pagination, search, and filter changes.
  • API route handlers sit in app/api/pb/records/[list|...id]/route.ts. They are the only place PB_TOKEN is referenced.

Filter syntax

PocketBase filter expressions used by the explorers:

  • Case-insensitive search: field :~ 'value'
  • Equality: field = 'value'
  • Boolean: is_active = true
  • Range match: enterprise_status :~ 'deregist'

The build*Filter helpers in app/directors/DirectorExplorer.tsx and app/companies/CompanyExplorer.tsx are the canonical place to read / change the filter behaviour.

Browser safety

  • lib/pb.ts imports "server-only" so any accidental import from a "use client" module trips a build-time error.
  • Tailwind utility classes reference CSS variables (bg-surface, text-fg, border-border — wired in tailwind.config.ts). No raw hex outside globals.css.

Project structure

.
├── app/
│   ├── api/pb/records/
│   │   ├── list/route.ts         # GET paginated list
│   │   └── [id]/route.ts         # GET single record
│   ├── companies/
│   │   ├── [id]/page.tsx
│   │   ├── CompanyExplorer.tsx
│   │   └── page.tsx
│   ├── directors/
│   │   ├── [id]/page.tsx
│   │   ├── DirectorExplorer.tsx
│   │   └── page.tsx
│   ├── error.tsx
│   ├── layout.tsx
│   ├── not-found.tsx
│   ├── globals.css
│   └── page.tsx
├── components/
│   ├── NavBar.tsx
│   ├── PageHeader.tsx
│   ├── QueryProvider.tsx
│   ├── Skeleton.tsx
│   ├── StatCard.tsx
│   └── StatusBadge.tsx
├── lib/
│   ├── api.ts                    # Browser-safe client (calls /api/pb/...)
│   ├── format.ts                 # Defensive formatters
│   ├── pb.ts                     # Server-only PB client
│   └── types.ts                  # Director + Company + PBList types
├── .env.local.example
├── .gitignore
├── next.config.mjs
├── package.json
├── postcss.config.mjs
├── tailwind.config.ts
└── tsconfig.json

Deploy

Local dev only for this iteration. To wire up Vercel later:

  1. Add the project as a Vercel app pointing at this directory.
  2. Set the two env vars (PB_URL, PB_TOKEN) in the Vercel project settings.
  3. The 14.x Next.js App Router setup auto-builds with no extra config.