# STA - Smart Temperature & Appliance Control > **🤖 AI-Assisted Development Notice**: This project uses Claude Code as a development assistant for task planning, code organization, and workflow management. However, all code is human-written, reviewed, and validated by the project maintainer. AI is used as a productivity tool, not as the author of the implementation. Web-based Modbus relay control system for managing 8-channel relay modules over TCP. > **⚠️ Development Status**: This project is in early development. Core features are currently being implemented following a specification-driven approach. ## Overview STA will provide a modern web interface for controlling Modbus-compatible relay devices, eliminating the need for specialized industrial software. The goal is to enable browser-based relay control with real-time status updates. ## Current Status ### Phase 1 Complete - Foundation - ✅ Monorepo structure (backend + frontend at root) - ✅ Rust web server with Poem 3.1 framework - ✅ Configuration system (YAML + environment variables) - ✅ Modbus TCP and relay settings structures - ✅ Health check and metadata API endpoints - ✅ OpenAPI documentation with Swagger UI - ✅ Rate limiting middleware - ✅ SQLite schema and repository for relay labels - ✅ Vue 3 + TypeScript frontend scaffolding with Vite - ✅ Type-safe API client generation from OpenAPI specs ### Phase 0.5 Complete - CORS Configuration & Production Security - ✅ T009: CorsSettings struct with comprehensive unit tests (5 tests) - ✅ T010: CorsSettings implementation with restrictive fail-safe defaults - ✅ T011: Development YAML configuration with permissive CORS - ✅ T012: Production YAML configuration with restrictive CORS - ✅ T013: From for Cors trait unit tests (6 tests) - ✅ T014: From for Cors implementation with security validation - ✅ T015: Middleware chain integration using From trait - ✅ T016: Integration tests for CORS headers (9 comprehensive tests) #### Key CORS Features Implemented - Environment-specific CORS configuration (development vs production) - Wildcard origin support for development (`allowed_origins: ["*"]`) - Multiple specific origins for production - Credentials support for Authelia authentication - Security validation (prevents wildcard + credentials) - Configurable preflight cache duration - Hardcoded secure methods and headers - Structured logging for CORS configuration - Comprehensive test coverage (15 tests total) ### Phase 2 Complete - Domain Layer (Type-Driven Development) - ✅ T017-T018: RelayId newtype with 1-8 validation and zero-cost abstraction - ✅ T019-T020: RelayState enum (On/Off) with serialization support - ✅ T021-T022: Relay aggregate with state control methods (toggle, turn_on, turn_off) - ✅ T023-T024: RelayLabel newtype with 1-50 character validation - ✅ T025-T026: ModbusAddress type with From trait (1-8 → 0-7 offset mapping) - ✅ T027: HealthStatus enum with state machine (Healthy/Degraded/Unhealthy) #### Key Domain Layer Features Implemented - 100% test coverage for domain layer (50+ comprehensive tests) - Zero external dependencies (pure business logic) - All newtypes use `#[repr(transparent)]` for zero-cost abstractions - Smart constructors with `Result` for type-safe validation - TDD workflow (red-green-refactor) for all implementations - RelayController and RelayLabelRepository trait definitions - Complete separation from infrastructure concerns (hexagonal architecture) ### Phase 3 Complete - Infrastructure Layer - ✅ T028-T029: MockRelayController tests and implementation - ✅ T030: RelayController trait with async methods (read_state, write_state, read_all, write_all) - ✅ T031: ControllerError enum (ConnectionError, Timeout, ModbusException, InvalidRelayId) - ✅ T032: MockRelayController comprehensive tests (6 tests) - ✅ T025a-f: ModbusRelayController implementation (decomposed): - Connection setup with tokio-modbus - Timeout-wrapped read_coils and write_single_coil helpers - RelayController trait implementation - ✅ T034: Integration test with real hardware (uses #[ignore] attribute) - ✅ T035-T036: RelayLabelRepository trait and SQLite implementation - ✅ T037-T038: MockRelayLabelRepository for testing - ✅ T039-T040: HealthMonitor service with state tracking #### Key Infrastructure Features Implemented - **ModbusRelayController**: Thread-safe Modbus TCP client with timeout handling - Uses `Arc>` for concurrent access - Native Modbus TCP protocol (MBAP header, no CRC16) - Configurable timeout with `tokio::time::timeout` - **MockRelayController**: In-memory testing without hardware - Uses `Arc>>` for state - Optional timeout simulation for error handling tests - **SqliteRelayLabelRepository**: Compile-time verified SQL queries - Automatic migrations via SQLx - In-memory mode for testing - **HealthMonitor**: State machine for health tracking - Healthy -> Degraded -> Unhealthy transitions - Recovery on successful operations ### Planned - Phases 4-8 - 📋 US1: Monitor & toggle relay states - MVP (Phase 4) - 📋 US2: Bulk relay controls (Phase 5) - 📋 US3: Health status display (Phase 6) - 📋 US4: Relay labeling (Phase 7) - 📋 Production deployment (Phase 8) See [tasks.org](specs/001-modbus-relay-control/tasks.org) for detailed implementation roadmap. ## Architecture **Current:** - **Backend**: Rust 2024 with Poem web framework (hexagonal architecture) - **Configuration**: YAML-based with environment variable overrides - **API**: RESTful HTTP with OpenAPI documentation - **CORS**: Production-ready configurable middleware with security validation - **Middleware Chain**: Rate Limiting -> CORS -> Data injection - **Modbus Integration**: tokio-modbus for Modbus TCP communication - **Persistence**: SQLite for relay labels with compile-time SQL verification **Planned:** - **Frontend**: Vue 3 with TypeScript - **Deployment**: Backend on Raspberry Pi, frontend on Cloudflare Pages - **Access**: Traefik reverse proxy with Authelia authentication ## Quick Start ### Prerequisites - Rust 1.83+ (edition 2024) - Just command runner ### Development ```bash # Run development server just run # Run tests just test # Run linter just lint # Format code just format # Watch mode with bacon bacon # clippy-all (default) bacon test # test watcher ``` ### Configuration Edit `backend/settings/base.yaml` for Modbus device settings: ```yaml modbus: host: "192.168.0.200" port: 502 slave_id: 0 timeout_secs: 5 relay: label_max_length: 50 ``` Override with environment variables: ```bash APP__MODBUS__HOST=192.168.1.100 cargo run ``` #### CORS Configuration **Development Mode** (frontend on `localhost:5173`): ```yaml # backend/settings/development.yaml cors: allowed_origins: - "*" # Permissive for local development allow_credentials: false # MUST be false with wildcard max_age_secs: 3600 ``` **Production Mode** (frontend on Cloudflare Pages): ```yaml # backend/settings/production.yaml cors: allowed_origins: - "https://sta.yourdomain.com" # Specific origin only allow_credentials: true # Required for Authelia authentication max_age_secs: 3600 ``` **Security Notes:** - Wildcard `"*"` origin is **only allowed with `allow_credentials: false`** - Production **must** use specific origins (e.g., `https://sta.example.com`) - Multiple origins are supported as a list - Credentials must be enabled for Authelia authentication to work **Hardcoded Security Defaults:** - **Methods**: GET, POST, PUT, PATCH, DELETE, OPTIONS (all required methods) - **Headers**: content-type, authorization (minimum for API + auth) **Fail-Safe Defaults:** - `allowed_origins: []` (restrictive - no origins allowed) - `allow_credentials: false` - `max_age_secs: 3600` (1 hour) See [CORS Configuration Guide](docs/cors-configuration.md) for complete documentation. ## API Documentation The server provides OpenAPI documentation via Swagger UI: - Swagger UI: `http://localhost:3100/` - OpenAPI Spec: `http://localhost:3100/specs` **Current Endpoints:** - `GET /api/health` - Health check endpoint - `GET /api/meta` - Application metadata **Planned Endpoints (see spec):** - `GET /api/relays` - List all relay states - `POST /api/relays/{id}/toggle` - Toggle relay state - `POST /api/relays/all/on` - Turn all relays on - `POST /api/relays/all/off` - Turn all relays off - `PUT /api/relays/{id}/label` - Set relay label ## Project Structure **Monorepo Layout:** ``` sta/ # Repository root ├── backend/ # Rust backend workspace member │ ├── src/ │ │ ├── lib.rs - Library entry point │ │ ├── main.rs - Binary entry point │ │ ├── startup.rs - Application builder and server config │ │ ├── telemetry.rs - Logging and tracing setup │ │ │ │ │ ├── domain/ - Business logic layer (Phase 2) │ │ │ ├── relay/ - Relay domain aggregate │ │ │ │ ├── types/ - RelayId, RelayState, RelayLabel newtypes │ │ │ │ ├── entity.rs - Relay aggregate with state control │ │ │ │ ├── controller.rs - RelayController trait & ControllerError │ │ │ │ └── repository/ - RelayLabelRepository trait │ │ │ ├── modbus.rs - ModbusAddress type with conversion │ │ │ └── health.rs - HealthStatus state machine │ │ │ │ │ ├── application/ - Use cases and orchestration (Phase 3) │ │ │ └── health/ - Health monitoring service │ │ │ └── health_monitor.rs - HealthMonitor with state tracking │ │ │ │ │ ├── infrastructure/ - External integrations (Phase 3) │ │ │ ├── modbus/ - Modbus TCP communication │ │ │ │ ├── client.rs - ModbusRelayController (real hardware) │ │ │ │ ├── client_test.rs - Hardware integration tests │ │ │ │ └── mock_controller.rs - MockRelayController for testing │ │ │ └── persistence/ - Database layer │ │ │ ├── entities/ - Database record types │ │ │ ├── sqlite_repository.rs - SqliteRelayLabelRepository │ │ │ └── label_repository.rs - MockRelayLabelRepository │ │ │ │ │ ├── presentation/ - API layer (planned Phase 4) │ │ ├── settings/ - Configuration module │ │ │ ├── mod.rs - Settings aggregation │ │ │ └── cors.rs - CORS configuration │ │ ├── route/ - HTTP endpoint handlers │ │ │ ├── health.rs - Health check endpoints │ │ │ └── meta.rs - Application metadata │ │ └── middleware/ - Custom middleware │ │ └── rate_limit.rs │ │ │ ├── settings/ - YAML configuration files │ │ ├── base.yaml - Base configuration │ │ ├── development.yaml - Development overrides │ │ └── production.yaml - Production overrides │ └── tests/ - Integration tests │ └── cors_test.rs - CORS integration tests │ ├── migrations/ - SQLx database migrations ├── src/ # Frontend source (Vue/TypeScript) │ └── api/ - Type-safe API client ├── docs/ # Project documentation │ ├── cors-configuration.md - CORS setup guide │ ├── domain-layer.md - Domain layer architecture │ └── Modbus_POE_ETH_Relay.md - Hardware documentation ├── specs/ # Feature specifications │ ├── constitution.md - Architectural principles │ └── 001-modbus-relay-control/ │ ├── spec.md - Feature specification │ ├── plan.md - Implementation plan │ ├── tasks.org - Task breakdown (org-mode format) │ ├── data-model.md - Data model specification │ ├── types-design.md - Domain types design │ ├── domain-layer-architecture.md - Domain layer docs │ └── lessons-learned.md - Phase 2/3 insights ├── package.json - Frontend dependencies ├── vite.config.ts - Vite build configuration └── justfile - Build commands ``` ## Technology Stack **Currently Used:** - Rust 2024 edition - Poem 3.1 (web framework with OpenAPI support) - Tokio 1.48 (async runtime) - tokio-modbus (Modbus TCP client for relay hardware) - SQLx 0.8 (async SQLite with compile-time SQL verification) - async-trait (async methods in traits) - config (YAML configuration) - tracing + tracing-subscriber (structured logging) - governor (rate limiting) - thiserror (error handling) - serde + serde_yaml (configuration deserialization) **Frontend** (scaffolding complete): - Vue 3 + TypeScript - Vite build tool - openapi-typescript (type-safe API client generation) ## Testing Strategy **Phase 0.5 CORS Testing:** - **Unit Tests**: 11 tests in `backend/src/settings/cors.rs` - CorsSettings deserialization (5 tests) - From for Cors trait (6 tests) - Security validation (wildcard + credentials check) - **Integration Tests**: 9 tests in `backend/tests/cors_test.rs` - Preflight OPTIONS requests - Actual request CORS headers - Max-age configuration - Credentials handling - Allowed methods verification - Wildcard origin behavior - Multiple origins support - Unauthorized origin rejection **Test Coverage Achieved**: 15 comprehensive tests covering all CORS scenarios **Phase 2 Domain Layer Testing:** - **Unit Tests**: 50+ tests embedded in domain modules - RelayId validation (5 tests) - RelayState serialization (3 tests) - RelayLabel validation (5 tests) - Relay aggregate behavior (8 tests) - ModbusAddress conversion (3 tests) - HealthStatus state transitions (15 tests) - **TDD Approach**: Red-Green-Refactor for all implementations - **Coverage**: 100% for domain layer (zero external dependencies) **Test Coverage Achieved**: 100% domain layer coverage with comprehensive test suites **Phase 3 Infrastructure Testing:** - **MockRelayController Tests**: 6 tests in `mock_controller.rs` - Read/write state operations - Read/write all relay states - Invalid relay ID handling - Thread-safe concurrent access - **ModbusRelayController Tests**: Hardware integration tests (#[ignore]) - Real hardware communication tests - Connection timeout handling - **SqliteRelayLabelRepository Tests**: Database layer tests - CRUD operations on relay labels - In-memory database for fast tests - Compile-time SQL verification - **HealthMonitor Tests**: 15+ tests in `health_monitor.rs` - State transitions (Healthy -> Degraded -> Unhealthy) - Recovery from failure states - Concurrent access safety **Test Coverage Achieved**: Comprehensive coverage across all layers with TDD approach ## Documentation ### Configuration Guides - [CORS Configuration](docs/cors-configuration.md) - Cross-origin setup for frontend-backend communication - [Modbus Hardware Documentation](docs/Modbus_POE_ETH_Relay.md) - 8-channel relay device documentation ### Architecture Documentation - [Domain Layer Architecture](docs/domain-layer.md) - Type-driven domain design and implementation - [Domain Layer Details](specs/001-modbus-relay-control/domain-layer-architecture.md) - Comprehensive domain layer documentation - [Phase 2 Lessons Learned](specs/001-modbus-relay-control/lessons-learned.md) - Implementation insights and best practices ### Development Guides - [Project Constitution](specs/constitution.md) - Architectural principles and development guidelines - [Modbus Relay Control Spec](specs/001-modbus-relay-control/spec.md) - Feature specification - [CLAUDE.md](CLAUDE.md) - Developer guide and code style rules ## License This project is under the AGPL-3.0 license. You can find it in the [LICENSE.md](LICENSE.md) file.