# Architecture

## Goal

Keep simulation, PLC logic, data access and UI on separate sides of clear interfaces so the project stays maintainable and can later be connected to a real machine.

## Assemblies

| Assembly | Role |
| --- | --- |
| `IndustrialTwin.Runtime` | Runtime simulation, UI, visualization |
| `IndustrialTwin.Editor` | Scene generator and validator |
| `IndustrialTwin.Tests` | Edit Mode unit tests |

## Layers

1. **Field devices**  
   `BeamSensor`, `SafetyDoor`, `ConveyorBelt`, `MachineStation`, `StatusLightTower`, `EmergencyStopDevice`

2. **PLC**  
   `PlcRuntime` owns the state machine and output image. `PlcController` samples inputs each scan and publishes state changes.

3. **Simulation**  
   `SimulationManager` spawns pooled products, applies PLC outputs to actuators, and records `ProductionMetrics`.

4. **Data**  
   `IDataProvider.GetCurrentTelemetry()` is the only API the dashboard needs.  
   Implemented: `SimulationDataProvider`.  
   Not implemented (by design): REST, WebSocket, native PLC. Add a new `MonoBehaviour` that implements `IDataProvider` and assign it on `DataManager`.

5. **Presentation**  
   `IndustrialUiController` and `VisualizationController` consume events and telemetry. They do not move the conveyor.

## Scan model

`SimulationTicker` fires:

- `ScanTick` at 50 Hz for PLC and motion
- `UiTick` at 4 Hz for dashboards and performance numbers

Allowed `Update()` usage:

- `SimulationTicker` (clock)
- `IndustrialOrbitCamera` (pointer input)
- `ComponentSelectionSystem` (click)
- `PerformanceMonitor` (frame sampling)
- `SafetyDoor` (only while the leaf is moving)

## PLC addresses

| Signal | Address |
| --- | --- |
| Entry sensor | I0.0 |
| Machine sensor | I0.1 |
| Exit sensor | I0.2 |
| Safety door closed | I0.3 |
| Conveyor motor | Q0.0 |
| Machine motor | Q0.1 |
| Status green | Q0.2 |
| Status red | Q0.3 |

## Safety

- Emergency stop latches. Motion stays inhibited until the device is released **and** RESET is pressed. START is ignored until then.
- Opening the safety door while operating raises `ALM-002` and enters `Fault`.
- START is interlocked on door closed and motor healthy.

## Events

`IndustrialEvents` is the process bus. Systems must not poll PLC state in `Update()` when an event already exists.

## Tests

Priority coverage lives under `Assets/_Project/Tests/Editor`:

- PLC transitions, e-stop, reset, safety door
- Alarm raise / ack / clear
- Production counters and utilization
