| name | fl-module-scaffold |
| description | Scaffolds a new feature module under apps/main/lib/presentation/modules using the bundled module generator |
| license | MIT |
| metadata | {"audience":"flutter-developers","framework":"flutter","pattern":"clean-architecture"} |
Module Scaffold Skill
When to use
- Adding a new feature/screen to
apps/main/.
- Creating the standard module quartet:
bloc/, views/, route, coordinator.
- Spinning up a parallel data-layer model/repository/usecase for that feature.
Preferred path: bundled module generator
The template ships an interactive generator that emits files matching the project's exact conventions. Always try this first.
make run_module_generator
Source: tools/module_generator/, templates in tools/module_generator/lib/res/templates/.
| Module type | What it scaffolds | Use for |
|---|
common module | Bloc + screen + route + coordinator with no list/detail bias | Forms, single-action screens |
listing module | List bloc with items, canLoadMore, refresh+load-more events | Browse/search screens |
detail module | Detail bloc parameterised by Args(initial, id), Get<X>Event | Item detail screens |
repository | Repo + impl in apps/main/lib/data/data_source/ | Wrap a Retrofit client |
usecase | Usecase class in apps/main/lib/domain/usecases/ | Wrap a repository |
model | Freezed model template under core/ or app | DTO between API and UI |
After generating, run make gen_all so freezed/injectable code is emitted, then register the new route.
File layout (what the generator produces)
apps/main/lib/presentation/modules/<feature>/
โโโ <feature>.dart # Barrel: exports route/bloc/screen (+ coordinator if compound)
โโโ <feature>_route.dart # IRoute โ CustomRouter<Args>
โโโ <feature>_coordinator.dart # ONLY for compound modules / non-trivial entry โ see CONTEXT.md
โโโ bloc/
โ โโโ <feature>_bloc.dart # part directives for event/state/freezed
โ โโโ <feature>_event.dart # abstract class + concrete events
โ โโโ <feature>_state.dart # _StateData (freezed) + state classes + _factories
โโโ views/
โโโ <feature>_screen.dart # StatefulWidget โ StateBase<>
โโโ <feature>.action.dart # part of screen โ handlers/listeners
โโโ widgets/ # screen-local widgets (optional)
The module generator omits the coordinator file when the chosen template's source map lacks a coordinator key (see tools/module_generator/lib/generator/module_generator_ext.dart). Simple modules call pushBehavior.push(context, FeatureScreen.routeName) directly; only compound modules and modules with non-trivial entry logic (arg translation, pre-nav guards) keep a coordinator. A one-line pushBehavior.push wrapper is shallow โ don't add one.
Domain + data live alongside, not under presentation/:
apps/main/lib/domain/usecases/<feature>/<feature>_usecase.dart
apps/main/lib/data/data_source/<feature>_repository.dart (and *_impl.dart)
Before adding a screen-local widget under views/widgets/, check fl-ui-components โ it catalogs every reusable widget already in fl_ui, fl_theme, fl_media, and common_widget. For shared widgets/services, add to core/ instead of apps/main/.
Compound features
When a feature has more than one screen, do not flatten it into one oversized module or bypass the established presentation structure. Use a parent module that owns the parent barrel, coordinator, and route aggregator; each non-trivial child screen gets its own sub-module with bloc/ and views/.
<feature>/
โโโ <feature>.dart
โโโ <feature>_route.dart # aggregates child routes
โโโ <feature>_coordinator.dart
โโโ <child_a>/
โ โโโ bloc/
โ โโโ views/
โโโ <child_b>/
โโโ bloc/
โโโ views/
If the user says a flow should follow a named project architecture, apply that architecture directly and ask before choosing a lighter UI structure.
Manual scaffold (when the generator does not fit)
Stick to the names below โ _factories, Args, routeName, the part wiring โ because other parts of the codebase rely on them.
- Create the directory tree above.
- Author the bloc/event/state with the patterns from
fl-bloc-pattern.
- Author the screen + action file with
fl-extension-action.
- Add the route + coordinator with
fl-route-config.
- Register the route in the parent
IRoute (e.g. apps/main/lib/presentation/route/route.dart).
- Wire any new injectables, then
make gen_all.
Checklist
Related