# Build — TaskFlow

Implements any feature end-to-end: deep research → TDD → integration tests → external setup checklist → verified PR.
Stack: **Riverpod** / **Feature-First** / **Supabase** / ios, android, web.

## Usage

```
/build <free-text description of what to implement>
```

**Examples:**
- `/build implement notification module end-to-end`
- `/build add biometric auth`
- `/build integrate Stripe payments`
- `/build add deep linking for shared product pages`
- `/build implement analytics event tracking`

---

## FEATURE_REGISTRY

The AI reads this registry to classify the request and load the right research, test scenarios, and setup steps.

```yaml
feature_registry:

  notifications:
    keywords: [notification, push, fcm, apns, alert, badge, silent push,
               remote notification, local notification, firebase messaging]
    pub_packages: [firebase_messaging, flutter_local_notifications, firebase_core]
    rules_to_load: [security-standards.mdc, platform-ios.mdc, platform-android.mdc]
    unit_test_scenarios:
      - parse notification payload to domain model
      - FCM token generation and storage
      - token refresh triggers re-registration
      - notification permission denied returns graceful fallback
      - notification service initialisation is idempotent
    widget_test_scenarios:
      - notification banner renders correct title and body
      - tap on notification navigates to correct route
      - badge count updates on new message
    integration_test_scenarios:
      - foreground notification receipt and display
      - background notification receipt (app backgrounded, not killed)
      - killed-state notification receipt (cold launch from notification tap)
      - tap-to-open in foreground state routes correctly
      - tap-to-open in background state routes correctly
      - tap-to-open in killed state routes correctly
      - notification payload parsing end-to-end
      - deep link routing from notification data field
      - multiple simultaneous notifications (ordering and dedup)
    external_setup:
      firebase: [Enable Cloud Messaging, download google-services.json, download GoogleService-Info.plist]
      ios: [Push Notifications capability, Background Modes remote notifications, APNs .p8 key upload to Firebase]
      android: [POST_NOTIFICATIONS permission, RECEIVE_BOOT_COMPLETED permission, google-services plugin]
    files_to_touch:
      new: [lib/features/notifications/, integration_test/notifications/]
      modified: [lib/main.dart, android/app/src/main/AndroidManifest.xml, ios/Runner/Info.plist, ios/Runner/AppDelegate.swift, pubspec.yaml]

  auth:
    keywords: [auth, authentication, login, sign in, sign out, logout,
               biometric, face id, touch id, fingerprint, oauth, jwt,
               session, token refresh, social login, google sign-in]
    pub_packages: [firebase_auth, supabase_flutter, local_auth, flutter_secure_storage, google_sign_in]
    rules_to_load: [security-standards.mdc, platform-ios.mdc, platform-android.mdc]
    unit_test_scenarios:
      - login success stores token securely
      - login failure (wrong password) returns typed error
      - login failure (network) returns typed error
      - token refresh succeeds and updates stored token
      - token refresh failure triggers logout
      - biometric auth success grants access
      - biometric auth failure falls back to password
      - biometric not enrolled returns correct error state
      - logout clears all stored credentials
      - session persistence: token loaded on cold start
    widget_test_scenarios:
      - login form renders correctly
      - validation errors shown inline
      - loading state disables submit button
      - biometric prompt shown when available
    integration_test_scenarios:
      - complete login flow (email and password)
      - login then logout then login again
      - invalid credentials shows error and stays on login
      - biometric login flow on enrolled device
      - biometric fallback to password
      - token refresh in background while user navigates
      - cold start with stored valid session skips login
      - cold start with expired session redirects to login
      - social auth OAuth redirect and return
      - deep link into protected route redirects to login then back
    external_setup:
      firebase: [Enable Email/Password provider, Enable Google provider, download updated config files]
      ios: [NSFaceIDUsageDescription in Info.plist, LocalAuthentication.framework in Xcode]
      android: [USE_BIOMETRIC permission, USE_FINGERPRINT permission, minSdkVersion 23 for biometric]
    files_to_touch:
      new: [lib/features/auth/, integration_test/auth/]
      modified: [lib/main.dart, lib/core/di/injection.dart, pubspec.yaml]

  payments:
    keywords: [payment, stripe, in-app purchase, iap, checkout, subscription,
               billing, apple pay, google pay, card, transaction, refund, revenue cat]
    pub_packages: [flutter_stripe, purchases_flutter, in_app_purchase]
    rules_to_load: [security-standards.mdc, platform-ios.mdc, platform-android.mdc]
    unit_test_scenarios:
      - checkout request builds correct PaymentIntent params
      - payment success updates order state
      - payment failure (card declined) returns typed error
      - webhook event parsed to domain model
      - refund request constructs correct API call
      - subscription status checked on app resume
    widget_test_scenarios:
      - checkout form renders with correct amount
      - payment loading state shown during processing
      - success confirmation screen renders
      - error state with retry option
    integration_test_scenarios:
      - end-to-end checkout with test card (Stripe test mode)
      - checkout with 3D Secure challenge
      - card declined shows error then retry succeeds
      - Apple Pay / Google Pay sheet appears (device capability check)
      - subscription purchase and entitlement unlock
      - subscription restore flow
      - refund flow from order history
    external_setup:
      stripe: [publishable and secret keys in flavor .env files, webhook endpoint in Stripe Dashboard, Apple Pay domain registration]
      ios: [In-App Purchase capability, Apple Pay capability and merchant identifier, com.apple.developer.in-app-payments entitlement]
      android: [Google Pay Console setup, BILLING permission for in_app_purchase]
    files_to_touch:
      new: [lib/features/payments/, integration_test/payments/]
      modified: [ios/Runner/Runner.entitlements, android/app/src/main/AndroidManifest.xml, pubspec.yaml]

  deep_links:
    keywords: [deep link, deep linking, universal link, app link, deferred deep link,
               dynamic link, branch, uri scheme, custom scheme, url scheme]
    pub_packages: [go_router, app_links, uni_links]
    rules_to_load: [platform-ios.mdc, platform-android.mdc]
    unit_test_scenarios:
      - URI parsed to correct route and parameters
      - unknown URI falls back to home
      - authenticated-only route redirects to login when unauthenticated
      - deep link preserves query parameters
    widget_test_scenarios:
      - navigation guard redirects unauthenticated deep link
    integration_test_scenarios:
      - cold start from Universal Link routes to correct screen
      - cold start from custom URI scheme routes correctly
      - backgrounded app receives deep link and navigates
      - foreground app receives deep link and navigates
      - deep link to authenticated route redirects to login then original destination
      - deep link with path parameters loads correct content
      - invalid or malformed deep link shows 404 screen
    external_setup:
      ios: [Associated Domains capability applinks:yourdomain.com, host apple-app-site-association file at /.well-known/]
      android: [intent-filter with android:autoVerify=true in AndroidManifest.xml, host assetlinks.json at /.well-known/]
    files_to_touch:
      new: [lib/core/routing/deep_link_handler.dart, integration_test/deep_links/]
      modified: [lib/core/routing/router.dart, android/app/src/main/AndroidManifest.xml, ios/Runner/Runner.entitlements, ios/Runner/Info.plist]

  analytics:
    keywords: [analytics, tracking, event, mixpanel, amplitude, firebase analytics,
               segment, posthog, screen view, funnel, cohort]
    pub_packages: [firebase_analytics, mixpanel_flutter, amplitude_flutter, posthog_flutter]
    rules_to_load: [security-standards.mdc]
    unit_test_scenarios:
      - analytics service logs correct event name and params
      - PII fields stripped before event sent
      - analytics disabled in dev flavor
      - screen name logged on navigation
    widget_test_scenarios:
      - RouteObserver triggers screen_view event
    integration_test_scenarios:
      - user action triggers expected event (verify via debug view)
      - screen transitions log screen_view with correct names
      - opt-out disables all tracking
    external_setup:
      firebase: [Enable Analytics in Firebase Console, enable DebugView for local testing, configure conversion events]
    files_to_touch:
      new: [lib/core/analytics/analytics_service.dart, lib/core/analytics/analytics_events.dart, integration_test/analytics/]
      modified: [lib/main.dart, pubspec.yaml]

  storage:
    keywords: [storage, file upload, download, cloud storage, firebase storage,
               supabase storage, s3, image upload, document, file picker,
               offline, cache, hive, isar, objectbox, sqflite, drift]
    pub_packages: [firebase_storage, supabase_flutter, hive_flutter, isar, drift, file_picker, image_picker, path_provider]
    rules_to_load: [security-standards.mdc, platform-ios.mdc, platform-android.mdc]
    unit_test_scenarios:
      - upload returns public URL on success
      - upload failure returns typed error
      - local cache read before remote fetch (offline-first)
      - cache invalidation on TTL expiry
      - large file upload uses resumable upload
    widget_test_scenarios:
      - file picker button triggers picker
      - upload progress indicator shown
      - image preview renders after selection
    integration_test_scenarios:
      - end-to-end file upload and retrieval
      - offline mode: local cache serves data
      - background upload completes when connectivity restored
      - file size limit enforced
    external_setup:
      firebase: [Enable Firebase Storage, configure Storage security rules, set CORS policy for web if applicable]
      ios: [NSPhotoLibraryUsageDescription in Info.plist, NSCameraUsageDescription in Info.plist]
      android: [READ_EXTERNAL_STORAGE or READ_MEDIA_IMAGES permission]
    files_to_touch:
      new: [lib/features/storage/, integration_test/storage/]
      modified: [android/app/src/main/AndroidManifest.xml, ios/Runner/Info.plist, pubspec.yaml]

  camera_media:
    keywords: [camera, photo, video, image picker, qr code, barcode scanner,
               ar, augmented reality, gallery, media, record, capture]
    pub_packages: [camera, image_picker, mobile_scanner, qr_flutter, image_cropper, video_player]
    rules_to_load: [security-standards.mdc, platform-ios.mdc, platform-android.mdc]
    unit_test_scenarios:
      - QR/barcode parsed to correct domain model
      - image compressed before upload
      - camera permission denied returns typed error
    widget_test_scenarios:
      - camera preview widget renders
      - capture button triggers photo take
    integration_test_scenarios:
      - camera opens and captures photo on real device
      - gallery picker selects image and returns
      - QR scan decodes valid code correctly
      - permission denied shows correct error UI
    external_setup:
      ios: [NSCameraUsageDescription, NSPhotoLibraryUsageDescription, NSMicrophoneUsageDescription for video]
      android: [CAMERA permission, READ_MEDIA_IMAGES for gallery access]
    files_to_touch:
      new: [lib/features/camera/, integration_test/camera/]
      modified: [android/app/src/main/AndroidManifest.xml, ios/Runner/Info.plist, pubspec.yaml]
```

