Development
Intranet Project Status
What's been built, how it works, and what's coming next.
13
Pages
17
Dashboard Widgets
30
WMS Documents
200+
Commits
Infrastructure & Hosting
Azure Static Web Apps, Entra ID, GitHub Actions
Infrastructure & Hosting
Azure Static Web Apps, Entra ID, GitHub Actions
- Azure Static Web Apps (Standard) — fully static site deployed to Azure SWA with custom domain
intranet.westlinklogistics.com - Entra ID authentication — platform-level SSO restricts access to Westlink employees. No public access
- GitHub Actions CI/CD — automated build and deploy on push to main. Build runs in workflow, SWA deployer receives pre-built output
- Azure Function proxy —
/api/proxyendpoint for RSS feeds and market data (CORS bypass) - Custom domain + SSL — automatic HTTPS via Azure-managed certificate
Technology Stack
Astro 6, React 19, Tailwind v4, shadcn/ui
Technology Stack
Astro 6, React 19, Tailwind v4, shadcn/ui
- Astro 6 — static site generator. Pages are
.astrocomponents that compile to zero-JS HTML by default - React 19 islands — interactive components (widgets, search, forms) hydrate client-side via
client:load/client:idledirectives. Layout stays pure Astro - Tailwind CSS v4 — utility-first styling via Vite plugin (not PostCSS). Design tokens as CSS variables in
globals.css - shadcn/ui (new-york) — accessible UI primitives (dialog, command palette, alert). HSL-based semantic tokens
- MSAL.js — Microsoft Authentication Library for client-side Graph API access. Incremental consent for feature-specific scopes
- Microsoft Graph API — powers People Directory, Calendar, To Do, Planner, Team Presence, Recent Files, and preferences sync
- Fluid typography — root font-size scales from 14px (768px viewport) to 16px (1920px baseline) via CSS
clamp() - View transitions — Astro view transitions for smooth page navigation. Named transitions on sidebar and main content
Dashboard & Widgets
18 widgets, drag-and-drop, roaming sync
Dashboard & Widgets
18 widgets, drag-and-drop, roaming sync
Fully customisable widget grid with drag-and-drop reordering, two-axis resizing, and a widget catalogue. Layout persists to localStorage and syncs to Microsoft Graph open extensions for cross-device roaming.
Widgets
Dashboard features
- Quick Actions bar — customisable coloured shortcut buttons with drag reorder, icon/colour/URL editing, gradient presets
- Container queries — widgets adapt content based on their actual rendered size, not viewport
- Roaming preferences — layout, widget sizes, quick actions, feed selections sync via Graph open extensions
- Timestamp-based sync guard — local changes always win over stale remote data
Intranet Pages
14 pages with branded heroes and section images
Intranet Pages
14 pages with branded heroes and section images
- Dashboard — personalised greeting, quick actions, customisable widget grid
- People Directory — live Graph API directory with search, filters, premium card layout, team availability timeline with meeting room status
- Templates — SharePoint document library browser with search, views, favourites, and M365 file icons
- Company — corporate details, office locations, ISO/DISP/JOSCAR certifications with certificates, FIATA membership, full insurance portfolio with expandable summaries and downloadable policy documents
- Help — 5-section guide covering getting started, widgets, customisation, accessibility, and troubleshooting with Intune/ad-blocker guidance
- Cyber Security — phishing awareness, password/MFA guidance, useful security links, incident reporting
- WMS Library — 27 management system documents via Astro content collections with Zod schema, search, classification banners, TOC sidebar, keyboard navigation
- Process Overview — interactive BPMN-style flowchart for WMS processes
- Leave Request — forms prototype (dev only)
- Leave Entry — admin-only annual leave entry (gated by
Westlink Leave AdminDataverse role); mirrors payroll-approved leave to the Travel & leave calendar - Dev Status — this page
- Custom 404 — branded error page
Authentication & APIs
MSAL, Graph API, incremental consent
Authentication & APIs
MSAL, Graph API, incremental consent
- MSAL.js — PublicClientApplication with localStorage cache. Silent token acquisition with redirect fallback
- Incremental consent — 4 base scopes at login (Directory.Read.All, ProfilePhoto.Read.All, Presence.Read.All, Calendars.Read), feature-specific scopes (Mail.Read, Chat.Read, Tasks.ReadWrite, Sites.Read.All, Schedule.Read.All, Files.Read, User.ReadWrite) requested on first use via popup
- Graph API endpoints — /me, /users, /me/calendarView, /me/todo/lists, /me/planner, /me/drive/recent, /me/presence, /me/extensions, /communications/presences
- SWA /.auth/me fallback — Azure SWA built-in auth endpoint as backup when MSAL is blocked by ad blockers
- Open extensions — preferences sync via Graph open extensions on /me (single extension stores all synced keys)
- External APIs — Open-Meteo (weather), Yahoo Finance (markets), MarineTraffic (fleet), Windy (weather map), RSS feeds via Azure Function proxy
Payments (deep dive)
React island, 5 Power Automate flows, Dataverse, Xero, Planner
Payments (deep dive)
React island, 5 Power Automate flows, Dataverse, Xero, Planner
The Payments page composes Accounts Payable bills into payment batches for the Payments v2 Planner plan. It is a single React island (client:load) that runs a drag-and-drop batching UI on the front end and orchestrates five Power Automate flows plus Dataverse on the back end. The page ships zero business data — every figure is fetched live from Xero (via Power Automate) at runtime. Entry point: src/pages/payments.astro → <PaymentsApp client:load />. All client code lives under src/components/payments/ and src/lib/payments/.
Page & components
- PaymentsApp.tsx — the orchestrator. Holds all state via
useReducer, wires@dnd-kitDndContext(pointer + keyboard sensors, keyboard-accessible drag), dispatches every flow call, and renders the three-pane layout - BillsPool.tsx / BillCard.tsx — left pane: unbatched AP bills, draggable, with AR-linkage and AM-cert badges
- BatchList.tsx / BatchCard.tsx — centre pane: composed batches as drop targets; per-batch totals, validation errors, and lock state
- PreviewPanel.tsx — right pane: inline PDF preview of a single bill or a merged batch
- CancelBatchDialog.tsx — confirmation dialog for cancelling a submitted batch
- badges.tsx — status / payment-type / AR-status pills
State management
- state.ts — a single
useReducer:PaymentsStateplus a discriminatedActionunion (~28 actions). The reducer is pure and is the only place state changes - Crash-resilient composition — batches reconstruct from
cf_compositionsnapshoton reload, so the page survives Flow 1 wiping the ephemeral batch-item rows; bills whose Xero payment-date has since changed are synthesised back from the snapshot (stale-date warning)
Business logic — suggestBatches.ts
- suggestBatches(bills) — auto-groups bills into batches: International by supplier + currency, BPay as singletons, DirectCredit by supplier / overhead
- derivePaymentTypeFromBills — International (any SWIFT/IBAN) > BPay > DirectCredit
- computeBatchTotals — totals + currency auto-derive (homogeneous → derived, mixed → keep declared)
- validateBatch — blocks submit on: empty, international multi-supplier, international multi-currency, BPay multi-item, or a missing AM certificate
Backend — five Power Automate flows
Long-running flows: fire-and-poll
Flows 1 and 3 exceed the Power Automate HTTP-gateway's ~120 s synchronous-response window. The client (flow.ts) fires the flow, uses the synchronous 200 if it arrives in time, and otherwise polls Dataverse (dataversePoll.ts) for the result the flow persists:
- Flow 1 writes the full bills envelope to
cf_payment_run.cf_billsjson; the client polls that column matched on a per-callcorrelationId, so a re-run never reads a stale envelope. 4 s interval, 600 s timeout - Flow 3 writes
cf_payment_batch.cf_mergedpdfurl/cf_mergedpdfsize; the client polls those. 3 s interval, 180 s timeout - FAST_FAIL_MS (10 s) discriminates a real failure (fast 502 / CORS → throw immediately) from the expected long run (slow timeout → poll). A failed flow's Response action never runs, so the gateway 502s just as fast as a hard error — hence the time-based heuristic
Authentication — two distinct paths
- Flow calls — anonymous SAS-signed HTTP-trigger URLs; the signature in the URL is the auth (no MSAL/Bearer). URLs are injected via
PUBLIC_FLOW_*_URL(Azure SWA app settings, never committed).postFlowenforceshttpsand strips the SAS query-string out of any error message - Dataverse polling — MSAL Dataverse token (
getDataverseToken, separate scopes from Graph) sent as a Bearer header viadvFetch - Page access — a finance allowlist enforced page-side in
financeAuth.ts(isFinanceUser: MSAL → SWA/.auth/me→ localhost-dev bypass). Because the flows are anonymous, this page gate plus the Sidebar Finance entry are the authorization set. Dataverse reads additionally require theWestlink - Payments (Intranet)security role
Data stores & integrations
- Dataverse —
cf_payment_run,cf_payment_batch(note the irregular Web API pluralcf_payment_batchs),cf_payment_batch_items(ephemeral — rewritten on every Flow 1 run) - Xero — AP bills and AR invoices, both via the Xero connector inside Flow 1
- SharePoint — merged-PDF storage. It is served with
X-Frame-Options: SAMEORIGIN, so the preview fetches it as a blob via Graph (Files.Read.All) and falls back to opening a new tab if blocked or oversized - Planner — the Payments v2 plan; one task per submitted batch. A task at
percentComplete = 100means the batch is paid → it locks (no edit / cancel / delete)
Dependencies & dev mode
- npm —
@dnd-kit/core+@dnd-kit/sortable(drag-and-drop),sonner(toasts),lucide-react(icons), shadcn/ui primitives, MSAL.js - Mock mode — set
PUBLIC_DEV_MODE_MOCK_FLOWS=1andmockFlows.tsintercepts all five flows with canned responses (8 sample bills) for offline UI work - Note — Power Automate flow definitions live in the Westlink PA environment, not this repo. The repo holds only the client and the contracts (
src/lib/payments/)
Design & UX
Brand identity, dark mode, accessibility, print
Design & UX
Brand identity, dark mode, accessibility, print
- Westlink brand identity — primary #015696, secondary #0c92d1, accent #F08920, teal #00b0ae. Gradient accent lines, triangle motifs, branded card borders
- Dark mode — navy palette (not neutral grey), .dark class + prefers-color-scheme fallback, inline script prevents FOUC, synced across devices
- AI-generated imagery — all hero banners and section images generated via nano-banana (Gemini Flash) at 21:9 2K
- Fluid typography — CSS clamp() scales root font from 14px to 16px baselined on 1920x1080
- WCAG 2.2 AA — skip links, focus-visible rings, aria-current on nav, semantic HTML, keyboard-accessible drag-and-drop
- Print styles — hides chrome, shows link URLs, "Uncontrolled when printed" footer for WMS docs
- Animations — fade-in-up entrance animations, staggered children, respects prefers-reduced-motion
- macOS dock effect — collapsed sidebar icons magnify on hover with neighbour scaling
- Command palette — Ctrl+K search across all pages and WMS documents
- Mega menu — header dropdown with all site links, searchable via command palette
WMS Document Library
27 documents, content collections, SharePoint sync
WMS Document Library
27 documents, content collections, SharePoint sync
- Content collections — 27 markdown documents with Zod-validated frontmatter schema (ref, title, status, department, document type, approver, effective date)
- Conversion pipeline —
scripts/convert-wms.mjstransforms SharePoint HTML exports into clean markdown - Dedicated layout —
WmsDocument.astrowith classification banner, auto-generated TOC sidebar, keyboard navigation (j/k/h), print styles - Dynamic routes —
[slug].astrogenerates a page per document at build time - Search — WMS documents searchable via command palette with ref and title matching
- Document types — policies (GOV-POL), procedures (GOV-PRO), standards (GOV-STD), schedules (GOV-SCH), manuals (QHSE-MAN), commercial documents (COM-DOC)
Corporate Document Library
Certificates, insurance policies, reference guides
Corporate Document Library
Certificates, insurance policies, reference guides
All corporate documents hosted locally on the intranet as static assets, downloadable directly from the Company page.
Certificates
- Certificate of Incorporation + Certificate of Change of Name
- ISO 9001:2015, ISO 14001:2015, ISO 45001:2018 (Equal Assurance)
- DISP Membership Certificate (Defence)
- JOSCAR Pre-qualification Certificate
- FIATA Membership Certificate
Insurance (31 documents)
- Insurance Manual 2025–26
- 9 policies — certificates of currency, schedules, and wordings for T&L, Excess, Management Liability, MPE, Business Package, Corporate Travel, Workers Comp (WA + QLD), Cyber, Charterers Liability
- 3 branded HTML reference guides — Charterers Summary, Charterers Quick Ref, T&L Quick Ref
- Charterers claims manual + Iran cancellation notice
Backlog & Ideas
Planned features and enhancements
Backlog & Ideas
Planned features and enhancements
- Vessel tracking widget — live AIS positions via VesselFinder API
- Project map — interactive map of active project locations and routes
- Approvals dashboard — centralised view of pending approvals across systems
- TV mode — full-screen auto-rotating dashboard for office displays
- WMS search — full-text search across all management system documents
- Cyber security updates — refresh when defence policies are rewritten in WMS project
Site Taxonomy
Complete inventory of all site elements by category
Site Taxonomy
Complete inventory of all site elements by category
Layouts (2)
| Layout | Shell | Usage |
|---|---|---|
Layout.astro | Standard intranet | Header + Sidebar + Content + Footer |
WmsDocument.astro | WMS documents | Classification banner + TOC sidebar + keyboard nav |
Pages (14)
| Page | Layout | Type | Key Component |
|---|---|---|---|
index.astro | Standard | Dashboard | DashboardGrid |
people.astro | Standard | Directory | PeopleDirectory |
documents.astro | Standard | Library | SharePointBrowser |
company.astro | Standard | Static content | — |
cyber-security.astro | Standard | Awareness | — |
help.astro | Standard | Static content | — |
forms/leave-request.astro | Standard | Form | LeaveRequestForm |
forms/leave-entry.astro | Standard | Form (admin) | LeaveEntryForm |
dev/index.astro | Standard | Dev tools | — |
dev/links.astro | Standard | Dev tools | SiteLinksEditor |
404.astro | Standard | Error | — |
wms/index.astro | Standard | WMS library | WmsLibrary |
wms/[slug].astro | WmsDocument | WMS document | DocumentControls |
wms/process-overview.astro | Standard | Flowchart | ProcessOverview |
Dashboard Widgets (18)
| Widget | Category | Data Source | Load |
|---|---|---|---|
| Weather & Clock | productivity | Open-Meteo API | eager |
| Microsoft To Do | productivity | Graph API (To Do) | lazy |
| Today's Calendar | productivity | Graph API (Calendar) | lazy |
| Quick Links | productivity | local config | eager |
| Recent Files | productivity | Graph API (OneDrive) | eager |
| Planner | productivity | Graph API (Planner) | lazy |
| Quote of the Day | communication | static (quotes.ts) | eager |
| Company News | communication | scraped articles | eager |
| Industry News | communication | RSS via /api/proxy | lazy |
| Team Presence | communication | Graph API (Presence) | lazy |
| NATO Phonetic | compliance | static | lazy |
| Live Fleet Tracker | data | MarineTraffic embed | lazy |
| Windy Weather | data | Windy embed | lazy |
| Markets | data | Yahoo Finance / RSS | lazy |
| Bunker Prices | data | Ship & Bunker / proxy | lazy |
| Inbox | communication | Graph API (Mail) | lazy |
| Teams Chats | communication | Graph API (Chat) | lazy |
| Travel & leave calendar | communication | Dataverse (travel briefings + leave entries) | lazy |
Dashboard Infrastructure (5)
| Component | Role |
|---|---|
DashboardGrid.tsx | Grid layout, drag-drop, persistence |
WidgetShell.tsx | Card wrapper (title, resize, remove) |
WidgetCatalogue.tsx | Add-widget picker dialog |
EditModeToolbar.tsx | Edit / reset controls |
SortableWidget.tsx | Drag handle wrapper |
Interactive Components — React Islands (15)
| Component | Page(s) | Auth |
|---|---|---|
PeopleDirectory.tsx | people | Graph API |
DocumentLibrary.tsx | orphaned | static data |
WmsLibrary.tsx | wms/index | — |
DocumentSearch.tsx | wms docs | — |
DocumentControls.tsx | wms/[slug] | — |
ProcessOverview.tsx | wms/process | — |
flowchart/FlowchartV2.tsx | wms/process | React Flow + dagre |
NodeDetail.tsx | wms/process | — |
ProcessBreadcrumb.tsx | wms/process | — |
LeaveRequestForm.tsx | forms/leave | — |
LeaveEntryForm.tsx | forms/leave-entry | Dataverse + Graph |
LeaveAdminFormCard.tsx | forms (conditional) | Dataverse (role check) |
CommandPalette.tsx | global (layout) | — |
SharePointBrowser.tsx | documents | Graph API |
TeamAvailability.tsx | people | Graph API |
TodayCalendar.tsx | dashboard (widget) | Graph API |
SiteLinksEditor.tsx | dev/links | — |
Chrome — Shared Shell (8)
| Component | Type | Scope |
|---|---|---|
Header.astro | Astro | both layouts |
Sidebar.astro | Astro | both layouts |
Footer.astro | Astro | both layouts |
Breadcrumb.astro | Astro | standard pages |
ThemeToggle.tsx | React | header |
SidebarToggle.tsx | React | header |
MegaMenu.tsx | React | header |
UserAvatar.tsx | React | header |
Utility Components (4)
| Component | Purpose |
|---|---|
Greeting.tsx | Time-based greeting on dashboard |
AnimatedCounter.tsx | Number animation for stats |
ScrollProgress.tsx | Reading progress bar |
LiveClock.tsx | Clock display |
UI Primitives — shadcn/ui (17)
alert-dialog, avatar, badge, breadcrumb, button, calendar, card, command, dialog, dropdown-menu, input, label, select, separator, skeleton, sonner, table, tabs, textarea
Content Collections (1)
| Collection | Schema | Count | Source |
|---|---|---|---|
wms | Zod (ref, title, revision, dates, classification, department, documentType, approval, downloads, revisionHistory) | 30 docs | convert-wms.mjs from ~/projects/wms/ |
Services & Libraries (4)
| Module | Purpose |
|---|---|
msal.ts | MSAL auth + Graph API token acquisition |
graph.ts | Graph API helpers |
preferences-sync.ts | Roaming preferences via Graph open extensions |
dashboard/storage.ts | Dashboard layout persistence |
Build & Deploy Infrastructure (5)
| Item | Purpose |
|---|---|
api/proxy/ | Azure Function — CORS proxy for RSS and market feeds |
.github/workflows/deploy.yml | CI/CD → Azure Static Web Apps |
scripts/convert-wms.mjs | WMS HTML → markdown content pipeline |
globals.css | Design tokens (HSL vars, dark mode, print styles) |
staticwebapp.config.json | SWA routing, auth, security headers |
Component Quality Matrix
Evaluation criteria per taxonomy category
Component Quality Matrix
Evaluation criteria per taxonomy category
Each taxonomy category is evaluated against dimensions specific to its role. Cells show current state: ✓ = implemented, ½ = partial, ✗ = missing.
1. Layouts
| Layout | Semantic HTML | Skip Links | Dark Mode | Print Styles | View Transitions | Responsive | CSP Headers |
|---|---|---|---|---|---|---|---|
Layout.astro | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
WmsDocument.astro | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
2. Pages
| Page | Hero | Animations | Semantic HTML | Accessibility | Meta Tags | Lines | |
|---|---|---|---|---|---|---|---|
index.astro | ✓ | ✓ | ✓ | ½ | ✓ | ✓ | 49 |
people.astro | ✓ | ✓ | ✓ | ½ | ✓ | ✓ | 29 |
documents.astro | ✓ | ½ | ✓ | ½ | ✓ | ✓ | 21 |
company.astro | ✓ | ✓ | ✓ | ½ | ✓ | ✓ | 643 |
cyber-security.astro | ✓ | ✓ | ✓ | ½ | ✓ | ✓ | 263 |
help.astro | ✓ | ✓ | ✓ | ½ | ✓ | ✓ | 423 |
forms/leave-request | ✓ | ✗ | ½ | ½ | ✓ | ✓ | 17 |
dev.astro | ✓ | ✓ | ✓ | ½ | ✓ | ✓ | 533 |
wms/index.astro | ✓ | ½ | ✓ | ½ | ✓ | ✓ | 54 |
wms/[slug].astro | ✗ | ✗ | ✓ | ✓ | ✓ | ✓ | 19 |
wms/process-overview | ✓ | ✗ | ½ | ½ | ✓ | ✓ | 26 |
Criteria: Hero = branded hero banner. Animations = entrance animations with stagger. Semantic = section/article/nav. Accessibility = aria attributes beyond layout-inherited. Print = page-specific print rules. Meta = title passed to layout.
3. Dashboard Widgets
| Widget | Loading State | Error State | Empty State | Auth | Refresh | Keyboard | A11y | Lines |
|---|---|---|---|---|---|---|---|---|
| Weather & Clock | ✓ | ✓ | ✗ | ✗ | ✓ | ✗ | ✓ | 396 |
| Microsoft To Do | ✓ | ✓ | ✓ | ✓ | ✗ | ✓ | ✓ | 1157 |
| Today's Calendar | Thin wrapper → delegates to TodayCalendar.tsx (a11y added) | 5 | ||||||
| Quick Links | ✗ | ✗ | ✗ | ✗ | ✗ | ½ | ✓ | 432 |
| Recent Files | ✓ | ✓ | ✓ | ✓ | ✗ | ✗ | ✓ | 197 |
| Planner | ✓ | ✓ | ✓ | ✓ | ✗ | ✗ | ✓ | 582 |
| Quote of the Day | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | 49 |
| Company News | ½ | ✗ | ✓ | ✗ | ✗ | ✗ | ✓ | 144 |
| Industry News | ✓ | ✓ | ✓ | ✗ | ✓ | ✗ | ✓ | 329 |
| Team Presence | ✓ | ✓ | ✓ | ✓ | ✗ | ✗ | ✓ | 365 |
| NATO Phonetic | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✓ | 199 |
| Live Fleet Tracker | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✓ | 244 |
| Windy Weather | ✓ | ✓ | ✗ | ✗ | ½ | ✗ | ✓ | 244 |
| Markets | ✓ | ✓ | ✗ | ✗ | ✓ | ✗ | ✓ | 339 |
| Bunker Prices | ✓ | ✓ | ✓ | ✗ | ✓ | ✗ | ✓ | 290 |
| Inbox | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ | ✓ | 494 |
| Teams Chats | ✓ | ✓ | ✓ | ✓ | ✗ | ✗ | ✓ | 361 |
| Travel Calendar | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ | ✓ | 370 |
Criteria: Loading = Skeleton/spinner while data loads. Error = error message on fetch failure. Empty = message when no data. Auth = uses Graph API token. Refresh = auto-refresh or manual refresh. Keyboard = focus/key handlers beyond browser defaults. A11y = aria labels, roles, sr-only text.
4. Dashboard Infrastructure
| Component | TypeScript | Error Handling | Persistence | Drag A11y | Migration | Perf |
|---|---|---|---|---|---|---|
DashboardGrid | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
WidgetShell | ✓ | ✓ | ✗ | ✓ | ✗ | ✓ |
WidgetCatalogue | ✓ | ✗ | ✗ | ✗ | ✗ | ✓ |
EditModeToolbar | ✓ | ✗ | ✗ | ✗ | ✗ | ✓ |
SortableWidget | ✓ | ✗ | ✗ | ✓ | ✗ | ✓ |
Criteria: TypeScript = fully typed props/state. Error Handling = try/catch on storage/render. Persistence = saves to localStorage or Graph. Drag A11y = keyboard-accessible drag-and-drop. Migration = handles layout version upgrades. Perf = lazy loading, memoization, or Suspense boundaries.
5. Interactive Components — React Islands
| Component | Loading | Error | Keyboard Nav | Search/Filter | Hydration | Graph API |
|---|---|---|---|---|---|---|
PeopleDirectory | ✓ | ½ | ✓ | ✓ | load | ✓ |
DocumentLibrary | ✗ | ✗ | ✓ | ✓ | load | ✗ |
WmsLibrary | ✗ | ✗ | ✓ | ✓ | load | ✗ |
DocumentSearch | ✗ | ✗ | ✓ | ✓ | load | ✗ |
DocumentControls | ✗ | ✗ | ✓ | ✗ | load | ✗ |
ProcessOverview | ½ | ✗ | ✓ | ✗ | load | ✗ |
FlowchartV2 | ✗ | ✗ | ✓ | ✓ | load | ✗ |
NodeDetail | ✗ | ✗ | ✗ | ✗ | load | ✗ |
ProcessBreadcrumb | ✗ | ✗ | ✗ | ✗ | load | ✗ |
LeaveRequestForm | ✗ | ½ | ✓ | ✗ | load | ✗ |
CommandPalette | ✗ | ✗ | ✓ | ✓ | load | ✗ |
SharePointBrowser | ✓ | ½ | ✓ | ✓ | load | ✓ |
Criteria: Loading = visual feedback during data fetch. Error = graceful failure UI. Keyboard = custom key handlers. Search = filter or search capability. Hydration = client:load vs client:idle directive. Graph = uses MSAL token.
6. Chrome — Shared Shell
| Component | Responsive | Dark Mode | Keyboard | ARIA | Animations | Focus Mgmt |
|---|---|---|---|---|---|---|
Header.astro | ✓ | ✓ | ½ | ✓ | ✓ | ½ |
Sidebar.astro | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Footer.astro | ✓ | ✓ | ✗ | ✓ | ✗ | ✗ |
Breadcrumb.astro | ✓ | ✓ | ✗ | ✓ | ✗ | ✗ |
ThemeToggle | ✓ | ✓ | ✓ | ½ | ✓ | ✓ |
SidebarToggle | ✓ | ✓ | ✓ | ½ | ✗ | ✓ |
MegaMenu | ✓ | ✓ | ½ | ½ | ✓ | ½ |
UserAvatar | ✓ | ✓ | ½ | ½ | ✗ | ½ |
Criteria: Responsive = adapts across breakpoints. Dark = themed for both modes. Keyboard = custom key handlers. ARIA = roles, labels, expanded/current. Animations = transitions/motion. Focus = trap/restore on open/close.
7. Utility Components
| Component | TypeScript | Reduced Motion | SSR Safe | Reusable | A11y |
|---|---|---|---|---|---|
Greeting | ✓ | ✗ | ½ | ✓ | ✓ |
AnimatedCounter | ✓ | ✓ | ½ | ✓ | ✓ |
ScrollProgress | ✓ | ✓ | ½ | ✓ | ✓ |
LiveClock | ✓ | ✗ | ½ | ✓ | ✓ |
Criteria: TypeScript = typed props. Reduced Motion = respects prefers-reduced-motion. SSR Safe = no window/document at import time. Reusable = no page-specific coupling. A11y = aria-live, sr-only, or role attributes.
8. UI Primitives — shadcn/ui
| Dimension | Status | Notes |
|---|---|---|
| Source | ✓ | shadcn/ui new-york style — upstream maintained |
| Customisation | ✓ | HSL CSS vars for brand palette in globals.css |
| WCAG 2.2 AA | ✓ | Radix primitives provide keyboard, focus, ARIA by default |
| Dark Mode | ✓ | Semantic tokens switch via .dark class |
| Tree-shaking | ✓ | Only imported primitives ship to client |
| Version Currency | ½ | Manually updated — no automated sync with upstream |
9. Content Collections
| Dimension | Status | Notes |
|---|---|---|
| Schema Validation | ✓ | Zod schema with coerced dates, enums, nested objects |
| Type Safety | ✓ | Astro generates TypeScript types from schema |
| Build-time Errors | ✓ | Invalid frontmatter fails the build |
| Cross-references | ✓ | relatedDocuments + referencedBy fields |
| Pipeline Automation | ½ | convert-wms.mjs exists but manual invocation |
| Freshness Tracking | ½ | reviewDueDate in schema but no automated alerts |
| Full-text Search | ✗ | Command palette matches ref/title only, not body content |
10. Services & Libraries
| Module | Types | Error Handling | Caching | Token Mgmt | Tests |
|---|---|---|---|---|---|
msal.ts | ✓ | ✓ | ✓ | ✓ | ✗ |
graph.ts | ✓ | ½ | ✗ | ✓ | ✗ |
preferences-sync.ts | ✓ | ✓ | ✓ | ✓ | ✗ |
dashboard/storage.ts | ✓ | ✓ | ✓ | ✗ | ✗ |
Criteria: Types = exported interfaces/generics. Error = try/catch with fallback. Caching = localStorage or in-memory cache. Token = silent acquisition with consent fallback. Tests = unit or integration tests.
11. Build & Deploy Infrastructure
| Item | Automated | Error Recovery | Security | Monitoring | Docs |
|---|---|---|---|---|---|
deploy.yml | ✓ | ½ | ✓ | ✗ | ½ |
api/proxy | ✓ | ½ | ½ | ✗ | ✗ |
convert-wms.mjs | ✗ | ½ | ✓ | ✗ | ½ |
globals.css | ✓ | ✓ | ✓ | ✗ | ✓ |
staticwebapp.config | ✓ | ✓ | ✓ | ✗ | ½ |
Criteria: Automated = runs without manual steps. Error Recovery = handles failures gracefully. Security = secrets management, CSP, auth. Monitoring = alerts or logging on failure. Docs = inline comments or README.
Coverage Summary
| Category | Components | Full | Partial | Missing | Score |
|---|---|---|---|---|---|
| Layouts | 2 | 14 | 0 | 0 | 100% |
| Pages | 11 | 42 | 17 | 8 | 75% |
| Dashboard Widgets | 17 | 56 | 0 | 55 | 50% |
| Dashboard Infra | 5 | 18 | 1 | 11 | 62% |
| React Islands | 12 | 23 | 8 | 29 | 45% |
| Chrome | 8 | 27 | 12 | 9 | 69% |
| Utility Components | 4 | 12 | 4 | 4 | 70% |
| UI Primitives | 17 | 5 | 1 | 0 | 92% |
| Content Collections | 1 | 4 | 2 | 1 | 71% |
| Services | 4 | 12 | 2 | 6 | 65% |
| Build & Deploy | 5 | 10 | 7 | 8 | 54% |