This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
PlaceOS Backoffice is an Angular 22 admin UI for managing PlaceOS building automation systems. It uses standalone components (no NgModules), zoneless change detection with signals, and integrates with PlaceOS backend APIs.
# Development
bun run start # Dev server at localhost:4200 with proxy to placeos-dev.aca.im
bun run build # Production build
# Testing
bun run test # Unit tests (Vitest)
bun run test:ci # Tests sequentially (CI mode)
bunx playwright install --with-deps
bun run e2e # Playwright E2E tests (mock backend)
e2e/stack/up.sh # Local PlaceOS stack in Docker (https://localhost:9543)
bun run e2e:local # Playwright E2E tests against the local stack
e2e/stack/down.sh # Stop the stack (--volumes to remove its data)
# Linting
bun run lint # ESLint- Framework: Angular 22 with standalone components and signals
- Build: Nx 23 + Vite 8 + @analogjs/vite-plugin-angular
- Testing: Vitest + Playwright
- Styling: Tailwind CSS 4 (legacy
tailwind.config.jsloaded via@config) with custom CSS variables - Backend: @placeos/ts-client for PlaceOS REST API integration
- Real-time: MQTT for dashboard updates
src/app/
├── common/ # Shared utilities and services
│ ├── placeos.ts # PlaceOS API setup (setupPlace())
│ ├── user-state.ts # Current user signals
│ └── async-handler.class.ts # Base class for subscription management
├── ui/ # Shared UI components and guards
│ └── guards/ # AuthorisedUserGuard, AuthorisedAdminGuard
├── overlays/ # Modal/dialog components
└── [features]/ # Feature modules: admin, systems, domains, drivers,
# modules, repositories, triggers, users, zones, metrics
Each feature follows this structure:
*.routes.ts- Lazy-loaded feature routing*-state.service.ts- Feature state management with signals/observables- Standalone components (the default since Angular 19, so
standalone: trueis not needed)
Signals for State: UI state uses Angular signals instead of zones
public readonly loading = signal(false);AsyncHandler Base Class: Components extend this for subscription management
export class MyComponent extends AsyncHandler {
ngOnInit() {
this.timeout('init', () => {...}, 1000);
this.interval('poll', () => {...}, 5000);
}
}PlaceOS Integration: API setup via setupPlace() in common/placeos.ts
- Selectors: Components use
app-*prefix (kebab-case), directives useapp*(camelCase) - Formatting: 4-space tabs, single quotes (Prettier configured)
- Tailwind: Uses
#placeosas important prefix for specificity - Dark mode: Class-based (
darkMode: 'class')
- Dev proxy configured in
config/proxy.conf.js(targets placeos-dev.aca.im) - Version info auto-generated to
src/env/version.tson postinstall - Production builds output to
dist/backoffice/browser
- Angular 22 with standalone components and signals
- TypeScript ~6.0
- Supports multiple locales (see
app.localesin settings) - Service worker support for PWA functionality (production builds)
- Custom localization support via
public/assets/locale, TranslatePipe and LocaleService.en-AU.jsonis the fallback locale - Use IconComponent for icons
- Use
feat/*,fix/*,perf/*, orrefactor/*for branch names
- Use snake_case for variables
- Use camelCase for functions
- Use PascalCase for classes, types and interfaces
- Use kebab-case for file names, directories and CSS selectors(id, class, attribute)
- Use CAPS_CASE for constants