# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ## [1.7.1] - 2026-07-19 ### Fixed - Web build failure with dio >= 5.8: `DioExceptionType` switch is now exhaustive across dio versions (CI resolves dependencies fresh) ## [1.7.0] - 2026-07-19 ### Changed - Default Core API and Tatlock API URLs now use the public domains `https://api.schweitz.net` and `https://tatlock.schweitz.net` (previously LAN `http://192.168.86.149:8083`/`:8000`), so default builds require OIDC auth; override via `--dart-define` for direct LAN development ### Removed - Netdata and Cloud IDE (code-server) quick links — both services are decommissioned; also dropped the unused `portainerUrl`/`netdataUrl` config constants ## [1.6.0] - 2026-01-08 ### Added - **News Ticker Widget** - Scrolling news headlines on dashboard - Full-width ticker between Welcome card and System Stats - Horizontal auto-scrolling at 40px/second with seamless looping - Fetches headlines from `/tools/news` endpoint - Placeholder headlines shown when no data (italic, muted style) - Auto-refresh every 30 minutes - News data model (`NewsData`, `NewsHeadline`) with Freezed - News datasource calling `GET /tools/news` - News provider with `hasNews` helper ## [1.5.9] - 2026-01-08 ### Changed - **Aligned horizon line across all widgets** - Consistent visual baseline at 50px from bottom - Weather and Air Quality dividers now align with Sun Position horizon line - Forecast card bottoms align with the same horizon - Creates unified visual rhythm across all environment cards ## [1.5.8] - 2026-01-08 ### Changed - **Bottom-aligned widget content** - All environment widgets now align content from the bottom - Creates consistent visual baseline across Sun Position, Weather, Air Quality, and Forecast cards - Footers (weather details, pollutants) sit at the same level across cards ### Added - **Wind direction in Weather** - Wind chip now shows direction (e.g., "SE 14 km/h") ## [1.5.7] - 2026-01-08 ### Fixed - **Environment widget alignment** - Consistent card heights across all environment widgets - Added `ConstrainedBox(minHeight: 170)` to Weather, Air Quality, and Forecast widgets - All cards now match Sun Position widget height when displaying data - **Sun position night labels** - Swap sunrise/sunset labels at night - During day: Sunrise on left, Sunset on right (day arc) - At night: Sunset on left, Sunrise on right (night arc) ### Changed - **Weather widget header** - Changed from location name to "Weather" for consistency - Location now displayed in content area below temperature ## [1.5.6] - 2026-01-07 ### Changed - **Environment user logging** - Now logs API user only once per session instead of on every refresh ## [1.5.5] - 2026-01-07 ### Fixed - **Sun position arc overflow** - Arc now constrained to fit within card boundaries - Prevents arc and sun/moon from overflowing on wider displays - Scales radius down when arc height exceeds available space ### Added - **Debug logging for environment user** - Logs authenticated user on environment data load ## [1.5.4] - 2026-01-07 ### Added - User display in environment section header (reverted in 1.5.5) ## [1.5.3] - 2026-01-07 ### Changed - **Sun position arc redesign** - Arc now touches horizon at sunrise/sunset points - Arc geometry uses chord-radius calculation for proper horizon intersection - Sunrise/sunset icons integrated at horizon endpoints (no duplicate labels) - Daylight duration centered below arc - Increased card height 20% for better arc visibility (140px → 170px) - **Visual balance improvements** - Sunrise/sunset labels raised 10px, daylight label at bottom ## [1.5.2] - 2026-01-07 ### Changed - **Proportional sun/moon arc visualization** - Arc angle now proportional to day/night duration - Day arc: spans (daylight hours / 24) × 360° above horizon - Night arc: spans (night hours / 24) × 360° with moon traversal - Horizon points represent sunrise/sunset times - Gradient colors: yellow/orange for day, blue/indigo for night - **Sun position widget now updates every 10 minutes** - Position aligned to clock intervals (0/10/20/30/40/50) - Converted to StatefulWidget with timer-based updates - Shows default 7am/5pm sunrise/sunset when API data unavailable (asymmetric for visual effect) - Always displays times and daylight duration (no more "--:--") - **Environment widgets consistent height** - All cards maintain same height in "no data" state ## [1.5.1] - 2026-01-07 ### Changed - **Environment widgets layout redesign** - All 4 widgets always visible with responsive layout - Desktop (>900px): 4-in-a-row with 30/20/20/30 width distribution (Sun | Weather | Air Quality | Forecast) - Tablet (600-900px): 2x2 grid layout - Mobile (<600px): Stacked vertically - Widgets now show "No data available" state instead of being hidden or using mock data - Sun position widget now calculates position from system clock - Defaults to 6am/6pm (12-hour day/night cycles) when API sun times unavailable - Environment data refresh interval changed from 5 minutes to 1 hour ## [1.5.0] - 2026-01-06 ### Added - **Dynamic Environment Widgets** - Live weather, sun position, and forecast data from Qdrant - `SunPositionWidget` - Animated semicircle arc showing sun/moon position based on current time - Gradient colors: yellow for daytime, orange for sunrise/sunset, blue for night - Displays sunrise, sunset times and daylight duration - `WeatherWidget` - Current temperature, conditions, humidity from API - `ForecastWidget` - Multi-day weather forecast with conditions icons - `AirQualityWidget` - AQI display (only shown when data available) - Environment data provider with auto-refresh every 5 minutes - Environment datasource calling `GET /tools/environment` - Freezed models for environment data (weather, forecast, sun times, air quality) - Comprehensive widget tests for environment section ### Changed - Dashboard layout now displays dynamic environment data instead of static widgets - Weather and air quality widgets accept optional API data parameters ## [1.4.0] - 2026-01-05 ### Added - **Decentralized Room Registry** - Each room registers itself with central registry - `RoomDefinition` class with id, label, icons, routes, and permissions - `RoomRegistry` singleton for managing all rooms - Dynamic navigation tabs built from registry - Settings dropdown builds from available rooms - Permission-based room filtering support - **Media Room** - New placeholder room for future media management features - **Parlor** - Now a proper feature folder with router registration ### Changed - Room navigation is now fully dynamic via registry - `top_header_bar.dart` uses `roomRegistry.all` instead of hardcoded list - `app_scaffold.dart` uses registry for route matching and navigation - Settings page dropdown populated from `roomRegistry.all` - Routers moved to per-room pattern: - `lib/features/front_hall/router.dart` (new) - `lib/features/parlor/router.dart` (new) - `lib/features/media_room/router.dart` (new) - Existing `control_room/router.dart` and `security/router.dart` now register with registry - Documentation updated in ARCHITECTURE.md with Room Registry Pattern section ### Removed - Hardcoded room lists in `top_header_bar.dart` and `app_scaffold.dart` - `_PlaceholderPage` widget in `app_router.dart` (each room has its own page) ## [1.3.1] - 2026-01-05 ### Fixed - Default room preference now applies on app load - Root `/` redirects to user's preferred default room - Front Hall moved to `/front-hall` route (was `/`) ## [1.3.0] - 2026-01-05 ### Added - **URL deep-linking for DataGrids** - State is now reflected in URL query parameters - `?search=` - DataGrid search query - `?sort=` - Column ID for sorting - `?order=desc` - Sort direction - `?id=` - Opened document ID (proxy hosts page) - `PageUrlState` utility class (`lib/routing/url_state.dart`) for URL ↔ state serialization - Browser URL updates via `replaceState` without triggering GoRouter rebuilds - `id` field added to `DataGridColumn` for unique column identification in URLs - `FilterPanelSemantics` class for filter panel semantic IDs - TESTING.md documentation for semantic widgets and automation testing ### Changed - `idSelector` in DataGridController now returns `String` (was `Object`) for URL compatibility - All DataGrid pages now support URL deep-linking: - Containers list (`/control-room/containers`) - Proxy hosts (`/control-room/proxy-hosts`) - Users (`/security/users`) - Groups (`/security/groups`) - Router passes `GoRouterState` to pages for query parameter access ## [1.2.0] - 2026-01-05 ### Added - **Semantic labels for UI automation** (`lib/core/semantics/`) - `semantic_ids.dart` - Centralized semantic identifier constants - `semantic_widget.dart` - Helper widget and extension for adding semantics - Enables browser automation tools (Puppeteer, WebDriver) via accessibility tree - Semantic IDs added to: - Profile dropdown button and menu items (theme options, settings, logout) - Room navigation tabs (Front Hall, Control Room, Security, Parlor) - NavPanel items (sidebar navigation) - `SemanticsBinding.instance.ensureSemantics()` enabled on web builds ## [1.1.16] - 2026-01-05 ### Fixed - Theme toggle causing logout due to AuthInterceptor auto-signout on 401 - Removed aggressive `signOut()` call in `AuthInterceptor.onError` - 401 errors now propagate to calling code for graceful handling - Preferences API 401 no longer triggers full logout redirect ## [1.1.15] - 2026-01-05 ### Fixed - Theme toggle causing auth issues due to AuthNotifier auto-dispose - Applied `@persistentRiverpod` annotation to AuthNotifier - AuthProvider now persists for app lifetime, preventing rebuild on theme change ## [1.1.14] - 2026-01-04 ### Fixed - Theme toggle causing auth issues due to ThemeProvider auto-dispose - Added `@persistentRiverpod` annotation for providers that need keepAlive - ThemeProvider now persists for app lifetime ### Added - `@persistentRiverpod` annotation in `core/providers/annotations.dart` - Reusable annotation for providers that should not auto-dispose - Documented in ARCHITECTURE.md ## [1.1.13] - 2026-01-04 ### Added - Settings page with Appearance, Navigation, and Account sections - Theme toggle in user profile dropdown (System/Light/Dark) - Theme syncs with API preferences on login - Default room preference syncs with backend ### Changed - Theme changes now persist to both local storage and API ## [1.1.12] - 2026-01-04 ### Changed - Control Room navigation reorganized: - New "Stack" section with Containers and Proxy Hosts - New "Data Management" section with PostgreSQL, Redis, Qdrant, Neo4j placeholders - Removed: Networks, Volumes, Images (Portainer) and Redirections, Streams, Certificates (NPM) ## [1.1.11] - 2026-01-04 ### Fixed - API client providers now use `keepAlive: true` to prevent Ref invalidation - Fixes "DioException [unknown]: null" error on /security/users and other API pages - AuthInterceptor's stored Ref was becoming invalid when provider auto-disposed ## [1.1.10] - 2026-01-04 ### Changed - Removed page swipe transitions - all navigation is now instant (NoTransitionPage) ## [1.1.9] - 2026-01-04 ### Changed - Moved health check to `/health` directory - URL is now `/health` instead of `/health.html` - Enables NPM forward auth path exclusion for health endpoint ## [1.1.8] - 2026-01-04 ### Changed - Dark background (`#1a1a2e`) on web/index.html to prevent white flash during auth redirects ## [1.1.7] - 2026-01-04 ### Removed - Removed `/callback` route from Flutter router - AuthController handles callback in main() before app starts - Removed `_OidcCallbackPage` widget - no visible auth UI needed ## [1.1.6] - 2026-01-04 ### Changed - **Auth moved to standalone controller** - Handles OIDC completely outside Riverpod - New `AuthController` runs in `main()` before `runApp()` - avoids provider lifecycle issues - Handles callback, token exchange, and /auth/sync before app starts - If auth not ready (redirecting), app doesn't start at all - `AuthProvider` now just loads stored tokens (no async OIDC logic) - Fixes "Cannot use Ref after disposed" errors from autoDispose providers ## [1.1.5] - 2026-01-04 ### Fixed - Race condition in OIDC callback: AuthProvider.build() was initiating silent OIDC while the callback page was processing, causing PKCE state to be cleared. Now skips silent OIDC when on `/callback` route. ## [1.1.4] - 2026-01-04 ### Fixed - Silent OIDC fallback: when `prompt=none` fails with `login_required` (no Authentik session), automatically fall back to regular OIDC flow to show login UI ## [1.1.3] - 2026-01-04 ### Changed - **Web auth uses silent OIDC with JWT Bearer tokens** - Uses `prompt=none` to silently obtain JWT when Authentik session exists (via NPM forward auth) - Flutter sends Bearer token to core-api instead of relying on forward auth cookies - Fixes cross-subdomain cookie issues between home.schweitz.net and api.schweitz.net - Callback now syncs with `/auth/sync` to get user profile and roles from core-api - API interceptor now adds Bearer token on web (previously skipped) ## [1.1.2] - 2026-01-04 ### Changed - **Web auth simplified**: Skip Flutter OIDC on web - NPM forward auth handles it - NPM authenticates at proxy level before app loads - No more redundant OIDC redirect after NPM auth completes - Fixes "Cannot use Ref after disposed" error from conflicting auth flows - Mobile still uses Flutter OIDC flow ### Added - Logout now redirects to Authentik to end SSO session - Clears local tokens AND invalidates Authentik session - Uses OIDC end_session_endpoint from discovery document - Redirects back to app after Authentik logout completes ## [1.1.0] - 2026-01-04 ### Changed - **Dockerfile rebuild fix**: Added `flutter clean` before build to prevent stale cached artifacts - VERSION build arg added for explicit cache busting - Reordered build steps: clean → pub get → build_runner → health.json → flutter build - Ensures deployed app always matches the version in health.json ### Fixed - Replaced deprecated `dart:html` with `package:web` in iframe_view_web.dart - Uses `web.HTMLIFrameElement` instead of `html.IFrameElement` - Fixes deprecation warnings for Flutter 3.x web builds ## [1.0.12] - 2026-01-04 ### Changed - Removed login page - auth now auto-initiates from AppScaffold - No more redirect to /login, just auto-start OIDC if not authenticated - Shows loading screen during auth, error screen on failure with retry - Seamless experience when Authentik session exists ### Removed - Removed /login route and _LoginPage widget ## [1.0.11] - 2026-01-04 ### Changed - Web auth now extracts user info directly from JWT instead of syncing with core-api - Eliminates CORS preflight issues with /auth/sync endpoint - Decodes JWT claims (name, email, groups) client-side - Bearer token will be used for API authentication ## [1.0.10] - 2026-01-04 ### Fixed - Fixed OIDC callback route being redirected to login before processing - Moved callback route exception check BEFORE the auth redirect check in router - This was preventing token exchange from ever happening - Added favicon.ico to web root for proper browser tab icon display ## [1.0.9] - 2026-01-04 ### Fixed - Fixed OIDC callback Riverpod state modification error - Deferred callback processing to `addPostFrameCallback` to avoid modifying state during widget build ## [1.0.8] - 2026-01-04 ### Changed - Switched from hash-based URLs (`/#/login`) to path-based URLs (`/login`) - Required for OIDC callback to work correctly - Uses conditional import to avoid breaking mobile/desktop builds ## [1.0.7] - 2026-01-04 ### Fixed - Fixed OIDC PKCE state loss across browser redirect - Code verifier and state now persist in sessionStorage instead of memory - Prevents "No code verifier" error after Authentik redirect ## [1.0.6] - 2026-01-04 ### Fixed - Fixed version generation in CI/CD builds - Removed generated files (version.g.dart, health.json) from git tracking - These files are now regenerated from pubspec.yaml during Docker build ## [1.0.5] - 2026-01-04 ### Changed - **Web authentication now uses OIDC** instead of NPM forward auth - Added `OidcServiceWeb` for browser redirect-based Authorization Code flow with PKCE - Added `/callback` route to handle Authentik redirect after login - Login page now shows "Sign in with Authentik" button for both web and mobile - Tokens stored in SharedPreferences and synced with core-api via `/auth/sync` - Added web utility functions (`web_utils.dart`) with conditional imports for non-web platforms - Added `crypto` and `web` packages for PKCE SHA-256 and browser API access ### Fixed - Removed cross-origin cookie dependency that caused authentication failures on web ## [1.0.4] - 2026-01-03 ### Added - `health.json` generated at build time with app version info - `health.html` now displays version, title, and status from health.json ## [1.0.3] - 2026-01-03 ### Fixed - Fixed auth endpoint path: `/auth/me` → `/auth/users/me` ## [1.0.2] - 2026-01-03 ### Fixed - Production Docker build now uses correct API URLs - Added `--dart-define` flags for `CORE_API_URL` and `TATLOCK_API_URL` - This enables `requiresAuth=true` so authentication is actually triggered - Updated AGENTS.md with clear service port reference table ## [1.0.1] - 2026-01-03 ### Fixed - Web authentication now works correctly with NPM forward auth - Dio client sends cookies with requests via `withCredentials: true` - Added platform-specific adapters (native vs web) for proper cookie handling ## [1.0.0] - 2026-01-03 ### Added - **Authentication System** - Dual-flow auth supporting web (NPM forward auth) and mobile (OIDC) - `AuthState` model with roles, permissions, and user preferences - `AuthProvider` with automatic web session detection via `/auth/me` - Permission system with Domain/Action enums and hierarchical access levels - `PermissionGate` and `AdminGate` widgets for UI permission checks - `Role` model with `{domain}.{category}:{action}` format parsing - Route guards redirect unauthenticated users to login page - Login page with Authentik OAuth redirect - Mobile auth platform configuration (iOS URL schemes, Android AppAuth) - Comprehensive auth test suite (60 unit tests) ### Changed - API interceptor skips Bearer tokens on web (uses cookies via NPM forward auth) - Router integrates auth state for protected route access - **First stable release** - Core functionality complete for home lab dashboard ## [0.3.3] - 2026-01-03 ### Added - Health check endpoint (`/health.html`) for Portainer container monitoring - Local search filtering in DataGrid (filters cached data client-side) - Container status badges now reflect health status (green=healthy, orange=unhealthy) - `ContainerHealth` enum for parsing Docker health status from status string ### Changed - Standardized header bar heights to 56px across all panels - Container grid now correctly parses Docker API JSON format (capitalized keys) - Status column displays clean uptime (stripped health indicators) - Status badges have consistent minimum width (90px) - Search bar styling improved (36px height, visible border, proper background) - Quick links now properly persist link type (iframe vs new tab) - Iframe switching now closes existing content before loading new link ### Fixed - Quick links form properly saves changes and refreshes panel - `ContainerState` type conflict resolved (removed duplicate enum) - Container data parsing handles null values safely ### Branding - Updated favicon and icons with Tatlock bucket logo - Updated manifest.json with Tatlock branding ## [0.3.2] - 2025-01-02 ### Changed - API defaults now use LAN IPs for local development (no auth required) - Auth interceptor skips authentication when using LAN endpoints ## [0.3.0] - 2025-12-30 ### Added - docs/UI_LAYOUT.md - Responsive layout specification with "Rooms of the Estate" navigation ### Changed - Directory structure now mirrors room navigation (front_hall/, control_room/, parlor/, library/, study/) - Chat moved to top-level `lib/chat/` (omnipresent, not a room) - Updated ARCHITECTURE.md and PLAN.md to reflect room-based structure - Version generation now automated via build_runner (replaces manual script) - `lib/version.g.dart` auto-generated from `pubspec.yaml` during build ## [0.2.0] - 2024-12-30 ### Added - **Phase 1: Foundation complete** - Clean Architecture folder structure (`core/`, `features/`, `shared/`, `routing/`) - Full dependency stack: Riverpod, Dio, go_router, freezed, flex_color_scheme - Core infrastructure: - `core/config/app_config.dart` - Environment configuration - `core/theme/app_theme.dart` - Material 3 theming with FlexColorScheme - `core/theme/theme_provider.dart` - Theme state with persistence - `core/error/app_exception.dart` - Typed exception hierarchy - `core/api/api_client.dart` - Dio HTTP clients for Core API and Tatlock API - `core/api/api_interceptors.dart` - Auth, logging, error interceptors - `core/auth/auth_provider.dart` - Authentication state management - Routing with go_router and shell route for navigation - Adaptive scaffold with responsive navigation (rail/bottom nav) - Dashboard page placeholder with welcome card and stat cards ## [0.1.0] - 2024-12-30 ### Added - Initial Flutter project setup with all platforms (web, android, ios, macos, linux, windows) - Build-time version generation from pubspec.yaml (`dart run tool/generate_version.dart`) - Version logging on app startup - Project documentation (PHILOSOPHY.md, README.md, AGENTS.md, PLAN.md) - Phase 0 technical documentation: - docs/ARCHITECTURE.md - Clean Architecture patterns - docs/API_INTEGRATION.md - Backend API reference - docs/DEPLOYMENT.md - Docker and infrastructure setup - docs/DATAGRID.md - DataGrid component specification - docs/THEMING.md - Material 3 theming guide