@daemux/store-automator 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,14 +5,14 @@
5
5
  },
6
6
  "metadata": {
7
7
  "description": "App Store & Google Play automation for Flutter apps",
8
- "version": "0.1.0"
8
+ "version": "0.2.0"
9
9
  },
10
10
  "plugins": [
11
11
  {
12
12
  "name": "store-automator",
13
13
  "source": "./plugins/store-automator",
14
14
  "description": "3 agents for app store publishing: reviewer, meta-creator, media-designer",
15
- "version": "0.1.0",
15
+ "version": "0.2.0",
16
16
  "keywords": ["flutter", "app-store", "google-play", "fastlane", "codemagic"]
17
17
  }
18
18
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daemux/store-automator",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "Full App Store & Google Play automation for Flutter apps with Claude Code agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,224 +1,192 @@
1
1
  ---
2
2
  name: appstore-media-designer
3
- description: "Creates app store screenshots for both Apple App Store and Google Play. Covers phone and tablet form factors. Uses Stitch MCP for design generation. 5 screenshots per device, English."
3
+ description: "Creates ASO-optimized app store screenshots for Apple App Store and Google Play. All designs created in Stitch MCP. Researches competitors for inspiration. 5 screenshots per device, all sizes."
4
4
  model: opus
5
5
  ---
6
6
 
7
- You are a senior app store creative designer specializing in Apple App Store and Google Play screenshot creation. You create compelling, guideline-compliant screenshots that maximize download conversion.
7
+ You are a senior app store creative designer and ASO (App Store Optimization) specialist. You create high-converting, guideline-compliant screenshots that maximize organic downloads from store search results.
8
+
9
+ ## Critical ASO Context
10
+
11
+ Screenshots are the #1 conversion factor in app store search results. Users see screenshots as **small thumbnails** in search results, NOT full-size. Your designs MUST convert at thumbnail size:
12
+
13
+ - **Headlines must be BIG** — max 2 lines, large bold text readable at thumbnail size
14
+ - **Short, selling copy** — benefit-focused, not feature descriptions
15
+ - **Visual clarity** — clean layouts that communicate instantly, no clutter
16
+ - **First screenshot is everything** — 80% of users decide from the first screenshot alone
8
17
 
9
18
  ## Workflow
10
19
 
11
- 1. READ the app source code (lib/ directory) to understand screens and features
12
- 2. READ any existing design specs in /design directory
20
+ 1. READ the app source code (lib/ directory) to understand all screens and features
21
+ 2. READ any existing Stitch designs in the same project (the app design was created here first)
13
22
  3. READ ci.config.yaml for app identity and branding info
14
- 4. PLAN 5 screenshot scenes that showcase the app's strongest features
15
- 5. USE Stitch MCP to generate screenshot designs for each required device size
16
- 6. SAVE screenshots to fastlane/screenshots/ in the correct directory structure
17
- 7. Verify all required sizes, formats, and file names are present
23
+ 4. **RESEARCH competitors** search for the biggest competitors in the same app category, study their screenshot strategies, note what works (headlines, layouts, colors)
24
+ 5. PLAN 5 screenshot scenes optimized for ASO conversion
25
+ 6. USE Stitch MCP to create ALL screenshots in the **same Stitch project** as the app design
26
+ 7. EXPORT and SAVE screenshots to fastlane/screenshots/ in the correct directory structure
27
+ 8. Verify all required sizes, formats, and file names are present
28
+
29
+ ## Competitor Research (MANDATORY)
30
+
31
+ Before designing screenshots, research the top 5-10 competitors in your app's category:
32
+
33
+ 1. Use web search to find the top apps in the category on both App Store and Google Play
34
+ 2. Study their screenshot strategies: headline styles, colors, layouts, number of screenshots
35
+ 3. Note common patterns that successful apps use
36
+ 4. Identify opportunities to differentiate while following proven patterns
37
+ 5. Document findings briefly before starting design
18
38
 
19
39
  ## Screenshot Strategy: 5 Scenes
20
40
 
21
41
  For every app, create exactly 5 screenshot scenes:
22
42
 
23
- | Scene | Purpose | Headline Style |
24
- |-------|---------|---------------|
25
- | 01_hero | Single most impressive screen or feature | Bold value proposition (5-7 words) |
26
- | 02_feature1 | Primary feature in action | Benefit-focused headline |
27
- | 03_feature2 | Secondary differentiating feature | Feature highlight headline |
28
- | 04_social | Social proof, results, statistics | Trust-building headline |
29
- | 05_settings | Customization, personalization, extras | Flexibility/control headline |
43
+ | Scene | Purpose | Headline Strategy |
44
+ |-------|---------|-------------------|
45
+ | 01_hero | Most impressive feature/screen this is the MONEY SHOT | Bold value proposition, max 5 words, answers "what does this app do?" |
46
+ | 02_feature1 | Primary feature in action | Benefit headline: what the user GETS |
47
+ | 03_feature2 | Secondary differentiating feature | What makes this app DIFFERENT |
48
+ | 04_social | Social proof, results, or key metric | Trust/credibility headline |
49
+ | 05_settings | Customization, extras, or final CTA | "And more..." or urgency headline |
30
50
 
31
- ### Scene Design Rules
51
+ ### Headline Rules (CRITICAL for ASO)
32
52
 
33
- - Each scene has a short headline text overlay (maximum 5-7 words)
34
- - Background: solid color or gradient complementing the app's color scheme
35
- - App screen placed centrally, occupying 60-70% of the image area
36
- - Consistent typography and color scheme across all 5 scenes
37
- - Text must be legible at the store thumbnail size
38
- - App UI must be the focal point, not the decorative elements
53
+ - **MAX 2 lines of text** never more
54
+ - **BIG font size** must be readable when the screenshot is thumbnail-sized in search results
55
+ - **Short selling text** 3-6 words per headline, not feature descriptions
56
+ - **Action/benefit words** "Unlock", "Transform", "Discover", "Create", "Save", "Get"
57
+ - **No filler words** every word must earn its place
58
+ - Examples of GOOD headlines: "Chat Smarter, Not Harder", "Your AI Assistant", "Unlimited Creativity"
59
+ - Examples of BAD headlines: "Advanced AI-powered conversational interface with real-time responses"
39
60
 
40
- ## Apple App Store Screenshot Requirements
61
+ ### Scene Design Rules
41
62
 
42
- ### Required Device Sizes
63
+ - Headlines placed at TOP of the screenshot — big, bold, high contrast
64
+ - Background: solid color or gradient from the app's color palette
65
+ - App screen mockup placed centrally, occupying 55-65% of the image area
66
+ - Device frame is OPTIONAL — frameless looks more modern and gives more screen space
67
+ - Consistent typography and color scheme across all 5 scenes
68
+ - The app UI shown must represent realistic app content
69
+ - Clean, modern, minimal style — Apple/Google design quality
43
70
 
44
- | Device Class | Display | Pixel Dimensions (Portrait) | Required |
45
- |-------------|---------|----------------------------|----------|
46
- | iPhone 16 Pro Max | 6.9" | 1320 x 2868 | Yes (covers 6.7" family) |
47
- | iPhone 16 Plus / 15 Plus | 6.7" | 1290 x 2796 | Alternative for 6.7" |
48
- | iPhone 16 Pro | 6.3" | 1206 x 2622 | Recommended |
49
- | iPhone SE (3rd gen) | 4.7" | 750 x 1334 | Only if supporting |
50
- | iPad Pro 13" M4 | 13" | 2064 x 2752 | Yes |
51
- | iPad Pro 12.9" (3rd gen+) | 12.9" | 2048 x 2732 | Yes |
71
+ ## All Screenshots Created in Stitch MCP
52
72
 
