Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 26 additions & 19 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,49 +4,56 @@ 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
3. **Connectivity-first** - Explicit handling of online/poor/offline states in repositories
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/`, `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.

## Common Commands

```bash
Expand Down
14 changes: 13 additions & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/`, `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.)

---

## Planned: Database Layer

> **Status: NOT IMPLEMENTED** - This section describes the planned database abstraction layer.
Expand Down
49 changes: 49 additions & 0 deletions docs/setup_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,55 @@ 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
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
```

Then wire it in `android/app/src/main/AndroidManifest.xml` on the `<application>` tag:

```xml
<application
android:networkSecurityConfig="@xml/network_security_config">
<!-- remaining manifest attributes omitted -->
</application>
```

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
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="false">192.168.1.50</domain>
</domain-config>
</network-security-config>
```

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 |
Expand Down
6 changes: 6 additions & 0 deletions docs/sphinx/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
2 changes: 1 addition & 1 deletion docs/sphinx/source/index.rst
Original file line number Diff line number Diff line change
@@ -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
Expand Down
33 changes: 15 additions & 18 deletions docs/sphinx/source/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -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?

Expand Down Expand Up @@ -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)
```
Loading