Connect your Shopify store β Sync products & orders β Run AI-optimized Meta Ads β Watch revenue grow
Quick Start Β· Architecture Β· API Reference Β· Testing Β· Deployment
GrowthPilot is a full-stack platform that connects your Shopify store with Meta (Facebook/Instagram) Ads and uses AI to automate growth decisions β ad copy generation, audience targeting, budget optimization, and anomaly detection.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β Shopify Store ββsyncβββΆ GrowthPilot ββoptimizeβββΆ Meta Ads β
β β β β β
β Products AI Engine Campaigns β
β Orders (GPT-4o-mini) Ad Sets β
β Customers Budget Optimization Audiences β
β Anomaly Detection Insights β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Feature | Description |
|---|---|
| π Shopify Sync | Real-time product, order & customer sync with webhook support |
| π’ Meta Ads Management | Create campaigns, ad sets, audiences via Meta Marketing API |
| π€ AI Ad Copy | GPT-4o-mini generates headlines, primary text, CTAs with tone control |
| π― Audience Suggestions | AI analyzes store data to discover untapped customer segments |
| π° Budget Optimization | Automatically reallocates spend across campaigns for max ROAS |
| π¨ Anomaly Detection | Detects CPA spikes, ROAS drops, creative fatigue in real-time |
| π Analytics Dashboard | Revenue, ROAS, orders, CTR, CPC β with period comparisons |
| β‘ Automation Rules | Trigger actions on ROAS drop, budget threshold, inventory low |
| Layer | Technology | Purpose |
|---|---|---|
| Frontend | Next.js 15 (App Router + Turbopack) | React server components, API routes |
| Auth | Clerk | Multi-tenant orgs, OAuth, session management |
| Database | PostgreSQL 16 + Prisma ORM | 21 models, type-safe queries |
| Validation | Zod | Runtime schema validation for all API inputs |
| AI | OpenAI GPT-4o-mini | Ad copy, audience suggestions, budget optimization |
| Styling | Tailwind CSS | Custom dark design system |
| Testing | Vitest + Testing Library | 60 unit tests across 6 suites |
| Monorepo | Turborepo + npm workspaces | Shared packages, parallel builds |
| Deployment | Docker + Railway | Multi-stage builds, health checks |
| Tool | Version | Check | Install (Mac) |
|---|---|---|---|
| Node.js | β₯ 20 | node -v |
brew install node@20 |
| Docker | Latest | docker --version |
brew install --cask docker |
| Git | Any | git --version |
brew install git |
# Clone the repo
git clone <your-repo-url> growthpilot
cd growthpilot
# Run the setup script β handles everything
chmod +x start.sh
./start.shThe script walks through 12 steps with color-coded output:
β Node.js v24.11.1 (β₯20 β) β Prerequisites check
β Docker 29.2.1 (running)
β Created .env with random CRON_SECRET β Environment config
β PostgreSQL container started β Database setup
β All dependencies installed β npm install
β Prisma client generated (20+ models) β ORM codegen
β All database tables created β Schema push
β 60 passed (60) β Full test suite
β Ready in 2.1s β Dev server live
git clone <your-repo-url> growthpilot
cd growthpilot
npm installWhat happens: npm resolves 3 workspaces β
apps/web,packages/database,packages/sharedβ and installs all dependencies including Next.js, Prisma, Vitest, Zod, Clerk SDK, and OpenAI SDK.
cp .env.example .envOpen .env in your editor and fill in API keys (see Configuration below).
# Start Postgres via Docker
docker compose -f docker/docker-compose.yml up -d db
# Verify it's running
docker psPort 5432 already in use? See Port Conflicts section.
npx prisma generate --schema=packages/database/prisma/schema.prismaWhat happens: Prisma reads the schema (21 models, 9 enums) and generates a fully typed TypeScript client in
node_modules/.prisma/client.
npx prisma db push --schema=packages/database/prisma/schema.prismaWhat happens: Creates all 21 tables in PostgreSQL β Organization, Product, Order, MetaAdCampaign, AIInsight, etc.
npm testExpected output:
Tests 60 passed (60)across 6 test suites.
npm run devWhat happens: Next.js 15 starts with Turbopack on port 3000. Compiles middleware, mounts all API routes, and serves the React app.
Once the dev server is running, you'll have access to:
| URL | What You'll See |
|---|---|
| localhost:3000 | π Marketing landing page |
| localhost:3000/sign-in | π Clerk authentication (sign up / sign in) |
| localhost:3000/dashboard | π Dashboard with metrics, charts, AI insights |
| localhost:3000/api/health | β€οΈ {"status":"ok","timestamp":"..."} |
| Token | Get it from | Required? |
|---|---|---|
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY |
dashboard.clerk.com β API Keys | β Yes |
CLERK_SECRET_KEY |
dashboard.clerk.com β API Keys | β Yes |
OPENAI_API_KEY |
platform.openai.com/api-keys | β Yes (for AI) |
SHOPIFY_API_KEY |
partners.shopify.com/organizations β Apps | β¬ Optional |
SHOPIFY_API_SECRET |
partners.shopify.com/organizations β Apps | β¬ Optional |
SHOPIFY_WEBHOOK_SECRET |
partners.shopify.com/organizations β Apps β Webhooks | β¬ Optional |
META_APP_ID |
developers.facebook.com/apps β Settings β Basic | β¬ Optional |
META_APP_SECRET |
developers.facebook.com/apps β Settings β Basic | β¬ Optional |
1. π Clerk (Authentication) β Required
- Open https://clerk.com/sign-up β Create a free account
- After sign-up, you'll land on the dashboard. If not, go to https://dashboard.clerk.com
- Click "Create application"
- Name it
GrowthPilot(or anything you like) - Under Sign-in options, check:
Email,Google,GitHub(pick what you want) - Click "Create application"
- You'll be taken to the Quickstart page β skip it
- In the left sidebar, click "API Keys"
- You'll see two keys:
- Publishable key β starts with
pk_test_ - Secret key β click "eye" icon to reveal, starts with
sk_test_
- Publishable key β starts with
- Copy both into your
.env:
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
CLERK_SECRET_KEY=sk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
β οΈ Without these keys, the app will crash on/dashboardwith an auth redirect error.
2. π€ OpenAI (AI Features) β Required for AI
- Open https://platform.openai.com/signup β Sign up (or sign in)
- You may need to add a payment method at https://platform.openai.com/settings/organization/billing/overview
- GrowthPilot uses
gpt-4o-miniwhich costs ~$0.15 per 1M input tokens (very cheap)
- GrowthPilot uses
- Go to https://platform.openai.com/api-keys
- Click "Create new secret key"
- Name it
GrowthPilot - Click "Create secret key"
- Copy it immediately β you won't be able to see it again
- Paste into
.env:
OPENAI_API_KEY=sk-proj-xxxxxxxxxxxxxxxxxxxxxxxxxxxxπ‘ Without this key, all other features (Shopify sync, dashboard, campaigns) still work β only the
/api/ai/generateendpoint requires it.
3. π Shopify (Store Integration) β Optional
- Open https://partners.shopify.com/signup β Create a free Partner account
- After sign-up, go to https://partners.shopify.com/organizations
- Select your organization (or create one)
- In the left sidebar, click "Apps"
- Click "Create app" β Choose "Create app manually"
- Name it
GrowthPilot, set the App URL tohttp://localhost:3000 - Click "Create"
- On the app page, click "Client credentials" tab
- You'll see:
- Client ID β this is your
SHOPIFY_API_KEY - Client secret β click "Show" β this is your
SHOPIFY_API_SECRET
- Client ID β this is your
- For webhooks, go to "App setup" β scroll to "Event subscriptions"
- Your webhook signing secret is the
SHOPIFY_WEBHOOK_SECRET
- Your webhook signing secret is the
SHOPIFY_API_KEY=your_client_id_here
SHOPIFY_API_SECRET=your_client_secret_here
SHOPIFY_WEBHOOK_SECRET=your_webhook_signing_secret- Back in Partners dashboard β "Stores" in the left sidebar
- Click "Add store" β "Create development store"
- Choose "Create a store to test and build"
- Fill in store name β Click "Create"
- In your dev store, go to Settings β Apps and sales channels β Develop apps
- Click "Create an app" β Name it β "Create app"
- Go to "Configuration" tab β Under Admin API access scopes, select:
read_products,write_productsread_orders,write_ordersread_customers
- Click "Save" β then go to "API credentials" tab
- Click "Install app" β "Install"
- Copy the Admin API access token (starts with
shpat_) β this is what you'll use when connecting the store via the GrowthPilot UI
π The
shpat_access token is entered through the GrowthPilot dashboard when you connect a store, NOT in.env. The.envkeys are for the app-level OAuth credentials.
4. π’ Meta / Facebook (Ads Integration) β Optional
- Open https://developers.facebook.com β Log in with your Facebook account
- If first time, click "Get Started" β agree to terms β verify your account
- Go to https://developers.facebook.com/apps/create/
- Select use case β "Other" β Click "Next"
- Select app type β "Business" β Click "Next"
- Name it
GrowthPilot, enter your email β Click "Create app"
- In the app dashboard left sidebar, click "App settings" β "Basic"
- You'll see:
- App ID β this is your
META_APP_ID - App secret β click "Show", enter password β this is your
META_APP_SECRET
- App ID β this is your
META_APP_ID=123456789012345
META_APP_SECRET=abcdef1234567890abcdef1234567890- In the left sidebar β "Add products" (or "Products +")
- Find "Marketing API" β Click "Set up"
- This gives your app access to create campaigns, ad sets, and audiences
- Go to https://developers.facebook.com/tools/explorer/
- This is the Graph API Explorer
- In the top-right dropdown, select your
GrowthPilotapp - Click "Generate Access Token"
- Grant permissions when prompted:
ads_managementads_readbusiness_management
- Copy the generated token β this is what you'll use when connecting a Meta ad account through the GrowthPilot UI
- Go to https://business.facebook.com/settings/ad-accounts
- Select your ad account
- The Ad Account ID is shown (format:
act_123456789) - You'll enter this in GrowthPilot when connecting Meta Ads
π‘ The access token from Graph API Explorer expires in ~1 hour. For production, you'll need a System User Token which doesn't expire.
# βββ Database (auto-configured if using Docker) ββββββββββββ
DATABASE_URL="postgresql://growthpilot:growthpilot_dev@localhost:5432/growthpilot"
REDIS_URL="redis://localhost:6379"
# βββ Auth (required) βββββββββββββββββββββββββββββββββββββββ
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="pk_test_..."
CLERK_SECRET_KEY="sk_test_..."
NEXT_PUBLIC_CLERK_SIGN_IN_URL="/sign-in"
NEXT_PUBLIC_CLERK_SIGN_UP_URL="/sign-up"
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL="/dashboard"
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL="/onboarding"
# βββ AI (required for AI features) βββββββββββββββββββββββββ
OPENAI_API_KEY="sk-..."
# βββ Shopify (optional) ββββββββββββββββββββββββββββββββββββ
SHOPIFY_API_KEY="..."
SHOPIFY_API_SECRET="..."
SHOPIFY_WEBHOOK_SECRET="..."
# βββ Meta Ads (optional) βββββββββββββββββββββββββββββββββββ
META_APP_ID="..."
META_APP_SECRET="..."
# βββ App ββββββββββββββββββββββββββββββββββββββββββββββββββββ
NEXT_PUBLIC_APP_URL="http://localhost:3000"
CRON_SECRET="auto-generated-by-start-script"growthpilot/
β
βββ apps/web/ β Next.js 15 Application
β βββ app/
β β βββ page.tsx β Landing page
β β βββ layout.tsx β Root layout + Clerk provider
β β βββ globals.css β Dark design system (Tailwind)
β β β
β β βββ dashboard/
β β β βββ layout.tsx β Sidebar (8 nav items)
β β β βββ page.tsx β Metrics, charts, AI insights
β β β
β β βββ api/
β β βββ health/route.ts β GET /api/health
β β βββ shopify/
β β β βββ connect/route.ts β POST/GET /api/shopify/connect
β β β βββ sync/route.ts β POST /api/shopify/sync
β β βββ meta/
β β β βββ connect/route.ts β POST/GET /api/meta/connect
β β βββ campaigns/route.ts β GET/POST /api/campaigns
β β βββ analytics/route.ts β GET /api/analytics
β β βββ ai/
β β β βββ generate/route.ts β POST /api/ai/generate
β β βββ webhooks/
β β β βββ shopify/route.ts β POST /api/webhooks/shopify
β β βββ cron/route.ts β GET /api/cron
β β
β βββ lib/ β Core business logic
β β βββ shopify/service.ts β Shopify Admin API client
β β βββ meta/service.ts β Meta Marketing API client
β β βββ ai/service.ts β OpenAI-powered AI engine
β β βββ prisma/client.ts β Database client singleton
β β βββ utils/
β β βββ auth.ts β Clerk auth + API helpers
β β βββ analytics.ts β Metrics aggregation engine
β β
β βββ __tests__/ β 6 test suites, 60 tests
β βββ setup.ts
β βββ schemas.test.ts
β βββ shopify-service.test.ts
β βββ meta-service.test.ts
β βββ ai-service.test.ts
β βββ analytics.test.ts
β βββ api-utils.test.ts
β
βββ packages/
β βββ database/ β Prisma ORM package
β β βββ prisma/schema.prisma β 21 models, 9 enums
β β βββ src/index.ts β Client export
β β
β βββ shared/ β Shared validation & types
β βββ src/index.ts β Zod schemas, TS types, plan constants
β
βββ docker/
β βββ Dockerfile β Multi-stage production build
β βββ docker-compose.yml β PostgreSQL + Redis
β
βββ start.sh β One-command Mac setup (12 steps)
βββ turbo.json β Turborepo pipeline
βββ railway.toml β Railway deployment config
βββ .env.example β Environment variable template
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Next.js API Routes β
β /shopify/* /meta/* /ai/* /campaigns /analytics β
ββββββββ¬βββββββββββββ¬ββββββββββ¬βββββββββββ¬ββββββββββββ¬ββββββββββ
β β β β β
βΌ βΌ βΌ βΌ βΌ
ββββββββββββββ βββββββββββ βββββββββββ ββββββββββββββββββββββββ
β Shopify β β Meta β β AI β β Analytics Service β
β Service β β Service β β Service β β β
β β β β β β β getDashboardMetrics β
β syncProds β β getCamp β β genCopy β β getComparisonMetrics β
β syncOrders β β adSets β β suggest β β β
β syncCust β β insight β β optimze β β β
β webhooks β β audienc β β anomaly β β β
βββββββ¬βββββββ ββββββ¬βββββ ββββββ¬βββββ ββββββββββββ¬ββββββββββββ
β β β β
βββββββββββββββ΄ββββββββββββ΄βββββββββββββββββββ
β
βββββββββββΌβββββββββββ
β Prisma ORM β
β 21 Models β
β PostgreSQL 16 β
ββββββββββββββββββββββ
Organization ββ¬βββΆ Member (role: OWNER | ADMIN | MEMBER | VIEWER)
β
ββββΆ ShopifyStore
β ββββΆ Product
β ββββΆ Order βββΆ OrderItem
β ββββΆ ShopifyCustomer
β
ββββΆ MetaAdAccount
β ββββΆ MetaAdCampaign
β ββββΆ MetaAdSet
β ββββΆ MetaAd βββΆ AdCreative
β
ββββΆ Campaign βββmany-to-manyβββΆ Audience
β (via CampaignAudience)
β
ββββΆ AIInsight (type: ANOMALY | RECOMMENDATION | PREDICTION)
ββββΆ AutomationRule βββΆ AutomationLog
ββββΆ BudgetAlert
ββββΆ SyncLog
Order βββΆ AdAttribution (tracks which ad drove which order)
All /api/* routes (except /api/health, /api/webhooks/*, /api/cron) require a valid Clerk session. The middleware at apps/web/middleware.ts enforces this automatically.
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/health |
None | Server status check |
GET |
/api/cron |
Bearer CRON_SECRET |
Scheduled sync for all stores & accounts |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST |
/api/shopify/connect |
Clerk | Connect a Shopify store |
GET |
/api/shopify/connect |
Clerk | List connected stores with counts |
POST |
/api/shopify/sync |
Clerk | Manual product/order/customer sync |
POST |
/api/webhooks/shopify |
HMAC-SHA256 | Receive real-time Shopify events |
π POST /api/shopify/connect β Connect Store
curl -X POST http://localhost:3000/api/shopify/connect \
-H "Content-Type: application/json" \
-d '{
"shopDomain": "my-store.myshopify.com",
"accessToken": "shpat_xxxxxxxxxxxx",
"scope": "read_products,read_orders,read_customers"
}'Response:
{
"success": true,
"data": {
"storeId": "clxyz...",
"shopDomain": "my-store.myshopify.com"
}
}What happens behind the scenes:
- Validates input with
ShopifyConnectSchema - Creates
ShopifyStorerecord - Triggers background sync: products β orders β customers
- Registers 8 webhook topics
π POST /api/shopify/sync β Manual Sync
curl -X POST http://localhost:3000/api/shopify/sync \
-H "Content-Type: application/json" \
-d '{ "storeId": "clxyz...", "type": "all" }'Type options: "all" | "products" | "orders" | "customers"
π Webhook Topics Handled
| Topic | Action |
|---|---|
orders/create |
Upsert order with line items |
orders/updated |
Update order status/totals |
products/create |
Create product record |
products/update |
Update product details |
products/delete |
Remove product |
customers/create |
Create customer profile |
customers/update |
Update customer data |
app/uninstalled |
Deactivate store |
All webhooks are verified with HMAC-SHA256 signature validation.
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST |
/api/meta/connect |
Clerk | Connect an ad account |
GET |
/api/meta/connect |
Clerk | List ad accounts with campaign counts |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/campaigns |
Clerk | List campaigns (paginated, filterable) |
POST |
/api/campaigns |
Clerk | Create a new campaign |
π GET /api/campaigns β Query Parameters
| Param | Type | Default | Description |
|---|---|---|---|
page |
number | 1 |
Page number |
limit |
number | 20 |
Items per page (max 100) |
sortBy |
string | createdAt |
Sort field |
sortOrder |
string | desc |
asc or desc |
status |
string | β | Filter by: DRAFT ACTIVE PAUSED COMPLETED ARCHIVED |
π POST /api/campaigns β Create Campaign
curl -X POST http://localhost:3000/api/campaigns \
-H "Content-Type: application/json" \
-d '{
"name": "Q1 Retargeting",
"type": "RETARGETING",
"goal": "Recover abandoned carts",
"budget": 1000,
"aiOptimized": true,
"audienceIds": ["aud-1", "aud-2"]
}'Campaign types: AWARENESS Β· TRAFFIC Β· CONVERSIONS Β· RETARGETING Β· LOOKALIKE Β· DYNAMIC_PRODUCT
All AI actions go through one endpoint with different action values:
POST /api/ai/generate
| Action | What It Does | Key Input |
|---|---|---|
ad-copy |
Generate headline, text, CTA + 2 variations | productId, tone, platform |
suggest-audiences |
Discover 3-5 audience segments | productIds? |
optimize-budget |
Reallocate spend for max ROAS | campaignIds, totalBudget |
detect-anomalies |
Find CPA spikes, ROAS drops, fatigue | β (analyzes all active campaigns) |
score-products |
Composite 0-10 performance score | storeId |
π Ad Copy Generation
curl -X POST http://localhost:3000/api/ai/generate \
-H "Content-Type: application/json" \
-d '{
"action": "ad-copy",
"productId": "prod-123",
"tone": "playful",
"platform": "meta_story",
"targetAudience": "Women 25-45",
"includeEmoji": true
}'Tones: professional Β· casual Β· urgent Β· playful Β· luxurious
Platforms: meta_feed Β· meta_story Β· meta_reel
Response includes: headline, primaryText, description, callToAction, plus 2 variations
π Budget Optimization
curl -X POST http://localhost:3000/api/ai/generate \
-H "Content-Type: application/json" \
-d '{
"action": "optimize-budget",
"campaignIds": ["camp-1", "camp-2", "camp-3"],
"totalBudget": 5000,
"optimizeFor": "roas"
}'Optimize for: roas Β· conversions Β· cpa
Returns per-campaign allocations with reasoning and expected impact.
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/analytics |
Clerk | Dashboard metrics |
GET |
/api/analytics?compare=true&period=month |
Clerk | Period-over-period comparison |
π Analytics Response Shape
{
"success": true,
"data": {
"totalRevenue": 15420.50,
"totalSpend": 3200.00,
"roas": 4.82,
"totalOrders": 142,
"averageOrderValue": 108.59,
"conversionRate": 3.2,
"impressions": 450000,
"clicks": 8500,
"ctr": 1.89,
"cpc": 0.38,
"cpa": 22.54,
"revenueByDay": [
{ "date": "2024-01-15", "revenue": 520.00, "spend": 100.00 }
],
"topProducts": [
{ "id": "prod-1", "title": "Premium Widget", "orders": 45, "revenue": 4500.00 }
],
"topCampaigns": [
{ "id": "camp-1", "name": "Holiday Sale", "spend": 500, "revenue": 3200, "roas": 6.40 }
]
}
}With ?compare=true, response includes current, previous, and changes objects with percentage deltas.
# From project root
npm test
# With verbose output
cd apps/web && npx vitest run --reporter=verbose
# Watch mode (re-runs on file save)
cd apps/web && npx vitest| Suite | File | Tests | What's Covered |
|---|---|---|---|
| Schemas | schemas.test.ts |
26 | All Zod schemas β Shopify, Meta, Campaign, AI, Pagination, Plans |
| Shopify | shopify-service.test.ts |
6 | Product/order/customer sync, webhook registration, API errors |
| Meta | meta-service.test.ts |
8 | Campaign CRUD, ad sets, audiences, insights, budget conversion |
| AI | ai-service.test.ts |
6 | Anomaly detection (CPA/ROAS/CTR thresholds), product scoring |
| Analytics | analytics.test.ts |
7 | Metric aggregation, sorting, empty data, period comparisons |
| API Utils | api-utils.test.ts |
5 | apiSuccess, apiError, AuthError helpers |
| 60 |
β __tests__/schemas.test.ts > ShopifyConnectSchema > accepts valid domain
β __tests__/schemas.test.ts > CampaignCreateSchema > accepts all campaign types
β __tests__/shopify-service.test.ts > syncProducts > syncs products from Shopify API
β __tests__/meta-service.test.ts > creates campaign with budget in cents
β __tests__/ai-service.test.ts > detects ROAS drop below 1.0
β __tests__/analytics.test.ts > calculates metrics from orders and campaigns
...
Test Files 6 passed (6)
Tests 60 passed (60)
Duration 1.17s
# Start PostgreSQL + Redis
docker compose -f docker/docker-compose.yml up -d
# View logs
docker compose -f docker/docker-compose.yml logs -f db
# Stop everything
docker compose -f docker/docker-compose.yml down
# Full reset (delete all data)
docker compose -f docker/docker-compose.yml down -vPort 5432 is commonly used by Homebrew Postgres or SSH tunnels.
# Check what's using the port
lsof -i :5432
# Option A: Use port 5433 instead
sed -i '' 's/5432:5432/5433:5432/' docker/docker-compose.yml
sed -i '' 's/localhost:5432/localhost:5433/' .env
docker compose -f docker/docker-compose.yml up -d db
# Option B: Stop existing Postgres
brew services stop postgresql@16
# Option C: Kill the process
lsof -ti:5432 | xargs kill -9Prisma Studio gives you a visual browser for all 21 tables:
npx prisma studio --schema=packages/database/prisma/schema.prismaOpens at localhost:5555 β browse Organizations, Products, Orders, Campaigns, AI Insights, etc.
Step 1 Push to GitHub
β
βΌ
Step 2 railway.app β New Project β Connect repo
β (auto-detects railway.toml)
βΌ
Step 3 Add PostgreSQL service
β (DATABASE_URL auto-injected)
βΌ
Step 4 Set environment variables
β (all keys from .env.example)
βΌ
Step 5 Deploy β Health check passes β Live
# Push to GitHub
git init && git add . && git commit -m "Initial commit"
gh repo create growthpilot --private --pushThe railway.toml configures everything:
- Multi-stage Docker build
- Health check on
/api/health - Auto-restart on failure (3 retries)
Set up cron job for data sync (every 6 hours):
GET https://your-app.up.railway.app/api/cron
Authorization: Bearer $CRON_SECRET
# Build
docker build -f docker/Dockerfile -t growthpilot .
# Run
docker run -p 3000:3000 --env-file .env growthpilot| Command | Description |
|---|---|
npm run dev |
Start dev server (Turbopack, port 3000) |
npm test |
Run all 60 tests |
npm run build |
Production build |
npx prisma studio --schema=packages/database/prisma/schema.prisma |
Visual database browser |
npx prisma db push --schema=packages/database/prisma/schema.prisma |
Push schema changes |
npx prisma generate --schema=packages/database/prisma/schema.prisma |
Regenerate typed client |
docker compose -f docker/docker-compose.yml up -d |
Start Postgres + Redis |
docker compose -f docker/docker-compose.yml logs db |
Database logs |
| Problem | Solution |
|---|---|
npm install fails |
rm -rf node_modules package-lock.json && npm install |
| Port 3000 in use | lsof -ti:3000 | xargs kill -9 |
| Port 5432 in use | See Port Conflicts above |
| Prisma generate fails | Run npm install first, then retry |
| Clerk auth errors | Verify both keys in .env (publishable + secret) |
turbo: command not found |
Use npm run dev β it calls Next.js directly |
| Docker not starting | Open Docker Desktop app, wait for engine to start |
| Tests fail on import | npx prisma generate --schema=packages/database/prisma/schema.prisma |
ECONNREFUSED on DB |
Check Postgres: docker ps β restart if needed |
| Vite CJS warning | Harmless deprecation notice β doesn't affect functionality |
MIT
Built with Next.js 15, Prisma, Clerk, OpenAI, and lots of β