# 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.** ```bash 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 ```bash 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 `EXPOSE`s 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/ PATCH https://your-host/api/collections/tracker_progress/records/ ``` 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 ```bash 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.