@growthub/cli 0.8.0 → 0.8.1
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.
- package/assets/worker-kits/growthub-agency-portal-starter-v1/.env.example +53 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/QUICKSTART.md +98 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/SKILL.md +89 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/.env.example +25 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/README.md +36 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/app/api/settings/integrations/route.js +13 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/app/api/workspace/route.js +27 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/app/globals.css +237 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/app/layout.jsx +14 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/app/page.jsx +165 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/app/settings/integrations/page.jsx +134 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/auth/index.js +21 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/env.js +28 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/integrations/growthub-connection-normalizer.js +95 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/integrations/index.js +178 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/payments/index.js +13 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/persistence/index.js +13 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/persistence/postgres.js +16 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/persistence/provider-managed.js +16 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/persistence/qstash-kv.js +16 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/domain/integrations.js +185 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/domain/portal.js +16 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/next.config.js +10 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/package-lock.json +976 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/package.json +17 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/postcss.config.mjs +3 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/vercel.json +5 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/brands/NEW-CLIENT.md +10 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/brands/_template/brand-kit.md +27 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/brands/growthub/brand-kit.md +25 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/bundles/growthub-agency-portal-starter-v1.json +65 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/docs/adapter-contracts.md +79 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/docs/fork-sync-integration.md +32 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/docs/governed-workspace-primitives.md +182 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/docs/starter-kit-overview.md +30 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/docs/vercel-serverless-deployment.md +46 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/docs/vite-ui-shell-guide.md +24 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/examples/portal-brief-sample.md +44 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/examples/workspace-sample.md +10 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/growthub-meta/README.md +11 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/growthub-meta/kit-standard.md +16 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/helpers/README.md +49 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/kit.json +156 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/output/README.md +13 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/output-standards.md +25 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/runtime-assumptions.md +15 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/setup/check-deps.sh +20 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/setup/verify-env.mjs +92 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/skills/README.md +55 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/skills.md +133 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/index.html +12 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/package-lock.json +1677 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/package.json +20 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/serve.mjs +42 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/src/App.jsx +162 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/src/app.css +138 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/src/main.jsx +10 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/vite.config.js +8 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/agent-contract.md +9 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/client-onboarding-plan.md +56 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/deployment-handoff.md +61 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/deployment-plan.md +22 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/portal-brief.md +65 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/project.md +55 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/supabase-setup-plan.md +26 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/workspace-brief.md +11 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/validation-checklist.md +32 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/workers/agency-portal-operator/CLAUDE.md +75 -0
- package/dist/index.js +33 -33
- package/package.json +1 -1
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Growthub Agency Portal Starter Kit — environment template
|
|
2
|
+
#
|
|
3
|
+
# The governed workspace remains adapter-first. Keep concrete provider secrets
|
|
4
|
+
# in your local `.env` or deployment provider; do not commit real values.
|
|
5
|
+
|
|
6
|
+
# Growthub local fork placement
|
|
7
|
+
GROWTHUB_KIT_FORKS_HOME=
|
|
8
|
+
GROWTHUB_GITHUB_HOME=
|
|
9
|
+
|
|
10
|
+
# Local-first studio shell
|
|
11
|
+
AGENCY_PORTAL_STUDIO_PORT=5173
|
|
12
|
+
|
|
13
|
+
# Vercel/serverless app lane
|
|
14
|
+
AGENCY_PORTAL_APP_ROOT=apps/agency-portal
|
|
15
|
+
AGENCY_PORTAL_DEPLOY_TARGET=vercel
|
|
16
|
+
AGENCY_PORTAL_APP_URL=http://localhost:3000
|
|
17
|
+
|
|
18
|
+
# Persistence adapters
|
|
19
|
+
# Supported contract values: postgres, qstash-kv, provider-managed
|
|
20
|
+
AGENCY_PORTAL_DATA_ADAPTER=provider-managed
|
|
21
|
+
DATABASE_URL=
|
|
22
|
+
QSTASH_KV_REST_URL=
|
|
23
|
+
QSTASH_KV_REST_TOKEN=
|
|
24
|
+
|
|
25
|
+
# Auth adapter
|
|
26
|
+
# Supported contract values: oidc, clerk, authjs, provider-managed
|
|
27
|
+
AGENCY_PORTAL_AUTH_ADAPTER=provider-managed
|
|
28
|
+
AUTH_SECRET=
|
|
29
|
+
AUTH_ISSUER=
|
|
30
|
+
AUTH_CLIENT_ID=
|
|
31
|
+
AUTH_CLIENT_SECRET=
|
|
32
|
+
|
|
33
|
+
# Payment adapter
|
|
34
|
+
# Supported contract values: stripe, polar, none
|
|
35
|
+
AGENCY_PORTAL_PAYMENT_ADAPTER=none
|
|
36
|
+
PAYMENT_SECRET_KEY=
|
|
37
|
+
PAYMENT_WEBHOOK_SECRET=
|
|
38
|
+
|
|
39
|
+
# Optional reporting adapter
|
|
40
|
+
AGENCY_PORTAL_REPORTING_ADAPTER=windsor
|
|
41
|
+
WINDSOR_API_KEY=
|
|
42
|
+
|
|
43
|
+
# Optional Growthub GH app MCP bridge integration adapter
|
|
44
|
+
# Supported contract values: static, growthub-bridge, byo-api-key
|
|
45
|
+
AGENCY_PORTAL_INTEGRATION_ADAPTER=static
|
|
46
|
+
GROWTHUB_BRIDGE_BASE_URL=
|
|
47
|
+
GROWTHUB_BRIDGE_INTEGRATIONS_PATH=/api/mcp/accounts
|
|
48
|
+
GROWTHUB_BRIDGE_ACCESS_TOKEN=
|
|
49
|
+
GROWTHUB_BRIDGE_USER_ID=
|
|
50
|
+
AGENCY_PORTAL_BYO_CONNECTIONS_JSON=
|
|
51
|
+
|
|
52
|
+
# Optional scheduled job auth
|
|
53
|
+
CRON_SECRET=
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Agency Portal Starter Kit — Quickstart
|
|
2
|
+
|
|
3
|
+
This kit is a governed Growthub workspace first. It contains two runtime surfaces:
|
|
4
|
+
|
|
5
|
+
- `studio/` — local-first Vite operator shell.
|
|
6
|
+
- `apps/agency-portal/` — Vercel-ready agency portal app.
|
|
7
|
+
|
|
8
|
+
## 0. Discover, export, and register the fork
|
|
9
|
+
|
|
10
|
+
From Growthub Local:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
growthub discover
|
|
14
|
+
growthub kit list --family studio
|
|
15
|
+
growthub kit download growthub-agency-portal-starter-v1 --out ./agency-portal-workspace --yes
|
|
16
|
+
growthub kit fork register ./agency-portal-workspace
|
|
17
|
+
growthub kit fork status <fork-id>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Natural-language prompt for an agent after export:
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
Read SKILL.md, skills.md, QUICKSTART.md, docs/adapter-contracts.md, and workers/agency-portal-operator/CLAUDE.md. Set up the local Vite shell, validate the Next/Vercel app, configure either Growthub bridge integrations or BYO API key integration metadata, then produce a deployment handoff for Vercel + GitHub.
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The exported directory is the governed environment. Do not move `apps/agency-portal/` out of the workspace root; the fork primitives live beside it.
|
|
27
|
+
|
|
28
|
+
## 1. Verify the governed workspace
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
bash setup/check-deps.sh
|
|
32
|
+
node setup/verify-env.mjs
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Set adapter env in `.env` or your shell. Defaults are documented in `.env.example`.
|
|
36
|
+
|
|
37
|
+
## 2. Run the local Growthub shell
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
cd studio
|
|
41
|
+
npm install
|
|
42
|
+
npm run dev
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
This validates local-first Vite support without requiring Vercel, database setup, Windsor, or third-party API credentials.
|
|
46
|
+
|
|
47
|
+
## 3. Run the Vercel app locally
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
cd apps/agency-portal
|
|
51
|
+
npm install
|
|
52
|
+
npm run dev
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Open `/settings/integrations` to validate the dedicated integrations page. It renders:
|
|
56
|
+
|
|
57
|
+
- Data pipeline objects: Windsor AI, Google Sheets blended data, Google Analytics, Shopify, Meta Facebook/Instagram.
|
|
58
|
+
- MCP connection integrations: Asana, Slack, GoHighLevel, Google Drive, Notion.
|
|
59
|
+
|
|
60
|
+
## 4. Choose integration authority
|
|
61
|
+
|
|
62
|
+
Use the first-party Growthub bridge when the user already has connections in the hosted GH app:
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
AGENCY_PORTAL_INTEGRATION_ADAPTER=growthub-bridge
|
|
66
|
+
GROWTHUB_BRIDGE_BASE_URL=<growthub-gh-app-url>
|
|
67
|
+
GROWTHUB_BRIDGE_INTEGRATIONS_PATH=/api/mcp/accounts
|
|
68
|
+
GROWTHUB_BRIDGE_ACCESS_TOKEN=<growthub-issued-bridge-token>
|
|
69
|
+
GROWTHUB_BRIDGE_USER_ID=<growthub-auth-user-id>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Use BYO API key setup only when the workspace owner wants explicit local/provider setup:
|
|
73
|
+
|
|
74
|
+
```text
|
|
75
|
+
AGENCY_PORTAL_INTEGRATION_ADAPTER=byo-api-key
|
|
76
|
+
WINDSOR_API_KEY=<set locally or in Vercel>
|
|
77
|
+
AGENCY_PORTAL_BYO_CONNECTIONS_JSON=[{"id":"slack","provider":"slack","status":"connected","secretEnvName":"SLACK_BOT_TOKEN"}]
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Both paths normalize into the same integration object shape. The bridge path is lower friction because Growthub GH app owns user auth, provider tokens, account IDs, scopes, and MCP verification.
|
|
81
|
+
|
|
82
|
+
## 5. Deploy to Vercel
|
|
83
|
+
|
|
84
|
+
Use `apps/agency-portal` as the Vercel project root. Configure adapter env according to `docs/adapter-contracts.md`.
|
|
85
|
+
|
|
86
|
+
Production deployment checklist:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
cd apps/agency-portal
|
|
90
|
+
npm install
|
|
91
|
+
npm run build
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Then connect the GitHub repo to Vercel with root directory `apps/agency-portal`. Reuse the Growthub GH app connection bridge for user-owned integrations where available.
|
|
95
|
+
|
|
96
|
+
## 6. Governed operation
|
|
97
|
+
|
|
98
|
+
Read `SKILL.md`, `skills.md`, and `workers/agency-portal-operator/CLAUDE.md` before material changes. Inside a registered fork, record material changes to `.growthub-fork/project.md` and `.growthub-fork/trace.jsonl`.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: growthub-agency-portal-starter-v1
|
|
3
|
+
description: First-party governed workspace starter for agency portals. Use when creating a composable agency operations portal that must run locally through the Growthub Vite workspace shell and deploy cleanly to Vercel with thin persistence/auth/payment adapters for Postgres, Qstash KV, or provider-managed backends.
|
|
4
|
+
triggers:
|
|
5
|
+
- agency portal starter
|
|
6
|
+
- agency operations portal
|
|
7
|
+
- composable worker kit
|
|
8
|
+
- vercel agency portal
|
|
9
|
+
- multi database portal
|
|
10
|
+
- fork growthub-agency-portal-starter-v1
|
|
11
|
+
progressiveDisclosure: true
|
|
12
|
+
sessionMemory:
|
|
13
|
+
path: .growthub-fork/project.md
|
|
14
|
+
selfEval:
|
|
15
|
+
criteria:
|
|
16
|
+
- Governed workspace primitives remain present and declared in kit.json frozenAssetPaths.
|
|
17
|
+
- Local-first Vite operator shell under studio/ remains runnable independently from Vercel deployment.
|
|
18
|
+
- Vercel app under apps/agency-portal/ depends on adapter contracts, not provider-specific kit identity.
|
|
19
|
+
- Persistence remains configurable through AGENCY_PORTAL_DATA_ADAPTER with Postgres, Qstash KV, and provider-managed options documented.
|
|
20
|
+
- Integration settings remain configurable through AGENCY_PORTAL_INTEGRATION_ADAPTER with Growthub bridge authority and static local catalog options documented.
|
|
21
|
+
- Windsor AI and Google Sheets blended data remain first-class data pipeline objects.
|
|
22
|
+
- GH app integration primitives are represented as catalog metadata plus normalized user connection state; the starter consumes bridge output and does not query hosted databases directly.
|
|
23
|
+
- Auth and payment surfaces remain thin adapter contracts selected by environment variables.
|
|
24
|
+
- .growthub-fork/project.md and .growthub-fork/trace.jsonl receive records for material changes inside a governed fork.
|
|
25
|
+
maxRetries: 3
|
|
26
|
+
traceTo: .growthub-fork/trace.jsonl
|
|
27
|
+
helpers: []
|
|
28
|
+
subSkills: []
|
|
29
|
+
mcpTools: []
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
# Agency Portal Starter — Governed Workspace
|
|
33
|
+
|
|
34
|
+
This kit is built from the custom workspace starter primitive. It preserves the Growthub local-first workspace shape and adds an adapter-first agency portal app.
|
|
35
|
+
|
|
36
|
+
## Boundaries
|
|
37
|
+
|
|
38
|
+
- `studio/` — Vite + React local operator shell for Growthub Local.
|
|
39
|
+
- `apps/agency-portal/` — Vercel-ready serverless app payload.
|
|
40
|
+
- `lib/adapters/*` inside the app — thin persistence/auth/payment/integration contracts.
|
|
41
|
+
- `apps/agency-portal/app/api/settings/integrations/route.js` — normalized Settings lanes for data sources and workspace integrations.
|
|
42
|
+
- `apps/agency-portal/app/settings/integrations/page.jsx` — dedicated integrations UI modeled after the GH app integration page primitive.
|
|
43
|
+
- `.growthub-fork/` in exported forks — identity, policy, session memory, trace, and optional authority.
|
|
44
|
+
|
|
45
|
+
## Integration primitives
|
|
46
|
+
|
|
47
|
+
Use the GH app mental model:
|
|
48
|
+
|
|
49
|
+
1. Catalog metadata describes what can be connected.
|
|
50
|
+
2. User connection state describes what is active for the signed-in user.
|
|
51
|
+
3. Provider tokens remain in hosted authority or explicit env vars, never in source.
|
|
52
|
+
4. The portal renders a single integrations page with separate object lanes.
|
|
53
|
+
|
|
54
|
+
Data pipeline objects:
|
|
55
|
+
|
|
56
|
+
- Windsor AI
|
|
57
|
+
- Google Sheets blended data
|
|
58
|
+
- Google Analytics
|
|
59
|
+
- Shopify
|
|
60
|
+
- Meta Facebook/Instagram
|
|
61
|
+
|
|
62
|
+
MCP connection integrations:
|
|
63
|
+
|
|
64
|
+
- Asana
|
|
65
|
+
- Slack
|
|
66
|
+
- GoHighLevel
|
|
67
|
+
- Google Drive
|
|
68
|
+
- Notion
|
|
69
|
+
|
|
70
|
+
## Read order
|
|
71
|
+
|
|
72
|
+
1. `.growthub-fork/project.md`
|
|
73
|
+
2. `SKILL.md`
|
|
74
|
+
3. `skills.md`
|
|
75
|
+
4. `docs/governed-workspace-primitives.md`
|
|
76
|
+
5. `docs/adapter-contracts.md`
|
|
77
|
+
6. `docs/vercel-serverless-deployment.md`
|
|
78
|
+
7. `workers/agency-portal-operator/CLAUDE.md`
|
|
79
|
+
|
|
80
|
+
## Execution verbs
|
|
81
|
+
|
|
82
|
+
- `growthub kit download growthub-agency-portal-starter-v1 --out <path>`
|
|
83
|
+
- `growthub kit fork register <path>`
|
|
84
|
+
- `growthub kit fork status <fork-id>`
|
|
85
|
+
- `growthub skills validate --root <path>`
|
|
86
|
+
- `bash setup/check-deps.sh`
|
|
87
|
+
- `node setup/verify-env.mjs`
|
|
88
|
+
- `cd studio && npm run dev`
|
|
89
|
+
- `cd apps/agency-portal && npm run dev`
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# ── Supabase ──────────────────────────────────────────────────────────────────
|
|
2
|
+
# Get these from: https://supabase.com/dashboard → your project → Settings → API
|
|
3
|
+
NEXT_PUBLIC_SUPABASE_URL=https://your-project-ref.supabase.co
|
|
4
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key-here
|
|
5
|
+
|
|
6
|
+
# Service role key — used only in server-side API routes (keep secret, never commit)
|
|
7
|
+
# Get from: Settings → API → service_role key
|
|
8
|
+
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key-here
|
|
9
|
+
|
|
10
|
+
# ── Windsor AI (optional — only needed for the automated report engine) ────────
|
|
11
|
+
# Get from: https://windsor.ai → Settings → API Key
|
|
12
|
+
WINDSOR_API_KEY=your-windsor-api-key-here
|
|
13
|
+
|
|
14
|
+
# ── Cron / Automation (optional) ─────────────────────────────────────────────
|
|
15
|
+
# A random secret you generate — used to authenticate the /api/reports/generate endpoint
|
|
16
|
+
# Generate one: openssl rand -hex 32
|
|
17
|
+
CRON_SECRET=your-random-secret-here
|
|
18
|
+
|
|
19
|
+
# The Supabase user ID of the portal owner (used by the cron report job)
|
|
20
|
+
# Find it in: Supabase Dashboard → Authentication → Users
|
|
21
|
+
PORTAL_USER_ID=your-supabase-user-uuid-here
|
|
22
|
+
|
|
23
|
+
# ── Agency settings ───────────────────────────────────────────────────────────
|
|
24
|
+
# Monthly revenue target shown on the dashboard (in your local currency)
|
|
25
|
+
NEXT_PUBLIC_REVENUE_TARGET=10000
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Agency Portal App
|
|
2
|
+
|
|
3
|
+
This app is the Vercel/serverless runtime payload for `growthub-agency-portal-starter-v1`.
|
|
4
|
+
|
|
5
|
+
It intentionally depends on adapter contracts:
|
|
6
|
+
|
|
7
|
+
- `AGENCY_PORTAL_DATA_ADAPTER`
|
|
8
|
+
- `AGENCY_PORTAL_AUTH_ADAPTER`
|
|
9
|
+
- `AGENCY_PORTAL_PAYMENT_ADAPTER`
|
|
10
|
+
- `AGENCY_PORTAL_INTEGRATION_ADAPTER`
|
|
11
|
+
- `GROWTHUB_BRIDGE_BASE_URL`
|
|
12
|
+
- `GROWTHUB_BRIDGE_INTEGRATIONS_PATH`
|
|
13
|
+
- `GROWTHUB_BRIDGE_ACCESS_TOKEN`
|
|
14
|
+
- `GROWTHUB_BRIDGE_USER_ID`
|
|
15
|
+
- `AGENCY_PORTAL_BYO_CONNECTIONS_JSON`
|
|
16
|
+
|
|
17
|
+
The Growthub local-first operator shell remains at `../../studio`.
|
|
18
|
+
|
|
19
|
+
Settings exposes two integration lanes:
|
|
20
|
+
|
|
21
|
+
- Data sources: Windsor AI, Google Sheets blended data, Google Analytics, Shopify, Meta Facebook/Instagram.
|
|
22
|
+
- Workspace integrations: Asana, Slack, GoHighLevel, Google Drive, Notion.
|
|
23
|
+
|
|
24
|
+
Use `AGENCY_PORTAL_INTEGRATION_ADAPTER=growthub-bridge` when the deployed app should read connection state from the Growthub GH app MCP bridge. The reusable primitive is `lib/adapters/integrations/growthub-connection-normalizer.js`; it accepts SDK/profile-style `integrations[]` payloads and GH app MCP `accounts[]` payloads, then emits the same normalized object shape used by `byo-api-key`. Keep provider tokens in the hosted authority layer or named env vars; this app consumes normalized connection metadata only.
|
|
25
|
+
|
|
26
|
+
## Run
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install
|
|
30
|
+
npm run dev
|
|
31
|
+
npm run build
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Deploy
|
|
35
|
+
|
|
36
|
+
Use this directory as the Vercel project root.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { describeIntegrationAdapter, listAgencyPortalIntegrations } from "@/lib/adapters/integrations";
|
|
3
|
+
import { groupIntegrationsByLane } from "@/lib/domain/integrations";
|
|
4
|
+
async function GET() {
|
|
5
|
+
const integrations = await listAgencyPortalIntegrations();
|
|
6
|
+
return NextResponse.json({
|
|
7
|
+
adapter: describeIntegrationAdapter(),
|
|
8
|
+
...groupIntegrationsByLane(integrations)
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
GET
|
|
13
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { describeAuthAdapter } from "@/lib/adapters/auth";
|
|
3
|
+
import { readAdapterConfig } from "@/lib/adapters/env";
|
|
4
|
+
import { describeIntegrationAdapter, listAgencyPortalIntegrations } from "@/lib/adapters/integrations";
|
|
5
|
+
import { describePaymentAdapter } from "@/lib/adapters/payments";
|
|
6
|
+
import { describePersistenceAdapter } from "@/lib/adapters/persistence";
|
|
7
|
+
import { groupIntegrationsByLane } from "@/lib/domain/integrations";
|
|
8
|
+
import { portalCapabilities } from "@/lib/domain/portal";
|
|
9
|
+
async function GET() {
|
|
10
|
+
const integrations = await listAgencyPortalIntegrations();
|
|
11
|
+
return NextResponse.json({
|
|
12
|
+
config: readAdapterConfig(),
|
|
13
|
+
adapters: {
|
|
14
|
+
persistence: describePersistenceAdapter(),
|
|
15
|
+
auth: describeAuthAdapter(),
|
|
16
|
+
payments: describePaymentAdapter(),
|
|
17
|
+
integrations: describeIntegrationAdapter()
|
|
18
|
+
},
|
|
19
|
+
capabilities: portalCapabilities,
|
|
20
|
+
settings: {
|
|
21
|
+
integrations: groupIntegrationsByLane(integrations)
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
export {
|
|
26
|
+
GET
|
|
27
|
+
};
|
package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/app/globals.css
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
color-scheme: dark;
|
|
3
|
+
--bg: #080b12;
|
|
4
|
+
--sidebar: #0d1118;
|
|
5
|
+
--panel: #111827;
|
|
6
|
+
--panel-soft: #0d1420;
|
|
7
|
+
--ink: #f7fafc;
|
|
8
|
+
--muted: #93a3b8;
|
|
9
|
+
--line: #223047;
|
|
10
|
+
--accent: #38bdf8;
|
|
11
|
+
--accent-soft: rgba(56, 189, 248, 0.12);
|
|
12
|
+
--good: #22c55e;
|
|
13
|
+
--warn: #f59e0b;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
* { box-sizing: border-box; }
|
|
17
|
+
html { scroll-behavior: smooth; }
|
|
18
|
+
body {
|
|
19
|
+
margin: 0;
|
|
20
|
+
background: var(--bg);
|
|
21
|
+
color: var(--ink);
|
|
22
|
+
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
23
|
+
}
|
|
24
|
+
a { color: inherit; }
|
|
25
|
+
code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.9em; }
|
|
26
|
+
|
|
27
|
+
.shell {
|
|
28
|
+
min-height: 100vh;
|
|
29
|
+
display: grid;
|
|
30
|
+
grid-template-columns: 232px minmax(0, 1fr);
|
|
31
|
+
background: radial-gradient(circle at top right, rgba(56, 189, 248, 0.12), transparent 360px), var(--bg);
|
|
32
|
+
}
|
|
33
|
+
.sidebar {
|
|
34
|
+
position: sticky;
|
|
35
|
+
top: 0;
|
|
36
|
+
height: 100vh;
|
|
37
|
+
display: flex;
|
|
38
|
+
flex-direction: column;
|
|
39
|
+
gap: 22px;
|
|
40
|
+
background: rgba(13, 17, 24, 0.96);
|
|
41
|
+
border-right: 1px solid var(--line);
|
|
42
|
+
padding: 22px 16px;
|
|
43
|
+
}
|
|
44
|
+
.brand { display: flex; align-items: center; gap: 10px; font-weight: 800; }
|
|
45
|
+
.brand-mark {
|
|
46
|
+
width: 34px;
|
|
47
|
+
height: 34px;
|
|
48
|
+
display: grid;
|
|
49
|
+
place-items: center;
|
|
50
|
+
border-radius: 8px;
|
|
51
|
+
background: var(--accent);
|
|
52
|
+
color: #06111d;
|
|
53
|
+
font-size: 13px;
|
|
54
|
+
font-weight: 900;
|
|
55
|
+
}
|
|
56
|
+
.nav { display: grid; gap: 5px; }
|
|
57
|
+
.nav a {
|
|
58
|
+
color: #c6d1e1;
|
|
59
|
+
text-decoration: none;
|
|
60
|
+
padding: 9px 10px;
|
|
61
|
+
border-radius: 7px;
|
|
62
|
+
font-size: 14px;
|
|
63
|
+
}
|
|
64
|
+
.nav a.active, .nav a:hover { background: #172133; color: white; }
|
|
65
|
+
.sidebar-footer {
|
|
66
|
+
margin-top: auto;
|
|
67
|
+
display: flex;
|
|
68
|
+
align-items: center;
|
|
69
|
+
gap: 8px;
|
|
70
|
+
color: var(--muted);
|
|
71
|
+
font-size: 13px;
|
|
72
|
+
}
|
|
73
|
+
.status-dot {
|
|
74
|
+
width: 8px;
|
|
75
|
+
height: 8px;
|
|
76
|
+
border-radius: 999px;
|
|
77
|
+
background: var(--good);
|
|
78
|
+
box-shadow: 0 0 0 4px rgba(34, 197, 94, 0.12);
|
|
79
|
+
}
|
|
80
|
+
.main {
|
|
81
|
+
width: min(100%, 1180px);
|
|
82
|
+
padding: 30px;
|
|
83
|
+
}
|
|
84
|
+
.utility-bar {
|
|
85
|
+
display: flex;
|
|
86
|
+
justify-content: space-between;
|
|
87
|
+
gap: 16px;
|
|
88
|
+
align-items: center;
|
|
89
|
+
margin-bottom: 20px;
|
|
90
|
+
padding: 12px 14px;
|
|
91
|
+
border: 1px solid var(--line);
|
|
92
|
+
border-radius: 8px;
|
|
93
|
+
background: rgba(17, 24, 39, 0.82);
|
|
94
|
+
}
|
|
95
|
+
.utility-bar strong { display: block; font-size: 14px; }
|
|
96
|
+
.utility-bar span, .page-heading p, .panel-copy, .card p, .setup-card p, .results-panel p {
|
|
97
|
+
color: var(--muted);
|
|
98
|
+
line-height: 1.5;
|
|
99
|
+
}
|
|
100
|
+
.utility-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
|
|
101
|
+
.utility-actions a, .pill, .badge {
|
|
102
|
+
display: inline-flex;
|
|
103
|
+
align-items: center;
|
|
104
|
+
min-height: 28px;
|
|
105
|
+
border: 1px solid var(--line);
|
|
106
|
+
border-radius: 999px;
|
|
107
|
+
padding: 5px 10px;
|
|
108
|
+
background: #0c1320;
|
|
109
|
+
color: #c9d7e8;
|
|
110
|
+
text-decoration: none;
|
|
111
|
+
font-size: 12px;
|
|
112
|
+
}
|
|
113
|
+
.page-heading { position: relative; margin-bottom: 22px; }
|
|
114
|
+
.page-heading h1 {
|
|
115
|
+
margin: 4px 0 8px;
|
|
116
|
+
font-size: clamp(32px, 5vw, 58px);
|
|
117
|
+
line-height: 0.98;
|
|
118
|
+
letter-spacing: 0;
|
|
119
|
+
}
|
|
120
|
+
.page-heading p { max-width: 780px; margin: 0 0 12px; }
|
|
121
|
+
.eyebrow { color: var(--accent); font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.12em; }
|
|
122
|
+
.hero-grid {
|
|
123
|
+
display: grid;
|
|
124
|
+
grid-template-columns: 1.2fr 0.9fr 0.9fr;
|
|
125
|
+
gap: 14px;
|
|
126
|
+
margin-bottom: 16px;
|
|
127
|
+
}
|
|
128
|
+
.hero-card, .card, .setup-card, .integration-section, .integration-toolbar, .results-panel {
|
|
129
|
+
border: 1px solid var(--line);
|
|
130
|
+
border-radius: 8px;
|
|
131
|
+
background: rgba(17, 24, 39, 0.9);
|
|
132
|
+
}
|
|
133
|
+
.hero-card { min-height: 188px; padding: 18px; }
|
|
134
|
+
.hero-card.primary { background: linear-gradient(135deg, rgba(56, 189, 248, 0.18), rgba(17, 24, 39, 0.95)); }
|
|
135
|
+
.hero-card.wide { min-height: 210px; }
|
|
136
|
+
.hero-card span, .card span, .setup-card span { color: var(--accent); font-size: 12px; font-weight: 800; text-transform: uppercase; }
|
|
137
|
+
.hero-card strong { display: block; margin-top: 10px; font-size: 34px; line-height: 1; }
|
|
138
|
+
.hero-card p { margin: 12px 0 0; color: var(--muted); line-height: 1.5; }
|
|
139
|
+
.card-label { color: var(--accent) !important; font-size: 12px; font-weight: 800; text-transform: uppercase; }
|
|
140
|
+
.muted { color: var(--muted) !important; }
|
|
141
|
+
.progress { height: 8px; margin: 18px 0 2px; overflow: hidden; border-radius: 999px; background: #0a101b; border: 1px solid var(--line); }
|
|
142
|
+
.progress span { display: block; height: 100%; background: var(--accent); }
|
|
143
|
+
.ops-strip, .setup-grid {
|
|
144
|
+
display: grid;
|
|
145
|
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
146
|
+
gap: 12px;
|
|
147
|
+
margin-bottom: 18px;
|
|
148
|
+
}
|
|
149
|
+
.setup-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
|
150
|
+
.ops-strip article, .setup-card { padding: 14px; border: 1px solid var(--line); border-radius: 8px; background: rgba(13, 20, 32, 0.88); }
|
|
151
|
+
.ops-strip strong, .setup-card strong { display: block; margin: 7px 0; font-size: 14px; }
|
|
152
|
+
.ops-strip p, .setup-card p { margin: 0 0 10px; font-size: 13px; }
|
|
153
|
+
.setup-card code { color: #d7e8ff; word-break: break-word; }
|
|
154
|
+
.grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }
|
|
155
|
+
.compact-grid .card { min-height: 124px; }
|
|
156
|
+
.card { min-height: 138px; padding: 16px; }
|
|
157
|
+
.card h3 { margin: 7px 0 8px; font-size: 15px; }
|
|
158
|
+
.metric { font-size: 26px; font-weight: 800; margin-top: 12px; }
|
|
159
|
+
.adapter { margin-top: 18px; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
|
|
160
|
+
.adapter .card { min-height: auto; }
|
|
161
|
+
.results-panel { margin-top: 18px; padding: 18px; display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
|
|
162
|
+
.results-panel h2 { margin: 0 0 8px; }
|
|
163
|
+
.results-metrics { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
|
|
164
|
+
.results-metrics span { display: block; color: var(--muted); font-size: 12px; }
|
|
165
|
+
.quick-actions {
|
|
166
|
+
position: fixed;
|
|
167
|
+
right: 20px;
|
|
168
|
+
bottom: 20px;
|
|
169
|
+
display: grid;
|
|
170
|
+
gap: 8px;
|
|
171
|
+
width: 190px;
|
|
172
|
+
}
|
|
173
|
+
.quick-actions button {
|
|
174
|
+
border: 1px solid var(--line);
|
|
175
|
+
border-radius: 8px;
|
|
176
|
+
padding: 10px 12px;
|
|
177
|
+
background: #0d1420;
|
|
178
|
+
color: var(--ink);
|
|
179
|
+
text-align: left;
|
|
180
|
+
font: inherit;
|
|
181
|
+
}
|
|
182
|
+
.integration-board { display: grid; gap: 14px; }
|
|
183
|
+
.integration-toolbar { display: flex; justify-content: space-between; align-items: center; gap: 16px; padding: 14px 16px; }
|
|
184
|
+
.integration-toolbar p { margin: 4px 0 0; color: var(--muted); font-size: 14px; }
|
|
185
|
+
.section-heading { display: flex; justify-content: space-between; gap: 14px; align-items: flex-start; margin-bottom: 12px; }
|
|
186
|
+
.integration-section { padding: 16px; }
|
|
187
|
+
.integration-section h2 { margin: 0 0 8px; font-size: 18px; }
|
|
188
|
+
.integration-list { display: grid; gap: 10px; }
|
|
189
|
+
.integration-card { border: 1px solid var(--line); border-radius: 8px; padding: 14px; background: #0d1420; }
|
|
190
|
+
.integration-card-top { display: grid; grid-template-columns: 38px minmax(0, 1fr) auto; gap: 12px; align-items: start; }
|
|
191
|
+
.provider-mark {
|
|
192
|
+
width: 34px;
|
|
193
|
+
height: 34px;
|
|
194
|
+
display: grid;
|
|
195
|
+
place-items: center;
|
|
196
|
+
border: 1px solid var(--line);
|
|
197
|
+
border-radius: 7px;
|
|
198
|
+
background: #101a2b;
|
|
199
|
+
font-weight: 800;
|
|
200
|
+
color: var(--accent);
|
|
201
|
+
}
|
|
202
|
+
.integration-card strong { display: block; font-size: 14px; }
|
|
203
|
+
.integration-card p { margin: 4px 0 0; color: var(--muted); font-size: 13px; line-height: 1.4; }
|
|
204
|
+
.status {
|
|
205
|
+
white-space: nowrap;
|
|
206
|
+
border: 1px solid var(--line);
|
|
207
|
+
border-radius: 999px;
|
|
208
|
+
padding: 4px 8px;
|
|
209
|
+
font-size: 12px;
|
|
210
|
+
color: var(--muted);
|
|
211
|
+
}
|
|
212
|
+
.status.connected { color: var(--good); border-color: rgba(34, 197, 94, 0.45); background: rgba(34, 197, 94, 0.1); }
|
|
213
|
+
.status.needs-connection { color: var(--warn); border-color: rgba(245, 158, 11, 0.5); background: rgba(245, 158, 11, 0.1); }
|
|
214
|
+
.integration-card-meta { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
|
|
215
|
+
.integration-card-meta span {
|
|
216
|
+
border: 1px solid var(--line);
|
|
217
|
+
border-radius: 999px;
|
|
218
|
+
padding: 3px 7px;
|
|
219
|
+
color: var(--muted);
|
|
220
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
221
|
+
font-size: 11px;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
@media (max-width: 1020px) {
|
|
225
|
+
.shell { grid-template-columns: 1fr; }
|
|
226
|
+
.sidebar { position: static; height: auto; }
|
|
227
|
+
.hero-grid, .grid, .adapter, .ops-strip, .setup-grid, .results-panel, .results-metrics { grid-template-columns: 1fr; }
|
|
228
|
+
.quick-actions { position: static; width: auto; margin: 20px 30px; }
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
@media (max-width: 720px) {
|
|
232
|
+
.main { padding: 20px; }
|
|
233
|
+
.utility-bar, .integration-toolbar, .section-heading { display: block; }
|
|
234
|
+
.utility-actions { margin-top: 10px; }
|
|
235
|
+
.integration-card-top { grid-template-columns: 34px minmax(0, 1fr); }
|
|
236
|
+
.integration-card-top .status { grid-column: 2; width: fit-content; }
|
|
237
|
+
}
|
package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/app/layout.jsx
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import "./globals.css";
|
|
2
|
+
const metadata = {
|
|
3
|
+
title: "Agency Portal",
|
|
4
|
+
description: "Composable agency operations portal with thin infrastructure adapters."
|
|
5
|
+
};
|
|
6
|
+
function RootLayout({ children }) {
|
|
7
|
+
return <html lang="en">
|
|
8
|
+
<body>{children}</body>
|
|
9
|
+
</html>;
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
RootLayout as default,
|
|
13
|
+
metadata
|
|
14
|
+
};
|