Commit graph

16 commits

Author SHA1 Message Date
DEls
30a45f759d Merge branch 'feat/site-scope' into main
Global site scope: one switcher in the topbar, carried in the URL as
?site=, resolved server-side via the getSiteScope() seam, and applied as
a PocketBase site= filter across every dashboard module. Replaces the
four independent per-table project-code dropdowns.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

# Conflicts:
#	docs/superpowers/plans/2026-09-11-site-scope.md
2026-09-11 23:57:51 +02:00
DEls
0c29049324 fix(site-scope): close two latent leaks and the stale scope pill
Three review findings, all of which break the moment `allowed` stops
being every site — i.e. as soon as PocketBase users land.

siteIdFilter(): the Overview spelled its `sites` filter out as
`mode === "all" ? "" : id="..."`, which drops the `unrestricted` check
that makes "all" safe and would load every site for a manager allowed
only a subset. Both field variants now go through one shared function so
the check cannot be forgotten again. Covered by six new tests.

Site pickers read scope.allowed: upload and create dialogs took their
options from unfiltered `sites` reads, so a restricted user could
attribute a PO, delivery note, timesheet or plant item to a site they
cannot even open — a write path, not just a display leak. View scope
must not narrow a picker, but permission scope must. Also drops one
redundant sites query on the equipment page.

useScopeFallback(): the pill fell back to a value the layout computes
once, and layouts do not re-render on navigation — so after any link
that doesn't carry ?site= forward (24 of them), the pill read
"All sites" over a single site's figures. It now reads the live cookie,
which the switcher keeps current, fixing every link rather than the four
scopeAwareHref already patched.

Verified against the running app: scope survives a client-side
navigation through a bare link, and the Overview reads 1/"The Hills
ext 12" scoped and 2/"Across every site" unscoped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 23:56:28 +02:00
DEls
4ac5f3a220 fix(site-scope): preserve ?site= across sidebar navigation
Bug: picking a site in the topbar pill updated both URL and cookie,
but the sidebar nav Links were plain paths ('/dashboard/sites',
'/dashboard/financial/purchase-orders', ...). Clicking any of them
stripped the '?site=' query string. The page's getSiteScope() then
fell back to the still-set cookie and filtered the data correctly,
but the pill's useSearchParams() and the layout's frozen fallbackValue
both produced mode='all' — so the topbar pill showed 'All sites · N'
while every table was filtered to the picked site. The visual pill
and the data disagreed on every screen the user clicked.

Fix: extract scopeAwareHref() and route every sidebar Link through
it. The helper carries the current '?site=' (and nothing else) into
the destination URL, so the URL stays the single source of truth
for both the page filter and the topbar pill across navigation.

Layouts do not re-render on navigation, so preserving the URL is
the only viable fix — making the layout re-run getSiteScope() on
every navigation is what the plan explicitly avoided by design.

Tests: 5 new unit tests for scopeAwareHref covering the bare-path,
scope-only, drop-other-params, url-encoding, and 'all' sentinel
cases. Total: 651 tests passing, typecheck clean.
2026-09-11 23:41:11 +02:00
DEls
729118d5dd feat(site-scope): exempt the Sites list, add a per-row scope action 2026-09-11 23:20:05 +02:00
DEls
6609ce8e50 feat(site-scope): add the topbar scope switcher 2026-09-11 23:03:10 +02:00
DEls
63eb8ed931 feat(site-scope): load the allowed site list in the dashboard layout 2026-09-11 23:02:30 +02:00
DEls
f80c30d369 feat(financial): wire up per-collection upload status pages
Adds the "Upload status" buttons on Purchase Orders and Delivery Notes,
the shared badge/KPI/filter UI they use, and removes the now-dead
Uploads sidebar entry and Financial landing card.
2026-09-11 21:44:12 +02:00
DEls
b454621ecf feat(suppliers): add Suppliers to the Financial sidebar group 2026-09-11 18:20:34 +02:00
DEls
1d706e1985 feat(dashboard): grouped sidebar navigation with landing pages
Implements docs/superpowers/specs/2026-09-11-sidebar-restructure-design.md.
Reorganizes the flat 7-item sidebar into Workforce/Plant/Financial groups,
each with a landing dashboard and sub-pages split out of the former
combined Employees and Purchasing pages. Old routes (/dashboard/employees,
/fuel, /fuel/[vehicleId], /plant/[vehicleId], /purchasing,
/purchasing/[poId]) now redirect to their new locations so existing
bookmarks and links keep working.

New pages: Workforce, Plant, Financial landing dashboards; Timesheets
(entries table + upload, surfacing document status that was previously
invisible); Fuel Logs (flat table across both vehicle types); Delivery
Notes (the page docs/superpowers/specs/2026-09-11-ingestion-restructure-design.md
section 8 deliberately deferred); Uploads (combined PO/DN ingestion status).

Moved-unchanged pages (Workers, Vehicles, Equipment) verified
byte-identical to their prior content via direct diff against main --
relocated only, nothing altered.

Reviewed the initial implementation and found two issues, both fixed
here before commit:
  - The delivery-note review queue (NeedsReviewDns) was duplicated onto
    the Purchase Orders page instead of moving to the new Delivery Notes
    page as specified -- same workflow rendered in two places from two
    independent queries. Removed from Purchase Orders; it now lives
    exclusively on Delivery Notes.
  - The new Uploads page's timestamp column fell back to a `created`
    field that doesn't exist on this PocketBase instance, so it could
    never help. All 24 real purchase_orders predate date_uploaded being
    backfilled and would have shown a blank column forever. Dropped the
    dead fallback; the view already degrades to an em-dash for missing
    timestamps.

