No description
Find a file
Dave 471cf6fb3c Project tracker seeded from the Mega Infrastructure Candy barchart
App for the Mega Infrastructure AI Integration programme (A000) and Mega
Plant (B110). 100 activities across 2 programmes, 06 Oct 2026 - 31 Aug 2027,
parsed from the client PDF and frozen as an immutable baseline.

Views: Dashboard, Timeline (month grid + week grid matching the PDF's
Friday-anchored week numbering), Todo list, WBS, Data.

Notes on the source data:
- Hierarchy is derived from the PDF's indentation, not the activity code.
  Codes do not sort structurally (A490 sits under Workforce, A510 under
  Financials), so a code-ordered import would produce a wrong tree.
- The schedule is built from the dates, not the PDF's "Durn" column, which
  disagrees with its own dates for 13 of the 100 activities.
- Spec issues found in the PDF are surfaced in-app under Data: 2 unresolved
  "?" placeholders, 6 activities sharing one stretched 6-week window while
  declared 15 days, 13 duration mismatches, 17 spelling corrections
  (original wording preserved and viewable).

Progress (status, % complete, note) is stored behind a pluggable adapter so
the site can be static today and point at a shared JSON store later without
touching the UI.
2026-10-01 08:48:51 +02:00
public Project tracker seeded from the Mega Infrastructure Candy barchart 2026-10-01 08:48:51 +02:00
scripts Project tracker seeded from the Mega Infrastructure Candy barchart 2026-10-01 08:48:51 +02:00
src Project tracker seeded from the Mega Infrastructure Candy barchart 2026-10-01 08:48:51 +02:00
.dockerignore Project tracker seeded from the Mega Infrastructure Candy barchart 2026-10-01 08:48:51 +02:00
.gitignore Project tracker seeded from the Mega Infrastructure Candy barchart 2026-10-01 08:48:51 +02:00
Dockerfile Project tracker seeded from the Mega Infrastructure Candy barchart 2026-10-01 08:48:51 +02:00
index.html Project tracker seeded from the Mega Infrastructure Candy barchart 2026-10-01 08:48:51 +02:00
nginx.conf Project tracker seeded from the Mega Infrastructure Candy barchart 2026-10-01 08:48:51 +02:00
package-lock.json Project tracker seeded from the Mega Infrastructure Candy barchart 2026-10-01 08:48:51 +02:00
package.json Project tracker seeded from the Mega Infrastructure Candy barchart 2026-10-01 08:48:51 +02:00
README.md Project tracker seeded from the Mega Infrastructure Candy barchart 2026-10-01 08:48:51 +02:00
tsconfig.json Project tracker seeded from the Mega Infrastructure Candy barchart 2026-10-01 08:48:51 +02:00
vite.config.ts Project tracker seeded from the Mega Infrastructure Candy barchart 2026-10-01 08:48:51 +02:00

Mega Infrastructure — Project Tracker

A project tracker seeded from Mega Infrastructure AI intergration system.pdf (a Candy 2.05p / P6 barchart printed 30 Sep 2026). 100 activities, 2 programmes, 06 Oct 2026 → 31 Aug 2027.

npm install
npm run dev        # http://localhost:4004
npm run build      # -> dist/  (static, drop on any host)

Port 4004 on purpose — 3000 is taken by another local app.

What's in it

View What it does
Dashboard Weighted % complete, counts by status, overdue, starting-this-week, workstream health, build-load-by-month chart
Timeline Collapsible WBS Gantt. Month grid for reading, Week grid matches the PDF (Friday-anchored, the SA convention Candy uses). Today-line, status colours, progress fill.
Todo list The 78 deliverables as a checklist. Filter by window (open / next 7d / next 30d / in-flight / overdue / unconfirmed), status, workstream, free text. Group by workstream, status or start month. Inline status + % slider.
WBS Full 100-row hierarchy matching the PDF, with rollup % and status. Toggle corrected names ↔ original PDF wording.
Data Source provenance, sharing config, export/import, and the spec issues found in the PDF.

Click any activity (bar, row or todo) to open the edit drawer: status, % complete, note, plus the plan facts and any flags attached to that activity.

Appearance

