Skip to content

UI Layout and Navigation

Status: Specified  ยท  Scope: All modules

Defines the application shell, navigation model, route structure, role-differentiated visibility, settings area, alert surfacing, and mobile behaviour. All module UIs are built within this shell.

GS
3 expiring this week 2 CSCS cards ยท 1 LOLER inspection (Site A crane) View all โ†’
RIDDOR deadline in 2 days Canary Wharf Ph.2 โ€” INC-004 must be reported to HSE View โ†’
4
Active Sites
2
Open Incidents
3
Expiring This Week
47
Workers On Site Today
Projects
Canary Wharf Phase 2PRJ-001
2
Sites
31
On site today
1
Open incidents
2 expiringRIDDOR due
Kings Cross StationPRJ-002
2
Sites
16
On site today
1
Open incidents
1 expiringNo overdue items
Recent Activity
๐Ÿ““
Site diary entry added โ€” Canary Wharf Ph.2, Site A
James Fletcher ยท 10 minutes ago
๐Ÿ‘ท
New worker added โ€” Marcus Obi (Steel Fixer)
Sarah Nwosu ยท 42 minutes ago
โš ๏ธ
Near miss reported โ€” Kings Cross, Platform 9 works
Dan Pearce ยท 1 hour ago

App Shell

Three fixed regions. All module content renders in the main content area.

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Top bar                                                โ”‚  48px fixed
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚               โ”‚                                         โ”‚
โ”‚   Sidebar     โ”‚   Main content area                     โ”‚
โ”‚   240px       โ”‚   flex-1, scrollable                    โ”‚
โ”‚   fixed       โ”‚                                         โ”‚
โ”‚               โ”‚                                         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Top bar

Zone Left Centre Right
Content Tenant logo (white-label) โ€” Notification bell ยท User avatar + dropdown
  • Tenant logo โ€” renders the tenant's uploaded logo; falls back to the Construo wordmark. Clicking it navigates to /dashboard.
  • Notification bell โ€” shows unread count badge. Opens a dropdown of the 10 most recent notifications, each linking directly to the relevant entity. "View all" link goes to /notifications.
  • User avatar dropdown โ€” name, role label, "My preferences", "Sign out".

Fixed at 240px. Collapses to icon-only (48px) at โ‰ค1024px breakpoint via a toggle. On mobile (โ‰ค768px) collapses entirely behind a hamburger menu in the top bar.

Structure:

[Tenant name / logo mark]
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  Dashboard

  Projects
  โ–พ Canary Wharf Phase 2        โ† expanded
      Site Diary
      Personnel
      Attendance
      Plant & Equipment
      Incidents
      Documents
      Deliveries
      Subcontractors
  โ–ธ Kings Cross Station         โ† collapsed
  โ–ธ A1 Upgrade โ€” Stevenage

  + New Project                 โ† Project Manager and above only

โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  Settings                      โ† Tenant Admin only

โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
[Avatar]  Gari Smith
          Technical Architect

Project expansion behaviour: - Clicking a collapsed project expands it in-place, revealing its module list. - Multiple projects can be expanded simultaneously. - The active route highlights the current module item. - The module list shown reflects the tenant's enabled modules โ€” disabled modules are hidden, not greyed out.

Main content area

Full height, scrollable. Contains:

  1. Page header โ€” page title, breadcrumb, primary action button (e.g. "New diary entry").
  2. Alert strip โ€” appears only when there are active alerts for the current context (see Alert Surfacing).
  3. Page content โ€” module-specific.

Dashboard (default landing)

Route: /dashboard

Cross-project view. Content is scoped to what the authenticated user can see based on their role and project access. Project access is not embedded in the JWT โ€” the API checks it live (Redis-cached) on every request. The React app queries the project list and receives only the projects the user can access; it does not read or decode JWT claims for authorisation.

Page sections:

  1. Alert strip โ€” priority-ordered list of all items requiring action (see Alert Surfacing).
  2. Summary tiles โ€” four stat tiles: Active Sites ยท Open Incidents ยท Expiring This Week ยท Workers on Site Today. Values are aggregated across all accessible projects.
  3. Project cards โ€” one card per accessible project showing: project name, site count, active headcount, open incident count, and any overdue items. Clicking a card expands the project in the sidebar and navigates to the project overview.
  4. Recent activity feed โ€” chronological list of recent entries across modules (diary entries, incidents raised, new personnel added). Scoped to the user's accessible projects.

Project overview

Route: /projects/:projectId

Summary view for a single project.

  • Site list with status and today's headcount per site
  • Open incidents
  • Items requiring attention (expiries, overdue inspections) scoped to this project

Module pages

Route: /projects/:projectId/[module] for project-level modules. Route: /projects/:projectId/sites/:siteId/[module] for site-level modules.

See individual module specs for page structure.


Route Structure

/                                               โ†’ redirect โ†’ /dashboard
/dashboard                                      โ†’ cross-project dashboard

/projects                                       โ†’ project list (fallback if no projects)
/projects/new                                   โ†’ create project form
/projects/:projectId                            โ†’ project overview
/projects/:projectId/edit                       โ†’ edit project

/projects/:projectId/sites/:siteId              โ†’ site overview
/projects/:projectId/sites/:siteId/diary        โ†’ site diary
/projects/:projectId/sites/:siteId/attendance   โ†’ attendance / sign-in
/projects/:projectId/sites/:siteId/plant        โ†’ plant & equipment
/projects/:projectId/sites/:siteId/incidents    โ†’ incidents & near misses
/projects/:projectId/sites/:siteId/deliveries   โ†’ deliveries

