specgen-flutter-riverpod — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited specgen-flutter-riverpod (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
This skill generates a comprehensive specification document (Markdown) that serves as a blueprint for building a Flutter mobile application. The spec is intended to be followed by a developer or a coding agent to produce a fully functional project scaffold targeting both Android and iOS.
The specification does NOT generate code. It produces a detailed, opinionated technical document describing every layer of the application — from pubspec.yaml configuration to Material Theme, from Riverpod providers to Dio retry interceptors — so that implementation becomes a mechanical exercise.
These are the fixed versions the spec targets. Do not deviate unless the user explicitly requests different versions.
| Component | Version |
|---|---|
| Flutter SDK | 3.24.x |
| Dart SDK | 3.5.x |
| flutter_riverpod | 2.5.x |
| riverpod_annotation | 2.3.x |
| riverpod_generator | 2.4.x |
| hooks_riverpod | 2.5.x |
| flutter_hooks | 0.20.x |
| hive | 2.2.x |
| hive_flutter | 1.1.x |
| dio | 5.7.x |
| dio_smart_retry | 6.0.x |
| pretty_dio_logger | 1.4.x |
| go_router | 14.x |
| freezed_annotation | 2.4.x |
| freezed | 2.5.x |
| json_annotation | 4.9.x |
| json_serializable | 6.8.x |
| build_runner | 2.4.x |
| firebase_core | 3.6.x |
| firebase_messaging | 15.1.x |
| flutter_local_notifications | 17.2.x |
| cached_network_image | 3.4.x |
| flutter_svg | 2.0.x |
| pull_to_refresh | 2.0.x |
| font_awesome_flutter | 10.7.x |
| material_design_icons_flutter | 7.0.x |
| intl | 0.19.x |
| url_launcher | 6.3.x |
| flutter_native_splash | 2.4.x |
| flutter_dotenv | 5.2.x |
| path_provider | 2.1.x |
| flutter_secure_storage | 9.2.x |
Include in the version table only when the corresponding integration is selected.
| Component | Version | When Selected |
|---|---|---|
| Keycloak | 26.x | Auth = Keycloak |
| flutter_appauth | 8.0.x | Auth = Keycloak or OIDC |
| openid_client | 0.4.x | Auth = Keycloak or OIDC |
| web_socket_channel | 3.0.x | WebSocket = yes |
| flutter_localizations | SDK | i18n = yes |
| share_plus | 10.0.x | Sharing = yes |
| image_picker | 1.1.x | ImagePicker = yes |
| file_picker | 8.1.x | FilePicker = yes |
| permission_handler | 11.3.x | Permissions = yes |
| firebase_analytics | 11.3.x | Analytics = yes |
| firebase_crashlytics | 4.1.x | Crashlytics = yes |
The spec must include these in the pubspec.yaml dependencies section (always):
Runtime dependencies:
flutter (sdk: flutter) — Core Flutter frameworkflutter_riverpod — Riverpod for Flutterriverpod_annotation — Annotations for riverpod_generatorhooks_riverpod — Riverpod with flutter_hooks integrationflutter_hooks — React-style hooks for Flutterhive + hive_flutter — Local NoSQL key-value databasedio — HTTP clientdio_smart_retry — Retry interceptor for Diopretty_dio_logger — Request/response logging in developmentgo_router — Declarative routingfreezed_annotation — Annotations for freezed code generationjson_annotation — Annotations for json_serializablefirebase_core — Firebase initializationfirebase_messaging — Push notification (FCM)flutter_local_notifications — Foreground/scheduled local notificationscached_network_image — Network image with caching and placeholdersflutter_svg — SVG renderingpull_to_refresh — Smart pull-to-refresh widgetfont_awesome_flutter — Font Awesome iconsmaterial_design_icons_flutter — Material Design Icons (MDI)intl — Internationalization, date/number formattingurl_launcher — Open URLs, dial, mailto, etc.flutter_dotenv — Load .env configuration filespath_provider — Filesystem paths for Hive initflutter_secure_storage — Encrypted key-value store (keychain/keystore)Development dependencies:
flutter_test (sdk: flutter) — Widget test frameworkbuild_runner — Code generation runnerfreezed — Immutable data class generatorjson_serializable — JSON serialization generatorriverpod_generator — Riverpod provider generatorhive_generator — Hive type adapter generatorflutter_lints — Recommended lint rulesflutter_native_splash — Native splash screen generatormocktail — Mock library for unit testsIf Auth = Keycloak or OIDC:
flutter_appauth — Native OAuth2/OIDC PKCE flow (uses AppAuth Android/iOS)openid_client — OIDC discovery and token parsingIf WebSocket = yes:
web_socket_channel — Cross-platform WebSocket clientIf i18n = yes:
flutter_localizations (sdk: flutter)intl is already in core — used for ARB-based message localizationIf Analytics = yes:
firebase_analyticsIf Crashlytics = yes:
firebase_crashlyticsIf ImagePicker = yes:
image_pickerpermission_handler (for camera/photo permissions)If FilePicker = yes:
file_pickerIf Sharing = yes:
share_plusGenerate the spec when the user provides an application name and version that corresponds to one of the custom applications defined in CLAUDE.md. The skill reads all required inputs from the project's context files — no interactive Q&A is needed for the core inputs.
The user invokes this skill by specifying the target application and version, for example:
/specgen-flutter-riverpod mobile v1.0.4/specgen-flutter-riverpod mobile v1.0.4 module:Hero Section/specgen-flutter-riverpod "Field Worker App" v1.0.4The skill then locates the matching context folder and reads all input files automatically.
Before starting any work, resolve the application folder first (see Input Resolution below), then check CHANGELOG.md in the application folder (<app_folder>/CHANGELOG.md):
<app_folder>/CHANGELOG.md does not exist, skip this check (first-ever execution for this application).<app_folder>/CHANGELOG.md exists, scan all ## vX.Y.Z headings and determine the highest version using semantic versioning comparison."Version {requested} is lower than the current application version {highest} recorded in <app_folder>/CHANGELOG.md. Execution rejected." Do NOT proceed with any work.This skill uses standardized input resolution. Provide:
| Argument | Required | Example | Description |
|---|---|---|---|
<application> | Yes | mobile | Application name to locate the context folder |
<version> | Yes | v1.0.4 | Version to scope processing |
module:<name> | No | module:Hero Section | Limit generation to a single module |
The application name is matched against root-level application folders:
<number>_ prefix from folder names (e.g., 1_mobile → mobile)| File | Resolved Path |
|---|---|
| PRD.md | <app_folder>/context/PRD.md |
| Module Models | <app_folder>/context/model/ |
| HTML Mockups | <app_folder>/context/mockup/ |
| Output (specification) | <app_folder>/context/specification/ |
When a version is provided, only include user stories, NFRs, and constraints from versions <= the provided version. For example, if v1.0.4 is specified:
[v1.0.0], [v1.0.1], [v1.0.2], [v1.0.3], [v1.0.4][v1.0.5] or laterWhen module:<name> is provided:
SPEC.md for that specific moduleSPECIFICATION.md (root) gets a partial update — only that module's entry in the TOCis added or updated; all other TOC entries are preserved as-is
The specification is driven by six input sources read from the project's context files. The skill does NOT ask the user for auth, API backend URL, or optional component choices — it determines these automatically from the context.
From CLAUDE.md (already loaded in context), locate the target application under the Custom Applications section. Extract:
base URL, authentication provider, and optional components
The application name is used to derive:
e.g., mobile_app, field_worker)
com.example.mobile_app) — Android applicationId and iOS CFBundleIdentifier
Read <app_folder>/context/PRD.md. This file contains all user stories organized by module. Extract:
# System Module heading (e.g., Authentication,Profile). These become system-level features.
# Business Module heading (e.g., Order,Catalogue). These become business-level features.
### User Story section contains tagged items.These define the functional requirements for each feature's repositories, providers, forms, and screens.
The user stories directly inform:
Important: Items with strikethrough (~~text~~) are deprecated — do NOT include them as active requirements. List them in the "Removed / Replaced" subsection of the traceability table.
### User Story, ### Non Functional Requirement,and ### Constraint section contains one or more version blocks formatted as [v1.0.x]. The skill must track the version tag for each item and carry it through to the generated specification's traceability section.
Within the same PRD.md, each module has a ### Non Functional Requirement section. These inform:
NFRs should be mapped to specific technical decisions in the spec — for example, an NFR stating "paginated with 20 items per page" confirms which Riverpod pagination pattern to use, while "must work offline" confirms which Hive box manages the offline cache.
Within the same PRD.md, each module has a ### Constraint section. These define hard boundaries that the spec must enforce:
Constraints are embedded directly into the relevant module blueprint — they inform freezed model definitions, repository method parameters, and route guard configurations.
Read <app_folder>/context/model/MODEL.md first as the index, then read the individual module model files in each module subfolder.
MODEL.md provides:
Per-module files (e.g., model/hero-section/model.md):
Per-module schema (e.g., model/hero-section/schemas.json):
The module model directly maps to:
@HiveType/@HiveField) for cached entitiesjson_serializableRead <app_folder>/context/mockup/MOCKUP.html first as the index page, then read the HTML files organized by role in subfolders.
MOCKUP.html provides:
Role-specific subfolders (e.g., mockup/worker/task/):
IMPORTANT — Role folders inform access control, NOT route paths. The role-specific folder structure (e.g., mockup/worker/task/task-list.html) determines:
redirect guard with role checkIt does NOT determine the route path. The route path is always module-based:
GoRoute(path: '/task', ...) — NOT GoRoute(path: '/worker/task', ...)The mockup screens directly map to:
Before determining optional components, check PRD.md for the following extended sections:
If PRD.md contains an # Architecture Principle section, extract patterns that affect mobile decisions:
| Pattern to Extract | How It Influences the Specification |
|---|---|
| "Stateless REST API" | Confirms Dio + Riverpod async provider pattern for API calls |
| "Event-driven" / "WebSocket" / "real-time" | Include web_socket_channel and a stream provider for live data |
| "API gateway" | Configure base URL to point to gateway rather than individual services |
| Backend framework mention | Validate API response format assumptions |
| "Offline-first" / "local cache" | Include Hive cache layer for read paths |
If the section is absent, proceed with existing CLAUDE.md-only detection.
If PRD.md contains a # Design System section with a file reference:
ThemeData configuration: color scheme, text theme,component themes (ElevatedButtonTheme, AppBarTheme, CardTheme, InputDecorationTheme)
ThemeData configuration in SPECIFICATION.md derived from thedesign system tokens
If the section is absent, use a default Material 3 theme (existing behavior).
If PRD.md contains a # High Level Process Flow section:
filter chips/dropdowns
If the section is absent, derive UI flow from user stories only (existing behavior).
Instead of asking the user, the skill determines optional components by analyzing the dependencies listed in CLAUDE.md, the # Architecture Principle section in PRD.md (if present), and cross-referencing with PRD.md NFRs and constraints.
Examine the "Depends on" list in CLAUDE.md for the target application:
| Dependency Pattern | API Configuration |
|---|---|
| References another application's REST API | API_BASE_URL set to that app's base URL |
| References a Spring Boot backend | Include Spring Boot CORS headers note |
| No explicit backend | Include mock API / json-server note for development |
| Dependency / PRD Pattern | Auth Selection |
|---|---|
| References "Single Sign On" or "Keycloak" in CLAUDE.md dependencies | Auth = Keycloak |
| PRD.md has login user stories with email/password | Auth = Local (local JWT from API) |
| PRD.md constraint says "public access, no auth required" | Auth = none |
| PRD.md has only public-facing content | Auth = none |
If Auth = Keycloak, also extract from CLAUDE.md:
<project-slug>-mobilehttp://localhost:8180/realms/<realm>worker → WORKER, admin → ADMIN)If Auth = Local (API-managed JWT):
flutter_secure_storage (Keychain / Android Keystore)flutter_secure_storageAuthorization: Bearer <token> header| PRD.md Pattern | Component Selection |
|---|---|
| NFRs mention "real-time", "live updates", "push notification" | FirebaseMessaging always-on (core); WebSocket = yes if user-driven streams |
| User stories mention "schedule reminder", "local alarm", "background reminder" | Local notifications always-on (core); add scheduled notification helper |
| NFRs mention "share to social", "share link" | Sharing = yes |
| User stories mention "upload photo", "take photo" | ImagePicker = yes |
| User stories mention "attach file", "upload document" | FilePicker = yes |
| PRD.md mentions multiple languages or localization | i18n = yes |
| NFRs mention "track screen views", "user analytics", "conversion funnel" | Analytics = yes |
| NFRs mention "crash reporting", "production error monitoring" | Crashlytics = yes |
| NFRs mention "camera", "gallery", "storage", "location" | Permissions = yes |
After analyzing all inputs, produce a determination summary before generating the spec. Present it to the user for confirmation:
Optional Component Determination:
- Backend API: http://localhost:<port>/api (from CLAUDE.md Port Allocation table → depends on backend app)
- Authentication: Keycloak PKCE via flutter_appauth (from CLAUDE.md → depends on Single Sign On)
- WebSocket: no
- i18n: yes (from PRD.md → English + Bahasa Malaysia required)
- Analytics: yes (from PRD.md NFR → screen view tracking)
- Crashlytics: yes (from PRD.md NFR → production error monitoring)
- ImagePicker: yes (from PRD.md → upload photo of completed task)
- FilePicker: no
- Sharing: no
- Permissions: yes (camera, photo library)If the user disagrees with any determination, allow them to override before proceeding.
After determination, these values are needed. Most are derived automatically:
Auto-derived from context files:
AppBar title and launcher labelAuto-derived from CLAUDE.md (Port Allocation table):
Port Allocation table in the Custom Applications section of CLAUDE.md. Construct the base URL as http://10.0.2.2:<port>/api/v1 for Android emulator development (which proxies localhost) and http://localhost:<port>/api/v1 for iOS simulator. Do NOT hardcode 8080 — the port MUST match the allocated port for the backend application this mobile app depends on.Optional (use sensible defaults if not found in context):
en20 (mobile-appropriate, from NFRs or fallback)23 (Android 6.0)13.0Once inputs are gathered from context files and optional components are determined, generate the specification as a multi-file output split by module. Read the spec template at references/spec-template.md for the exact structure and content of each section. The template is the authoritative guide — follow it closely.
The specification is split into two categories:
routing, auth configuration, Hive/Dio/Firebase init, and application-level sections that apply across all modules.
self-contained specification covering that module's complete blueprint.
This split enables a coding agent to:
SPECIFICATION.md<module>/SPEC.mdImportant: The generated spec must use real module data from the context files, not generic placeholders. Specifically:
(e.g., task, order, catalogue — not module1, module2)
not placeholder fieldOne/fieldTwo
says "view list of tasks", the repository needs fetchTasks())
worker/task/task-list.html exists, there must be a matching route and screen widget). The route path is module-based (e.g., /task), NOT role-prefixed (e.g., NOT /worker/task).
traceability section must include its version tag (e.g., USA000030 [v1.0.4]). ALL traceability sub-tables (User Stories, NFRs, AND Constraints) MUST include the `| Version |` column.
subsection listing deprecated items — showing the removed ID, the version that removed it, the replacement ID (if any), and a brief reason.
<app_folder>/context/specification/
├── SPECIFICATION.md ↠TOC + shared/application-level specs
├── task/
│ └── SPEC.md ↠Module blueprint for Task
├── order/
│ └── SPEC.md ↠Module blueprint for Order
├── catalogue/
│ └── SPEC.md ↠Module blueprint for Catalogue
├── ... ↠One folder per module from PRD.mdSPECIFICATION.md (Root)The root file contains the TOC and all shared/application-level sections. These are sections a coding agent implements first before any module work:
#### 1. Project Overview Project metadata, application description, technology stack summary, user roles, module index table linking to each module's SPEC.md, target platforms (Android/iOS) and minimum OS versions.
#### 2. Package Configuration Complete pubspec.yaml with all dependencies (core + selected conditional), build_runner scripts, and asset/font declarations.
#### 3. Application Configuration analysis_options.yaml (lints), .gitignore, Flutter flavors if multi-environment needed, native splash and launcher icon configuration, Android build.gradle & iOS Info.plist notes (permissions, deep links, FCM background handler).
#### 3a. Application Version Configuration The application MUST include a version value derived from the version argument provided during skill invocation. If multiple versions were provided, use the highest one.
In pubspec.yaml:
version: 1.0.3+1The first part (1.0.3) is the human-readable version; the suffix (+1) is the build number. The build number MUST be incremented manually or via CI on each release.
The application MUST expose this version in a Settings/About screen or persistent drawer footer. Use package_info_plus (add as dependency if surfacing programmatically):
final info = await PackageInfo.fromPlatform();
final versionLabel = 'v${info.version}+${info.buildNumber}';#### 3b. .env File Generation from ENVIRONMENT.md Generate .env.development and .env.production files at the project root for use with flutter_dotenv. The .env.development file is populated by reading ENVIRONMENT.md from the project root, mapping credential and platform values to plain environment variable names (no VITE_ prefix — Flutter does not use Vite). The .env.production file uses placeholder values for production.
Process:
ENVIRONMENT.md from the project rootENVIRONMENT.md (# Supporting 3rd Party Applicationsfor Keycloak host/realm/client, plus # External Services such as Firebase config); the backend API host/port comes from the # Port Allocation table in CLAUDE.md. Read any toolchain paths from DEVTOOL.md
.env.development with actual local values.env.production with production placeholder valuesassets: in pubspec.yamlExample `.env.development` output (derived from ENVIRONMENT.md):
# Backend API
API_BASE_URL=http://10.0.2.2:<port from CLAUDE.md Port Allocation table>/api/v1
API_TIMEOUT_MS=30000
API_RETRY_ATTEMPTS=3
# Authentication (Keycloak)
KEYCLOAK_ISSUER=http://10.0.2.2:8180/realms/urp
KEYCLOAK_CLIENT_ID=urp-mobile
KEYCLOAK_REDIRECT_URI=com.example.mobile_app:/oauth2redirectRules:
dotenv.env['API_BASE_URL']TODOdevelopment (Android emulator uses 10.0.2.2 for host's localhost)
.env.development and .env.production are gitignored, but the **files MUSTstill be declared under assets:** in pubspec.yaml so flutter_dotenv can load them at runtime
google-services.json, GoogleService-Info.plist) is checked inper-flavor but the Firebase project ID/sender ID are read from .env if dynamic
#### 4. Directory Structure The complete source tree under lib/. The structure follows feature-based architecture where each PRD module maps to a lib/features/<module>/ folder. Read references/routing-patterns.md for the module folder layout.
#### 5. Theme Configuration Custom Material 3 ThemeData built from design tokens extracted from mockup screens. Includes color scheme (seeded from primary), text theme (Google Fonts or custom font family), component themes (ElevatedButtonTheme, AppBarTheme, CardTheme, InputDecorationTheme, FloatingActionButtonTheme), and shape/radius tokens. Read references/component-patterns.md for theme setup patterns.
#### 6. Authentication Configuration (conditional — include only if Auth != none) If Auth = Keycloak: PKCE Authorization Code flow using flutter_appauth. The native AppAuth library (Android + iOS) handles the system browser redirect. AuthRepository exposes signIn(), signOut(), getAccessToken(). Tokens stored in flutter_secure_storage. Dio interceptor reads access token. Refresh token used to renew silently. Deep link callback configured for both platforms. Read references/security-patterns.md for the full auth architecture.
If Auth = Local (API JWT): Login screen submits to backend API, JWT stored in flutter_secure_storage, Dio interceptor attaches Authorization header, token refresh interceptor handles 401 responses, route guard via go_router redirect callback redirects unauthenticated users.
#### 7. Router Configuration go_router v14 route tree — top-level routes, nested shell routes for bottom navigation, route guards via redirect, deep link configuration for FCM/Keycloak callbacks, typed route helpers (optional, via go_router_builder). Read references/routing-patterns.md for route patterns.
#### 8. API Client Configuration Dio instance with baseUrl from dotenv.env['API_BASE_URL'], request/response interceptors:
DioSmartRetry — exponential backoff on 5xx, network errors, retry idempotent methods)PrettyDioLogger, dev only — guard with kDebugMode)DioException → typed ApiFailure sealed class)connectTimeout, receiveTimeout, sendTimeout from .env.
#### 9. Local Storage (Hive) Hive.initFlutter() in main(), type adapters registered for each cached entity, typed Box<T> providers via Riverpod, helper extension methods for upsert/find/clear, encryption optional (HiveAesCipher with key from flutter_secure_storage). Read references/storage-patterns.md for Hive patterns.
#### 10. Riverpod Setup ProviderScope wrapping MyApp, code generation via riverpod_generator, AsyncNotifier/Notifier providers for state, family providers for parameterized queries, naming convention: <entity>RepositoryProvider, <entity>ListProvider, <entity>ByIdProvider(id). Read references/state-patterns.md for Riverpod patterns.
#### 11. Shared Layouts AppShellScreen (bottom navigation + Scaffold body via ShellRoute), AuthShell (login/forgot-password scaffolding), PublicShell for unauthenticated content (if any). Each shell uses Material 3 widgets.
#### 12. Shared Widgets Reusable widgets used across multiple modules: AppScaffold (AppBar + body slot), LoadingIndicator, EmptyState, ErrorState, ConfirmDialog, StatusChip, SearchBarField, FormTextField, FormDatePickerField, FormDropdownField, ImagePickerField (if ImagePicker = yes), PullToRefreshList, InfiniteScrollList, CachedSvgIcon, AppNetworkImage (wraps CachedNetworkImage with placeholder/error).
#### 13. Navigation Configuration Bottom navigation items (or drawer items) derived from mockup nav files, organized by role. Each item has label, icon (Material/MDI/FA), path, and required role. Navigation is rendered dynamically based on the authenticated user's roles.
#### 14. Form Infrastructure Reusable form-field widgets wrapping TextFormField / DropdownButtonFormField / DatePicker with consistent decoration, validators (Validator static methods: required, email, min/maxLength, url, compose), submit button with loading state (CircularProgressIndicator inside ElevatedButton).
#### 15. Error Handling Strategy Top-level FlutterError.onError and PlatformDispatcher.instance.onError for uncaught errors (route to Crashlytics if enabled), Dio error interceptor mapping DioException → ApiFailure sealed class, Riverpod AsyncValue.when(...) for screen-level error/loading states, ErrorState widget for full-screen errors with retry button, ScaffoldMessenger (SnackBar) for transient errors.
#### 16. Notification System Push notifications (FCM):
firebase_messaging foreground/background/terminated handlersLocal notifications:
flutter_local_notifications initialized with platform settings (Android channels,iOS categories)
foreground by default on iOS/Android)
In-app toasts:
ScaffoldMessenger.of(context).showSnackBar(...) for non-critical user feedback.Read references/notification-patterns.md for the full notification architecture.
#### 17. Theming & Dark Mode MaterialApp.themeMode toggled via UI control, persisted in Hive settings box. lightTheme and darkTheme constructed via ThemeData(colorScheme: ColorScheme.fromSeed(...)) with brightness override. ThemeToggle widget switches mode and writes to Hive.
#### 18. Testing Strategy Overview: flutter_test + mocktail for widget/unit tests, ProviderContainer for testing Riverpod providers in isolation, golden tests for critical screens, integration tests via integration_test package. Per-feature test conventions matching the module spec.
#### 19. Build & Distribution
flutter build apk --release / flutter build appbundle --release (Android)flutter build ipa --release (iOS)~/.gradle/gradle.properties; iOS:Apple Developer team + provisioning profile)
flutter_native_splash (dart run flutter_native_splash:create)flutter_launcher_icons (optional)#### 20. Internationalisation (conditional — include only if i18n = yes) flutter_localizations enabled, intl for ARB messages, flutter_gen_l10n configured in pubspec.yaml, lib/l10n/app_en.arb + per-locale ARBs, generated AppLocalizations class, MaterialApp.localizationsDelegates and supportedLocales wired, locale-switch provider persisted in Hive.
#### 21. WebSocket Integration (conditional — include only if WebSocket = yes) web_socket_channel setup, connection management Riverpod provider with auto-reconnect + exponential backoff, typed event handler with sealed-class events, lifecycle hook in AppShellScreen to open/close socket on app foreground/background.
#### 22. Firebase Initialization Always required (push notifications depend on it). Cover:
Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform) in main()before runApp(...)
google-services.json (Android) + GoogleService-Info.plist (iOS) placementflutterfire configure CLI workflow (used once during scaffolding)@pragma('vm:entry-point') function<module>/SPEC.md (Per-Module)For EACH module from PRD.md and MODEL.md, create a folder named after the module (kebab-case, e.g., task/) and generate a SPEC.md inside it.
Each module SPEC.md is a self-contained blueprint that a coding agent can pick up and implement independently (after the shared infrastructure is in place). It must include:
SPECIFICATION.mdmockup screen filenames, all with version tags
@freezed data classes matching the module model fields(field-for-field), including fromJson/toJson via json_serializable
@HiveType adapter with fieldnumbers matching the freezed model
Form validator closures derivedfrom PRD constraints
AsyncNotifierProvider for list, family provider for detail,mutation methods on a Notifier for CUD operations, cache invalidation pattern via ref.invalidate()
Form + GlobalKey<FormState> + reusablefield widgets
redirect guardsmatching the mockup role folder access control
See references/spec-template.md for the exact per-module template structure.
After all specification files are successfully generated, append an entry to CHANGELOG.md in the application folder (<app_folder>/CHANGELOG.md):
<app_folder>/CHANGELOG.md. If it does not exist, create it with: # Changelog
- This file tracks all skill executions by version for this application.
- The highest version recorded here is the current application version.
- Skills MUST NOT execute for a version lower than the highest version in this file.
---## {version} heading matching the current version.--- below the context header and before any existing ## vX.Y.Z section (newest-first ordering), with a new table header and the first row.| {YYYY-MM-DD} | {application_name} | specgen-flutter-riverpod | {module or "All"} | Generated Flutter Riverpod mobile technical specification |The generated specification is a folder of files, not a single document:
<app_folder>/context/specification/
├── SPECIFICATION.md ↠Root: TOC + shared/application-level specs
├── <module-1>/
│ └── SPEC.md ↠Module blueprint (self-contained)
├── <module-2>/
│ └── SPEC.md
├── <module-N>/
│ └── SPEC.mdThese constraints apply to every code sample in the generated spec:
Null-safe Dart everywhere. Target Dart 3.5+ with sound null safety. No dynamic unless the API genuinely returns unstructured JSON — prefer Object? with explicit type checks, or strongly typed Map<String, dynamic> only at the JSON boundary.
Feature-based architecture. Every module maps to lib/features/<module>/. Nothing module-specific leaks into lib/shared/ or lib/core/. Shared widgets must be genuinely reusable across at least two modules.
No tokens in plaintext storage. JWT access and refresh tokens are stored in flutter_secure_storage (Keychain / Android Keystore), never in SharedPreferences, Hive, or in-memory globals that persist beyond the process. Hive is encrypted (HiveAesCipher) when storing user-sensitive cached data — encryption key lives in flutter_secure_storage.
Riverpod for all state. Do not use setState for state that crosses widgets, and do not use InheritedWidget directly — use Riverpod providers. setState is only acceptable for purely local widget UI state (animation controllers, hover, focus).
Freezed for all data models. No hand-rolled equality / hashCode / copyWith. Every data class is @freezed with fromJson/toJson if it crosses the API boundary.
Generated code via build_runner. Always include the standard commands in the spec:
dart run build_runner build --delete-conflicting-outputs — one-shot generationdart run build_runner watch --delete-conflicting-outputs — watch mode for developmentMaterial 3 only. ThemeData(useMaterial3: true). Do not mix in Cupertino-only widgets in cross-platform screens — use Adaptive* constructors or platform-aware wrappers if truly necessary.
go_router for navigation. Do not use raw Navigator.push/Navigator.pop. All navigation is context.go(...), context.push(...), or context.pop() via go_router. Deep link configuration is centralized in lib/router/app_router.dart.
Consistent file naming (Dart conventions):
PascalCase class names in snake_case.dart files (e.g.,task_list_screen.dart defines class TaskListScreen)
riverpod_generator from <feature>_providers.dart<feature>_repository.dart (e.g., task_repository.dart)<entity>.dart for @freezed data class, generated *.freezed.dart &*.g.dart are committed
<file>_test.dart co-located in test/<feature>/ mirroring lib/features/~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.