sg_cli 1.0.8
sg_cli: ^1.0.8 copied to clipboard
CLI tool that scaffolds Max Architecture โ SolGuruz's mature Flutter project structure with BLoC, type-safe navigation, state handlers, and 48+ widgets.
SG CLI
Flutter Architecture Generator by SolGuruz
Scaffold production-ready Flutter apps in seconds โ BLoC, type-safe navigation, state handlers, and 48+ widgets, all wired up from a single command.
๐๏ธ What is Max Architecture? #
Max Architecture is simply the name we gave to our most mature internal Flutter architecture after years of building production apps. It combines the patterns, tooling, and project structure that consistently worked well for us and covers the common requirements we need in almost every project, while keeping developers comfortable and productive.
Fun fact: we initially maintained multiple internal architecture variants with color-based names like Amber, Bronze, and Cyan, each evolving with different ideas and features. Over time, they all converged into a single approach that worked best across projects, so we called it Max โ not because it's "finished", but because it represented the most complete version of everything we'd learned.
โจ What You Get #
One sg init sets up the entire Max Architecture โ the same foundation used in SolGuruz production apps:
| Feature | Details | |
|---|---|---|
| ๐งฑ | BLoC State Management | Typed base classes, events, 5 ready-to-use state handlers |
| ๐งญ | Type-Safe Navigation | Go class, route configs, typed arguments โ zero magic strings |
| โก | ViewState Widgets | Auto-handles loading / error / empty / data โ no boilerplate |
| ๐จ | Design System | AppColors (light + dark), AppTextStyles, 48+ production widgets |
| โ๏ธ | Code Generators | Screens, bottom sheets, dialogs, events โ routes wired automatically |
| ๐ | Flavor & Deep Link Setup | Dev / stage / prod in one command |
๐ฆ Installation #
dart pub global activate sg_cli
Add the pub cache bin to your PATH (one-time setup):
export PATH="$PATH":"$HOME/.pub-cache/bin"
Verify:
sg help
โก Quick Start #
# 1. Go to your Flutter project root
cd my_flutter_app
# 2. Scaffold the entire Max architecture
sg init
# 3. Generate screens, bottom sheets, dialogs
sg create screen login
sg create screen home
sg create bs select_language
sg create dialog confirm_action
# 4. Add BLoC events
sg create event submit_login in login
Routes, BLoC files, state classes, and widget folders โ all generated and wired automatically.
๐ Commands #
Project Setup #
| Command | What it does |
|---|---|
sg init |
Scaffold the complete Max architecture into your Flutter project |
sg setup_flavors |
Add dev / stage / prod flavors for Android & iOS |
sg setup_deeplink |
Configure per-flavor deep links (Android manifests + iOS entitlements) |
sg setup_firebase |
Automated Firebase setup via FlutterFire CLI |
sg setup_firebase_manual |
Generate Firebase placeholder configs |
Code Generation #
| Command | What it does |
|---|---|
sg create screen <name> |
Screen + BLoC (event, state) + route auto-registered |
sg create sub_screen <name> in <parent> |
Sub-screen nested under a parent route |
sg create bs <name> |
Bottom sheet + BLoC + route auto-registered |
sg create dialog <name> |
Dialog + BLoC + route auto-registered |
sg create event <name> in <page> |
Add a BLoC event + handler to an existing screen / bs / dialog |
All names must be
snake_case. All generated code follows Max Architecture conventions.
๐ What Gets Generated #
sg create screen profile #
lib/presentation/screens/profile/
โโโ logic/
โ โโโ profile_bloc.dart โ BaseBloc with eventListeners()
โ โโโ profile_event.dart โ Abstract event extends BaseEvent
โ โโโ profile_state.dart โ Immutable state with copyWith
โโโ view/
โโโ profile_screen.dart โ StatefulWidget, BLoC via context extension
โโโ widgets/ โ Screen-specific widget files
Auto-updated:
app/app_routes/screen_routes.dartapp/app_routes/_route_names.dart
sg create event load_profile in profile #
class LoadProfile extends ProfileEvent {
const LoadProfile();
@override
Map<String, dynamic> getAnalyticParameters() => {};
@override
List<Object?> get props => [];
}
Handler stub registered in profile_bloc.dart automatically.
๐ Architecture Highlights #
๐งญ Type-Safe Navigation #
// Navigate with typed arguments
Go.to(ProfileRoute(
arguments: ProfileArguments(userId: '42', userName: 'John'),
));
// Open a bottom sheet and await its result
final result = await Go.openBottomSheet<bool, SelectLanguageArguments>(
const SelectLanguageRoute(),
showDragHandle: true,
);
// Clear stack and go to login
Go.replaceAllTo(const LoginRoute());
โก State Handlers + ViewState Widgets #
Five handlers cover every data-loading pattern. Pair with the matching widget โ loading, error, empty, and data are handled automatically:
// BLoC โ one handler replaces all manual emit() calls
late final scriptsHandler = PaginatedListHandler<ScriptModel>(
bloc: this,
getViewState: () => state.scripts,
updateViewState: (s) => emit(state.copyWith(scripts: s)),
loadMoreEvent: () => const ScriptsLoadMore(),
repositoryCall: () => ScriptRepository.getScripts(
page: state.scripts.paginationData?.nextPage,
search: state.scripts.searchController?.text,
),
);
// Screen โ auto loading / empty / error / paginate
SliverListStateWidget<ScriptsBloc, ScriptsState, ScriptModel>(
listStateSelector: (s) => s.scripts,
onLoadMore: (_) => bloc.add(const ScriptsLoadMore()),
padding: const EdgeInsets.symmetric(horizontal: kHorizontalPadding),
itemBuilder: (context, script, index) => ScriptCard(script: script),
)
๐งฑ BLoC Pattern #
class LoginBloc extends BaseBloc<LoginEvent, LoginState> {
LoginBloc() : super(LoginState.initial());
final emailCtrl = TextFieldController();
final submitCtrl = AppButtonController();
@override
void eventListeners() {
on<SubmitLogin>(_onSubmitLogin);
}
Future<void> _onSubmitLogin(SubmitLogin event, Emitter<LoginState> emit) async {
submitCtrl.startLoading();
final response = await AuthRepository.loginWithEmail(email: emailCtrl.text);
submitCtrl.stopLoading();
if (response.isSuccess) Go.replaceAllTo(const HomeRoute());
}
@override
Future<void> close() {
emailCtrl.dispose();
submitCtrl.dispose();
return super.close();
}
}
๐ท Architecture Versions #
| Version | Best For | Includes |
|---|---|---|
| Max โญ | Full production apps | All commands โ init, create, setup_* |
| Bronze | Apps with custom routing | create screen / bs / dialog / event |
| Amber | Role-based basic structure | create page / bs / event |
Version is configured in sg_cli.yaml at your project root after sg init.
๐ Requirements #
| Minimum | |
|---|---|
| Dart SDK | ^3.11.0 |
| Flutter SDK | ^3.41.1 |
| Firebase CLI | Only needed for setup_firebase |
| FlutterFire CLI | Only needed for setup_firebase |
๐ Documentation #
Full architecture docs, tutorials, and API reference at sgcli.solguruz.com
| Topic | What's covered |
|---|---|
| Architecture Overview | Folder structure, 3-layer design, data flow |
| State Handlers | All 5 handlers โ BasicData, PaginatedList, FullList, and more |
| Navigation | Type-safe routing, route arguments, nested navigation |
| Widget Library | 48+ widgets โ AppButton, OTP, TextFields, ImagePicker, tabs |
| Theming | AppColors (light/dark), AppTextStyles, design system |
| Forms & Validation | Controllers, validators, input formatters |
| Networking | ApiClient, repositories, response pipeline |
| Reactor | Cross-BLoC reactive sync without boilerplate |
| Local Storage | PrefManager, type-safe persistence |
| Environments | Dev / stage / prod config, flavors, deep links |
๐ง Troubleshooting #
sg command not found
export PATH="$PATH":"$HOME/.pub-cache/bin"
# Persist: add the above line to ~/.zshrc or ~/.bashrc
Template errors after sg init
The boilerplate is bundled inside the package. Re-activating fixes most path issues:
dart pub global activate sg_cli
setup_firebase fails
npm install -g firebase-tools
dart pub global activate flutterfire_cli
firebase login
๐ข About SolGuruz #
Engineering quality mobile and web solutions โ with passion.
๐ License #
MIT ยฉ 2025 SolGuruz Private Limited โ see LICENSE for full text.
Made with โค๏ธ by SolGuruz ยท sgcli.solguruz.com