skill-service 0.2.0__tar.gz

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.
Files changed (118) hide show
  1. skill_service-0.2.0/.env.example +57 -0
  2. skill_service-0.2.0/.gitignore +65 -0
  3. skill_service-0.2.0/Dockerfile +11 -0
  4. skill_service-0.2.0/PKG-INFO +73 -0
  5. skill_service-0.2.0/README.md +55 -0
  6. skill_service-0.2.0/alembic/versions/0001_init_skills.sql +40 -0
  7. skill_service-0.2.0/alembic/versions/0002_wallet_and_billing.sql +74 -0
  8. skill_service-0.2.0/alembic/versions/0003_recharge_and_payments.sql +53 -0
  9. skill_service-0.2.0/alembic/versions/0004_subscriptions.sql +26 -0
  10. skill_service-0.2.0/alembic/versions/0005_admin_config_logs.sql +19 -0
  11. skill_service-0.2.0/alembic/versions/0006_sessions.sql +15 -0
  12. skill_service-0.2.0/alembic/versions/0007_order_pay_params.sql +9 -0
  13. skill_service-0.2.0/alembic/versions/0008_subscription_stripe.sql +48 -0
  14. skill_service-0.2.0/alembic/versions/0009_subscription_billing_period.sql +5 -0
  15. skill_service-0.2.0/alembic/versions/0010_subscription_stripe_unique.sql +5 -0
  16. skill_service-0.2.0/alembic/versions/0011_subscription_constraints.sql +25 -0
  17. skill_service-0.2.0/deploy/.env.live.example +35 -0
  18. skill_service-0.2.0/deploy/nginx/skill.deinai.ai.conf +60 -0
  19. skill_service-0.2.0/deploy/nginx/skill.prod.conf +66 -0
  20. skill_service-0.2.0/deploy/nginx/skill.test.conf +104 -0
  21. skill_service-0.2.0/deploy/scripts/deploy-test-server.ps1 +37 -0
  22. skill_service-0.2.0/deploy/scripts/deploy-test-server.sh +69 -0
  23. skill_service-0.2.0/docker-compose.dev.yml +65 -0
  24. skill_service-0.2.0/docker-compose.prod.yml +25 -0
  25. skill_service-0.2.0/docker-compose.yml +24 -0
  26. skill_service-0.2.0/docs/DEPLOY_CHECKLIST.md +343 -0
  27. skill_service-0.2.0/docs/DeiNai_SKILL_/344/272/244/344/273/230/347/211/251/350/257/264/346/230/216.txt +122 -0
  28. skill_service-0.2.0/docs/OPENCLAW_E2E_TEST.md +193 -0
  29. skill_service-0.2.0/docs/PAYMENT_CALLBACKS.md +204 -0
  30. skill_service-0.2.0/docs/PAYMENT_LIVE_SETUP.md +200 -0
  31. skill_service-0.2.0/docs/PAYMENT_STRIPE.md +119 -0
  32. skill_service-0.2.0/docs/PRODUCTION_RELEASE.md +482 -0
  33. skill_service-0.2.0/docs/SCRIPTS.md +397 -0
  34. skill_service-0.2.0/main.py +9 -0
  35. skill_service-0.2.0/output/registry/.gitignore +2 -0
  36. skill_service-0.2.0/output/registry/IMPLEMENTATION.md +36 -0
  37. skill_service-0.2.0/output/registry/PUBLISH.md +97 -0
  38. skill_service-0.2.0/output/registry/README.md +122 -0
  39. skill_service-0.2.0/output/registry/server.json +50 -0
  40. skill_service-0.2.0/output/registry/server.json.legacy-backend.json +50 -0
  41. skill_service-0.2.0/output/registry/server.json.md +29 -0
  42. skill_service-0.2.0/pyproject.toml +29 -0
  43. skill_service-0.2.0/scripts/deploy_prod_server.py +208 -0
  44. skill_service-0.2.0/scripts/init_db.py +55 -0
  45. skill_service-0.2.0/scripts/prod_test_account_flow.py +340 -0
  46. skill_service-0.2.0/scripts/seed_dev_account.py +108 -0
  47. skill_service-0.2.0/scripts/sync_prod_stripe_plans.py +221 -0
  48. skill_service-0.2.0/skill_service/__init__.py +2 -0
  49. skill_service-0.2.0/skill_service/api/__init__.py +2 -0
  50. skill_service-0.2.0/skill_service/api/authz.py +16 -0
  51. skill_service-0.2.0/skill_service/api/middleware/__init__.py +2 -0
  52. skill_service-0.2.0/skill_service/api/middleware/skill_auth.py +125 -0
  53. skill_service-0.2.0/skill_service/api/routes/__init__.py +28 -0
  54. skill_service-0.2.0/skill_service/api/routes/admin.py +103 -0
  55. skill_service-0.2.0/skill_service/api/routes/auth.py +74 -0
  56. skill_service-0.2.0/skill_service/api/routes/locations.py +36 -0
  57. skill_service-0.2.0/skill_service/api/routes/payments.py +181 -0
  58. skill_service-0.2.0/skill_service/api/routes/portal.py +37 -0
  59. skill_service-0.2.0/skill_service/api/routes/recharge.py +66 -0
  60. skill_service-0.2.0/skill_service/api/routes/search.py +106 -0
  61. skill_service-0.2.0/skill_service/api/routes/subscriptions.py +179 -0
  62. skill_service-0.2.0/skill_service/api/routes/tokens.py +67 -0
  63. skill_service-0.2.0/skill_service/api/routes/wallet.py +90 -0
  64. skill_service-0.2.0/skill_service/app.py +62 -0
  65. skill_service-0.2.0/skill_service/config/__init__.py +2 -0
  66. skill_service-0.2.0/skill_service/config/settings.py +66 -0
  67. skill_service-0.2.0/skill_service/db.py +72 -0
  68. skill_service-0.2.0/skill_service/integrations/__init__.py +2 -0
  69. skill_service-0.2.0/skill_service/integrations/modash/__init__.py +2 -0
  70. skill_service-0.2.0/skill_service/integrations/modash/client.py +119 -0
  71. skill_service-0.2.0/skill_service/integrations/modash/types.py +189 -0
  72. skill_service-0.2.0/skill_service/integrations/payments/alipay_notify.py +68 -0
  73. skill_service-0.2.0/skill_service/integrations/payments/alipay_qr.py +79 -0
  74. skill_service-0.2.0/skill_service/integrations/payments/base.py +23 -0
  75. skill_service-0.2.0/skill_service/integrations/payments/config_status.py +98 -0
  76. skill_service-0.2.0/skill_service/integrations/payments/mock_provider.py +33 -0
  77. skill_service-0.2.0/skill_service/integrations/payments/notify_urls.py +12 -0
  78. skill_service-0.2.0/skill_service/integrations/payments/pem_util.py +12 -0
  79. skill_service-0.2.0/skill_service/integrations/payments/providers.py +174 -0
  80. skill_service-0.2.0/skill_service/integrations/payments/stripe_checkout.py +65 -0
  81. skill_service-0.2.0/skill_service/integrations/payments/stripe_notify.py +70 -0
  82. skill_service-0.2.0/skill_service/integrations/payments/stripe_subscription.py +88 -0
  83. skill_service-0.2.0/skill_service/integrations/payments/wechat_v3.py +83 -0
  84. skill_service-0.2.0/skill_service/integrations/payments/wechat_v3_notify.py +100 -0
  85. skill_service-0.2.0/skill_service/mcp/__init__.py +2 -0
  86. skill_service-0.2.0/skill_service/mcp/match.py +51 -0
  87. skill_service-0.2.0/skill_service/mcp/models/__init__.py +2 -0
  88. skill_service-0.2.0/skill_service/mcp/models/common.py +13 -0
  89. skill_service-0.2.0/skill_service/mcp/models/get_location_ids.py +12 -0
  90. skill_service-0.2.0/skill_service/mcp/models/search_influencers.py +88 -0
  91. skill_service-0.2.0/skill_service/mcp/server.py +35 -0
  92. skill_service-0.2.0/skill_service/mcp/tools/__init__.py +10 -0
  93. skill_service-0.2.0/skill_service/mcp/tools/common.py +21 -0
  94. skill_service-0.2.0/skill_service/mcp/tools/get_location_ids.py +48 -0
  95. skill_service-0.2.0/skill_service/mcp/tools/search_influencers.py +113 -0
  96. skill_service-0.2.0/skill_service/portal/static/checkout.html +137 -0
  97. skill_service-0.2.0/skill_service/portal/static/common.css +154 -0
  98. skill_service-0.2.0/skill_service/portal/static/index.html +21 -0
  99. skill_service-0.2.0/skill_service/portal/static/login.html +38 -0
  100. skill_service-0.2.0/skill_service/portal/static/mock-checkout.html +37 -0
  101. skill_service-0.2.0/skill_service/portal/static/recharge.html +12 -0
  102. skill_service-0.2.0/skill_service/portal/static/subscription.html +330 -0
  103. skill_service-0.2.0/skill_service/portal/static/tokens.html +138 -0
  104. skill_service-0.2.0/skill_service/services/__init__.py +2 -0
  105. skill_service-0.2.0/skill_service/services/admin_service.py +184 -0
  106. skill_service-0.2.0/skill_service/services/auth_service.py +105 -0
  107. skill_service-0.2.0/skill_service/services/influencer_search_executor.py +59 -0
  108. skill_service-0.2.0/skill_service/services/influencer_search_filters.py +75 -0
  109. skill_service-0.2.0/skill_service/services/location_service.py +28 -0
  110. skill_service-0.2.0/skill_service/services/payment_checkout_service.py +104 -0
  111. skill_service-0.2.0/skill_service/services/payment_security.py +29 -0
  112. skill_service-0.2.0/skill_service/services/recharge_service.py +232 -0
  113. skill_service-0.2.0/skill_service/services/search_service.py +129 -0
  114. skill_service-0.2.0/skill_service/services/session_service.py +115 -0
  115. skill_service-0.2.0/skill_service/services/subscription_errors.py +19 -0
  116. skill_service-0.2.0/skill_service/services/subscription_service.py +1524 -0
  117. skill_service-0.2.0/skill_service/services/token_service.py +101 -0
  118. skill_service-0.2.0/skill_service/services/wallet_service.py +127 -0