---

## Phase 1: Context Loading

**When the user types `/build <request>`, do the following before writing a single line of code:**

1. Read `project-brief.yaml` from the repo root. Extract and hold in context:
   - `stack.state_management` → **riverpod**
   - `stack.architecture` → **feature_first**
   - `stack.routing` → **gorouter**
   - `stack.backend` → **supabase**
   - `stack.platforms` → **ios, android, web**
   - `stack.codegen` → **freezed, json_serializable**
   - `testing.depth` → **unit_widget**
   - `testing.e2e_tool` → **patrol**
   - `features.modules` (existing features) → **auth, tasks, profile**
   - `features.special` → ****
   - `environments.flavors` → **dev, prod**
   - `environments.cicd` → **github_actions**

2. Parse the user's free-text request. Match against `FEATURE_REGISTRY` keywords using longest-match. Multiple types are allowed if the request spans features.

3. Load `.cursor/rules/` files listed under `rules_to_load` for the matched feature type.

4. If the user's message contains a URL or GitHub repo reference, fetch and index it for pattern reference.

5. Check `features.modules` — if the feature already exists in the list, ask: "This feature is already listed in project-brief.yaml. Building additional capability on top of it? (y/n)"

6. Print the context summary table before proceeding:

```
| Field            | Value                        |
|------------------|------------------------------|
| Feature type     | [detected type]              |
| State management | Riverpod         |
| Architecture     | Feature-First             |
| Backend          | Supabase                  |
| Platforms        | ios, android, web           |
| E2E tool         | patrol                 |
| Rules loaded     | [list from rules_to_load]    |
| Existing modules | auth, tasks, profile            |
```