/projects/:projectId/personnel                  โ†’ personnel (project-level)
/projects/:projectId/documents                  โ†’ document register
/projects/:projectId/subcontractors             โ†’ subcontractors
/projects/:projectId/inductions                 โ†’ induction management

/notifications                                  โ†’ full notification history

/settings                                       โ†’ settings landing  [Tenant Admin]
/settings/users                                 โ†’ user management
/settings/modules                               โ†’ module enable/disable
/settings/fields                                โ†’ field schema builder
/settings/notifications                         โ†’ notification configuration
/settings/branding                              โ†’ logo, colours, white-label

/profile                                        โ†’ user preferences, SMS opt-in/out

All routes under /settings redirect to /dashboard for non-admin roles. The Settings nav item is hidden entirely for non-admin roles โ€” the redirect is a defence in depth measure.


Settings Area

Accessible only to Tenant Admin and Platform Admin roles. Reached via the "Settings" item at the bottom of the sidebar.

Settings has its own sub-navigation (left rail within the main content area):

Section Purpose
Users Invite users, assign roles, deactivate accounts
Modules Enable or disable platform modules for this tenant
Fields Field schema builder โ€” add custom fields to any entity
Notifications Configure event types: enabled, channels, recipients, thresholds
Branding Upload logo, set primary colour, configure email from-name

Settings pages do not have a project context โ€” they are tenant-wide.


Role-Differentiated Visibility

What each role sees

Area Platform Admin Tenant Admin Project Manager Site Manager Site Operative Viewer
Dashboard All tenants All projects Assigned projects Assigned sites Own sites Assigned projects
Project list All All Assigned Assigned Assigned Assigned
Module pages All All Full CRUD Create/edit on assigned sites Own entries only Read-only
Settings โ€” Full access Hidden Hidden Hidden Hidden
New Project button โ€” โœ… โœ… Hidden Hidden Hidden
New Site button โ€” โœ… โœ… Hidden Hidden Hidden

UI treatment of restricted actions

  • Hidden โ€” element does not appear in the DOM. Used for entire nav sections and primary action buttons a role can never access.
  • Disabled โ€” element is visible but non-interactive, with a tooltip explaining why. Used sparingly, only where awareness that the action exists is useful (e.g. a Site Manager seeing a greyed-out "Export PDF" that requires Project Manager role).
  • Read-only form โ€” inputs render as static text. Used for Viewer role on all entity detail pages.

The API is always the authoritative enforcement point. UI visibility is UX only.


Alert Surfacing

Alerts appear in two places:

1. Notification bell (top bar)

  • Badge shows count of unread notifications.
  • Dropdown lists the 10 most recent, newest first.
  • Each item shows: event type icon ยท description ยท entity name ยท time ago.
  • Clicking an item marks it read and navigates to the entity.
  • "Mark all read" action at the top of the dropdown.
  • "View all" navigates to /notifications.

2. Alert strip (dashboard and module pages)

The alert strip appears at the top of the main content area whenever there are active unresolved alerts in scope.

On the dashboard โ€” shows all alerts across all accessible projects, grouped by severity:

๐Ÿ”ด  2 overdue items          LOLER cert expired (Site A crane) ยท RIDDOR deadline missed
๐ŸŸก  5 due this week          3 licences expiring ยท 1 plant inspection ยท 1 document

Clicking a grouped alert expands it to show individual items, each linking to the entity.

On a module page โ€” shows only alerts relevant to that module and project/site context. For example, on the Plant & Equipment page for Site A, the strip shows only plant-related alerts for Site A.

Severity colours:

Colour Meaning
๐Ÿ”ด Red Overdue or expired โ€” action required now
๐ŸŸก Amber Due within the configured threshold โ€” action required soon
๐Ÿ”ต Blue Informational โ€” e.g. induction blocked sign-in (resolved when induction completes)

Mobile Responsive Behaviour

Breakpoints:

Breakpoint Behaviour
โ‰ฅ1280px Full layout โ€” sidebar expanded at 240px
1024pxโ€“1279px Sidebar collapses to icon-only (48px)
โ‰ค768px Sidebar hidden; hamburger menu in top bar opens a full-height overlay nav

Mobile-specific layout rules:

  • Tables โ€” render as stacked cards on โ‰ค768px. Each row becomes a card with label + value pairs. Sort and filter controls move to a slide-up drawer.
  • Forms โ€” single column. Full-width inputs.
  • Page header โ€” title and primary action button stack vertically if the title is long.
  • Alert strip โ€” shows only the highest-severity alert; tap to expand all.
  • Module pages โ€” no layout changes beyond the above. All modules are accessible on mobile.

High-frequency on-site flows (sign-in, diary entry, plant log, incident report) are tested on real devices in Sprint 18 and given priority treatment for touch targets and thumb reach.


Component Conventions

All UI is built with shadcn/ui components and Tailwind CSS utility classes. The following conventions apply across all module UIs:

Pattern Implementation
Data tables TanStack Table v8 with shadcn Table. Sortable columns, column visibility toggle, CSV export.
Forms React Hook Form + Zod. Inline field-level errors. Submit disabled until form is valid.
Modals / sheets shadcn Dialog for confirmations and small forms. Sheet (slide-in panel) for larger create/edit forms.
Empty states Centred illustration + heading + primary action button. Every list page must have an empty state.
Loading states Skeleton loaders (shadcn Skeleton) for initial page load. Spinner on form submission buttons.
Confirmation dialogs shadcn AlertDialog for destructive actions. Never use browser confirm().
Toasts shadcn Sonner for success/error feedback after mutations. Position: bottom-right.
Custom fields Rendered dynamically from field_definitions. Field type determines component: text โ†’ Input, select โ†’ Select, date โ†’ DatePicker, boolean โ†’ Switch, file โ†’ FileUpload.