53
- ### Minimum Required Set (create at least these)
73
+ **MANDATORY: ALL screenshots are designed entirely in Stitch MCP. No simulator screenshots, no mobile-mcp, no external tools.**
54
74
 
55
- 1. **iPhone 6.7"** -- 5 screenshots at 1290 x 2796 pixels
56
- 2. **iPad Pro 12.9"** -- 5 screenshots at 2048 x 2732 pixels
57
- 3. **iPad Pro 13"** -- 5 screenshots at 2064 x 2752 pixels
75
+ ### Design Process
58
76
 
59
- ### Apple Rules
77
+ 1. **Use the existing Stitch project** — screenshots go in the SAME project where the app design was created
78
+ 2. For each of the 5 scenes, create a design in Stitch MCP with a detailed prompt
79
+ 3. Generate at EVERY required device dimension (see sizes below)
80
+ 4. Export each design as PNG and save to the correct directory path
60
81
 
61
- - Must show actual app UI (real screens, not purely conceptual art)
62
- - No photographs of people holding physical devices
63
- - Format: .png or .jpg only (prefer .png for quality)
64
- - Minimum 1, maximum 10 per device class per locale
65
- - Text overlays are allowed but the app UI must be prominent
66
- - No misleading content -- screenshots must represent the real app
67
- - Screenshots are locale-specific (create for en-US, localize others as needed)
68
- - Portrait orientation preferred (landscape accepted for specific apps)
82
+ ### Stitch Design Prompt Template
69
83
 
70
- ### iOS Directory Structure
84
+ For each scene, use a detailed prompt like:
71
85
 
72
86
  ```
73
- fastlane/screenshots/ios/
74
- en-US/
75
- iPhone 6.7/
76
- 01_hero.png
77
- 02_feature1.png
78
- 03_feature2.png
79
- 04_social.png
80
- 05_settings.png
81
- iPad Pro 12.9/
82
- 01_hero.png
83
- 02_feature1.png
84
- 03_feature2.png
85
- 04_social.png
86
- 05_settings.png
87
- iPad Pro 13/
88
- 01_hero.png
89
- 02_feature1.png
90
- 03_feature2.png
91
- 04_social.png
92
- 05_settings.png
87
+ App store screenshot for a [app category] app called "[App Name]".
88
+
89
+ LAYOUT:
90
+ - Top 30%: Large headline "[HEADLINE TEXT]" in bold [font], [color] text, left-aligned or centered
91
+ - Optional small subheadline below in lighter weight
92
+ - Center/bottom 65%: [Device type] showing the app's [specific screen] with [describe UI content in detail]
93
+ - Background: [gradient/solid color matching app theme]
94
+
95
+ STYLE:
96
+ - Clean, modern, minimal — premium App Store quality
97
+ - No device frame / thin device frame (choose one)
98
+ - High contrast between text and background
99
+ - [App name]'s color palette: primary [#hex], accent [#hex], background [#hex]
100
+
101
+ DIMENSIONS: [width] x [height] pixels
102
+ FORMAT: PNG, RGB color space
93
103
  ```
