This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
PlaceOS Backoffice is an Angular 20 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
npm start # Dev server at localhost:4200 with proxy to placeos-dev.aca.im
npm run build # Production build
# Testing
npm test # Unit tests (Vitest)
npx nx test backoffice --runInBand # Tests sequentially (CI mode)
npx nx e2e backoffice # Playwright E2E tests
# Linting
npx nx lint backoffice # ESLint- Framework: Angular 20 with standalone components and signals
- Build: Nx 22 + Vite 7 + @analogjs/vite-plugin-angular
- Testing: Vitest + Playwright
- Styling: Tailwind CSS 3.4 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- Component files with
standalone: true
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 20 with standalone components and signals
- TypeScript 5.8.3
- Supports multiple locales (see
app.localesin settings) - Service worker support for PWA functionality (production builds)
- Custom localization support via
public/assets/locales, TranslationPipe and LocalesService - Use IconComponent for icons
- 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