Typecheck and full suite verified clean before and after both fixes
(583/583).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 17:47:27 +02:00
DEls
395c0ff114 feat(chat): sidebar link, editable-while-waiting, sticky footer, limit warning
Three concerns from testing:

1. Chat typing UX: the textarea was disabled while a request was in
   flight, so the user couldn't draft the next question. Removed the
   disabled attribute; Enter is just a no-op while busy. Send button
   still gates actual submission.

2. Sticky footer: switched the chat wrapper to 100svh (mobile-keyboard
   aware) and made the composer sticky bottom-0 with a solid background
   so it no longer fades into the scroll area.

3. Limit-warning: the SSE stream now reads the 'done' event and surfaces
   a banner when the server reports the agent loop hit its iteration
   cap, so a quiet stream end isn't mistaken for a complete answer.

Sidebar: added 'Ask' nav item pointing at /dashboard/chat with the
Sparkles icon so the chat is reachable from the dashboard even if the
standalone-PWA install path keeps misbehaving.
2026-08-30 23:51:45 +02:00
DEls
20a16a27f8 Enhance Dashboard and Sidebar Navigation
- Updated the Dashboard page to improve card styling with a warm-amber glow strip and adjusted icon presentation for better visual appeal.
- Expanded the Sidebar navigation by adding new entries for "Sites," "Workforce," "Plant & Equipment," "Fleet & Fuel," and "Purchasing," each with corresponding icons and descriptions to enhance user navigation and access to key features.
2026-08-19 01:54:16 +02:00
DEls
c5b1acfc7f Update package dependencies and remove unused API routes
- Added `pocketbase` as a dependency in `package.json` and `package-lock.json`.
- Updated the `dev` script in `package.json` to run on port 6004 instead of 3000.
- Removed unused API routes: `src/app/api/health/route.ts`, `src/app/api/mcp/route.ts`, `src/app/api/upload/route.ts`, and their associated logic to streamline the codebase.
- Cleaned up `package-lock.json` by removing unnecessary peer dependencies and ensuring consistency in the dependency tree.
2026-08-19 00:14:47 +02:00
DEls
97cb5a48b5 Sidebar: switch breakpoint from xl (1280px) to lg (1024px)
The sidebar was hidden until 1280px wide, which meant laptops and
small desktops between 1024-1280px (incl. iPads in landscape, many
Windows laptops, Chromebooks) saw the hamburger instead of the
persistent sidebar. That felt wrong on what was clearly a desktop.

Dropping to 'lg' (1024px):
- Phone portrait (< 768 px)  → hamburger ✅
- Tablet portrait (768-1024 px) → hamburger ✅
- iPad landscape / laptop (1024 px+) → sidebar ✅
- 932 px iPhone landscape cap is below 1024 px, so the hamburger
  still kicks in for all landscape phones.

Changed 4 occurrences: 3x 'xl:hidden' → 'lg:hidden', 1x
'hidden xl:block' → 'hidden lg:block' on the <aside> element.
2026-08-18 13:31:31 +02:00
DEls
3506640e4a Add Uploads page with 4 colored drop zones
New /dashboard/uploads page with a 2x2 grid of drop zones, one per
ingest source:

  - Orders (orange) — CSV / XLS / XLSX, max 10 MB
  - Delivery Notes (teal) — PDF / images, max 20 MB
  - Fuel Logs (yellow-green) — CSV / XLS / XLSX, max 5 MB
  - Time Sheets (green) — CSV / XLS / XLSX, max 5 MB

Each block has:
  - A coloured left stripe + icon disc in the accent colour
  - Title, format-count badge, and a long description of what to upload
  - File-format chips and a max-size hint
  - A drag-and-drop drop zone that also accepts files via click
  - A primary 'Upload X' button in the accent colour
  - A 'Recent' list showing the last 4 uploads with status badges

When files are dropped or picked, the client POSTs to
/api/upload with a 'type' field. The endpoint validates MIME and size
against the kind-specific rules in src/lib/uploads.ts and returns a
JSON descriptor with accepted/rejected entries. New entries are
prepended to the page's recent-uploads list in real time, and a
bottom-right toast shows accepted/rejected counts.

The sidebar gets a new 'Uploads' nav item with the upload icon.

Files:
  - src/lib/types.ts                    type definitions
  - src/lib/uploads.ts                   acceptance rules + mock history
  - src/app/api/upload/route.ts          type-aware upload handler
  - src/app/dashboard/uploads/page.tsx   the new page
  - src/components/layout/sidebar.tsx    Uploads nav entry
2026-08-09 19:30:00 +02:00
SJCoetz
df459de0f5 Remove Active Sites card from sidebar
The card showed hardcoded '5 projects · 3 flagged · 2 on schedule'
stats that were never updated from the mock data and duplicated
information in the Sites module. Removing it gives the sidebar a
cleaner Logo → Nav → Lock structure and means the Lock screen button
is visible without scrolling on standard heights.

Also align the mobile drawer's close-button breakpoint from lg to xl
to match the rest of the sidebar's breakpoint logic.
2026-08-09 03:02:59 +02:00
SJCoetz
eeea5b7592 Initial commit: MEGA INFRASTRUCTURE dashboard + Coolify Dockerfile 2026-08-09 01:37:40 +02:00