Files
painter/architecture.mmd
Gabriel Kaszewski f652785acb
All checks were successful
CI / ci (push) Successful in 7m16s
v1.0.0 — Hexagonal architecture rewrite
Restructure the monolithic 252-line main.rs into a 10-crate workspace
with clean hexagonal architecture, swappable adapters, and a production-
ready deployment pipeline.

Backend architecture:
- domain: Canvas, Color/Position/PixelUpdate value objects, port traits
  (CanvasStore, CanvasPersistence, EventBroadcaster), BroadcastEvent
- application: use cases (place_pixel, get_state, save/restore snapshot,
  connect/disconnect), AppState with Arc snapshot cache
- config: AppConfig structs + ConfigSource trait
- api-types: shared DTOs, event name constants
- adapters: config-env, canvas-file, http-axum (rust-embed), socketio,
  websocket — all behind port traits, swappable via feature flags
- server: composition root with graceful shutdown (SIGTERM/SIGINT)

Frontend:
- Transport abstraction: Socket.IO and native WebSocket via VITE_TRANSPORT
- Canvas zoom/pan with mouse wheel, pinch-to-zoom, and +/- buttons
- ImageData rendering (~50x faster than fillRect loop)
- Touch support, responsive CSS scaling, mobile-friendly layout
- OG/Twitter Card meta tags for rich link previews

Production:
- Docker: musl static build on scratch — 2.73MB image
- CI workflows for Gitea and GitHub Actions (fmt, clippy, test, Docker push)
- deploy.sh for private registry
- 39 unit tests across domain and application
- Zero unwraps, zero unsafe, graceful error handling with tracing
- Periodic canvas snapshots with rotation, restored on startup
- All config via environment variables with typed defaults
2026-08-18 01:41:40 +02:00

84 lines
2.9 KiB
Plaintext

graph TB
subgraph Binary ["Server (Composition Root)"]
server["server<br/><i>wires adapters, starts Axum</i>"]
end
subgraph Application ["Application Layer"]
AppState["AppState"]
PlacePixel["canvas::place_pixel"]
GetState["canvas::get_state"]
SaveSnapshot["canvas::save_snapshot"]
RestoreSnapshot["canvas::restore_snapshot"]
Connect["soldiers::connect"]
Disconnect["soldiers::disconnect"]
InMemoryCanvas["InMemoryCanvasStore"]
InProcessBroadcast["InProcessBroadcaster"]
end
subgraph Domain ["Domain Layer (0 infra deps)"]
Canvas["Canvas"]
ValueObjects["Color | Position | PixelUpdate"]
BroadcastEvent["BroadcastEvent"]
DomainError["DomainError"]
subgraph Ports ["Port Traits"]
CanvasStore["CanvasStore"]
CanvasPersistence["CanvasPersistence"]
EventBroadcaster["EventBroadcaster"]
end
end
subgraph Shared ["Shared Types"]
Config["config<br/><i>AppConfig, ConfigSource trait</i>"]
ApiTypes["api-types<br/><i>PixelUpdatePayload, event constants</i>"]
end
subgraph Adapters ["Adapters"]
subgraph Transport ["Transport (driving)"]
SocketIO["socketio<br/><i>Socket.IO protocol</i>"]
WebSocket["websocket<br/><i>native WebSocket + JSON</i>"]
end
subgraph Infrastructure ["Infrastructure (driven)"]
ConfigEnv["config-env<br/><i>env var loader</i>"]
CanvasFile["canvas-file<br/><i>file snapshots</i>"]
HttpAxum["http-axum<br/><i>HTTP routes, rate limit,<br/>embedded static files</i>"]
end
end
server --> Application
server --> Transport
server --> Infrastructure
server --> Config
PlacePixel --> CanvasStore
PlacePixel --> EventBroadcaster
SaveSnapshot --> CanvasStore
SaveSnapshot --> CanvasPersistence
RestoreSnapshot --> CanvasStore
RestoreSnapshot --> CanvasPersistence
Connect --> EventBroadcaster
Disconnect --> EventBroadcaster
InMemoryCanvas -.->|implements| CanvasStore
InProcessBroadcast -.->|implements| EventBroadcaster
CanvasFile -.->|implements| CanvasPersistence
ConfigEnv -.->|implements| Config
SocketIO --> Application
WebSocket --> Application
SocketIO --> ApiTypes
HttpAxum --> Config
classDef domain fill:#e8f5e9,stroke:#2e7d32
classDef app fill:#e3f2fd,stroke:#1565c0
classDef adapter fill:#fff3e0,stroke:#e65100
classDef shared fill:#f3e5f5,stroke:#6a1b9a
classDef binary fill:#fce4ec,stroke:#c62828
class Canvas,ValueObjects,BroadcastEvent,DomainError,CanvasStore,CanvasPersistence,EventBroadcaster domain
class AppState,PlacePixel,GetState,SaveSnapshot,RestoreSnapshot,Connect,Disconnect,InMemoryCanvas,InProcessBroadcast app
class SocketIO,WebSocket,ConfigEnv,CanvasFile,HttpAxum adapter
class Config,ApiTypes shared
class server binary