@@ -0,0 +1,57 @@
1
+ # Skill Service — environment template
2
+ # Copy to .env and fill in values. Do not commit .env.
3
+
4
+ # --- docker-compose.dev.yml (host-side scripts) ---
5
+ # SKILL_DATABASE_URL=postgresql://skill_app:skill_dev_pass@127.0.0.1:5433/skills
6
+ # SKILL_REDIS_URL=redis://127.0.0.1:6380/0
7
+
8
+ APP_NAME=Creator SKILL
9
+ APP_VERSION=0.2.0
10
+ SKILL_HTTP_PORT=8080
11
+
12
+ SKILL_DATABASE_URL=postgresql://skill_app:CHANGE_ME@127.0.0.1:5432/skills
13
+ SKILL_DATABASE_NAME=skills
14
+ SKILL_REDIS_URL=redis://:CHANGE_ME@127.0.0.1:6379/0
15
+
16
+ MODASH_API_KEY=
17
+ MODASH_BASE_URL=https://api.modash.io/v1
18
+ MODASH_TIMEOUT=30
19
+ MODASH_MAX_RETRIES=3
20
+
21
+ SKILL_TOKEN_PREFIX=sk_live_
22
+ SESSION_TOKEN_PREFIX=sk_sess_
23
+ SESSION_TTL_HOURS=24
24
+
25
+ PAYMENT_MODE=mock
26
+ # live 时建议 false,避免凭证缺失却走 mock
27
+ PAYMENT_ALLOW_MOCK_FALLBACK=false
28
+
29
+ SKILL_PUBLIC_BASE_URL=http://127.0.0.1:8080
30
+
31
+ # --- WeChat Pay API v3 ---
32
+ WECHAT_APP_ID=
33
+ WECHAT_MCH_ID=
34
+ WECHAT_MCH_SERIAL_NO=
35
+ WECHAT_MCH_PRIVATE_KEY=
36
+ WECHAT_MCH_PRIVATE_KEY_PATH=
37
+ WECHAT_API_V3_KEY=
38
+ WECHAT_PLATFORM_PUBLIC_KEY=
39
+
40
+ # --- Alipay ---
41
+ ALIPAY_APP_ID=
42
+ ALIPAY_PRIVATE_KEY=
43
+ ALIPAY_PRIVATE_KEY_PATH=
44
+ ALIPAY_PUBLIC_KEY=
45
+ ALIPAY_GATEWAY_URL=https://openapi.alipay.com/gateway.do
46
+
47
+ STRIPE_SECRET_KEY=
48
+ STRIPE_WEBHOOK_SECRET=
49
+ STRIPE_PUBLISHABLE_KEY=
50
+ STRIPE_CURRENCY=cny
51
+
52
+ # OpenClaw test-only: enables POST /api/v1/subscriptions/automation/complete-checkout
53
+ # SKILL_OPENCLAW_AUTOMATION_KEY=
54
+
55
+ # mock / dev HMAC callbacks (optional)
56
+ WECHAT_NOTIFY_SECRET=
57
+ ALIPAY_NOTIFY_SECRET=
@@ -0,0 +1,65 @@
1
+ # --- Secrets & local config (never commit) ---
2
+ .env
3
+ .env_prod
4
+ prod.yaml
5
+ deploy/.env.test-server
6
+ secrets/
7
+
8
+ # --- Python ---
9
+ .venv/
10
+ __pycache__/
11
+ *.py[cod]
12
+ *$py.class
13
+ *.egg-info/
14
+ .eggs/
15
+ dist/
16
+ build/
17
+ .pytest_cache/
18
+ .mypy_cache/
19
+ .ruff_cache/
20
+
21
+ # --- Build / deploy artifacts ---
22
+ *.tgz
23
+ deploy.tgz
24
+ deploy-sync.tgz
25
+ skill-service-deploy.tgz
26
+
27
+ # --- scripts/: only init_db + seed_dev_account go to remote ---
28
+ scripts/*
29
+ !scripts/init_db.py
30
+ !scripts/seed_dev_account.py
31
+ !scripts/deploy_prod_server.py
32
+ !scripts/sync_prod_stripe_plans.py
33
+ !scripts/prod_test_account_flow.py
34
+
35
+ # --- Tests (local only) ---
36
+ tests/
37
+
38
+ # --- Dev / E2E docs (see docs/SCRIPTS.md for script index) ---
39
+ docs/CI_SMOKE.md
40
+ docs/CURSOR_DEBUG.md
41
+ docs/PAYMENT_E2E_TEST.md
42
+ docs/SUBSCRIPTION_E2E_TEST.md
43
+ docs/STRIPE_TEST_ENV_SETUP.md
44
+ docs/PLAN.md
45
+
46
+ # --- CI workflow (needs remote smoke secrets) ---
47
+ .github/
48
+
49
+ # --- Dev-only compose ---
50
+ docker-compose.test-deploy.yml
51
+
52
+ # --- Registry local publish helpers ---
53
+ output/registry/publish-registry.cmd
54
+ output/registry/publish-registry.ps1
55
+
56
+ # --- Logs ---
57
+ *.log
58
+
59
+ # --- IDE / OS ---
60
+ .idea/
61
+ .vscode/
62
+ *.swp
63
+ *~
64
+ .DS_Store
65
+ Thumbs.db
@@ -0,0 +1,11 @@
1
+ FROM python:3.11-slim
2
+
3
+ WORKDIR /app
4
+ COPY . /app
5
+
6
+ RUN pip install --no-cache-dir --upgrade pip && \
7
+ pip install --no-cache-dir .
8
+
9
+ EXPOSE 8080
10
+
11
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]
@@ -0,0 +1,73 @@
1
+ Metadata-Version: 2.4
2
+ Name: skill-service
3
+ Version: 0.2.0
4
+ Summary: Standalone Creator SKILL MCP service
5
+ Requires-Python: >=3.11
6
+ Requires-Dist: asyncpg>=0.29.0
7
+ Requires-Dist: cryptography>=42.0.0
8
+ Requires-Dist: email-validator>=2.2.0
9
+ Requires-Dist: fastapi>=0.115.0
10
+ Requires-Dist: fastmcp<4,>=3.3.1
11
+ Requires-Dist: httpx>=0.27.0
12
+ Requires-Dist: loguru>=0.7.2
13
+ Requires-Dist: pydantic-settings>=2.3.0
14
+ Requires-Dist: pydantic>=2.8.0
15
+ Requires-Dist: stripe>=10.0.0
16
+ Requires-Dist: uvicorn>=0.30.0
17
+ Description-Content-Type: text/markdown
18
+
19
+ # skill-service
20
+
21
+ Standalone Creator SKILL service — MCP + REST API + independent billing.
22
+
23
+ <!-- mcp-name: ai.deinai/creator-skill-v2 -->
24
+
25
+ ## Quick start
26
+
27
+ ```bash
28
+ cd apps/skill-service
29
+ python -m venv .venv
30
+ .venv/Scripts/python -m pip install -U pip
31
+ .venv/Scripts/pip install -e .
32
+ cp .env.example .env # edit database / modash keys
33
+ .venv/Scripts/python scripts/init_db.py
34
+ .venv/Scripts/python scripts/seed_dev_account.py --email dev@demo.com --password "12345678" --credits 5000
35
+ .venv/Scripts/python main.py
36
+ ```
37
+
38
+ Health: `GET http://127.0.0.1:8080/health`
39
+ MCP: `http://127.0.0.1:8080/mcp` (Bearer `sk_live_...`)
40
+
41
+ ## Production
42
+
43
+ - **Release (Stripe only)**: [docs/PRODUCTION_RELEASE.md](docs/PRODUCTION_RELEASE.md)
44
+ - **Prod deploy script**: `python scripts/deploy_prod_server.py` (uses `prod.yaml` + `.env_prod`)
45
+ - Deploy: [docs/DEPLOY_CHECKLIST.md](docs/DEPLOY_CHECKLIST.md)
46
+ - Local dev: `docker compose -f docker-compose.dev.yml up -d --build` or `scripts/dev_up.ps1 -Build`
47
+ - Payments: [docs/PAYMENT_CALLBACKS.md](docs/PAYMENT_CALLBACKS.md)
48
+ - Payment E2E (Plan A/C): [docs/PAYMENT_E2E_TEST.md](docs/PAYMENT_E2E_TEST.md)
49
+ - Subscription E2E: [docs/SUBSCRIPTION_E2E_TEST.md](docs/SUBSCRIPTION_E2E_TEST.md)
50
+ - **OpenClaw + ClawHub E2E**: [docs/OPENCLAW_E2E_TEST.md](docs/OPENCLAW_E2E_TEST.md)
51
+ - **Stripe 测试环境配置**: [docs/STRIPE_TEST_ENV_SETUP.md](docs/STRIPE_TEST_ENV_SETUP.md)
52
+ - MCP Registry: [output/registry/](output/registry/)
53
+ - Coze HTTP SOP: `deinai_backend/output/coze/PATH-A-SOP.md`
54
+
55
+ ## Stdio bridge (Cursor / Claude Desktop)
56
+
57
+ ```bash
58
+ export SKILL_TOKEN="sk_live_..."
59
+ skill-service-match
60
+ # or: uvx --from skill-service skill-service-match
61
+ ```
62
+
63
+ Optional: `SKILL_MCP_URL` (default `https://skill.deinai.ai/mcp`).
64
+
65
+ ## Status
66
+
67
+ - Independent account / session (`sk_sess_`) / API token (`sk_live_`)
68
+ - Wallet, recharge, consumption ledger
69
+ - **Portal** (`/portal/`): login, recharge, mock checkout, token management
70
+ - **Payment checkout**: `POST /recharge/orders` returns `payParams` (mock / wechat / alipay)
71
+ - MCP tools: `ping`, `get_location_ids`, `searchInfluencers`
72
+ - REST: `GET /api/v1/account/status`, `POST /api/v1/search/influencers`
73
+ - Admin: credit packages, consume rules, audit logs
@@ -0,0 +1,55 @@
1
+ # skill-service
2
+
3
+ Standalone Creator SKILL service — MCP + REST API + independent billing.
4
+
5
+ <!-- mcp-name: ai.deinai/creator-skill-v2 -->
6
+
7
+ ## Quick start
8
+
9
+ ```bash
10
+ cd apps/skill-service
11
+ python -m venv .venv
12
+ .venv/Scripts/python -m pip install -U pip
13
+ .venv/Scripts/pip install -e .
14
+ cp .env.example .env # edit database / modash keys
15
+ .venv/Scripts/python scripts/init_db.py
16
+ .venv/Scripts/python scripts/seed_dev_account.py --email dev@demo.com --password "12345678" --credits 5000
17
+ .venv/Scripts/python main.py
18
+ ```
19
+
20
+ Health: `GET http://127.0.0.1:8080/health`
21
+ MCP: `http://127.0.0.1:8080/mcp` (Bearer `sk_live_...`)
22
+
23
+ ## Production
24
+
25
+ - **Release (Stripe only)**: [docs/PRODUCTION_RELEASE.md](docs/PRODUCTION_RELEASE.md)
26
+ - **Prod deploy script**: `python scripts/deploy_prod_server.py` (uses `prod.yaml` + `.env_prod`)
27
+ - Deploy: [docs/DEPLOY_CHECKLIST.md](docs/DEPLOY_CHECKLIST.md)
28
+ - Local dev: `docker compose -f docker-compose.dev.yml up -d --build` or `scripts/dev_up.ps1 -Build`
29
+ - Payments: [docs/PAYMENT_CALLBACKS.md](docs/PAYMENT_CALLBACKS.md)
30
+ - Payment E2E (Plan A/C): [docs/PAYMENT_E2E_TEST.md](docs/PAYMENT_E2E_TEST.md)
31
+ - Subscription E2E: [docs/SUBSCRIPTION_E2E_TEST.md](docs/SUBSCRIPTION_E2E_TEST.md)
32
+ - **OpenClaw + ClawHub E2E**: [docs/OPENCLAW_E2E_TEST.md](docs/OPENCLAW_E2E_TEST.md)
33
+ - **Stripe 测试环境配置**: [docs/STRIPE_TEST_ENV_SETUP.md](docs/STRIPE_TEST_ENV_SETUP.md)
34
+ - MCP Registry: [output/registry/](output/registry/)
35
+ - Coze HTTP SOP: `deinai_backend/output/coze/PATH-A-SOP.md`
36
+
37
+ ## Stdio bridge (Cursor / Claude Desktop)
38
+
39
+ ```bash
40
+ export SKILL_TOKEN="sk_live_..."
41
+ skill-service-match
42
+ # or: uvx --from skill-service skill-service-match
43
+ ```
44
+
45
+ Optional: `SKILL_MCP_URL` (default `https://skill.deinai.ai/mcp`).
46
+
47
+ ## Status
48
+
49
+ - Independent account / session (`sk_sess_`) / API token (`sk_live_`)
50
+ - Wallet, recharge, consumption ledger
51
+ - **Portal** (`/portal/`): login, recharge, mock checkout, token management
52
+ - **Payment checkout**: `POST /recharge/orders` returns `payParams` (mock / wechat / alipay)
53
+ - MCP tools: `ping`, `get_location_ids`, `searchInfluencers`
54
+ - REST: `GET /api/v1/account/status`, `POST /api/v1/search/influencers`
55
+ - Admin: credit packages, consume rules, audit logs
@@ -0,0 +1,40 @@
1
+ -- 0001_init_skills.sql
2
+ -- Minimal Phase-3 schema for DB-backed token auth.
3
+
4
+ CREATE EXTENSION IF NOT EXISTS "pgcrypto";
5
+
6
+ CREATE TABLE IF NOT EXISTS skill_accounts (
7
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
8
+ email VARCHAR UNIQUE,
9
+ password_hash VARCHAR,
10
+ display_name VARCHAR,
11
+ status VARCHAR NOT NULL DEFAULT 'active',
12
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
13
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
14
+ );
15
+
16
+ CREATE TABLE IF NOT EXISTS skill_tokens (
17
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
18
+ account_id UUID NOT NULL REFERENCES skill_accounts(id),
19
+ token_hash VARCHAR NOT NULL UNIQUE,
20
+ token_prefix VARCHAR(16) NOT NULL,
21
+ name VARCHAR,
22
+ scopes TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[],
23
+ expires_at TIMESTAMPTZ,
24
+ revoked_at TIMESTAMPTZ,
25
+ last_used_at TIMESTAMPTZ,
26
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
27
+ );
28
+
29
+ CREATE TABLE IF NOT EXISTS skill_account_roles (
30
+ account_id UUID NOT NULL REFERENCES skill_accounts(id),
31
+ role VARCHAR NOT NULL,
32
+ granted_by UUID,
33
+ granted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
34
+ PRIMARY KEY (account_id, role)
35
+ );
36
+
37
+ CREATE INDEX IF NOT EXISTS idx_skill_tokens_account_id ON skill_tokens(account_id);
38
+ CREATE INDEX IF NOT EXISTS idx_skill_tokens_revoked_at ON skill_tokens(revoked_at);
39
+ CREATE INDEX IF NOT EXISTS idx_skill_accounts_status ON skill_accounts(status);
40
+
@@ -0,0 +1,74 @@
1
+ -- 0002_wallet_and_billing.sql
2
+ -- Wallet, billing rules, and consumption records.
3
+
4
+ CREATE TABLE IF NOT EXISTS skill_wallets (
5
+ account_id UUID PRIMARY KEY REFERENCES skill_accounts(id),
6
+ balance BIGINT NOT NULL DEFAULT 0,
7
+ frozen_balance BIGINT NOT NULL DEFAULT 0,
8
+ version INT NOT NULL DEFAULT 0,
9
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
10
+ );
11
+
12
+ CREATE TABLE IF NOT EXISTS skill_pricing_rules (
13
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
14
+ feature VARCHAR NOT NULL,
15
+ unit_price INT NOT NULL,
16
+ effective_from TIMESTAMPTZ NOT NULL DEFAULT NOW(),
17
+ effective_to TIMESTAMPTZ
18
+ );
19
+
20
+ CREATE TABLE IF NOT EXISTS skill_feature_consume_rules (
21
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
22
+ feature VARCHAR UNIQUE NOT NULL,
23
+ unit_type VARCHAR NOT NULL DEFAULT 'per_result',
24
+ unit_price INT NOT NULL DEFAULT 1,
25
+ min_charge INT NOT NULL DEFAULT 0,
26
+ max_charge INT NOT NULL DEFAULT 0,
27
+ is_active BOOLEAN NOT NULL DEFAULT true,
28
+ effective_from TIMESTAMPTZ NOT NULL DEFAULT NOW(),
29
+ effective_to TIMESTAMPTZ,
30
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
31
+ );
32
+
33
+ CREATE TABLE IF NOT EXISTS skill_ledger_entries (
34
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
35
+ account_id UUID NOT NULL REFERENCES skill_accounts(id),
36
+ entry_type VARCHAR NOT NULL,
37
+ amount BIGINT NOT NULL,
38
+ balance_after BIGINT NOT NULL,
39
+ ref_type VARCHAR,
40
+ ref_id UUID,
41
+ idempotency_key VARCHAR UNIQUE,
42
+ metadata JSONB NOT NULL DEFAULT '{}'::JSONB,
43
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
44
+ );
45
+
46
+ CREATE TABLE IF NOT EXISTS skill_consumption_records (
47
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
48
+ account_id UUID NOT NULL REFERENCES skill_accounts(id),
49
+ token_id UUID REFERENCES skill_tokens(id),
50
+ tool_name VARCHAR NOT NULL,
51
+ request_id VARCHAR,
52
+ units INT NOT NULL,
53
+ unit_price INT NOT NULL,
54
+ total_cost INT NOT NULL,
55
+ ledger_entry_id UUID REFERENCES skill_ledger_entries(id),
56
+ metadata JSONB NOT NULL DEFAULT '{}'::JSONB,
57
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
58
+ );
59
+
60
+ CREATE INDEX IF NOT EXISTS idx_skill_ledger_account_id ON skill_ledger_entries(account_id);
61
+ CREATE INDEX IF NOT EXISTS idx_skill_consumption_account_id ON skill_consumption_records(account_id);
62
+
63
+ INSERT INTO skill_feature_consume_rules (feature, unit_type, unit_price, min_charge, max_charge, is_active)
64
+ VALUES ('search', 'per_result', 1, 0, 0, true)
65
+ ON CONFLICT (feature) DO NOTHING;
66
+
67
+ INSERT INTO skill_feature_consume_rules (feature, unit_type, unit_price, min_charge, max_charge, is_active)
68
+ VALUES ('get_location_ids', 'per_call', 0, 0, 0, true)
69
+ ON CONFLICT (feature) DO NOTHING;
70
+
71
+ INSERT INTO skill_feature_consume_rules (feature, unit_type, unit_price, min_charge, max_charge, is_active)
72
+ VALUES ('ping', 'per_call', 0, 0, 0, true)
73
+ ON CONFLICT (feature) DO NOTHING;
74
+
@@ -0,0 +1,53 @@
1
+ -- 0003_recharge_and_payments.sql
2
+ -- Recharge packages, orders, and payment transaction tables.
3
+
4
+ CREATE TABLE IF NOT EXISTS skill_credit_packages (
5
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
6
+ code VARCHAR UNIQUE NOT NULL,
7
+ credits INT NOT NULL,
8
+ price_cents INT NOT NULL,
9
+ list_price_cents INT,
10
+ title VARCHAR,
11
+ description VARCHAR,
12
+ is_active BOOLEAN NOT NULL DEFAULT true,
13
+ effective_from TIMESTAMPTZ NOT NULL DEFAULT NOW(),
14
+ effective_to TIMESTAMPTZ,
15
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
16
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
17
+ );
18
+
19
+ CREATE TABLE IF NOT EXISTS skill_recharge_orders (
20
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
21
+ account_id UUID NOT NULL REFERENCES skill_accounts(id),
22
+ order_no VARCHAR UNIQUE NOT NULL,
23
+ package_id UUID REFERENCES skill_credit_packages(id),
24
+ amount_cents INT NOT NULL,
25
+ credits_granted INT NOT NULL,
26
+ channel VARCHAR NOT NULL, -- wechat | alipay
27
+ status VARCHAR NOT NULL DEFAULT 'pending', -- pending | paid | closed | refunded
28
+ idempotency_key VARCHAR UNIQUE,
29
+ paid_at TIMESTAMPTZ,
30
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
31
+ );
32
+
33
+ CREATE TABLE IF NOT EXISTS skill_payment_transactions (
34
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
35
+ order_id UUID NOT NULL REFERENCES skill_recharge_orders(id),
36
+ channel VARCHAR NOT NULL,
37
+ provider_txn_id VARCHAR UNIQUE,
38
+ raw_notify JSONB NOT NULL DEFAULT '{}'::JSONB,
39
+ status VARCHAR NOT NULL,
40
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
41
+ );
42
+
43
+ CREATE INDEX IF NOT EXISTS idx_skill_recharge_orders_account_id ON skill_recharge_orders(account_id);
44
+ CREATE INDEX IF NOT EXISTS idx_skill_recharge_orders_status ON skill_recharge_orders(status);
45
+
46
+ INSERT INTO skill_credit_packages (code, credits, price_cents, title, description, is_active)
47
+ VALUES
48
+ ('D', 100, 2600, 'D 档', '入门体验,1.2 倍单价', true),
49
+ ('C', 400, 9400, 'C 档', '轻度使用,1.1 倍单价', true),
50
+ ('B', 1600, 34300, 'B 档', '标准包,基准定价', true),
51
+ ('A', 5000, 85800, 'A 档', '高频大户,8 折优惠', true)
52
+ ON CONFLICT (code) DO NOTHING;
53
+
@@ -0,0 +1,26 @@
1
+ -- 0004_subscriptions.sql
2
+ -- Minimal subscription schema for renewal gate.
3
+
4
+ CREATE TABLE IF NOT EXISTS skill_subscription_plans (
5
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
6
+ name VARCHAR NOT NULL,
7
+ price_cents INT NOT NULL,
8
+ credits_per_period INT NOT NULL,
9
+ period_days INT NOT NULL,
10
+ auto_renew BOOLEAN NOT NULL DEFAULT false
11
+ );
12
+
13
+ CREATE TABLE IF NOT EXISTS skill_subscriptions (
14
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
15
+ account_id UUID NOT NULL REFERENCES skill_accounts(id),
16
+ plan_id UUID NOT NULL REFERENCES skill_subscription_plans(id),
17
+ status VARCHAR NOT NULL DEFAULT 'active', -- active | past_due | grace | canceled | expired
18
+ current_period_start TIMESTAMPTZ NOT NULL,
19
+ current_period_end TIMESTAMPTZ NOT NULL,
20
+ auto_renew BOOLEAN NOT NULL DEFAULT false,
21
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
22
+ );
23
+
24
+ CREATE INDEX IF NOT EXISTS idx_skill_subscriptions_account_id ON skill_subscriptions(account_id);
25
+ CREATE INDEX IF NOT EXISTS idx_skill_subscriptions_status ON skill_subscriptions(status);
26
+
@@ -0,0 +1,19 @@
1
+ -- 0005_admin_config_logs.sql
2
+ -- Config change audit log for admin/ops operations.
3
+
4
+ CREATE TABLE IF NOT EXISTS skill_config_change_logs (
5
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
6
+ config_type VARCHAR NOT NULL, -- credit_package | consume_rule
7
+ config_key VARCHAR NOT NULL, -- package code or feature
8
+ action VARCHAR NOT NULL, -- create | update | enable | disable
9
+ before_value JSONB NOT NULL DEFAULT '{}'::JSONB,
10
+ after_value JSONB NOT NULL DEFAULT '{}'::JSONB,
11
+ operator_id UUID,
12
+ operator_email VARCHAR,
13
+ reason VARCHAR,
14
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
15
+ );
16
+
17
+ CREATE INDEX IF NOT EXISTS idx_skill_cfg_logs_type_key ON skill_config_change_logs(config_type, config_key);
18
+ CREATE INDEX IF NOT EXISTS idx_skill_cfg_logs_created_at ON skill_config_change_logs(created_at);
19
+
@@ -0,0 +1,15 @@
1
+ -- 0006_sessions.sql
2
+ -- Portal session tokens for account management without password on each request.
3
+
4
+ CREATE TABLE IF NOT EXISTS skill_sessions (
5
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
6
+ account_id UUID NOT NULL REFERENCES skill_accounts(id),
7
+ session_hash VARCHAR NOT NULL UNIQUE,
8
+ expires_at TIMESTAMPTZ NOT NULL,
9
+ revoked_at TIMESTAMPTZ,
10
+ last_used_at TIMESTAMPTZ,
11
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
12
+ );
13
+
14
+ CREATE INDEX IF NOT EXISTS idx_skill_sessions_account_id ON skill_sessions(account_id);
15
+ CREATE INDEX IF NOT EXISTS idx_skill_sessions_expires_at ON skill_sessions(expires_at);
@@ -0,0 +1,9 @@
1
+ -- 0007_order_pay_params.sql
2
+ -- Store gateway prepay payload on recharge orders.
3
+
4
+ ALTER TABLE skill_recharge_orders
5
+ ADD COLUMN IF NOT EXISTS pay_params JSONB NOT NULL DEFAULT '{}'::JSONB,
6
+ ADD COLUMN IF NOT EXISTS provider_prepay_id VARCHAR,
7
+ ADD COLUMN IF NOT EXISTS expires_at TIMESTAMPTZ;
8
+
9
+ CREATE INDEX IF NOT EXISTS idx_skill_recharge_orders_order_no ON skill_recharge_orders(order_no);
@@ -0,0 +1,48 @@
1
+ -- 0008_subscription_stripe.sql
2
+ -- Stripe auto-subscription plans + account linkage.
3
+
4
+ ALTER TABLE skill_subscription_plans
5
+ ADD COLUMN IF NOT EXISTS code VARCHAR,
6
+ ADD COLUMN IF NOT EXISTS stripe_product_id VARCHAR,
7
+ ADD COLUMN IF NOT EXISTS stripe_price_id_monthly VARCHAR,
8
+ ADD COLUMN IF NOT EXISTS stripe_price_id_yearly VARCHAR,
9
+ ADD COLUMN IF NOT EXISTS seats INT NOT NULL DEFAULT 1;
10
+
11
+ DO $$
12
+ BEGIN
13
+ IF NOT EXISTS (
14
+ SELECT 1 FROM pg_constraint WHERE conname = 'skill_subscription_plans_code_key'
15
+ ) THEN
16
+ ALTER TABLE skill_subscription_plans ADD CONSTRAINT skill_subscription_plans_code_key UNIQUE (code);
17
+ END IF;
18
+ END $$;
19
+
20
+ ALTER TABLE skill_subscriptions
21
+ ADD COLUMN IF NOT EXISTS stripe_subscription_id VARCHAR,
22
+ ADD COLUMN IF NOT EXISTS stripe_customer_id VARCHAR,
23
+ ADD COLUMN IF NOT EXISTS credits_period_month VARCHAR;
24
+
25
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_skill_subscriptions_stripe_sub_id
26
+ ON skill_subscriptions(stripe_subscription_id) WHERE stripe_subscription_id IS NOT NULL;
27
+
28
+ ALTER TABLE skill_recharge_orders
29
+ ADD COLUMN IF NOT EXISTS order_kind VARCHAR NOT NULL DEFAULT 'one_time',
30
+ ADD COLUMN IF NOT EXISTS plan_code VARCHAR,
31
+ ADD COLUMN IF NOT EXISTS billing_interval VARCHAR;
32
+
33
+ INSERT INTO skill_subscription_plans (
34
+ code, name, price_cents, credits_per_period, period_days, auto_renew,
35
+ stripe_product_id, stripe_price_id_monthly, seats
36
+ ) VALUES
37
+ ('starter', '基础版 Starter', 4900, 1200, 30, true, 'prod_UkTCwwK294NReq', 'price_1TkyFp1IU0S8vi06Qlg2uLdD', 3),
38
+ ('pro', '专业版 Pro', 19900, 6000, 30, true, 'prod_UkTCmMULdliGZ2', 'price_1TkyGO1IU0S8vi060XbAmbAr', 5),
39
+ ('growth', '增长版 Growth', 49900, 20000, 30, true, 'prod_UkTD5o9CVt48dU', 'price_1TkyHI1IU0S8vi06h2pdiAQd', 10)
40
+ ON CONFLICT (code) DO UPDATE SET
41
+ name = EXCLUDED.name,
42
+ price_cents = EXCLUDED.price_cents,
43
+ credits_per_period = EXCLUDED.credits_per_period,
44
+ period_days = EXCLUDED.period_days,
45
+ auto_renew = EXCLUDED.auto_renew,
46
+ stripe_product_id = EXCLUDED.stripe_product_id,
47
+ stripe_price_id_monthly = EXCLUDED.stripe_price_id_monthly,
48
+ seats = EXCLUDED.seats;
@@ -0,0 +1,5 @@
1
+ -- 0009_subscription_billing_period.sql
2
+ -- Credits follow Stripe billing period; drop calendar-month tracking.
3
+
4
+ ALTER TABLE skill_subscriptions
5
+ ADD COLUMN IF NOT EXISTS last_credit_invoice_id VARCHAR;
@@ -0,0 +1,5 @@
1
+ -- 0010_subscription_stripe_unique.sql
2
+ -- Required for idempotent subscription upserts.
3
+
4
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_skill_subscriptions_stripe_sub_id_unique
5
+ ON skill_subscriptions(stripe_subscription_id);
@@ -0,0 +1,25 @@
1
+ -- 0011_subscription_constraints.sql
2
+ -- One active subscription per account; faster pending-order lookup.
3
+
4
+ -- Keep newest billing period per account when cleaning legacy duplicates.
5
+ WITH ranked AS (
6
+ SELECT id,
7
+ ROW_NUMBER() OVER (
8
+ PARTITION BY account_id
9
+ ORDER BY current_period_end DESC NULLS LAST, created_at DESC
10
+ ) AS rn
11
+ FROM skill_subscriptions
12
+ WHERE status = 'active'
13
+ )
14
+ UPDATE skill_subscriptions s
15
+ SET status = 'canceled', auto_renew = false
16
+ FROM ranked r
17
+ WHERE s.id = r.id AND r.rn > 1;
18
+
19
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_skill_subscriptions_one_active_per_account
20
+ ON skill_subscriptions(account_id)
21
+ WHERE status = 'active';
22
+
23
+ CREATE INDEX IF NOT EXISTS idx_skill_recharge_orders_sub_pending
24
+ ON skill_recharge_orders(account_id, plan_code, status)
25
+ WHERE order_kind = 'subscription' AND status = 'pending';
@@ -0,0 +1,35 @@
1
+ # Live payment — copy to server /root/apps/skill-service/.env (merge with existing)
2
+ # See docs/PAYMENT_LIVE_SETUP.md and docs/PAYMENT_STRIPE.md
3
+
4
+ PAYMENT_MODE=live
5
+ # Do NOT set true in production unless debugging
6
+ PAYMENT_ALLOW_MOCK_FALLBACK=false
7
+
8
+ SKILL_PUBLIC_BASE_URL=http://15.135.232.100:18080
9
+
10
+ # --- WeChat Pay API v3 (Native QR) ---
11
+ WECHAT_APP_ID=
12
+ WECHAT_MCH_ID=
13
+ WECHAT_MCH_SERIAL_NO=
14
+ # Option A: PEM inline with \n
15
+ WECHAT_MCH_PRIVATE_KEY=
16
+ # Option B: mount file in container e.g. /secrets/wechat_apiclient_key.pem
17
+ WECHAT_MCH_PRIVATE_KEY_PATH=
18
+ WECHAT_API_V3_KEY=
19
+ WECHAT_PLATFORM_PUBLIC_KEY=
20
+
21
+ # --- Alipay ---
22
+ ALIPAY_APP_ID=
23
+ ALIPAY_PRIVATE_KEY=
24
+ ALIPAY_PRIVATE_KEY_PATH=
25
+ ALIPAY_PUBLIC_KEY=
26
+ # Production:
27
+ ALIPAY_GATEWAY_URL=https://openapi.alipay.com/gateway.do
28
+ # Sandbox:
29
+ # ALIPAY_GATEWAY_URL=https://openapi-sandbox.dl.alipaydev.com/gateway.do
30
+
31
+ # --- Stripe (Checkout + Webhook) ---
32
+ STRIPE_SECRET_KEY=sk_test_...
33
+ STRIPE_WEBHOOK_SECRET=whsec_...
34
+ STRIPE_PUBLISHABLE_KEY=pk_test_...
35
+ STRIPE_CURRENCY=cny