Facilities UI Library Architecture
- Status: Implemented (v0.2.0)
- Date: 2025-12-06
- Author: Rudi Haarhoff
- Related: Golf Cart UI/UX Specification
Overview
This document proposes the architecture for a reusable Facilities UI library that can be consumed by tee-time, SCL, and other applications requiring facility management components.
Current Monorepo UI Structure
libs/
├── ui/ # Core shared UI libraries
│ ├── antd/ # @digiwedge/ui-antd (Ant Design wrapper)
│ ├── theme/ # @digiwedge/ui-theme (shared theme)
│ ├── messaging-ui/ # Cross-domain messaging components
│ └── wallet/ # Cross-domain wallet components
├── tee-time-ui/ # @digiwedge/tee-time-ui (domain-specific)
├── scl/ui/ # SCL domain UI
│ ├── web-components/ # Reusable web components
│ ├── web-pages/ # Page-level components
│ └── mobile-components/ # Mobile components
└── facilities/
└── facilities-service/ # Backend service (existing)
Current Structure
Implemented library lives under libs/facilities/ui/golf-cart (@digiwedge/facilities-ui-golf-cart):
libs/facilities/ui/
└── golf-cart/ # @digiwedge/facilities-ui-golf-cart (v0.2.0)
├── src/
│ ├── index.ts # Barrel
│ └── lib/
│ ├── components/
│ │ ├── BatteryIndicator/
│ │ ├── CartStatusCard/
│ │ ├── CartGrid/
│ │ ├── FleetDashboard/
│ │ ├── UtilizationChart/
│ │ ├── ZoneMap/
│ │ ├── MaintenancePanel/
│ │ ├── PredictiveMaintenance/
│ │ ├── IncidentReporter/
│ │ └── AssignmentHistory/
│ ├── hooks/
│ │ └── useGolfCarts.ts (hooks factory)
│ └── types/
│ └── index.ts
├── package.json
├── project.json
└── vite.config.ts
Technology Stack
Following the established patterns in the codebase:
| Technology | Version | Purpose |
|---|---|---|
| React | 19.1.0 | UI framework |
| Ant Design | 5.26.3 | Component library |
| @digiwedge/ui-antd | workspace:* | Themed Ant Design wrapper |
| @digiwedge/ui-theme | workspace:* | Shared theme |
| TanStack Query | 5.81.5 | Server state management |
| Recharts | 2.15.4 | Charts and graphs |
| Vite | 7.0.6 | Build tool |
| TypeScript | 5.x | Type safety |
Component Specifications
Core Components (implemented)
| Component | Description | Consumers |
|---|---|---|
FleetDashboard | Metrics cards, utilization, zone summary | Admin apps |
CartStatusCard | Individual cart with battery, condition, zone | All apps |
CartGrid | Filterable grid with search/pagination | Admin apps |
BatteryIndicator | Visual battery with thresholds | All apps |
ZoneMap | Zone summary table (drill-down to carts) | Admin apps |
MaintenancePanel | Service due list + actions | Admin apps |
PredictiveMaintenance | Upcoming service candidates | Admin apps |
UtilizationChart | Windowed utilization chart | Admin apps |
IncidentReporter | Incident form | Staff apps |
AssignmentHistory | Assignment timeline | All apps |
Hooks
createGolfCartHooks(api: GolfCartApi) returns typed TanStack Query hooks wired to your API implementation:
useGolfCarts,useGolfCartuseFleetSummary,useZoneSummary,useUtilizationusePredictiveMaintenance- Mutations:
useAssignCart,useReturnCart,useReportIncident,useUpdateCart,useUpdateLocation,useUpdateBattery
Types (re-exported from service)
// Re-export from @digiwedge/facilities-service or define locally
export type {
GolfCart,
CartAssignment,
CartIncident,
FleetSummary,
ZoneSummary,
UtilizationReport,
CartType,
CartCondition,
IncidentType,
IncidentSeverity,
} from '@digiwedge/facilities-service';
Consumption Pattern
In Tee-Time Admin
import {
FleetDashboard,
CartGrid,
useGolfCarts,
useFleetSummary
} from '@digiwedge/facilities-ui-golf-cart';
export function TeeTimeCartManagement() {
const { data: carts } = useGolfCarts({ tenantId: 1, clubId: 10 });
const { data: summary } = useFleetSummary(1, 10);
return (
<div>
<FleetDashboard summary={summary} />
<CartGrid carts={carts} onSelect={handleSelect} />
</div>
);
}
In SCL Admin
import {
CartStatusCard,
MaintenancePanel,
usePredictiveMaintenance
} from '@digiwedge/facilities-ui-golf-cart';
export function SCLFacilitiesPage() {
const { data: maintenanceDue } = usePredictiveMaintenance({
tenantId: 1,
horizonDays: 7
});
return (
<MaintenancePanel carts={maintenanceDue} />
);
}
File Templates
package.json
{
"name": "@digiwedge/facilities-ui-golf-cart",
"version": "0.0.1",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
},
"./index.css": "./dist/index.css"
},
"dependencies": {
"react": "19.1.0",
"antd": "^5.26.3",
"@ant-design/icons": "^5.6.1",
"recharts": "^2.15.4",
"@tanstack/react-query": "^5.81.5"
},
"peerDependencies": {
"@digiwedge/ui-antd": "workspace:*",
"@digiwedge/ui-theme": "workspace:*"
},
"devDependencies": {
"@digiwedge/dev-vite": "workspace:*",
"vite": "7.0.6",
"vite-plugin-dts": "4.5.4"
},
"private": true
}
project.json
{
"name": "facilities-ui-golf-cart",
"$schema": "../../../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "{projectRoot}/src",
"projectType": "library",
"tags": ["scope:facilities", "scope:web", "type:ui"],
"targets": {
"lint": {
"executor": "@nx/eslint:lint",
"options": {
"lintFilePatterns": [
"{projectRoot}/**/*.{ts,tsx,js,jsx}",
"{projectRoot}/project.json"
]
}
},
"build": {
"executor": "@nx/vite:build",
"options": {
"configFile": "{projectRoot}/vite.config.ts",
"tsConfig": "{projectRoot}/tsconfig.lib.json",
"outputPath": "{projectRoot}/dist",
"skipTypeCheck": true,
"buildLibsFromSource": true,
"emptyOutDir": true,
"lib": {
"entry": "src/index.ts",
"formats": ["es"]
},
"generatePackageJson": false
},
"outputs": ["{projectRoot}/dist"],
"dependsOn": []
},
"storybook": {
"executor": "@nx/storybook:storybook",
"options": {
"configDir": "{projectRoot}/.storybook",
"port": 4420
}
},
"build-storybook": {
"executor": "@nx/storybook:build",
"outputs": ["{options.outputDir}"],
"options": {
"configDir": "{projectRoot}/.storybook",
"outputDir": "dist/storybook/{projectName}"
}
},
"test:unit": {},
"test": {
"executor": "nx:noop",
"dependsOn": ["test:unit"]
}
}
}
Implementation Phases
Phase 1: Library Setup
- Create
libs/facilities/ui/golf-cart/directory structure - Configure Nx project, Vite, TypeScript
- Set up Storybook for component development
- Create base types and exports
Phase 2: Core Components
CartStatusCard- Individual cart displayBatteryIndicator- Battery level visualizationCartGrid- List view with filteringFleetDashboard- Summary metrics
Phase 3: Advanced Components
ZoneMap- Interactive GPS mapUtilizationChart- Analytics chartsMaintenancePanel- Service managementPredictiveMaintenance- AI predictions
Phase 4: Hooks & Integration
- TanStack Query hooks for data fetching
- Mutation hooks for actions
- Context providers for configuration
- Integration tests
Phase 5: Consumer Integration
- Add to tee-time-admin
- Add to scl-admin
- Documentation and examples
Related Documents
- Golf Cart Management Specification
- Golf Cart UI/UX Specification
- ADR-0001 Facilities Service (pending)
Open Questions
- API Client: Use dedicated facilities API client or generic fetch?
- Theme Extension: Extend ui-theme or use separate golf-cart theme tokens?
- Mobile Support: Create separate mobile library or responsive web components?
- Storybook: Shared Storybook or per-library Storybook instances?