From be79ce37535b5bd13389d69d873c28d51d8a4da6 Mon Sep 17 00:00:00 2001 From: valorengels Date: Wed, 19 Aug 2026 16:56:32 +0700 Subject: [PATCH 1/4] docs: reconcile template docs with source-bearing state - Rewrite CLAUDE.md Repository Overview/Project Structure to describe the implemented lib/ tree (drop documentation-only/no-source-code framing) - Add Optional Authentication section (enable or strip) to CLAUDE.md and docs/architecture.md - Add network-security-config pattern for LAN apps (base-config + manifest wiring + per-domain alternative + tradeoff) to docs/setup_reference.md --- CLAUDE.md | 45 ++++++++++++++++++++++---------------- docs/architecture.md | 14 +++++++++++- docs/setup_reference.md | 48 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 20 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 69c3743..fffa06c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,17 +4,18 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Repository Overview -This is a **documentation-only Flutter architecture template** for small teams (2-5 people) using AI-assisted development. It contains no source code—only architecture guides and setup documentation to copy into new Flutter projects. +This is a **source-bearing Flutter architecture template** for small teams (2-5 people) using AI-assisted development. It ships a real, runnable app under `lib/` alongside the architecture guides and setup documentation — use it as the starting point to copy into new Flutter projects. ## Key Files - `docs/architecture.md` - Reference guidelines + **planned features** (Database Layer) - `docs/implemented.md` - Documentation for already-built features (connectivity, network, offline queue, BLoC patterns) - `docs/setup_reference.md` - Environment setup and critical implementation patterns +- `lib/` - The implemented source tree (see Project Structure below) ## Architecture Principles -When implementing features based on this template: +This repository is organized around these principles: 1. **Two-layer architecture** - Presentation + Data only (no separate domain layer) 2. **Freezed everywhere** - Models, BLoC events, and states use sealed unions @@ -22,31 +23,37 @@ When implementing features based on this template: 4. **BLoC pattern** - State management with flutter_bloc + hydrated_bloc 5. **get_it** - Service locator for dependency injection -## Project Structure (When Implemented) +## Project Structure ``` lib/ +├── main.dart # App entry point +├── l10n/ # Localization (app_en.arb, app_es.arb) ├── core/ -│ ├── theme/ # App theme -│ ├── routes/ # go_router setup -│ ├── network/ # DioClient, offline queue -│ ├── database/ # DatabaseService, StorageService (Firebase/Supabase) -│ ├── connectivity/ # ConnectivityBloc & service -│ ├── di/ # get_it configuration -│ └── utils/ # Logger, constants, extensions +│ ├── theme/ # AppTheme +│ ├── routes/ # go_router setup + auth_guard +│ ├── network/ # DioClient, offline queue, request executor, auth token manager + interceptor +│ ├── database/ # DatabaseService (interface), LocalCacheService, sync status, cached document +│ ├── connectivity/ # ConnectivityBloc & service +│ ├── auth/ # OPTIONAL auth layer (AuthRepository, AuthBloc) — see Optional Authentication +│ ├── analytics/ # AnalyticsService + NoopAnalyticsService (default) +│ ├── di/ # get_it configuration +│ └── utils/ # Result type, connectivity-aware mixin ├── features/ -│ └── [feature_name]/ -│ ├── data/ -│ │ ├── models/ # Freezed models -│ │ ├── repositories/ -│ │ └── datasources/ -│ └── presentation/ -│ ├── bloc/ # BLoC + Freezed events/states -│ ├── pages/ -│ └── widgets/ +│ └── home/ # Example feature (data + presentation + BLoC) └── shared/ + └── widgets/ # Reusable widgets (error view, connectivity banner, loading, empty state) ``` +## Optional Authentication + +The auth layer ships **unwired**. `lib/core/auth/` contains `AuthRepository`, `AuthBloc`, `AuthEvent`, and `AuthState`, and `AuthTokenManager` + `AuthInterceptor` exist under `lib/core/network/` — but the repository and BLoC are **not** registered in dependency injection (`lib/core/di/injection.dart` has the registrations commented out under an "Auth (uncomment after implementing AuthRepository)" block). Choose one: + +- **Enable auth**: implement a concrete `AuthRepository` (the commented block references a `FirebaseAuthRepository` stub to write), then uncomment the `AuthRepository`/`AuthBloc` registrations in `lib/core/di/injection.dart` along with their `auth_bloc.dart`/`auth_repository.dart` imports. `AuthTokenManager`, `AuthInterceptor`, and `RequestExecutor` are already wired and ready once the repository exists. +- **Strip auth** (full removal): delete `lib/core/auth/` and `test/core/auth/`; remove `AuthTokenManager` from `lib/core/di/injection.dart`, drop the `authManager` dependency from `DioClient` and `RequestExecutor`, delete `auth_interceptor.dart` and `auth_token_manager.dart`, and remove the `auth_exception.dart` import + `on AuthException` catch in `offline_queue.dart`. + +See [docs/architecture.md](docs/architecture.md) → Optional Authentication for details. + ## Common Commands ```bash diff --git a/docs/architecture.md b/docs/architecture.md index f04d22b..0043363 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -153,11 +153,23 @@ lib/ For teams under 5 people: - **Freezed models** already provide immutability and type safety - **No business logic complexity** requiring separate entities -- **AI code generation** works better with simpler structure +- **AI code generation** works well with simpler structure - **Easy to add later** if complexity grows --- +## Optional Authentication + +> **Status: UNWIRED** - The auth layer ships in the template but is **not** enabled. See [CLAUDE.md](../CLAUDE.md#optional-authentication) for the enable-or-strip closure. + +The template includes `lib/core/auth/` (`AuthRepository`, `AuthBloc`, `AuthEvent`, `AuthState`) plus `AuthTokenManager` and `AuthInterceptor` under `lib/core/network/`. The repository and BLoC are **not** registered in `lib/core/di/injection.dart` (the registrations sit commented out under an "Auth (uncomment after implementing AuthRepository)" block), so a fresh app runs without authentication. + +**Enable:** write a concrete `AuthRepository` implementation, then uncomment the `AuthRepository`/`AuthBloc` registrations and their `auth_bloc.dart`/`auth_repository.dart` imports in `injection.dart`. The token manager, interceptor, and request executor are already wired. + +**Strip:** delete `lib/core/auth/` and `test/core/auth/`; remove the `AuthTokenManager` registration from `injection.dart`, drop the `authManager` dependency from `DioClient` and `RequestExecutor`, delete `auth_interceptor.dart` and `auth_token_manager.dart`, and remove the `auth_exception.dart` import + `on AuthException` catch in `offline_queue.dart`. + +--- + ## Planned: Database Layer > **Status: NOT IMPLEMENTED** - This section describes the planned database abstraction layer. diff --git a/docs/setup_reference.md b/docs/setup_reference.md index 91241e2..f8822d1 100644 --- a/docs/setup_reference.md +++ b/docs/setup_reference.md @@ -691,6 +691,54 @@ class MockConnectivityService extends Mock implements ConnectivityService {} --- +## 9. Network Security Config for LAN Apps (Cleartext) + +### Problem + +Android 9 (API 28+) blocks cleartext (plain HTTP) traffic by default. A LAN app that talks to a local host over HTTP (e.g. `http://192.168.1.50:8080` on the home network) fails with `CLEARTEXT communication to [ip] not permitted by network security policy`. + +### Pattern: base-config (simplest, for LAN apps) + +For a LAN app with unpredictable host IPs (Android's `domain-config` cannot wildcard or CIDR-match a subnet), set cleartext permitted globally via `base-config`. Create `android/app/src/main/res/xml/network_security_config.xml`: + +```xml + + + + +``` + +Then wire it in `android/app/src/main/AndroidManifest.xml` on the `` tag: + +```xml + +``` + +Setting `android:networkSecurityConfig` makes `android:usesCleartextTraffic` ignored, so keep the config in the XML file. Note: API 37+ has an implicit localhost cleartext config; API 28-36 must configure localhost explicitly if your LAN app also talks to `localhost`/`127.0.0.1`. + +### Alternative: per-domain `domain-config` (known hosts only) + +If your LAN host IPs are stable, restrict cleartext to specific hosts instead of globally: + +```xml + + + + 192.168.1.50 + + +``` + +The most-specific matching `domain-config` wins. You cannot CIDR-match a subnet — list each host explicitly. + +### Security Tradeoff + +`base-config cleartextTrafficPermitted="true"` permits cleartext to **all** hosts, weakening transport security app-wide. Use it only for LAN-only apps (no internet credentials over cleartext), and prefer the per-domain `domain-config` variant whenever hosts are known and stable. Never ship the global cleartext config to a production app that talks to the public internet. + +--- + ## Summary of Critical Decisions | Issue | Decision | Rationale | From ba7016d6ec396312611579234bc79c9123a84821 Mon Sep 17 00:00:00 2001 From: valorengels Date: Wed, 19 Aug 2026 17:08:43 +0700 Subject: [PATCH 2/4] docs: include auth_guard.dart in strip-auth closure --- CLAUDE.md | 2 +- docs/architecture.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index fffa06c..a5a174d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -50,7 +50,7 @@ lib/ The auth layer ships **unwired**. `lib/core/auth/` contains `AuthRepository`, `AuthBloc`, `AuthEvent`, and `AuthState`, and `AuthTokenManager` + `AuthInterceptor` exist under `lib/core/network/` — but the repository and BLoC are **not** registered in dependency injection (`lib/core/di/injection.dart` has the registrations commented out under an "Auth (uncomment after implementing AuthRepository)" block). Choose one: - **Enable auth**: implement a concrete `AuthRepository` (the commented block references a `FirebaseAuthRepository` stub to write), then uncomment the `AuthRepository`/`AuthBloc` registrations in `lib/core/di/injection.dart` along with their `auth_bloc.dart`/`auth_repository.dart` imports. `AuthTokenManager`, `AuthInterceptor`, and `RequestExecutor` are already wired and ready once the repository exists. -- **Strip auth** (full removal): delete `lib/core/auth/` and `test/core/auth/`; remove `AuthTokenManager` from `lib/core/di/injection.dart`, drop the `authManager` dependency from `DioClient` and `RequestExecutor`, delete `auth_interceptor.dart` and `auth_token_manager.dart`, and remove the `auth_exception.dart` import + `on AuthException` catch in `offline_queue.dart`. +- **Strip auth** (full removal): delete `lib/core/auth/`, `lib/core/routes/auth_guard.dart`, and `test/core/auth/`; remove `AuthTokenManager` from `lib/core/di/injection.dart`, drop the `authManager` dependency from `DioClient` and `RequestExecutor`, delete `auth_interceptor.dart` and `auth_token_manager.dart`, and remove the `auth_exception.dart` import + `on AuthException` catch in `offline_queue.dart`. (The stale, commented-out auth references in `lib/core/routes/app_router.dart` — the `auth_guard`/`auth_bloc`/`injection` imports and the commented `redirect:` block — can also be cleaned up.) See [docs/architecture.md](docs/architecture.md) → Optional Authentication for details. diff --git a/docs/architecture.md b/docs/architecture.md index 0043363..1f2304c 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -166,7 +166,7 @@ The template includes `lib/core/auth/` (`AuthRepository`, `AuthBloc`, `AuthEvent **Enable:** write a concrete `AuthRepository` implementation, then uncomment the `AuthRepository`/`AuthBloc` registrations and their `auth_bloc.dart`/`auth_repository.dart` imports in `injection.dart`. The token manager, interceptor, and request executor are already wired. -**Strip:** delete `lib/core/auth/` and `test/core/auth/`; remove the `AuthTokenManager` registration from `injection.dart`, drop the `authManager` dependency from `DioClient` and `RequestExecutor`, delete `auth_interceptor.dart` and `auth_token_manager.dart`, and remove the `auth_exception.dart` import + `on AuthException` catch in `offline_queue.dart`. +**Strip:** delete `lib/core/auth/`, `lib/core/routes/auth_guard.dart`, and `test/core/auth/`; remove the `AuthTokenManager` registration from `injection.dart`, drop the `authManager` dependency from `DioClient` and `RequestExecutor`, delete `auth_interceptor.dart` and `auth_token_manager.dart`, and remove the `auth_exception.dart` import + `on AuthException` catch in `offline_queue.dart`. (The stale, commented-out auth references in `lib/core/routes/app_router.dart` — the `auth_guard`/`auth_bloc`/`injection` imports and the commented `redirect:` block — can also be cleaned up.) --- From f60d69ca77a42ffc63245d3d99c69d6c3717361d Mon Sep 17 00:00:00 2001 From: valorengels Date: Wed, 19 Aug 2026 17:23:34 +0700 Subject: [PATCH 3/4] Docs: cascade source-bearing framing into sphinx docs site (overview, index) Reconciles the sphinx docs site (overview.md, index.rst) with the source-bearing template framing landed in CLAUDE.md: drop 'documentation-only'/'no source code' description and the 'When Implemented' project-structure tree in favor of the implemented lib/ layout. Docs-only. --- docs/sphinx/source/index.rst | 2 +- docs/sphinx/source/overview.md | 33 +++++++++++++++------------------ 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/docs/sphinx/source/index.rst b/docs/sphinx/source/index.rst index 4c1e65b..19bad95 100644 --- a/docs/sphinx/source/index.rst +++ b/docs/sphinx/source/index.rst @@ -1,7 +1,7 @@ Flutter Project Template ======================== -A documentation-only Flutter architecture template for small teams (2-5 people) using AI-assisted development. No source code — just battle-tested architecture guides and patterns to copy into new Flutter projects. +A source-bearing Flutter architecture template for small teams (2-5 people) using AI-assisted development. Ships a real, runnable app under `lib/` — use it as the starting point to copy into new Flutter projects. .. toctree:: :maxdepth: 2 diff --git a/docs/sphinx/source/overview.md b/docs/sphinx/source/overview.md index d557061..5c52b55 100644 --- a/docs/sphinx/source/overview.md +++ b/docs/sphinx/source/overview.md @@ -2,7 +2,7 @@ ## What Is This? -This is a **documentation-only Flutter architecture template** for small teams (2-5 people) using AI-assisted development. It contains no source code — only architecture guides and setup documentation to copy into new Flutter projects. +This is a **source-bearing Flutter architecture template** for small teams (2-5 people) using AI-assisted development. It ships a real, runnable app under `lib/` alongside the architecture guides and setup documentation — use it as the starting point to copy into new Flutter projects. ## Who Is It For? @@ -33,27 +33,24 @@ This is a **documentation-only Flutter architecture template** for small teams ( | [Architecture](architecture.md) | Reference guidelines + planned features (database layer) | | [Setup Reference](setup_reference.md) | Critical implementation details, auth flows, retry logic, pitfalls | -## Project Structure (When Implemented) +## Project Structure ``` lib/ +├── main.dart # App entry point +├── l10n/ # Localization (app_en.arb, app_es.arb) ├── core/ -│ ├── theme/ # App theme -│ ├── routes/ # go_router setup -│ ├── network/ # DioClient, offline queue -│ ├── database/ # DatabaseService, StorageService -│ ├── connectivity/ # ConnectivityBloc & service -│ ├── di/ # get_it configuration -│ └── utils/ # Logger, constants, extensions +│ ├── theme/ # AppTheme +│ ├── routes/ # go_router setup + auth_guard +│ ├── network/ # DioClient, offline queue, request executor, auth token manager + interceptor +│ ├── database/ # DatabaseService (interface), LocalCacheService, sync status, cached document +│ ├── connectivity/ # ConnectivityBloc & service +│ ├── auth/ # OPTIONAL auth layer (AuthRepository, AuthBloc) — see Optional Authentication +│ ├── analytics/ # AnalyticsService + NoopAnalyticsService (default) +│ ├── di/ # get_it configuration +│ └── utils/ # Result type, connectivity-aware mixin ├── features/ -│ └── [feature_name]/ -│ ├── data/ -│ │ ├── models/ # Freezed models -│ │ ├── repositories/ -│ │ └── datasources/ -│ └── presentation/ -│ ├── bloc/ # BLoC + Freezed events/states -│ ├── pages/ -│ └── widgets/ +│ └── home/ # Example feature (data + presentation + BLoC) └── shared/ + └── widgets/ # Reusable widgets (error view, connectivity banner, loading, empty state) ``` From 46d9ed72f9fcb6cb5da89dc3a515bce5ebfbb115 Mon Sep 17 00:00:00 2001 From: valorengels Date: Fri, 21 Aug 2026 17:50:12 +0700 Subject: [PATCH 4/4] docs: fix build-docs warnings (suppress myst external-file xref, valid XML snippet) --- docs/setup_reference.md | 5 +++-- docs/sphinx/source/conf.py | 6 ++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/setup_reference.md b/docs/setup_reference.md index f8822d1..45fd7b9 100644 --- a/docs/setup_reference.md +++ b/docs/setup_reference.md @@ -712,8 +712,9 @@ Then wire it in `android/app/src/main/AndroidManifest.xml` on the ` ```xml + android:networkSecurityConfig="@xml/network_security_config"> + + ``` Setting `android:networkSecurityConfig` makes `android:usesCleartextTraffic` ignored, so keep the config in the XML file. Note: API 37+ has an implicit localhost cleartext config; API 28-36 must configure localhost explicitly if your LAN app also talks to `localhost`/`127.0.0.1`. diff --git a/docs/sphinx/source/conf.py b/docs/sphinx/source/conf.py index 352add3..cedbf26 100644 --- a/docs/sphinx/source/conf.py +++ b/docs/sphinx/source/conf.py @@ -31,6 +31,12 @@ myst_heading_anchors = 3 +# The docs/ markdown files are copied into the sphinx source dir at build time, +# so relative links back to the repo-root CLAUDE.md (e.g. ../CLAUDE.md#anchor) +# resolve correctly on GitHub but not from sphinx/source. Suppress the resulting +# myst.xref_missing warning; these links fall back to plain hyperlinks. +suppress_warnings = ['myst.xref_missing'] + # Source file suffixes source_suffix = { '.rst': 'restructuredtext',