Dark/light mode plus four accent colours, set from the topbar.

  • Mode — sun/moon toggle, dark by default. An explicit choice sticks from then on.
  • Accent — Blue, Violet, Emerald, Amber. Each has a lighter variant tuned for dark mode (#2563eb light / #60a5fa dark, and so on) so contrast holds in both.

Both persist to localStorage. An inline script in index.html resolves the theme before first paint, so there's no flash of the wrong colours on reload — it mirrors src/lib/appearance.ts (DEFAULT_MODE / DEFAULT_ACCENT), so keep the two in sync if you change the defaults or the key names.

All colour is token-driven from the top of src/styles.css. To add a fifth accent, add one entry to ACCENTS in src/lib/appearance.ts, a [data-accent="..."] rule and its [data-theme="dark"][data-accent="..."] counterpart in styles.css, and the value to the inline script's whitelist.

Deploying to Coolify

docker build -t mega-tracker .

Multi-stage: node:22-alpine builds, nginx:alpine serves the static output. Final image is nginx plus ~215 KB of files — no Node runtime, no node_modules.

In Coolify: New Resource → Dockerfile, point it at this repo/directory. It finds the Dockerfile automatically.

  • Port: 80 (the Dockerfile EXPOSEs it; Coolify/Traefik routes to it)
  • Build args: none needed
  • Domain: set it on the resource; Coolify generates the Traefik route and TLS for you
  • Health check: baked into the image (wget --spider every 30s)

Use a subdomain, not a path. The build emits absolute asset URLs (/assets/…). That is correct for a dedicated hostname like tracker.mega.co.za, and wrong for a path mount like example.com/mega/, which would 404 on every asset. If you ever need a subpath, set base: '/mega/' in vite.config.ts and rebuild.

Caching is deliberate. Hashed assets under /assets/ get max-age=31536000, immutable; the app shell gets no-store. A new deploy emits new asset filenames, so this is always correct, and it prevents the classic "the update didn't work" browser cache bug.

If you ever need build-time config

Vite inlines VITE_* variables into the bundle at build time, so they must be set as build arguments in Coolify, not runtime environment variables. There is currently nothing to configure — no API base URL, no feature flags. If you add the shared progress store (below) and need a default endpoint, add a --build-arg VITE_PROGRESS_URL=… and read it via import.meta.env.

Data model

The plan (codes, names, dates, hierarchy) is baked into src/data/baseline.ts and is never edited by the app. Only progress is recorded: status, % complete, and a note, keyed by activity code.

Parent rollups are duration-weighted from the children, using spanDays — the working days the activity's own dates actually span — rather than the PDF's Durn column, which disagrees with the dates for 13 of the 100 activities.

Storage, and the honest limitation

Progress defaults to localStorage. That means a static deploy shows the project owner the plan but not your progress — the plan is in the bundle, the progress is in your browser. The owner would see every activity at 0%.

To share, open Data → Share progress with the project owner and point it at any endpoint that accepts GET and PUT of a JSON body. A single-row PocketBase record works and needs no schema knowledge in the app:

GET   https://your-host/api/collections/tracker_progress/records/<RECORD_ID>
PATCH https://your-host/api/collections/tracker_progress/records/<RECORD_ID>

The adapter is endpoint-agnostic (src/lib/storage.ts → remoteBlobAdapter), so it also works against a tiny hand-rolled endpoint or a KV store. The auth token is kept in the browser only and is never bundled into the deployed files.

Export/import JSON works regardless of adapter, so you always have a portable backup.

Spec issues found in the PDF

Flagged in-app under Data → Spec issues, and derived at runtime from the baseline rather than hardcoded:

  • 2 activities still contain a ? — B220 Payments ?, B340 Per Bank?. Unfinished spec text.
  • 6 activities share one identical 6-week window (A490, A140, A180, A220, A260, A320, all 08 Dec 26 → 19 Jan 27) while each is declared 15 working days but occupies 31. Reads as a bulk edit or a scheduling-constraint artefact in Candy, not a plan.
  • 13 activities have a duration that disagrees with their own dates.
  • 17 spelling corrections applied for display; the original wording is preserved and viewable in the WBS tab.
  • A000 and A010 cover the identical window — worth confirming whether "Site Dashboard" is a module or the whole programme.
  • The plan is heavily front-loaded: 33 of 78 deliverables start in the first 8 weeks, peaking at 10 concurrent in the week of 13 Oct 2026.

Regenerating from a new PDF

pdftotext -layout "new-plan.pdf" /tmp/mega.txt
python3 scripts/parse_pdf.py       # -> /tmp/mega_acts.json
python3 scripts/gen_baseline.py    # -> src/data/baseline.ts

Hierarchy is taken from the PDF's indentation, not the activity code. Codes do not sort structurally — A490 sits under Workforce, A510 under Financials, A580/A590 under Health & Safety. Re-importing from a spreadsheet that sorts by code will produce a wrong tree.