---

## Phase 2: Deep Research

**Before touching any file, print the full research output.**

1. From the FEATURE_REGISTRY, enumerate all `pub_packages` for the detected type. For each, determine the correct version compatible with current Flutter stable (`flutter --version`). Print the full `pubspec.yaml` additions.

2. Build the complete file manifest, adapting to `Feature-First`:

   **For Feature-First (feature_first):**
   - `clean`: expand each feature layer explicitly → `domain/entities/`, `domain/repositories/`, `domain/usecases/`, `data/models/`, `data/datasources/`, `data/repositories/`, `presentation/`
   - `feature_first`: `[feature]/[feature]_screen.dart`, `[feature]_provider.dart` or `[feature]_bloc.dart`, `[feature]_repository.dart`, `[feature]_model.dart`, `widgets/`
   - `mvc`: `[feature]/model/`, `[feature]/view/`, `[feature]/controller/`

   **State management file naming (Riverpod / riverpod):**
   - `bloc`: `[feature]_bloc.dart`, `[feature]_event.dart`, `[feature]_state.dart`
   - `riverpod`: `[feature]_provider.dart`, `[feature]_notifier.dart`
   - `getx`: `[feature]_controller.dart`, `[feature]_binding.dart`

3. List all modified files from `files_to_touch.modified` — show exactly what change goes in each file.

