Dual Mission: Production App + Architecture Validation This project has an unusual constraint: I'm simultaneously defining the architecture standards and building the first major application using them. This 'dogfooding' approach ensures the developer tooling (generators, CLI, component library) is battle-tested immediately rather than discovering flaws months after teams have adopted it.
The application manages Statsbygg's extensive property portfolio, allowing facility managers to track maintenance schedules, occupancy data, energy consumption, and compliance documentation across thousands of buildings. The core challenge was building a data-heavy dashboard application that could scale to handle complex relational data while maintaining sub-second response times.
Next.js App Router & React Server Components I architected the application to maximize the benefits of Next.js 14's App Router and React Server Components (RSC). The strategy was to push as much data fetching to the server as possible, reducing client bundle size and eliminating loading spinners for initial renders.
For example, the building detail pages use Server Components to fetch building metadata, recent maintenance logs, and energy statistics in parallel server-side. This data is then streamed to the client using React Suspense boundaries, allowing the page shell to render immediately while data sections populate incrementally.
The tricky part was determining the boundary between Server and Client Components. Complex interactive features like the maintenance scheduler required client-side state, but I wrapped them in `'use client'` boundaries as deep in the component tree as possible to preserve the server-rendering benefits for the surrounding layout.
TanStack Query for Complex Data Orchestration TanStack Query handles all client-side server state. I established patterns for query key namespacing (e.g., `['buildings', 'list', { filters }]`) to ensure predictable cache invalidation. All API calls are encapsulated in feature-specific custom hooks like `useBuildings()` and `useCreateMaintenanceTask()`.
The most complex data pattern was handling dependent queries for hierarchical data. When a user selects a building, the app needs to fetch its floors, then rooms on those floors, then equipment in those rooms - each dependent on the previous selection. I used TanStack Query's `enabled` option to orchestrate this waterfall efficiently while preventing redundant requests.
For mutations (creating/updating records), I implemented optimistic updates with rollback logic. When a facility manager creates a maintenance task, the UI updates immediately while the API call happens in the background. If the server rejects the request, the optimistic update is rolled back and the user sees an error notification - providing instant feedback while maintaining data consistency.
Zustand for Complex UI State While TanStack Query manages server state, Zustand handles client-side UI state that needs to be shared across components. I created separate stores for distinct concerns: a `useFiltersStore()` for persisting dashboard filter selections, a `useLayoutStore()` for sidebar collapse state and theme preferences, and a `useNotificationsStore()` for managing toast messages.
The filter store was particularly interesting. It persists filter selections to LocalStorage and syncs them with URL query parameters, allowing users to bookmark filtered views. I used Zustand middleware to automatically encode/decode the state, making the persistence logic invisible to components that consume the store.
Microfrontend-Ready Architecture A critical requirement was future-proofing for a multi-team environment where different applications would be deployed independently but appear as one cohesive system to end users. I implemented the '@statsbygg/layout' package to solve this.
The layout system provides a shell with global navigation and breadcrumbs. Each application registers its routes with the layout via a simple API. The layout maintains a client-side registry (persisted in LocalStorage) that aggregates routes from all active zones.
For example, when this Property Management app loads, it calls `registerZone({ name: 'property', routes: [...] })`. If a user then navigates to the Finance app (a separate deployment), that app registers its own routes. The navigation bar dynamically updates to show both zones, creating a seamless multi-app experience.
The most challenging aspect was state sharing between zones. Since they're technically different deployments, they can't share React context. I solved this using a message-passing system built on `postMessage` for cross-origin communication and BroadcastChannel API for same-origin scenarios. This allows one zone to trigger actions in another (e.g., 'Refresh your data, a building was updated') without tight coupling.
Form Handling & Validation All forms use React Hook Form with Zod schemas for validation. I created a pattern for co-locating schemas with their forms in `.schema.ts` files, making validation logic easy to find and test independently.
Complex forms like the maintenance task wizard use React Hook Form's `useFieldArray` for dynamic field generation. Facility managers can add multiple tasks at once, each with its own set of fields. The form state handles arbitrary nesting while maintaining type safety through discriminated union types in Zod.
I also implemented cross-field validation for business rules. For example, a maintenance task's scheduled date must be after today but before the building's next inspection date. Zod's `.refine()` method handles this elegantly, providing clear error messages when constraints are violated.