diet-guard/docs/DOCS-flutter-rules-state-and-data.md
Krzysztof kuhy Rudnicki 03e14e17f3
Some checks failed
file-length / file length <= 250 lines (push) Has been cancelled
md-naming / markdown naming convention (push) Has been cancelled
pre-commit / pre-commit (push) Has been cancelled
Tests / test (3.10) (push) Has been cancelled
Tests / test (3.11) (push) Has been cancelled
Tests / test (3.12) (push) Has been cancelled
release-apk / release (APK) (push) Has been cancelled
Adopt the four markdown namespaces and gate them
Renames this repo's markdown onto README.md / CLAUDE*.md / DOCS*.md /
TODO*.md so a future session can tell a live task from a finished
record without reading the file to find out.

TODO files carry the literal "REMOVE ME AFTER FINISH" and are deleted
when the work lands. Enforced by the md-naming pre-commit hook and CI
workflow, both delegating to the shared gate in kuhyx/utils so this
repo's idea of a valid name cannot drift from every other repo's.

Includes the patch bump this repo's bump-patch-version hook applies to
app/pubspec.yaml on every commit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A47aX5DJwmA3QFn3pkEWi7
2026-08-24 15:57:20 +02:00

184 lines
6.0 KiB
Markdown

<!--
Vendored from flutter/flutter docs/rules/rules.md, split across five files
so each stays under this repo's 250-line cap. Upstream content: edit it here
only to re-sync with upstream, not to record decisions about this repo --
those belong in CLAUDE.md.
-->
# Architecture, lint rules, state and data
_Vendored Flutter/Dart AI rules. See [CLAUDE.md](../CLAUDE.md)._
### Application Architecture
* **Separation of Concerns:** Aim for separation of concerns similar to MVC/MVVM, with defined Model,
View, and ViewModel/Controller roles.
* **Logical Layers:** Organize the project into logical layers:
* Presentation (widgets, screens)
* Domain (business logic classes)
* Data (model classes, API clients)
* Core (shared classes, utilities, and extension types)
* **Feature-based Organization:** For larger projects, organize code by feature,
where each feature has its own presentation, domain, and data subfolders. This
improves navigability and scalability.
### Lint Rules
Include the package in the `analysis_options.yaml` file. Use the following
`analysis_options.yaml` file as a starting point:
```yaml
include: package:flutter_lints/flutter.yaml
linter:
rules:
# Add additional lint rules here:
# avoid_print: false
# prefer_single_quotes: true
```
#### State Management
* **Built-in Solutions:** Prefer Flutter's built-in state management solutions.
Do not use a third-party package unless explicitly requested.
* **Streams:** Use `Streams` and `StreamBuilder` for handling a sequence of
asynchronous events.
* **Futures:** Use `Futures` and `FutureBuilder` for handling a single
asynchronous operation that will complete in the future.
* **ValueNotifier:** Use `ValueNotifier` with `ValueListenableBuilder` for
simple, local state that involves a single value.
```dart
// Define a ValueNotifier to hold the state.
final ValueNotifier<int> _counter = ValueNotifier<int>(0);
// Use ValueListenableBuilder to listen and rebuild.
ValueListenableBuilder<int>(
valueListenable: _counter,
builder: (context, value, child) {
return Text('Count: $value');
},
);
```
* **ChangeNotifier:** For state that is more complex or shared across multiple
widgets, use `ChangeNotifier`.
* **ListenableBuilder:** Use `ListenableBuilder` to listen to changes from a
`ChangeNotifier` or other `Listenable`.
* **MVVM:** When a more robust solution is needed, structure the app using the
Model-View-ViewModel (MVVM) pattern.
* **Dependency Injection:** Use simple manual constructor dependency injection
to make a class's dependencies explicit in its API, and to manage dependencies
between different layers of the application.
* **Provider:** If a dependency injection solution beyond manual constructor
injection is explicitly requested, `provider` can be used to make services,
repositories, or complex state objects available to the UI layer without tight
coupling (note: this document generally defaults against third-party packages
for state management unless explicitly requested).
#### Data Flow
* **Data Structures:** Define data structures (classes) to represent the data
used in the application.
* **Data Abstraction:** Abstract data sources (e.g., API calls, database
operations) using Repositories/Services to promote testability.
#### Routing
* **GoRouter:** Use the `go_router` package for declarative navigation, deep
linking, and web support.
* **GoRouter Setup:** To use `go_router`, first add it to your `pubspec.yaml`
using the `pub` tool's `add` command.
```dart
// 1. Add the dependency
// flutter pub add go_router
// 2. Configure the router
final GoRouter _router = GoRouter(
routes: <RouteBase>[
GoRoute(
path: '/',
builder: (context, state) => const HomeScreen(),
routes: <RouteBase>[
GoRoute(
path: 'details/:id', // Route with a path parameter
builder: (context, state) {
final String id = state.pathParameters['id']!;
return DetailScreen(id: id);
},
),
],
),
],
);
// 3. Use it in your MaterialApp
MaterialApp.router(
routerConfig: _router,
);
```
* **Authentication Redirects:** Configure `go_router`'s `redirect` property to
handle authentication flows, ensuring users are redirected to the login screen
when unauthorized, and back to their intended destination after successful
login.
* **Navigator:** Use the built-in `Navigator` for short-lived screens that do
not need to be deep-linkable, such as dialogs or temporary views.
```dart
// Push a new screen onto the stack
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const DetailsScreen()),
);
// Pop the current screen to go back
Navigator.pop(context);
```
#### Data Handling & Serialization
* **JSON Serialization:** Use `json_serializable` and `json_annotation` for
parsing and encoding JSON data.
* **Field Renaming:** When encoding data, use `fieldRename: FieldRename.snake`
to convert Dart's camelCase fields to snake_case JSON keys.
```dart
// In your model file
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
@JsonSerializable(fieldRename: FieldRename.snake)
class User {
final String firstName;
final String lastName;
User({required this.firstName, required this.lastName});
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
```
#### Logging
* **Structured Logging:** Use the `log` function from `dart:developer` for
structured logging that integrates with Dart DevTools.
```dart
import 'dart:developer' as developer;
// For simple messages
developer.log('User logged in successfully.');
// For structured error logging
try {
// ... code that might fail
} catch (e, s) {
developer.log(
'Failed to fetch data',
name: 'myapp.network',
level: 1000, // SEVERE
error: e,
stackTrace: s,
);
}
```