Keyboard Shortcuts

j / kScroll down / up
ggScroll to top
GScroll to bottom
/Open search
?Show this help
EscClose search / help
n / NNext / previous section
hGo to landing
dGo to docs
:Command mode — type section name

Press ? or Esc to close

Architecture

Layers

Five layers. Strict responsibilities between them. Each layer has exactly one job — nothing leaks across boundaries.

01Presentationfeatures/*/presentation/

Stateless widgets only. Reads Cubit/Bloc state via BlocBuilder, dispatches events — nothing else. No business logic, no store calls, no API calls.

Screens are StatefulWidget only to call cubit methods in initState. All visual decisions come from design tokens — never raw colors or hardcoded sizes.

StatelessWidgetBlocBuildercontext.colors.*AppSpacingAppTap
02Logic — Cubit / Blocfeatures/*/logic/

Cubit is the default — simple, lightweight, no boilerplate. Multiple Cubits per feature are allowed when concerns are clearly separate (e.g. form state vs data state).

Bloc when you need event transformations (debounce, throttle, switchMap), event history/traceability, or complex event→state chains. Not "better" — just more structured when complexity warrants it.

State always has an initial() factory and copyWith(). Always emit loading before an async operation — never jump directly to success.

Cubit (default)Bloc (complex)ApiResponse<T>initial()copyWith()
03Storefeatures/*/data/store/

Extends BaseStore (in config/network/). Orchestrates the cache strategy: checks local first, fetches remote if stale, returns ApiResponse<T>.

All try/catch happens inside BaseStore — feature stores never write their own try/catch. The Store decides what to call and when. BaseStore decides how errors are wrapped.

BaseStoreexecuteWithCacheApiResponsecache orchestration
04DataSource + Localfeatures/*/data/source/ · local/

DataSource — raw HTTP only. Returns raw Response. No base class needed. No business logic, no parsing, no try/catch. Just HTTP calls.

Local (opt-in) — sqflite CRUD only. Handles freshness via cached_at. Only added when offline is a confirmed requirement.

dio Responsesqflite (opt-in)cached_atfromMap / toMap
05Core / Configapp/ · config/

app/ is composition only — no business logic. Only global/core services registered at bootstrap: ApiClient, AppDatabase, GlobalErrorCubit, ThemeCubit, LocalizationCubit.

config/ is stateless, globally available, zero feature imports. Interceptors: AuthInterceptor (token + 401 refresh lock), LoggingInterceptor (debug only), ErrorInterceptor (maps errors → GlobalErrorCubit).

get_itgo_routerGlobalErrorCubitThemeCubitAuthInterceptor
sam's arch — A Pragmatic Flutter Architecture