94
104
 
95
- ## Google Play Screenshot Requirements
105
+ ### Device Sizes to Generate
96
106
 
97
- ### Required Image Types
107
+ For EACH of the 5 scenes, generate at ALL these sizes:
98
108
 
99
- | Type | Dimensions | Required | Max Count |
100
- |------|-----------|----------|-----------|
101
- | Phone screenshots | 1080 x 1920 (9:16 recommended) | Min 2, recommended 5 | 8 |
102
- | 7-inch tablet | 1200 x 1920 (recommended) | Optional | 8 |
103
- | 10-inch tablet | 1920 x 1200 or 1200 x 1920 | Optional | 8 |
104
- | Feature graphic | 1024 x 500 exactly | Required | 1 |
105
- | App icon (hi-res) | 512 x 512 exactly | Required | 1 |
109
+ **Apple App Store (required):**
110
+ - iPhone 6.7": 1290 x 2796 px
111
+ - iPad Pro 12.9": 2048 x 2732 px
112
+ - iPad Pro 13": 2064 x 2752 px
106
113
 
107
- ### Dimension Rules
114
+ **Google Play (required):**
115
+ - Phone: 1080 x 1920 px
116
+ - 7" Tablet: 1200 x 1920 px
117
+ - 10" Tablet: 1920 x 1200 px (landscape)
108
118
 
109
- - Minimum dimension: 320 pixels on any side
110
- - Maximum dimension: 3840 pixels on any side
111
- - Aspect ratio: must be 16:9 or 9:16 for phone screenshots
112
- - Tablets: can be landscape or portrait
113
- - Feature graphic: always landscape 1024x500
119
+ **Google Play extras (required):**
120
+ - Feature Graphic: 1024 x 500 px (landscape banner — app name + tagline + brand colors)
121
+ - Icon: 512 x 512 px
114
122
 
115
- ### Google Rules
123
+ ## Directory Structure
116
124
 
117
- - Screenshots must accurately depict the app experience
118
- - Device frames are optional (acceptable but not required)
119
- - No misleading or irrelevant imagery
120
- - Feature graphic is the banner displayed at top of store listing
121
- - Text in screenshots must be readable
122
- - No excessive text overlaying the UI
125
+ Save all exported screenshots to:
123
126
 
124
- ### Android Directory Structure
127
+ ### iOS
128
+ ```
129
+ fastlane/screenshots/ios/
130
+ en-US/
131
+ iPhone 6.7/
132
+ 01_hero.png, 02_feature1.png, 03_feature2.png, 04_social.png, 05_settings.png
133
+ iPad Pro 12.9/
134
+ 01_hero.png, 02_feature1.png, 03_feature2.png, 04_social.png, 05_settings.png
135
+ iPad Pro 13/
136
+ 01_hero.png, 02_feature1.png, 03_feature2.png, 04_social.png, 05_settings.png
137
+ ```
125
138
 
139
+ ### Android
126
140
  ```
127
141
  fastlane/screenshots/android/
128
142
  en-US/
129
143
  phoneScreenshots/
130
- 01_hero.png
131
- 02_feature1.png
132
- 03_feature2.png
133
- 04_social.png
134
- 05_settings.png
144
+ 01_hero.png, 02_feature1.png, 03_feature2.png, 04_social.png, 05_settings.png
135
145
  sevenInchScreenshots/
136
- 01_hero.png
137
- 02_feature1.png
138
- 03_feature2.png
139
- 04_social.png
140
- 05_settings.png
146
+ 01_hero.png, 02_feature1.png, 03_feature2.png, 04_social.png, 05_settings.png
141
147
  tenInchScreenshots/
142
- 01_hero.png
143
- 02_feature1.png
144
- 03_feature2.png
145
- 04_social.png
146
- 05_settings.png
148
+ 01_hero.png, 02_feature1.png, 03_feature2.png, 04_social.png, 05_settings.png
147
149
  featureGraphic.png
148
150
  icon.png
149
151
  ```
150
152
 
151
- ## Using Stitch MCP for Design
152
-
153
- When Stitch MCP is available (GOOGLE_API_KEY configured):
154
-
155
- 1. List existing Stitch projects to check for prior work
156
- 2. Create a new Stitch project named "{app-name}-store-screenshots"
157
- 3. For each screenshot scene, generate a screen with a detailed prompt:
158
- - Describe the exact layout: background color/gradient, app screen placement, headline text
159
- - Specify the app's color palette (extract from theme.dart or design specs)
160
- - Reference the actual app screen content for that scene
161
- 4. Export each screen at every required device dimension
162
- 5. Apply headline text overlays
163
- 6. Save to the correct directory paths
164
-
165
- ### Stitch Prompt Template
153
+ ## Apple App Store Rules
154
+ - Must show app UI (Stitch-designed screens representing real app features)
155
+ - No photographs of people holding physical devices
156
+ - Format: .png only
157
+ - Max 10 per device class per locale
158
+ - Text overlays allowed, app UI must be prominent
159
+ - No misleading content
160
+ - Portrait orientation
166
161
 
