Lucien Cartier-Tilet a7a7e7ef18 test(domain): write failing tests for Relay aggregate
Created test suite for Relay entity covering construction, state toggling,
and explicit state control methods. Tests intentionally fail as Relay
struct is not yet implemented.

Tests cover:
- Relay::new() with id, state, and optional label
- toggle() flipping state between On/Off
- turn_on() setting state to On
- turn_off() setting state to Off

TDD phase: RED - Tests written, implementation pending (T022)

Ref: T021 (specs/001-modbus-relay-control/tasks.md)
2026-01-22 00:57:11 +01:00
2026-01-11 00:39:18 +01:00
2026-01-11 00:39:18 +01:00
2026-01-11 00:39:18 +01:00
2026-01-11 00:39:18 +01:00

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 Planned - Domain Layer

  • 📋 Domain types with Type-Driven Development (RelayId, RelayState, RelayLabel)
  • 📋 100% test coverage for domain layer

Planned - Phases 3-8

  • 📋 Modbus TCP client with tokio-modbus (Phase 3)
  • 📋 Mock controller for testing (Phase 3)
  • 📋 Health monitoring service (Phase 3)
  • 📋 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.md for detailed implementation roadmap (102 tasks across 9 phases).

Architecture

Current:

  • Backend: Rust 2024 with Poem web framework
  • 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

Planned:

  • Modbus Integration: tokio-modbus for Modbus TCP communication
  • Frontend: Vue 3 with TypeScript
  • Deployment: Backend on Raspberry Pi, frontend on Cloudflare Pages
  • Access: Traefik reverse proxy with Authelia authentication
  • Persistence: SQLite for relay labels and configuration

Quick Start

Prerequisites

  • Rust 1.83+ (edition 2024)
  • Just command runner

Development

# 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:

modbus:
  host: "192.168.0.200"
  port: 502
  slave_id: 0
  timeout_secs: 5

relay:
  label_max_length: 50

Override with environment variables:

APP__MODBUS__HOST=192.168.1.100 cargo run

CORS Configuration

Development Mode (frontend on localhost:5173):

# 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):

# 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 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
│   │   ├── settings/        - Configuration module
│   │   │   ├── mod.rs       - Settings aggregation
│   │   │   └── cors.rs      - CORS configuration (NEW in Phase 0.5)
│   │   ├── telemetry.rs     - Logging and tracing setup
│   │   ├── domain/          - Business logic (planned Phase 2)
│   │   │   └── relay/       - Relay domain types and repository traits
│   │   ├── application/     - Use cases (planned Phase 3-4)
│   │   ├── infrastructure/  - External integrations (Phase 3)
│   │   │   └── persistence/ - SQLite repository implementation
│   │   ├── presentation/    - API layer (planned Phase 4)
│   │   ├── 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 (NEW in Phase 0.5)
│   │   └── production.yaml  - Production overrides (NEW in Phase 0.5)
│   └── tests/               - Integration tests
│       └── cors_test.rs     - CORS integration tests (NEW in Phase 0.5)
├── src/                     # Frontend source (Vue/TypeScript)
│   └── api/                 - Type-safe API client
├── docs/                    # Project documentation
│   ├── cors-configuration.md    - CORS setup guide
│   └── 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.md         - Task breakdown (102 tasks)
│       └── research-cors.md - CORS configuration research (NEW in Phase 0.5)
├── 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)
  • config (YAML configuration)
  • tracing + tracing-subscriber (structured logging)
  • governor (rate limiting)
  • thiserror (error handling)
  • serde + serde_yaml (configuration deserialization)

Planned Dependencies:

  • tokio-modbus 0.17 (Modbus TCP client)
  • SQLx 0.8 (async SQLite database access)
  • mockall 0.13 (mocking for tests)

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

Documentation

Configuration Guides

Development Guides

License

This project is under the AGPL-3.0 license. You can find it in the LICENSE.md file.

Description
Smart Temperature & Appliance control
Readme 1.1 MiB
Languages
Rust 95.4%
TypeScript 1.6%
Nix 1.4%
Vue 0.6%
CSS 0.5%
Other 0.5%