Workflow-App/Workflow
sjcoetzeesj-coder 2f01b55d5a feat(sars): end-of-month submission tick-boxes on SARS registrations
Add a simple yes/no tick box on the far right of every table in the
SARS registrations tab, so SJ can tick off each client as the period's
return is filed and confirm nothing was missed at end of month.

- New PB collection sars_submission_flags (pbc_3539276419): company
  relation, return_type select, period (YYYYMM), submitted bool,
  submitted_at date. One row per (company, return_type, period).
- New route /api/sars-submission-flags with GET (list), POST (upsert,
  server owns submitted_at) and DELETE (Clear all for a period).
  Hard-allowlisted fields and a fixed collection id.
- Explorer gains a period banner, a submitted/total counter, a
  Submitted column on desktop and a tick box on the mobile cards,
  and a Clear all button guarded by a confirm.

The counter is scoped to the rows actually on screen. A flag can
outlive the filter that surfaced its company (a client can lose its
PAY/E number), and counting those made the banner read 4/18 while
only 3 boxes were ticked.

Period is the current month and rolls over on its own; Clear all is
what resets a type between periods. Per-month history is deliberately
out of scope for this first pass.
2026-10-20 12:30:06 +02:00
..
app feat(sars): end-of-month submission tick-boxes on SARS registrations 2026-10-20 12:30:06 +02:00
assets feat: commit Workflow app source; move CIPC credentials to env 2026-10-18 15:21:45 +02:00
components fix: resolve all 7 type errors that broke the production build 2026-10-18 15:48:50 +02:00
docs/superpowers feat: commit Workflow app source; move CIPC credentials to env 2026-10-18 15:21:45 +02:00
lib feat(sars): end-of-month submission tick-boxes on SARS registrations 2026-10-20 12:30:06 +02:00
scripts fix(cipc): stop deadlocking wrapper on agent-browser daemon start 2026-10-19 13:40:36 +02:00
.cipc-service-launcher.cmd feat: commit Workflow app source; move CIPC credentials to env 2026-10-18 15:21:45 +02:00
.dockerignore build: make Dockerfile Coolify-ready 2026-10-18 15:30:20 +02:00
.env.example feat(auth): password gate replacing the IP-only middleware guard 2026-10-18 18:39:27 +02:00
.run-dev.ps1 feat: commit Workflow app source; move CIPC credentials to env 2026-10-18 15:21:45 +02:00
.start-cipc-service.ps1 feat: commit Workflow app source; move CIPC credentials to env 2026-10-18 15:21:45 +02:00
docker-compose.yml build: make Dockerfile Coolify-ready 2026-10-18 15:30:20 +02:00
Dockerfile build: make Dockerfile Coolify-ready 2026-10-18 15:30:20 +02:00
favicon.png feat: commit Workflow app source; move CIPC credentials to env 2026-10-18 15:21:45 +02:00
image-1.png feat: commit Workflow app source; move CIPC credentials to env 2026-10-18 15:21:45 +02:00
image-2.png feat: commit Workflow app source; move CIPC credentials to env 2026-10-18 15:21:45 +02:00
image.png feat: commit Workflow app source; move CIPC credentials to env 2026-10-18 15:21:45 +02:00
logo.png feat: commit Workflow app source; move CIPC credentials to env 2026-10-18 15:21:45 +02:00
middleware.ts feat(auth): password gate replacing the IP-only middleware guard 2026-10-18 18:39:27 +02:00
next-env.d.ts feat: commit Workflow app source; move CIPC credentials to env 2026-10-18 15:21:45 +02:00
next.config.mjs feat: commit Workflow app source; move CIPC credentials to env 2026-10-18 15:21:45 +02:00
package-lock.json feat: commit Workflow app source; move CIPC credentials to env 2026-10-18 15:21:45 +02:00
package.json feat: commit Workflow app source; move CIPC credentials to env 2026-10-18 15:21:45 +02:00
postcss.config.mjs feat: commit Workflow app source; move CIPC credentials to env 2026-10-18 15:21:45 +02:00
README.md feat: commit Workflow app source; move CIPC credentials to env 2026-10-18 15:21:45 +02:00
Sample_ChangeInShareholders_Letter.docx feat: commit Workflow app source; move CIPC credentials to env 2026-10-18 15:21:45 +02:00
Sample_ChangeInShareholders_Letter.pdf feat: commit Workflow app source; move CIPC credentials to env 2026-10-18 15:21:45 +02:00
tailwind.config.ts feat: commit Workflow app source; move CIPC credentials to env 2026-10-18 15:21:45 +02:00
tsconfig.json feat: commit Workflow app source; move CIPC credentials to env 2026-10-18 15:21:45 +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.