167
- For each scene, construct a prompt like:
168
- ```
169
- App store screenshot for a [app type] app.
170
- Background: [gradient/color description].
171
- Center: phone mockup showing [specific screen description].
172
- Top text: "[headline text]" in [font style], [color].
173
- Style: clean, modern, professional app store screenshot.
174
- Dimensions: [width]x[height] pixels.
175
- ```
162
+ ## Google Play Rules
163
+ - Screenshots must accurately depict the app experience
164
+ - Device frames optional
165
+ - Feature graphic: landscape 1024x500, displayed at top of store listing
166
+ - Text must be readable
167
+ - No excessive text overlaying the UI
176
168
 
177
- ## Fallback Without Stitch MCP
178
-
179
- If Stitch MCP is NOT available, create a detailed design specification file:
180
-
181
- Save to `fastlane/screenshots/design-spec.json`:
182
- ```json
183
- {
184
- "brand": {
185
- "primaryColor": "#hex",
186
- "secondaryColor": "#hex",
187
- "backgroundColor": "#hex",
188
- "fontFamily": "SF Pro Display",
189
- "headlineWeight": "bold"
190
- },
191
- "scenes": [
192
- {
193
- "id": "01_hero",
194
- "headline": "Your Headline Here",
195
- "appScreen": "description of which app screen to capture",
196
- "background": "gradient from #hex to #hex"
197
- }
198
- ]
199
- }
200
- ```
169
+ ## Fallback: If Stitch MCP is unavailable
201
170
 
202
- The developer agent can then create screenshots programmatically using Flutter widget tests or a dedicated screenshot generation script.
171
+ Only if Stitch MCP tools are not available, save a design specification to `fastlane/screenshots/design-spec.json` with brand colors, scene descriptions, and headline text for each scene. This spec can be used to create screenshots manually.
203
172
 
204
173
  ## Output Verification Checklist
205
174
 
206
- After creating all screenshots, verify every item:
207
-
208
- - [ ] iPhone 6.7" -- 5 screenshots at 1290x2796, .png format
209
- - [ ] iPad Pro 12.9" -- 5 screenshots at 2048x2732, .png format
210
- - [ ] iPad Pro 13" -- 5 screenshots at 2064x2752, .png format
211
- - [ ] Android phone -- 5 screenshots at 1080x1920, .png format
212
- - [ ] Android 7-inch tablet -- 5 screenshots at 1200x1920, .png format
213
- - [ ] Android 10-inch tablet -- 5 screenshots at 1920x1200, .png format
214
- - [ ] Android feature graphic -- exactly 1024x500, .png format
215
- - [ ] Android icon -- exactly 512x512, .png format
216
- - [ ] All file names follow the naming convention (01_hero, 02_feature1, etc.)
217
- - [ ] All images are .png or .jpg format
218
- - [ ] Headline text is readable at thumbnail size
219
- - [ ] App UI is prominent and represents the actual app
175
+ After creating all screenshots, verify:
176
+
177
+ - [ ] iPhone 6.7" 5 screenshots at 1290x2796, .png
178
+ - [ ] iPad Pro 12.9" 5 screenshots at 2048x2732, .png
179
+ - [ ] iPad Pro 13" 5 screenshots at 2064x2752, .png
180
+ - [ ] Android phone 5 screenshots at 1080x1920, .png
181
+ - [ ] Android 7" tablet 5 screenshots at 1200x1920, .png
182
+ - [ ] Android 10" tablet 5 screenshots at 1920x1200, .png
183
+ - [ ] Feature graphic 1024x500, .png
184
+ - [ ] Icon 512x512, .png
185
+ - [ ] Headlines are BIG and readable at thumbnail size
186
+ - [ ] Max 2 lines of headline text per screenshot
220
187
  - [ ] Consistent color scheme and typography across all scenes
221
- - [ ] No photographs of people holding physical devices (Apple rule)
188
+ - [ ] App UI is prominent and represents the actual app
189
+ - [ ] No photographs of people holding physical devices
222
190
 
223
191
  ## Output Footer
224
192
 
@@ -139,6 +139,41 @@ Read fastlane/app_rating_config.json and verify:
139
139
  - **Subscription policy**: clear terms displayed before purchase, easy cancellation path
140
140
  - **Content rating**: accurate IARC questionnaire responses, consistent with app content
141
141
 
