From dd6bcbdbdade2ddffe8ad16177ca476610696906 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Wed, 31 Dec 2025 00:04:04 +0100 Subject: [PATCH] feat: LAN-first development with optional auth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Default API URLs now use LAN IPs (192.168.86.149) - Auth interceptor skips auth when using LAN endpoints - Production builds override with --dart-define Development: flutter run -d chrome (no auth needed on LAN) Production: flutter build web --dart-define=CORE_API_URL=https://api.schweitz.net 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- CHANGELOG.md | 4 ++++ lib/core/api/api_interceptors.dart | 15 +++++++++++++++ lib/core/config/app_config.dart | 27 ++++++++++++++++++++++++--- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af97534..539b0e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### 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 diff --git a/lib/core/api/api_interceptors.dart b/lib/core/api/api_interceptors.dart index 2973596..135d292 100644 --- a/lib/core/api/api_interceptors.dart +++ b/lib/core/api/api_interceptors.dart @@ -4,9 +4,12 @@ import 'package:dio/dio.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../auth/auth_provider.dart'; +import '../config/app_config.dart'; import '../error/app_exception.dart'; /// Adds authentication token to requests. +/// +/// Skipped entirely when [AppConfig.requiresAuth] is false (LAN development). class AuthInterceptor extends Interceptor { AuthInterceptor(this._ref); @@ -14,6 +17,12 @@ class AuthInterceptor extends Interceptor { @override void onRequest(RequestOptions options, RequestInterceptorHandler handler) { + // Skip auth for LAN development + if (!AppConfig.requiresAuth) { + handler.next(options); + return; + } + final authState = _ref.read(authNotifierProvider); authState.whenData((auth) { @@ -27,6 +36,12 @@ class AuthInterceptor extends Interceptor { @override void onError(DioException err, ErrorInterceptorHandler handler) { + // Skip auth error handling for LAN development + if (!AppConfig.requiresAuth) { + handler.next(err); + return; + } + if (err.response?.statusCode == 401) { // Token expired - trigger re-authentication _ref.read(authNotifierProvider.notifier).signOut(); diff --git a/lib/core/config/app_config.dart b/lib/core/config/app_config.dart index 76946be..4fefa51 100644 --- a/lib/core/config/app_config.dart +++ b/lib/core/config/app_config.dart @@ -1,19 +1,35 @@ /// Application configuration from compile-time environment variables. /// -/// Set via: flutter build --dart-define=API_URL=https://... +/// ## Development (LAN - no auth required) +/// Default values use LAN IPs for local development: +/// ```bash +/// flutter run -d chrome +/// ``` +/// +/// ## Production (public URLs - auth required) +/// Override with public URLs for production builds: +/// ```bash +/// flutter build web \ +/// --dart-define=CORE_API_URL=https://api.schweitz.net \ +/// --dart-define=TATLOCK_API_URL=https://tatlock.schweitz.net +/// ``` class AppConfig { AppConfig._(); /// Core API base URL + /// - LAN default: No auth required + /// - Production: https://api.schweitz.net (requires OIDC) static const coreApiUrl = String.fromEnvironment( 'CORE_API_URL', - defaultValue: 'https://api.schweitz.net', + defaultValue: 'http://192.168.86.149:8083', ); /// Tatlock API base URL + /// - LAN default: No auth required + /// - Production: https://tatlock.schweitz.net (requires OIDC) static const tatlockApiUrl = String.fromEnvironment( 'TATLOCK_API_URL', - defaultValue: 'https://tatlock.schweitz.net', + defaultValue: 'http://192.168.86.149:8000', ); /// Authentik OIDC discovery URL @@ -37,4 +53,9 @@ class AppConfig { /// Whether running in debug mode static const isDebug = bool.fromEnvironment('DEBUG', defaultValue: false); + + /// Whether auth is required (false for LAN development) + static bool get requiresAuth => + coreApiUrl.contains('schweitz.net') || + tatlockApiUrl.contains('schweitz.net'); }