4. List all external service configuration required per platform (from `external_setup`). Only show platforms present in `ios, android, web`.

5. Print research results in this format:

```
## Research Results

### Packages to add to pubspec.yaml
- [package_name]: ^[version]

### Files to create (Feature-First / Riverpod)
lib/features/[name]/...  (full list)

### Files to modify
[file_path]  — [what changes]

### External services requiring configuration
- [Service] ([platform]) — [what to do]
```

Do not touch any file until the user has seen this output.

---

## Phase 3: TDD Implementation

> **Invoke skill: `superpowers:test-driven-development`**

Follow Red → Green → Refactor strictly. Show actual terminal output at each step.

### Step 3a — Red: Write all failing tests first

1. Mirror the feature directory under `test/features/[feature]/`.
2. Write unit tests for **every scenario** in `FEATURE_REGISTRY.unit_test_scenarios` for the detected type.
3. Write widget tests for **every scenario** in `FEATURE_REGISTRY.widget_test_scenarios`.
4. Use `mocktail` for all dependencies.
5. Test naming convention: `'given [precondition], when [action], then [expected outcome]'`
6. Use the state management test pattern for **Riverpod**:
   ```
   final container = ProviderContainer(overrides: [myProvider.overrideWithValue(mockValue)]); addTearDown(container.dispose);
   ```
7. Run and confirm red:
   ```
   flutter test test/features/[feature]/ --no-pub
   ```
   **Paste the actual output here before proceeding.**
   If failures are unclear or non-deterministic after one iteration, use **`/debug`** with full pasted output before guessing fixes.

### Step 3b — Green: Implement

1. Create domain entities and repository interfaces.
2. Create data-layer implementations wiring to `Supabase`.
3. Create presentation layer using **Riverpod** patterns.
4. Register in DI container — follow `- features/auth/ MUST NOT import from features/home/ etc.
- Shared code lives in core/ or shared/ only
- Each feature is self-contained: screen + provider + model + repo`.
5. Wire the route in `GoRouter` router.
6. If `freezed, json_serializable` is not `none`: run `dart run build_runner build --delete-conflicting-outputs` after adding models.
7. Run tests and confirm green:
   ```
   flutter test test/features/[feature]/ --no-pub
   ```
   **Paste the actual output here before proceeding.**

### Step 3c — Refactor

1. Review for duplication, naming, and layer boundary violations per `.cursor/rules/flutter-core.mdc`.
2. Run and confirm clean:
   ```
   flutter analyze
   ```
   **Paste the actual output here before proceeding.**
3. Run tests once more to confirm still green.

If output stays red or errors are ambiguous after two focused attempts, stop and use **`/debug`** with the full failing command and log before changing more code.

---

## Phase 4: Integration Test Generation

**Generate `integration_test/[feature_type]/` before asking the user to run anything.**

### Integration test file structure

Each test file follows this template:

```dart
// integration_test/[feature]/[scenario]_test.dart
// Generated by /build — TaskFlow
// Feature: [feature_type] | Scenario: [scenario_name]
// Run with: flutter test integration_test/[feature]/[scenario]_test.dart -d <device_id>

import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:com.test.taskflow/main.dart' as app;

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();

  group('[FeatureType] — [Scenario Name]', () {
    setUp(() async {
      // Seed state / configure mocks / reset storage
    });

    tearDown(() async {
      // Cleanup
    });

    testWidgets(
      'given [precondition], when [action], then [expected outcome]',
      (tester) async {
        app.main();
        await tester.pumpAndSettle();
        // test body
      },
    );
  });
}
```

**For `patrol` (patrol):** swap `flutter_test` imports for `package:patrol` and use Patrol's `$` NativeAutomator selector syntax.

### Files to generate

