diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..03b86d2
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1,9 @@
+# Flutter/Dart
+.dart_tool/
+build/
+.flutter-plugins
+.flutter-plugins-dependencies
+*.iml
+.idea/
+# 系统
+.DS_Store
diff --git a/app/.metadata b/app/.metadata
new file mode 100644
index 0000000..ea0a198
--- /dev/null
+++ b/app/.metadata
@@ -0,0 +1,45 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+ revision: "058e0af2c2b57e369d905a03ac9748b0ebf543c6"
+ channel: "stable"
+
+project_type: app
+
+# Tracks metadata for the flutter migrate command
+migration:
+ platforms:
+ - platform: root
+ create_revision: 058e0af2c2b57e369d905a03ac9748b0ebf543c6
+ base_revision: 058e0af2c2b57e369d905a03ac9748b0ebf543c6
+ - platform: android
+ create_revision: 058e0af2c2b57e369d905a03ac9748b0ebf543c6
+ base_revision: 058e0af2c2b57e369d905a03ac9748b0ebf543c6
+ - platform: ios
+ create_revision: 058e0af2c2b57e369d905a03ac9748b0ebf543c6
+ base_revision: 058e0af2c2b57e369d905a03ac9748b0ebf543c6
+ - platform: linux
+ create_revision: 058e0af2c2b57e369d905a03ac9748b0ebf543c6
+ base_revision: 058e0af2c2b57e369d905a03ac9748b0ebf543c6
+ - platform: macos
+ create_revision: 058e0af2c2b57e369d905a03ac9748b0ebf543c6
+ base_revision: 058e0af2c2b57e369d905a03ac9748b0ebf543c6
+ - platform: web
+ create_revision: 058e0af2c2b57e369d905a03ac9748b0ebf543c6
+ base_revision: 058e0af2c2b57e369d905a03ac9748b0ebf543c6
+ - platform: windows
+ create_revision: 058e0af2c2b57e369d905a03ac9748b0ebf543c6
+ base_revision: 058e0af2c2b57e369d905a03ac9748b0ebf543c6
+
+ # User provided section
+
+ # List of Local paths (relative to this file) that should be
+ # ignored by the migrate tool.
+ #
+ # Files that are not part of the templates will be ignored by default.
+ unmanaged_files:
+ - 'lib/main.dart'
+ - 'ios/Runner.xcodeproj/project.pbxproj'
diff --git a/app/README.md b/app/README.md
new file mode 100644
index 0000000..8ddca5b
--- /dev/null
+++ b/app/README.md
@@ -0,0 +1,17 @@
+# slogan_app
+
+A new Flutter project.
+
+## Getting Started
+
+This project is a starting point for a Flutter application.
+
+A few resources to get you started if this is your first Flutter project:
+
+- [Learn Flutter](https://docs.flutter.dev/get-started/learn-flutter)
+- [Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
+- [Flutter learning resources](https://docs.flutter.dev/reference/learning-resources)
+
+For help getting started with Flutter development, view the
+[online documentation](https://docs.flutter.dev/), which offers tutorials,
+samples, guidance on mobile development, and a full API reference.
diff --git a/app/analysis_options.yaml b/app/analysis_options.yaml
new file mode 100644
index 0000000..0d29021
--- /dev/null
+++ b/app/analysis_options.yaml
@@ -0,0 +1,28 @@
+# This file configures the analyzer, which statically analyzes Dart code to
+# check for errors, warnings, and lints.
+#
+# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
+# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
+# invoked from the command line by running `flutter analyze`.
+
+# The following line activates a set of recommended lints for Flutter apps,
+# packages, and plugins designed to encourage good coding practices.
+include: package:flutter_lints/flutter.yaml
+
+linter:
+ # The lint rules applied to this project can be customized in the
+ # section below to disable rules from the `package:flutter_lints/flutter.yaml`
+ # included above or to enable additional rules. A list of all available lints
+ # and their documentation is published at https://dart.dev/lints.
+ #
+ # Instead of disabling a lint rule for the entire project in the
+ # section below, it can also be suppressed for a single line of code
+ # or a specific dart file by using the `// ignore: name_of_lint` and
+ # `// ignore_for_file: name_of_lint` syntax on the line or in the file
+ # producing the lint.
+ rules:
+ # avoid_print: false # Uncomment to disable the `avoid_print` rule
+ # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options
diff --git a/app/android/.gitignore b/app/android/.gitignore
new file mode 100644
index 0000000..be3943c
--- /dev/null
+++ b/app/android/.gitignore
@@ -0,0 +1,14 @@
+gradle-wrapper.jar
+/.gradle
+/captures/
+/gradlew
+/gradlew.bat
+/local.properties
+GeneratedPluginRegistrant.java
+.cxx/
+
+# Remember to never publicly share your keystore.
+# See https://flutter.dev/to/reference-keystore
+key.properties
+**/*.keystore
+**/*.jks
diff --git a/app/android/app/build.gradle.kts b/app/android/app/build.gradle.kts
new file mode 100644
index 0000000..0346753
--- /dev/null
+++ b/app/android/app/build.gradle.kts
@@ -0,0 +1,45 @@
+plugins {
+ id("com.android.application")
+ // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
+ id("dev.flutter.flutter-gradle-plugin")
+}
+
+android {
+ namespace = "com.slogan.slogan_app"
+ compileSdk = flutter.compileSdkVersion
+ ndkVersion = flutter.ndkVersion
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+
+ defaultConfig {
+ // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
+ applicationId = "com.slogan.slogan_app"
+ // You can update the following values to match your application needs.
+ // For more information, see: https://flutter.dev/to/review-gradle-config.
+ minSdk = flutter.minSdkVersion
+ targetSdk = flutter.targetSdkVersion
+ versionCode = flutter.versionCode
+ versionName = flutter.versionName
+ }
+
+ buildTypes {
+ release {
+ // TODO: Add your own signing config for the release build.
+ // Signing with the debug keys for now, so `flutter run --release` works.
+ signingConfig = signingConfigs.getByName("debug")
+ }
+ }
+}
+
+kotlin {
+ compilerOptions {
+ jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
+ }
+}
+
+flutter {
+ source = "../.."
+}
diff --git a/app/android/app/src/debug/AndroidManifest.xml b/app/android/app/src/debug/AndroidManifest.xml
new file mode 100644
index 0000000..399f698
--- /dev/null
+++ b/app/android/app/src/debug/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/app/android/app/src/main/AndroidManifest.xml b/app/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..d01b264
--- /dev/null
+++ b/app/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/android/app/src/main/kotlin/com/slogan/slogan_app/MainActivity.kt b/app/android/app/src/main/kotlin/com/slogan/slogan_app/MainActivity.kt
new file mode 100644
index 0000000..b68d5d5
--- /dev/null
+++ b/app/android/app/src/main/kotlin/com/slogan/slogan_app/MainActivity.kt
@@ -0,0 +1,5 @@
+package com.slogan.slogan_app
+
+import io.flutter.embedding.android.FlutterActivity
+
+class MainActivity : FlutterActivity()
diff --git a/app/android/app/src/main/res/drawable-v21/launch_background.xml b/app/android/app/src/main/res/drawable-v21/launch_background.xml
new file mode 100644
index 0000000..f74085f
--- /dev/null
+++ b/app/android/app/src/main/res/drawable-v21/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/app/android/app/src/main/res/drawable/launch_background.xml b/app/android/app/src/main/res/drawable/launch_background.xml
new file mode 100644
index 0000000..304732f
--- /dev/null
+++ b/app/android/app/src/main/res/drawable/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..db77bb4
Binary files /dev/null and b/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..17987b7
Binary files /dev/null and b/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..09d4391
Binary files /dev/null and b/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..d5f1c8d
Binary files /dev/null and b/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..4d6372e
Binary files /dev/null and b/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/android/app/src/main/res/values-night/styles.xml b/app/android/app/src/main/res/values-night/styles.xml
new file mode 100644
index 0000000..06952be
--- /dev/null
+++ b/app/android/app/src/main/res/values-night/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/app/android/app/src/main/res/values/styles.xml b/app/android/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..cb1ef88
--- /dev/null
+++ b/app/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/app/android/app/src/profile/AndroidManifest.xml b/app/android/app/src/profile/AndroidManifest.xml
new file mode 100644
index 0000000..399f698
--- /dev/null
+++ b/app/android/app/src/profile/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/app/android/build.gradle.kts b/app/android/build.gradle.kts
new file mode 100644
index 0000000..dbee657
--- /dev/null
+++ b/app/android/build.gradle.kts
@@ -0,0 +1,24 @@
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+val newBuildDir: Directory =
+ rootProject.layout.buildDirectory
+ .dir("../../build")
+ .get()
+rootProject.layout.buildDirectory.value(newBuildDir)
+
+subprojects {
+ val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
+ project.layout.buildDirectory.value(newSubprojectBuildDir)
+}
+subprojects {
+ project.evaluationDependsOn(":app")
+}
+
+tasks.register("clean") {
+ delete(rootProject.layout.buildDirectory)
+}
diff --git a/app/android/gradle.properties b/app/android/gradle.properties
new file mode 100644
index 0000000..e96108c
--- /dev/null
+++ b/app/android/gradle.properties
@@ -0,0 +1,6 @@
+org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
+android.useAndroidX=true
+# This newDsl flag was added by the Flutter template
+android.newDsl=false
+# This builtInKotlin flag was added by the Flutter template
+android.builtInKotlin=false
diff --git a/app/android/gradle/wrapper/gradle-wrapper.properties b/app/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..2d428bf
--- /dev/null
+++ b/app/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-all.zip
diff --git a/app/android/settings.gradle.kts b/app/android/settings.gradle.kts
new file mode 100644
index 0000000..c21f0c5
--- /dev/null
+++ b/app/android/settings.gradle.kts
@@ -0,0 +1,26 @@
+pluginManagement {
+ val flutterSdkPath =
+ run {
+ val properties = java.util.Properties()
+ file("local.properties").inputStream().use { properties.load(it) }
+ val flutterSdkPath = properties.getProperty("flutter.sdk")
+ require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
+ flutterSdkPath
+ }
+
+ includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
+
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+
+plugins {
+ id("dev.flutter.flutter-plugin-loader") version "1.0.0"
+ id("com.android.application") version "9.0.1" apply false
+ id("org.jetbrains.kotlin.android") version "2.3.20" apply false
+}
+
+include(":app")
diff --git a/app/docs/superpowers/plans/2026-07-31-commerce-p0-app.md b/app/docs/superpowers/plans/2026-07-31-commerce-p0-app.md
new file mode 100644
index 0000000..7cdbdc6
--- /dev/null
+++ b/app/docs/superpowers/plans/2026-07-31-commerce-p0-app.md
@@ -0,0 +1,969 @@
+# 商业化 P0 实现计划(客户端)· slogan-app
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** 会员中心(套餐展示 → 下单 → 系统浏览器支付 → 轮询确认)+ 广告激励入口(Mock 激励视频 → 领取加次/体验会员),后端未配置时接口报错自动隐藏充值入口。
+
+**Architecture:** /commercial 页重构为会员中心(home 第 4 Tab 与路由都指向它)。新增 `lib/core/ads/`(AdsService 抽象 + Mock 实现,P1 换穿山甲)、`lib/features/member/`(provider + 会员中心页 + 支付页)。支付用 `url_launcher` 打开系统浏览器,`/pay` 页 2s 轮询订单状态(60s 上限),成功后刷新会员状态。iOS 端隐藏充值入口(App Store 政策),保留广告激励。
+
+**Tech Stack:** Flutter 3.44 / Riverpod 3 / go_router 17 / dio 5 / url_launcher ^6.3.0
+
+**关联 spec:** `docs/superpowers/specs/2026-07-31-commerce-monetization-design.md` 支柱 A/B 客户端部分。
+
+**验证方式(沿用 MVP 惯例):** `dart analyze`(中文路径下 flutter analyze 崩溃)、`flutter test`、`flutter build web --release` 全量编译、mock 后端冒烟。
+
+---
+
+## 任务总览与文件映射
+
+| 任务 | 文件 |
+|---|---|
+| T1 | `pubspec.yaml`、`lib/core/ads/ads_service.dart`、`test/features/member/benefits_test.dart` |
+| T2 | `lib/features/member/member_provider.dart` |
+| T3 | `lib/features/member/member_center_page.dart`(新建)、`lib/features/commercial/commercial_page.dart`(删除)、`lib/features/home/home_page.dart`、`lib/main.dart` |
+| T4 | `lib/features/member/pay_page.dart`、`lib/main.dart` 路由 |
+| T5 | analyze + test + build + 冒烟 |
+
+---
+
+### Task 1: url_launcher 依赖 + 广告抽象 + 权益文案纯函数(TDD)
+
+**Files:**
+- Modify: `pubspec.yaml`
+- Create: `lib/core/ads/ads_service.dart`
+- Test: `test/features/member/benefits_test.dart`
+
+- [ ] **Step 1: 写失败测试**(权益 key → 中文文案;benefitTexts 尚未存在)
+
+`test/features/member/benefits_test.dart`:
+```dart
+import 'package:flutter_test/flutter_test.dart';
+import 'package:slogan_app/features/member/member_provider.dart';
+
+void main() {
+ test('benefitTexts 映射已知权益文案,未知 key 原样保留', () {
+ final info = MemberInfo(
+ isVip: true,
+ expireAt: '2026-08-30 12:00:00',
+ planName: '月卡',
+ benefits: const ['effect_unlimited', 'unknown_key'],
+ );
+ expect(benefitTexts(info), ['无限效果图', 'unknown_key']);
+ });
+
+ test('benefitTexts 空权益返回空列表', () {
+ final info = MemberInfo(
+ isVip: false,
+ expireAt: '',
+ planName: '',
+ benefits: const [],
+ );
+ expect(benefitTexts(info), isEmpty);
+ });
+}
+```
+
+- [ ] **Step 2: 运行确认失败**
+
+Run: `dart analyze lib test 2>&1 | head -5` Expected: 报 `member_provider.dart` 不存在 / import 失败
+
+- [ ] **Step 3: pubspec 加 url_launcher**
+
+```yaml
+ url_launcher: ^6.3.0
+```
+
+- [ ] **Step 4: 广告抽象 `lib/core/ads/ads_service.dart`**
+
+```dart
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+/// 广告服务抽象:P0 用 Mock(保证业务链路可开发可测),P1 换穿山甲 SDK
+abstract class AdsService {
+ bool get enabled;
+ Future showRewarded();
+}
+
+/// 本地模拟激励视频(约 1 秒"播放"后返回完整观看)
+class MockAdsService implements AdsService {
+ @override
+ bool get enabled => true;
+
+ @override
+ Future showRewarded() async {
+ await Future.delayed(const Duration(milliseconds: 900));
+ return true;
+ }
+}
+
+final adsServiceProvider = Provider((ref) {
+ // P1:AppConfig.pangleAppId 非空时替换为 PangleAdsService(穿山甲 SDK 实现)
+ return MockAdsService();
+});
+```
+
+- [ ] **Step 5: 提交**
+
+```bash
+git add pubspec.yaml lib/core/ads test/features/member
+git commit -m "feat: 广告服务抽象(Mock 激励视频)+ url_launcher 依赖"
+```
+
+---
+
+### Task 2: member provider(会员状态/套餐/下单/轮询/领奖)
+
+**Files:**
+- Create: `lib/features/member/member_provider.dart`
+
+- [ ] **Step 1: 实现 member_provider.dart**(含 Task 1 测试依赖的 `MemberInfo` 与 `benefitTexts`)
+
+```dart
+import 'dart:convert';
+
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+import '../../core/network/api_client.dart';
+
+class MemberInfo {
+ final bool isVip;
+ final String expireAt;
+ final String planName;
+ final List benefits;
+
+ const MemberInfo({
+ required this.isVip,
+ required this.expireAt,
+ required this.planName,
+ required this.benefits,
+ });
+
+ factory MemberInfo.fromJson(Map e) => MemberInfo(
+ isVip: e['is_vip'] as bool? ?? false,
+ expireAt: e['expire_at'] as String? ?? '',
+ planName: e['plan_name'] as String? ?? '',
+ benefits: (e['benefits'] as List? ?? []).cast(),
+ );
+}
+
+/// 权益 key → 文案
+const benefitLabels = {
+ 'effect_unlimited': '无限效果图',
+ 'ai_priority': '优先 AI 方案',
+ 'cps_commission_x15': '返现加成 1.5x',
+ 'store_discount': '门店折扣',
+};
+
+List benefitTexts(MemberInfo m) =>
+ m.benefits.map((b) => benefitLabels[b] ?? b).toList();
+
+class MemberNotifier extends AsyncNotifier {
+ @override
+ Future build() async {
+ final api = ref.read(apiClientProvider);
+ final data = await api.get