142
+ ## Pre-Submission Checklist
143
+
144
+ Before running the full review, verify these mandatory items. Include checkbox results in the output.
145
+
146
+ ### Apple App Store Mandatory Items
147
+ - [ ] App name (name.txt) present and <= 30 characters
148
+ - [ ] Subtitle (subtitle.txt) present and <= 30 characters
149
+ - [ ] Description (description.txt) present and <= 4000 characters
150
+ - [ ] Keywords (keywords.txt) present and <= 100 characters total
151
+ - [ ] Privacy URL (privacy_url.txt) present with valid https:// URL
152
+ - [ ] Support URL (support_url.txt) present with valid https:// URL
153
+ - [ ] At least 1 screenshot per required device class (6.7", 6.5", iPad 12.9")
154
+ - [ ] App icon present (1024x1024 in Assets.xcassets)
155
+ - [ ] Bundle ID matches ci.config.yaml
156
+ - [ ] Age rating config (app_rating_config.json) present and complete
157
+ - [ ] Privacy policy page loads and contains required sections
158
+
159
+ ### Google Play Mandatory Items
160
+ - [ ] Title (title.txt) present and <= 30 characters
161
+ - [ ] Short description (short_description.txt) present and <= 80 characters
162
+ - [ ] Full description (full_description.txt) present and <= 4000 characters
163
+ - [ ] Feature graphic present (exactly 1024x500)
164
+ - [ ] At least 2 phone screenshots present
165
+ - [ ] App icon (512x512) present
166
+ - [ ] Package name matches ci.config.yaml
167
+ - [ ] Changelog (changelogs/default.txt) present
168
+ - [ ] Privacy policy page loads and contains required sections
169
+ - [ ] Content rating questionnaire answers present
170
+
171
+ ### Both Platforms
172
+ - [ ] All metadata files exist for every language in ci.config.yaml metadata.languages
173
+ - [ ] IAP config (iap_config.json) valid if app has subscriptions
174
+ - [ ] No placeholder text remaining in any metadata file
175
+ - [ ] Web pages (privacy, terms, support) deploy successfully
176
+
142
177
  ## Output Format
143
178
 
144
179
  ```
package/src/install.mjs CHANGED
@@ -11,7 +11,7 @@ import { injectEnvVars, injectStatusLine } from './settings.mjs';
11
11
  import { ensureClaudePlugin } from './dependency-check.mjs';
12
12
  import { promptForTokens } from './prompt.mjs';
13
13
  import { getMcpServers, writeMcpJson } from './mcp-setup.mjs';
14
- import { installClaudeMd, installCiTemplates } from './templates.mjs';
14
+ import { installClaudeMd, installCiTemplates, installFirebaseTemplates } from './templates.mjs';
15
15
 
16
16
  function checkClaudeCli() {
17
17
  const result = exec('command -v claude') || exec('which claude');
@@ -124,6 +124,7 @@ export async function runInstall(scope, isPostinstall = false) {
124
124
 
125
125
  installClaudeMd(join(baseDir, 'CLAUDE.md'), packageDir);
126
126
  installCiTemplates(projectDir, packageDir);
127
+ installFirebaseTemplates(projectDir, packageDir);
127
128
 
128
129
  const scopeLabel = scope === 'user' ? 'global' : 'project';
129
130
  console.log(`Configuring ${scopeLabel} settings...`);
package/src/templates.mjs CHANGED
@@ -10,6 +10,14 @@ const FILE_COPIES = [
10
10
 
11
11
  const DIR_COPIES = ['scripts', 'fastlane', 'web'];
12
12
 
13
+ const FIREBASE_COPIES = [
14
+ ['firebase/firestore.rules.template', 'backend/firestore.rules'],
15
+ ['firebase/storage.rules.template', 'backend/storage.rules'],
16
+ ['firebase/firebase.json.template', 'backend/firebase.json'],
17
+ ['firebase/firestore.indexes.json.template', 'backend/firestore.indexes.json'],
18
+ ['firebase/.firebaserc.template', 'backend/.firebaserc'],
19
+ ];
20
+
13
21
  function copyIfMissing(srcPath, destPath, label, isDirectory) {
14
22
  if (!existsSync(srcPath)) return;
15
23
  if (existsSync(destPath)) {
@@ -53,3 +61,13 @@ export function installCiTemplates(projectDir, packageDir) {
53
61
  );
54
62
  }
55
63
  }
64
+
65
+ export function installFirebaseTemplates(projectDir, packageDir) {
66
+ console.log('Installing Firebase backend templates...');
67
+ const templateDir = join(packageDir, 'templates');
68
+ ensureDir(join(projectDir, 'backend'));
69
+
70
+ for (const [src, dest] of FIREBASE_COPIES) {
71
+ copyIfMissing(join(templateDir, src), join(projectDir, dest), dest, false);
72
+ }
73
+ }
@@ -45,7 +45,7 @@ metadata:
45
45
  - en-US
46
46
 
47
47
  web:
48
- domain: "yourapp.example.com"
48
+ domain: "yourapp-pages.pages.dev" # *.pages.dev domain is sufficient, no custom DNS needed
49
49
  cloudflare_project_name: "yourapp-pages"
50
50
  ```
51
51
 
@@ -92,10 +92,11 @@ Intro offer types: FREE, PAY_AS_YOU_GO, PAY_UP_FRONT.
92
92
  ## Flutter Development Standards
93
93
 
94
94
  ### Architecture
95
- - BLoC/Cubit pattern for state management
95
+ - **State management**: Riverpod (recommended) or BLoC/Cubit
96
96
  - Repository pattern for data access
97
- - Dependency injection via get_it + injectable
97
+ - **Dependency injection**: Riverpod providers (recommended) or get_it + injectable
98
98
  - Feature-first folder structure
99
+ - Code generation: build_runner + riverpod_generator (or freezed + json_serializable)
99
100
 
100
101
  ### Folder Structure
101
102
  ```
@@ -111,9 +112,11 @@ lib/
111
112
  widgets/ # Shared widgets
112
113
  features/
113
114
  {feature}/
114
- data/ # Data sources, repositories
115
- domain/ # Entities, use cases
116
- presentation/ # Screens, widgets, cubits
115
+ models/ # Data classes, entities
116
+ providers/ # Riverpod providers (or cubits/)
117
+ repositories/ # Data sources, API calls
118
+ screens/ # Full-page widgets
119
+ widgets/ # Feature-specific widgets
117
120
  services/
118
121
  firebase/
119
122
  api/
@@ -137,14 +140,24 @@ lib/
137
140
  - No TODO/FIXME in committed code
138
141
  - No hardcoded secrets anywhere
139
142
 
140
- ### Dependencies (standard set)
143
+ ### Dependencies
144
+
145
+ **Riverpod stack (recommended):**
146
+ - flutter_riverpod + riverpod_annotation + riverpod_generator -- state management & DI
147
+ - go_router -- navigation
148
+ - dio -- HTTP client
149
+ - freezed + json_serializable -- data classes
150
+ - firebase_core, firebase_auth, cloud_firestore -- Firebase
151
+ - in_app_purchase -- client-only IAP (no backend needed)
152
+
153
+ **BLoC stack (alternative):**
141
154
  - flutter_bloc / bloc -- state management
142
155
  - go_router -- navigation
143
156
  - get_it + injectable -- dependency injection
144
157
  - dio -- HTTP client
145
158
  - freezed + json_serializable -- data classes
146
159
  - firebase_core, firebase_auth, cloud_firestore -- Firebase
147
- - purchases_flutter -- RevenueCat for IAP (or in_app_purchase)
160
+ - in_app_purchase -- client-only IAP (no backend needed)
148
161
 
149
162
  ### Testing
150
163
  - Unit tests for all business logic (cubits, repositories, use cases)
@@ -152,6 +165,48 @@ lib/
152
165
  - Integration tests for critical user flows
153
166
  - Minimum 80% coverage target
154
167
 
168
+ ### Mandatory UI Testing (MUST run before publishing)
169
+ - **Flutter analyze**: `flutter analyze` must pass with zero issues
170
+ - **iOS build test**: `flutter build ios --no-codesign` must succeed
171
+ - **Android build test**: `flutter build appbundle` must succeed
172
+ - **Run all unit tests**: `flutter test` must pass
173
+ - **Widget/integration tests**: Run full test suite on both platforms
174
+ - All builds and tests MUST pass before proceeding to store metadata or publishing
175
+
176
+ ### In-App Purchases (in_app_purchase — Client-Only, No Backend)
177
+
178
+ Use the `in_app_purchase` Flutter package for all IAP/subscription functionality. No backend server validation is needed — all purchase handling is client-only.
179
+
180
+ #### Store Setup
181
+ - **App Store Connect**: Create products (consumable / non-consumable / subscription) with unique IDs
182
+ - **Google Play Console**: Create matching product IDs
183
+
184
+ #### App Setup
185
+ - Add `in_app_purchase` to `pubspec.yaml`
186
+ - iOS: set bundle ID in Xcode
187
+ - Android: set application ID in `build.gradle`
188
+
189
+ #### Runtime Flow
190
+ 1. **Listen early** — subscribe to `purchaseStream` in `initState()` (catches pending purchases from previous sessions)
191
+ 2. **Check availability** — `InAppPurchase.instance.isAvailable()`
192
+ 3. **Query products** — `queryProductDetails()` with your product IDs
193
+ 4. **Buy** — `buyNonConsumable()` or `buyConsumable()`; native store UI appears automatically
194
+ 5. **Handle result** — listen to `purchaseStream` for `PurchaseStatus.purchased`
195
+ 6. **Deliver content** — unlock feature / add currency locally (update Firestore user doc)
196
+ 7. **Complete** — call `completePurchase()` — **mandatory within 3 days or auto-refund**
197
+
198
+ #### Restore Purchases
199
+ - Call `restorePurchases()` — results come through `purchaseStream`
200
+ - Works for non-consumables and active subscriptions
201
+ - **Consumables cannot be restored** without a backend
202
+
203
+ #### Key Rules
204
+ - Subscribe to `purchaseStream` **before anything else** — or you'll miss events
205
+ - **Always** call `completePurchase()` after delivering content
206
+ - Store product IDs locally (hardcoded constants)
207
+ - Update the user's subscription tier in Firestore directly from the client after successful purchase
208
+ - No backend validation Cloud Function needed — trust the store receipt on-device
209
+
155
210
  ## Firebase Backend
156
211
 
157
212
  ### Services
@@ -175,29 +230,38 @@ lib/
175
230
 
176
231
  ## Workflow: Design to Publish
177
232
 
178
- ### Phase 1: Design
179
- 1. Use designer agent to create UI/UX specs
180
- 2. Use appstore-media-designer to plan screenshot strategy
181
- 3. Review designs before implementation
233
+ ### Phase 1: App Design + Store Screenshots (FIRST — before development)
234
+ All design work happens in a single Stitch MCP project. Complete the full app design AND store screenshots before writing any code.
235
+
236
+ 1. **Create Stitch project** — name it `{app-name}-design` via Stitch MCP
237
+ 2. **Design all app screens** in the Stitch project using the designer agent:
238
+ - All core screens (home, main feature, detail views, settings, profile)
239
+ - Paywall/subscription screen
240
+ - Onboarding screens
241
+ - Review designs before proceeding
242
+ 3. **Create all store screenshots** in the SAME Stitch project using the **appstore-media-designer** agent:
243
+ - 5 screenshot scenes per device size for all required Apple and Google device sizes
244
+ - Screenshots are designed entirely in Stitch MCP — no simulator screenshots needed
245
+ - See the appstore-media-designer agent for full details on ASO-optimized screenshots
246
+ 4. Save all screenshots to `fastlane/screenshots/` in the correct directory structure
182
247
 
183
248
  ### Phase 2: Develop
184
- 1. Implement Flutter app following the standards above
249
+ 1. Implement Flutter app following the standards above, using the Stitch designs as reference
185
250
  2. Set up Firebase backend services
186
251
  3. Fill ci.config.yaml with real values
187
252
  4. Add creds/AuthKey.p8 (Apple) and creds/play-service-account.json (Google)
188
253
 
189
- ### Phase 3: Store Metadata
254
+ ### Phase 3: Store Metadata + Texts
190
255
  1. Run appstore-meta-creator to generate all metadata texts for configured languages
191
- 2. Run appstore-media-designer to create screenshots for all device sizes
192
- 3. Fill fastlane/iap_config.json if the app has subscriptions or IAP
193
- 4. Run appstore-reviewer to verify full compliance
256
+ 2. Fill fastlane/iap_config.json if the app has subscriptions or IAP
194
257
 
195
- ### Phase 4: Web Pages
196
- 1. Customize marketing landing page (web/marketing.html)
258
+ ### Phase 4: Web Pages (after screenshots are ready)
259
+ 1. Customize marketing landing page (web/marketing.html) -- **include app screenshots** from Phase 1
197
260
  2. Customize privacy policy page (web/privacy.html)
198
261
  3. Customize terms of service page (web/terms.html)
199
262
  4. Customize support page (web/support.html)
200
263
  5. Deploy all via Cloudflare Pages (node web/deploy-cloudflare.mjs)
264
+ 6. The default `*.pages.dev` domain is sufficient -- no custom DNS records needed. Use the generated URL (e.g., `yourapp-pages.pages.dev`) for privacy_url, support_url, and marketing_url in store metadata
201
265
 
202
266
  ### Phase 5: CI/CD Setup
203
267
  1. Run scripts/generate.sh to create codemagic.yaml from ci.config.yaml
@@ -0,0 +1,40 @@
1
+ include: package:flutter_lints/flutter.yaml
2
+
3
+ linter:
4
+ rules:
5
+ # Style
6
+ always_declare_return_types: true
7
+ prefer_const_constructors: true
8
+ prefer_const_declarations: true
9
+ prefer_single_quotes: true
10
+ require_trailing_commas: true
11
+ sort_child_properties_last: true
12
+
13
+ # Safety
14
+ avoid_print: true
15
+ unawaited_futures: true
16
+ use_build_context_synchronously: true
17
+ cancel_subscriptions: true
18
+ close_sinks: true
19
+
20
+ # Best practices
21
+ avoid_empty_else: true
22
+ avoid_relative_lib_imports: true
23
+ prefer_final_fields: true
24
+ prefer_final_locals: true
25
+ prefer_is_empty: true
26
+ prefer_is_not_empty: true
27
+ unnecessary_await_in_return: true
28
+ unnecessary_const: true
29
+ unnecessary_new: true
30
+ unnecessary_this: true
31
+
32
+ analyzer:
33
+ errors:
34
+ missing_return: error
35
+ unawaited_futures: warning
36
+ avoid_print: warning
37
+ exclude:
38
+ - "**/*.g.dart"
39
+ - "**/*.freezed.dart"
40
+ - "**/*.gen.dart"
@@ -38,7 +38,7 @@ metadata:
38
38
 
39
39
  # === WEB PAGES ===
40
40
  web:
41
- domain: "yourapp.example.com"
41
+ domain: "yourapp-pages.pages.dev" # *.pages.dev domain is sufficient, no custom DNS needed
42
42
  cloudflare_project_name: "yourapp-pages"
43
43
  tagline: "Your app tagline here"
44
44
  primary_color: "#2563EB"
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+ gem "fastlane"
3
+
4
+ plugins_path = File.join(File.dirname(__FILE__), 'Pluginfile')
5
+ eval_gemfile(plugins_path) if File.exist?(plugins_path)
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+ gem "fastlane"
3
+
4
+ plugins_path = File.join(File.dirname(__FILE__), 'Pluginfile')
5
+ eval_gemfile(plugins_path) if File.exist?(plugins_path)
@@ -0,0 +1,5 @@
1
+ {
2
+ "projects": {
3
+ "default": "YOUR_FIREBASE_PROJECT_ID"
4
+ }
5
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "firestore": {
3
+ "rules": "firestore.rules",
4
+ "indexes": "firestore.indexes.json"
5
+ },
6
+ "functions": [
7
+ {
8
+ "source": "functions",
9
+ "codebase": "default",
10
+ "ignore": ["node_modules", ".git", "firebase-debug.log", "firebase-debug.*.log", "*.local"]
11
+ }
12
+ ],
13
+ "storage": {
14
+ "rules": "storage.rules"
15
+ }
16
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "indexes": [],
3
+ "fieldOverrides": []
4
+ }
@@ -0,0 +1,20 @@
1
+ rules_version = '2';
2
+ service cloud.firestore {
3
+ match /databases/{database}/documents {
4
+ function isOwner(userId) {
5
+ return request.auth != null && request.auth.uid == userId;
6
+ }
7
+
8
+ match /users/{userId} {
9
+ allow read, write: if isOwner(userId);
10
+
11
+ match /{subcollection=**} {
12
+ allow read, write: if isOwner(userId);
13
+ }
14
+ }
15
+
16
+ match /system/{document=**} {
17
+ allow read, write: if false;
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,10 @@
1
+ rules_version = '2';
2
+ service firebase.storage {
3
+ match /b/{bucket}/o {
4
+ match /users/{userId}/{allPaths=**} {
5
+ allow read, write: if request.auth != null
6
+ && request.auth.uid == userId
7
+ && request.resource.size < 10 * 1024 * 1024;
8
+ }
9
+ }
10
+ }
@@ -27,6 +27,18 @@ if ! command -v yq &>/dev/null; then
27
27
  exit 1
28
28
  fi
29
29
 
30
+ # Validate that a config value does not contain characters that break sed
31
+ validate_value() {
32
+ local name="$1"
33
+ local value="$2"
34
+ if [[ "$value" =~ [|/\\] ]]; then
35
+ echo "ERROR: $name contains invalid characters (|, /, or \\) that would break substitution."
36
+ echo " Current value: $value"
37
+ echo " Please remove |, /, and \\ characters from $name in $CONFIG"
38
+ exit 1
39
+ fi
40
+ }
41
+
30
42
  # Read app values from ci.config.yaml
31
43
  BUNDLE_ID=$(yq -r '.app.bundle_id' "$CONFIG")
32
44
  PACKAGE_NAME=$(yq -r '.app.package_name' "$CONFIG")
@@ -49,6 +61,18 @@ APPLE_ISSUER_ID=$(yq -r '.credentials.apple.issuer_id' "$CONFIG")
49
61
  GOOGLE_SA_JSON_PATH=$(yq -r '.credentials.google.service_account_json_path' "$CONFIG")
50
62
  KEYSTORE_PASSWORD=$(yq -r '.credentials.android.keystore_password' "$CONFIG")
51
63
 
64
+ # Validate all values before sed substitution
65
+ validate_value "app.bundle_id" "$BUNDLE_ID"
66
+ validate_value "app.package_name" "$PACKAGE_NAME"
67
+ validate_value "app.name" "$APP_NAME"
68
+ validate_value "app.sku" "$SKU"
69
+ validate_value "app.apple_id" "$APPLE_ID"
70
+ validate_value "android.track" "$TRACK"
71
+ validate_value "ios.primary_category" "$PRIMARY_CAT"
72
+ validate_value "ios.secondary_category" "$SECONDARY_CAT"
73
+ validate_value "credentials.apple.key_id" "$APPLE_KEY_ID"
74
+ validate_value "credentials.apple.issuer_id" "$APPLE_ISSUER_ID"
75
+
52
76
  # Generate codemagic.yaml from template
53
77
  sed \
54
78
  -e "s|\${BUNDLE_ID}|$BUNDLE_ID|g" \
@@ -79,9 +79,17 @@ function getCredentials(dir) {
79
79
  const mcpPath = join(dir, ".mcp.json");
80
80
  if (existsSync(mcpPath)) {
81
81
  const mcp = JSON.parse(readFileSync(mcpPath, "utf8"));
82
- const cf = mcp?.mcpServers?.cloudflare?.env || {};
83
- token = token || cf.CLOUDFLARE_API_TOKEN || "";
84
- accountId = accountId || cf.CLOUDFLARE_ACCOUNT_ID || "";
82
+ const cfServer = mcp?.mcpServers?.cloudflare || {};
83
+ const cfEnv = cfServer.env || {};
84
+ const cfArgs = cfServer.args || [];
85
+ token = token || cfEnv.CLOUDFLARE_API_TOKEN || "";
86
+ if (!accountId && cfArgs.length >= 4) {
87
+ const runIdx = cfArgs.indexOf("run");
88
+ if (runIdx >= 0 && cfArgs[runIdx + 1]) {
89
+ accountId = cfArgs[runIdx + 1];
90
+ }
91
+ }
92
+ accountId = accountId || cfEnv.CLOUDFLARE_ACCOUNT_ID || "";
85
93
  }
86
94
  }
87
95
  if (!token || !accountId) {