9.4 KiB
9.4 KiB
Apps Domain Rules
This file governs apps/** (Flutter). Keep rules strict, short, and reusable.
Scope & Precedence
- Inherits root
AGENTS.mdand workspace runtime rules. - If rules conflict, apply the stricter one.
- Visual language source of truth:
apps/rules/visual_design_language.md.
Flutter Directory Contract (Must)
apps/libonly allows these second-level directories:app/,core/,data/,features/,shared/,l10n/.apps/lib/main.dartis the only allowed root entry file.- Do not add new second-level directories under
apps/libwithout explicit approval.
Module Responsibilities (Must)
app/: app bootstrap, DI wiring, global lifecycle orchestration, router composition.core/: cross-feature business primitives/protocols/orchestrators (no feature-specific page logic).data/: shared infrastructure only (cache/network/storage/adapters), not feature business repositories/models.features/: user-facing bounded feature modules with clear product ownership.shared/: reusable UI widgets and presentation helpers without feature business orchestration.- Cross-cutting capabilities (e.g. notification orchestration, UI schema protocol) must live in
core/+shared/, not underfeatures/.
Placement Rules (Must)
- Put code in
features/only when it belongs to one bounded product capability/screen flow. - Put code in
core/when it is cross-feature protocol, policy, or orchestration that does not belong to one feature. - Put reusable UI renderers in
shared/widgets/; they must not contain feature-only business orchestration. - In feature data layers, use semantic subfolders:
data/apis/,data/repositories/,data/services/,data/models/. - Avoid deep redundant nesting like
models/<same_name>/...; prefer flat by concern.
Shared Data Layer Boundary (Must)
- Do not place feature business repositories/models under
apps/lib/data/. - Feature business repositories/models must live under each feature's
data/tree. apps/lib/data/is only for infrastructure abstractions and implementations (cache/network/storage), reusable by features.
UI Design System (Must)
- Semantic colors: always use
Theme.of(context).colorScheme.*(primary, surface, error, etc.). Never hardcode hex orColors.*. - Brand palette colors (event presets, avatar colors, Eisenhower matrix quadrants): use
Theme.of(context).extension<AppColorPalette>()!.*. - Spacing / Radius: use
AppSpacing/AppRadiusfromdesign_tokens.dart. No hardcoded values. AppTheme.light/AppTheme.darkprovide completeColorScheme(light + dark).MaterialAppwires them viatheme:/darkTheme:.- If a semantic slot is missing from
ColorScheme, add it toAppTheme— do not bypasscolorSchemewith hardcoded values.
Divination Terminology (Must)
- Divination domain terminology must use fixed Chinese terms in code contracts, protocol fields, and UI semantic labels.
- Do not localize or translate canonical terms such as: 六爻、爻、动爻、静爻、六亲、六神、世爻、应爻、伏神、月建、日辰、月破、日冲、空亡、五行旺衰、上上签、中上签、中下签。
- l10n can translate explanatory copy, but must not alter canonical divination terminology semantics.
Reuse & Composition (Must)
- Prefer
apps/lib/shared/widgets/before adding new components. - Extract repeated page structures/components; do not duplicate sibling-page scaffolds.
- Detail page top-right actions must use shared action-menu components.
- Destructive confirmations must use project-consistent shared surfaces.
Interaction & Feedback (Must)
- User feedback:
Toast/AppBanneronly. - Loading indicators:
AppLoadingIndicatoronly. - Form pages should default to keyboard-overlay behavior to avoid full-page layout jumps.
ToastType.infoshould be minimized: do not show informational toast for normal success paths (e.g., login success). Prefer silent success unless user must take action.
Interaction & Feedback (Must)
Agent Chat Protocol (Must)
- Agent chat must follow AG-UI over SSE.
- Lifecycle events are mandatory:
RUN_STARTEDand exactly one ofRUN_FINISHEDorRUN_ERROR. - Current default text delivery is finalized
TEXT_MESSAGE_ENDpayloads; do not require token-levelTEXT_MESSAGE_CONTENTunless backend protocol explicitly enables it.
HTTP Error Parse Contract (Must)
- Frontend must parse backend errors as RFC7807:
type/title/status/detail/instance+ extensioncode/params. - Error code registry single source of truth:
docs/protocols/common/http-error-codes.md. - Frontend mapping must be based on documented
codeonly (code -> l10n key), not inferred fromdetailtext. - Any new/changed code requires protocol doc update first, then frontend mapping update.
- Unknown code fallback order: status-generic localized message -> safe generic localized message.
High-Risk Modules (Must)
Auth
AuthBlocis the single source of truth.- 401 invalidation must go through global callback chain; no feature-level token clearing or direct login navigation.
Home Message Viewport
- Home message auto-scroll/anchor restore must be event-driven.
- Preserve viewport during history prepend and when user is reading above bottom.
Cache / Repository
- Reads/writes that affect consistency must go through repository layer.
- Cache keys and invalidation policy belong to repository, not UI/Bloc.
- Shared cache infrastructure must live under
apps/lib/data/cache/; feature modules must not duplicate low-level cache store logic. - Shared cache infrastructure (
apps/lib/data/cache/) must remain domain-agnostic: do not importfeatures/**or business model DTOs there. - Domain object serialization/deserialization belongs to repository/feature layer via local mappers/codecs; do not centralize feature-specific codecs in shared cache layer.
- Shared cache layer may only encode/decode primitives, collections, and cache metadata wrappers.
- Cache strategy default is
SWR + TTL + invalidation/reload. - Local partial cache patching is allowed only for simple single-entity updates with clear rollback paths; complex cross-list/cross-feature states must invalidate and refetch.
- Feature TTL policy must be defined in each feature repository; do not add centralized feature TTL registries in shared cache infra.
- Runtime cache is hybrid (
memory + local persistent) managed by DI singletons; do not create per-screen/per-widget cache store instances. - Cross-feature data access must go through app-level facade/usecase boundaries; do not import another feature's data implementation directly from UI/Bloc.
- Repository instances should be resolved from DI singletons to reuse cache and avoid per-feature re-creation.
Reminder / Notification Rewrite Boundary
- Reminder/notification data-interaction logic is under rewrite. Do not reintroduce local-notification scheduling/callback execution paths in
apps/lib/data/services/. - During rewrite, keep protocol/orchestration in
core/notification/**and reusable rendering inshared/widgets/notification/**.
Testing Policy
- Prioritize tests for model parsing, service logic, and high-regression interaction flows.
- Simple static UI changes may skip tests.
- Auth/Home/Cache changes must include targeted regression tests.
Logging Conventions (Must)
Logger Setup
import 'core/logging/logger.dart';
class SomeBloc extends Cubit<SomeState> {
final Logger _logger = getLogger('features.<feature>.<component>');
}
Log Level Policy
| Level | When to Use | Noise Level |
|---|---|---|
| error | All exceptions and failures - MUST log every error site | Required, never skip |
| warning | Degraded behavior, retry, fallback, malformed data | Minimal, only when action taken |
| info | Key business events (login, logout, send message) | Minimal, only milestone events |
| debug | Detailed flow tracing (only in debug builds) | High, avoid in release |
Error Logging Requirements
Every try-catch that handles an exception MUST log it:
try {
await _repository.someOperation();
} catch (e, stackTrace) {
_logger.error(
message: 'Operation failed: $operationName',
error: e,
stackTrace: stackTrace,
extra: {'context': 'relevant_data'},
);
// handle error
}
Info Logging Requirements
Only log these milestone events:
- User login/logout
- Message sent/received
- Data sync completed
- Important state transitions
_logger.info(
message: 'User logged in',
extra: {'user_id': user.id},
);
Warning Logging Requirements
Only log when taking corrective action:
- Retrying after failure
- Using fallback data
- Skipping malformed data
- Deprecation warnings
_logger.warning(
message: 'Cache miss, loading from remote',
extra: {'key': cacheKey},
);
Module Naming Convention
| Feature | Module Path |
|---|---|
| auth | features.auth |
| calendar | features.calendar |
| chat | features.chat |
| contacts | features.contacts |
| home | features.home |
| messages | features.messages |
| settings | features.settings |
| todo | features.todo |
Prohibited Practices
- Never log sensitive data: passwords, tokens, PII, message content
- Never log at debug level in production (release mode)
- Never skip error logging even if you "handle" the error
- Never log for every iteration in loops - only on failures