# Tatlock UI A Flutter-based unified homelab dashboard for the Tower of Joy infrastructure, replacing Organizr at `home.schweitz.net`. ## Overview Tatlock UI provides a single interface for: - **Dashboard**: System metrics, service status, quick actions - **Tatlock Chat**: LLM conversation interface with streaming responses - **Infrastructure**: Container management, logs, resource monitoring - **Housekeeping**: Home automation control via Home Assistant See [PHILOSOPHY.md](PHILOSOPHY.md) for the guiding vision. ## Tech Stack | Layer | Technology | |-------|------------| | Framework | Flutter 3.38+ | | State Management | Riverpod 2.x with code generation | | Routing | go_router | | HTTP Client | Dio + Retrofit | | Authentication | Authentik OIDC via flutter_appauth | | Theming | flex_color_scheme (Material 3) | | Code Generation | freezed, json_serializable, riverpod_generator | ## Platforms | Platform | Status | Notes | |----------|--------|-------| | Web | Primary | Docker deployment at port 8092 | | Android | Supported | For mobile access | | iOS | Supported | For mobile access | | macOS | Supported | Native desktop | | Linux | Supported | Native desktop | | Windows | Supported | Native desktop | ## Architecture This project follows **Clean Architecture** with feature-based organization: ``` lib/ ├── app.dart # MaterialApp.router setup ├── main.dart # Entry point ├── core/ # Shared infrastructure │ ├── api/ # HTTP client, interceptors, SSE │ ├── auth/ # Authentik OIDC integration │ ├── config/ # Environment, service locator │ └── theme/ # Material 3 theming ├── routing/ # go_router configuration ├── shared/ # Reusable components │ ├── components/ # DataGrid, widgets │ └── layouts/ # App scaffold, navigation └── features/ # Feature modules ├── dashboard/ ├── chat/ ├── containers/ └── housekeeping/ ``` Each feature follows the three-layer pattern: ``` features/{feature}/ ├── presentation/ # UI Layer │ ├── pages/ # Full screen widgets │ ├── widgets/ # Feature-specific widgets │ └── providers/ # Riverpod providers ├── domain/ # Business Logic Layer │ ├── entities/ # Immutable business objects │ ├── repositories/ # Abstract interfaces │ └── usecases/ # Single-purpose operations └── data/ # Data Layer ├── models/ # JSON serializable DTOs ├── datasources/ # API clients └── repositories/ # Repository implementations ``` **Layer Rules**: - Domain layer has NO dependencies on Flutter or external packages - Data layer implements domain interfaces - Presentation layer only depends on domain layer - Cross-layer communication via dependency injection (Riverpod) ## Backend APIs | Service | URL | Purpose | |---------|-----|---------| | Core API | `https://api.schweitz.net` | Infrastructure, widgets, housekeeping | | Tatlock API | `https://tatlock.schweitz.net` | LLM chat completions, streaming | Both APIs are behind Authentik SSO. **Key Endpoints**: - `GET /infrastructure/containers` - Container list and management - `GET /infrastructure/resources/system` - CPU, memory, disk metrics - `GET /housekeeping/devices` - Home Assistant devices - `POST /v1/chat/completions` - Tatlock LLM (SSE streaming) ## Development Setup ### Prerequisites - Flutter SDK 3.38+ - Dart SDK 3.10+ - Java 17+ (required for Android builds with Gradle 8.14+) - For mobile: Android Studio / Xcode 26+ - For desktop: Platform-specific toolchains ### Getting Started ```bash # Clone the repository git clone ssh://git@git.schweitz.net:2222/jpmschweitzer/tatlock-ui.git cd tatlock-ui # Install dependencies flutter pub get # Generate code (freezed, json_serializable, riverpod) dart run build_runner build --delete-conflicting-outputs # Run development server flutter run -d chrome # Web flutter run -d macos # macOS flutter run # Default device ``` ### Code Generation Run build_runner after modifying: - `@freezed`, `@JsonSerializable`, or `@riverpod` annotated code - `pubspec.yaml` version (auto-generates `lib/version.g.dart`) ```bash dart run build_runner build --delete-conflicting-outputs # Or watch mode during development dart run build_runner watch --delete-conflicting-outputs ``` **Generated files**: - `*.freezed.dart` - Freezed immutable classes - `*.g.dart` - JSON serialization, Riverpod providers - `lib/version.g.dart` - App version from pubspec.yaml ## Deployment ### Web (Docker) ```bash # Build the image docker build -t git.schweitz.net/jpmschweitzer/tatlock-ui:latest . # Or use the Gitea CI/CD pipeline git push origin main ``` **Deployment target**: Port 8092, proxied via NPM at `home.schweitz.net` ### Portainer Stack ```yaml version: '3.8' services: tatlock-ui: image: git.schweitz.net/jpmschweitzer/tatlock-ui:latest container_name: tatlock-ui restart: unless-stopped ports: - "8092:80" networks: - docker-dataplane networks: docker-dataplane: external: true ``` ## Navigation Structure ``` ├── Homepage (Dashboard) ├── Tatlock (Chat) ├── Jellyfin (external) ├── SearXNG (external) ├── AMP │ └── AMP Home ├── Coding │ ├── Cloud IDE (external) │ └── Gitea (external) ├── Infrastructure │ ├── Containers │ ├── Netdata (external) │ ├── Portainer (external) │ └── Proxy Manager (external) ├── Housekeeping ├── API Docs (external) └── Settings ``` ## Authentication Uses Authentik OIDC with the following configuration: | Setting | Value | |---------|-------| | Application | `tatlock-ui` | | Client Type | Public | | Redirect URIs | `https://home.schweitz.net/callback`, `net.schweitz.tatlock://callback`, `http://localhost:*/callback` | ## Project Links - **Repository**: [git.schweitz.net/jpmschweitzer/tatlock-ui](https://git.schweitz.net/jpmschweitzer/tatlock-ui) - **Deployment**: [home.schweitz.net](https://home.schweitz.net) (replaces Organizr) - **Core API Docs**: [api.schweitz.net/docs](https://api.schweitz.net/docs) - **Tatlock API Docs**: [household.schweitz.net/docs](https://household.schweitz.net/docs) ## Related Repositories - **tatlock**: Backend LLM orchestration service - **core-api**: Infrastructure and housekeeping API - **portainer-core**: Docker Swarm stack definitions ## License Private - All rights reserved