# Flutter Mobile Development Constraints This document defines **hard constraints** for Flutter mobile development. Treat all items as **non-negotiable** unless explicitly overridden. ## 0) Scope and Precedence (MUST) - This file applies to all changes under `apps/**`. - It extends root routing rules in `AGENTS.md` and workspace global runtime rules. - It also incorporates the visual design language from `apps/rules/visual_design_language.md` as a binding constraint. - If rules conflict, apply the stricter requirement. - Keep Flutter-specific constraints in this file; avoid duplicating them in root `AGENTS.md`. ## 1) Design Tokens (MUST) - **MUST** use design tokens from `apps/lib/core/theme/design_tokens.dart`: - Colors: `AppColors.*` - Spacing: `AppSpacing.*` - Radius: `AppRadius.*` - **MUST NOT** hardcode any visual values. - Design tokens are the single source of truth for all visual values. Any missing visual semantics should be added to tokens, not approximated locally. - This ensures consistency with the visual design language defined in `apps/rules/visual_design_language.md`. ## 2) Component Architecture (MUST) - **SHOULD** extract repeated UI patterns into reusable components. - **SHOULD** prefer existing shared components before creating new ones. - **SHOULD** place reusable components in `apps/lib/shared/widgets/` following existing naming conventions. - **MUST NOT** introduce parallel UI systems (e.g., custom button styles, custom loading indicators) that duplicate existing shared components. - When creating new UI components, ensure they follow the design tokens and visual design language. ## 2.1) Navigation/Header Reuse Rules (MUST) - For page groups with clear parent-child relationships (e.g., Settings and its subpages), **MUST** use one shared header pattern: back button + page title. - **MUST** extract shared page scaffolds/header wrappers instead of duplicating `SafeArea + header + scroll` structures across sibling pages. - Detail-page right-side actions (edit/delete/share etc.) **MUST** use a shared action-menu component, not per-page ad-hoc button groups. - Header action menus **MUST NOT** overlap the trigger button area; menu surfaces should open below/right-aligned to the trigger and preserve title readability. ## 2.2) Interaction Surface Reuse Rules (MUST) - Repeated state-switch controls (toggle/switch UI) **MUST** be extracted into shared widgets. - Destructive confirmations (delete/remove) **MUST** use shared project-style confirmation surfaces (e.g., unified action sheet), not platform-default dialog styles. - **MUST NOT** use raw platform-default popup/dialog/dropdown visuals when they break project visual language; use token-driven shared components instead. ## 3) Layout Mapping & Alignment (MUST) - **MUST** explicitly set `crossAxisAlignment` for every `Row` / `Column` (do not rely on defaults). - **MUST** preserve layout semantics from root to leaf: - alignment/justification intent must be explicitly represented in Flutter widgets. - **MUST NOT** skip necessary container layers if doing so loses layout meaning or makes mapping non-traceable. ## 4) Centering & Visual Balance (MUST) - **MUST** evaluate centering within `SafeArea` usable bounds (not full-screen bounds). - **MUST NOT** rely on `Spacer` / proportional flex as the only centering mechanism for critical content. - If persistent header/footer regions exist, **MUST** center primary content within the remaining usable region. - **MUST** prioritize *visual centering* over purely geometric centering when they differ. ## 4.1) Keyboard Overlay Behavior (MUST) - For pages with text input, keyboard appearance **MUST** prefer overlay behavior and avoid reflowing the whole page. - Input pages **MUST** avoid global layout jump when keyboard opens/closes (including subtle shifts caused by safe-area padding changes). - Default strategy for full-screen pages with fixed hierarchy: `Scaffold.resizeToAvoidBottomInset = false`. - If a page truly requires keyboard-driven scrolling to keep focused fields reachable, this must be an explicit opt-in and justified by page structure. - When using `SafeArea` on keyboard-overlay pages, **MUST** stabilize bottom safe-area behavior (for example, maintain bottom view padding) to prevent center recalculation jitter. ## 5) Testing Strategy (MUST) Follow lightweight testing strategy - prioritize value over coverage: **Write tests for:** - Model / DTO parsing (json → model) - Service layer logic (business rules, API call handling) - High-regression UI interaction flows only (multi-state/multi-step widgets, viewport/scroll decision logic, route return stability) **Default skip for UI tests:** - Simple UI pages, regular buttons, basic layouts - Pure visual structure/snapshot-like checks without behavior risk - Low-risk styling and static rendering changes **UI test policy:** - UI tests are opt-in, not default; only keep or add them when failure risk is high and there is clear regression value. - If a UI test does not protect critical interaction behavior, remove it or avoid adding it. ## 6) UI Feedback System (MUST) - All user-facing feedback **MUST** use the Toast system. - Transient notifications: `Toast.show(...)` - Persistent inline form errors: `AppBanner` - **MUST NOT** create custom SnackBar/Dialog/Banner feedback components. - **MUST NOT** use raw `ScaffoldMessenger` for feedback messaging. ## 6.1) Loading Indicator System (MUST) - All loading spinners **MUST** use `AppLoadingIndicator` from `apps/lib/shared/widgets/app_loading_indicator.dart`. - **MUST NOT** use raw `CircularProgressIndicator` directly in feature/page code. - Use variants consistently: - page/surface loading: `AppLoadingVariant.surface` - inline small loading (list/search/section): `AppLoadingVariant.inline` - button loading: `AppLoadingVariant.button` - If visual semantics are missing, extend `AppLoadingIndicator` variant mapping first; do not create ad-hoc loading styles in feature files. ## 7) Agent Chat (AG-UI Protocol) (MUST) Agent chat functionality **MUST** follow the AG-UI protocol. **Use the `ag-ui` skill** for protocol reference and implementation guidance. - **MUST** use Server-Sent Events (SSE) for streaming. - **MUST** emit required lifecycle events: - `RUN_STARTED` is required for every run - End with exactly one of: `RUN_FINISHED` or `RUN_ERROR` - **MUST** follow standard text streaming flow: - `TEXT_MESSAGE_START` → `TEXT_MESSAGE_CONTENT` (delta) → `TEXT_MESSAGE_END` - **MUST** support the standard AG-UI event type set as defined in the spec. - **MUST NOT** return non-streaming responses for agent chat. - **MUST NOT** omit required lifecycle events. - **MUST NOT** use non-AG-UI event formats (except where the spec explicitly allows). ## 8) Visual Design Language (MUST) All UI/UX work **MUST** follow the visual design language defined in `apps/rules/visual_design_language.md`. - **MUST** ensure screens feel like a premium personal assistant product, not a wireframe, admin console, or document page. - **MUST** apply the surface-based design system (background, primary, secondary, interactive surfaces). - **MUST** follow the motion and interaction feel guidelines (soft, responsive, premium). - **MUST** achieve visual hierarchy through spacing, surface grouping, radius, depth, density, contrast, scale, and motion—not color alone. - **MUST** prioritize compact informational delivery in top bars: when the page purpose can be clearly expressed by a concise header title, avoid repeating equivalent explanatory hints in the body. - **MUST NOT** duplicate page identity text between header and first content block unless the repeated text introduces new decision-critical information. - **MUST** keep interface copy minimal and action-oriented: every text node must justify its presence by either enabling a decision, reducing error risk, or satisfying compliance requirements. - **MUST NOT** stack multiple instructional hints around the same control (for example title + subtitle + placeholder + helper text all repeating the same meaning). - **MUST** follow copy priority for auth and form pages: `Primary action > Required input labels > Error/recovery > Compliance`. Secondary explanatory copy should be removed when users can complete the task without it. - **MUST** ensure each form field has at most one primary hint source in normal state (prefer placeholder or label, not both with duplicated wording). - **MUST** follow the screen-level decision rules: 1. What is the primary focus? 2. What is the surface hierarchy? 3. What needs strongest emphasis? 4. What should be grouped? 5. What should be lightweight/secondary? 6. Where should motion reinforce understanding? 7. How can the result feel more like a premium assistant app and less like a document page? - **MUST NOT** create UIs that match the anti-patterns listed in the visual design language document: - plain document page, white slab with blue buttons, spreadsheet-like admin panel - low-fidelity wireframe, default Flutter demo app, generic template marketplace screen - full-screen flat white blocks, arbitrary shadow usage, inconsistent card treatments - raw container stacking without surface semantics Before finalizing any UI, mentally verify: - Does this feel like a product, not a page? - Is there clear hierarchy? - Do surfaces feel intentional? - Does the screen feel calm and premium? - Is the assistant identity visually present? - Would this look plausible in a polished shipping app? ## 9) Auth Global Module Rules (MUST) Auth is a global module. All auth/session behavior MUST follow a single state machine. - **MUST** treat `AuthBloc` as the single source of truth for authentication state. - **MUST NOT** implement ad-hoc auth state in feature modules (no parallel flags, no local auth caches). - **MUST** route all 401 refresh-failure handling through the global callback chain: `ApiInterceptor -> ApiClient auth failure callback -> AuthBloc(AuthSessionInvalidated)`. - **MUST NOT** clear tokens directly inside feature/page code. - **MUST NOT** navigate to login directly from feature code on token errors; rely on router redirect driven by global auth state. - **MUST** distinguish logout semantics: - manual logout: revoke server session + clear local session - auto expiry/logout on refresh failure: clear local session only - **MUST** ensure startup session recovery has exception fallback and never leaves app stuck in boot/loading state. - **MUST** add/maintain tests for: - startup recovery fallback - concurrent 401 refresh failure singleflight - session invalidation -> unauthenticated redirect path If a new auth-related requirement cannot fit this model, update this section first, then implement code. ## 10) Home Message Loading & Scroll Rules (MUST) Home 首页历史消息加载与滚动策略属于高回归模块,必须遵循以下约束: - **MUST** use event-driven viewport decisions for Home message list behavior. - Use `HomeMessageViewportController` as the decision engine. - **MUST NOT** drive auto-scroll directly from `items.length` diffs or ad-hoc boolean combinations. - **MUST** distinguish semantic events at minimum: - initial history loaded - history prepend start/finish - new message appended - sub-route resume - refresh completed - user scroll state changed - **MUST** preserve reading position when user is away from bottom. - New messages while reading history should show unread indicator instead of forcing bottom jump. - **MUST** preserve viewport anchor during history prepend. - **MUST NOT** mix prepend restore with unconditional bottom auto-scroll. - **MUST** use `returnToHomePreserveState` for business-subroute returns to Home (calendar/todo/message-related flows). - **MUST NOT** introduce new direct business-route `go('/home')` shortcuts. - Auth entry flows (login/register success) are allowed to navigate to Home directly. - **MUST** add or update tests when touching Home message loading/scroll behavior: - controller-level state transition tests - widget-level unread indicator and scroll behavior tests - route-return stability tests when navigation behavior changes