Create one file per logical scenario cluster from `FEATURE_REGISTRY.integration_test_scenarios`.
Also generate `integration_test/[feature]/README.md` with the full test matrix and run commands.

### PAUSE GATE — user must run on device

After generating all files, print this table and **stop**. Wait for the user to paste device output before Phase 6.

```
## ACTION REQUIRED — Run Integration Tests on Real Device

| File | Covers | Requires Hardware |
|------|--------|------------------|
| integration_test/[feature]/[scenario]_test.dart | [what it covers] | Yes/No |
...

Run on iOS:
  flutter test integration_test/[feature]/ -d <your_ios_device_id>

Run on Android:
  flutter test integration_test/[feature]/ -d <your_android_device_id>

Paste the output here to continue.
```

---

## Phase 5: External Setup Checklist

**Print before asking the user to verify anything. Group by service/platform. Only show sections for platforms in `ios, android, web`.**

### Format for console/service steps (numbered list):

```markdown
### Firebase (backend: Supabase)
- [ ] 1. Open Firebase Console → [exact menu path]
- [ ] 2. [Specific action]
- [ ] 3. Download updated config file → place at [exact path]
```

### Format for native platform steps (table):

```markdown
### iOS Setup
| Step | Where | What | How to Verify |
|------|-------|------|---------------|
| [Step name] | [Xcode location / file path] | [Exact change] | [Verification method] |
```

```markdown
### Android Setup
- [ ] 1. Open `android/app/src/main/AndroidManifest.xml`
  - Add: `<uses-permission android:name="[permission]"/>`
- [ ] 2. [Next step with exact value]
```

### Flavor scoping note (flavors: dev, prod)

Config files and API keys must be scoped per flavor. Never place production keys in `dev` flavor files. Follow the pattern established in `.cursor/rules/` for flavor-based configuration.

---

## Phase 6: Verification Gate

> **Invoke skill: `superpowers:verification-before-completion`**

**Do not claim completion without pasting real output for every item below.**

```
VERIFICATION REQUIRED — paste real output for each:

[ ] flutter test test/features/[feature]/ --no-pub
    Required: "All N tests passed."

[ ] flutter analyze
    Required: "No issues found!"

[ ] Integration test device output (from Phase 4 pause gate)
    Required: actual device test output

[ ] lefthook run pre-commit
    Required: all hooks passed
```

If any check fails: invoke `superpowers:systematic-debugging` to diagnose before retrying.
For noisy errors or weak reproduction, run **`/debug`** and fill the BugReport skeleton with logs before retrying.
For small, isolated changes, **`/verify`** is enough to re-check tests and analyze without re-reading this whole skill.
Do not proceed to Phase 7 until all four checks are green.

---

## Phase 7: PR Preparation

> **Invoke skill: `superpowers:finishing-a-development-branch`**

1. **Commit message** (conventional commits format):
   ```
   feat([feature_type]): implement [feature] end-to-end
   ```

2. **PR description template:**
   ```markdown
   ## What
   [One sentence: what feature was implemented]

   ## Test coverage
   - Unit/widget tests: N passing
   - Integration test matrix:
     | Scenario | iOS | Android |
     |----------|-----|---------|
     | [scenario] | ✅ | ✅ |

   ## External setup completed
   - [ ] [Service 1 setup]
   - [ ] [Service 2 setup]

   ## Notes
   [Any follow-up TODOs or known limitations]
   ```

3. **CI/CD advice for GitHub Actions (github_actions):**
   Ensure workflow secrets are scoped per flavor (dev, prod). Never expose production keys in dev environment secrets. Verify the CI workflow runs `flutter test` and `flutter analyze` before deploy steps.

---

## Rules applied every phase

Always active — read before writing any code:
- `.cursor/rules/flutter-core.mdc`
- `.cursor/rules/security-standards.mdc`
- `.cursor/rules/project-context.mdc`
- Feature-type-specific rules from `FEATURE_REGISTRY.rules_to_load`

Architecture import rules for **Feature-First**:
- features/auth/ MUST NOT import from features/home/ etc.
- Shared code lives in core/ or shared/ only
- Each feature is self-contained: screen + provider + model + repo

---

## Code generation notes

**Codegen tools configured: freezed, json_serializable**

After adding any new model or injectable class, run:
```
dart run build_runner build --delete-conflicting-outputs
```

Commit generated files (`.g.dart`, `.freezed.dart`, `injection.config.dart`) — do not gitignore them.

**Template version:** 1.0.5
