Skip to content

Commit 1c4862d

Browse files
authored
Merge pull request #28 from navapbc/fg/playwright-artifacts-schema
feat: migrate traces and artifacts storage to GCP deployed db
2 parents 269ae79 + 5b59dd2 commit 1c4862d

File tree

11 files changed

+973
-11
lines changed

11 files changed

+973
-11
lines changed

mastra-test-app/docs/DEPLOYMENT_NOTES.md

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This guide provides an exact, copy‑pasteable sequence to deploy `mastra-test-a
66
- Google Cloud project with billing enabled
77
- `gcloud` CLI installed and authenticated
88
- API keys: OpenAI, Anthropic, Exa
9-
- PostgreSQL connection URL (currently Neon)
9+
- GCP Cloud SQL PostgreSQL database (see [GCP_POSTGRESQL_SETUP.md](./GCP_POSTGRESQL_SETUP.md))
1010

1111
---
1212

@@ -55,14 +55,32 @@ cd labs-asp-experiments/mastra-test-app
5555
pnpm install
5656
```
5757

58-
### 5) Configure environment
58+
### 5) Authorize VM IP for database access
59+
```bash
60+
# Get the VM's external IP
61+
EXTERNAL_IP=$(gcloud compute instances describe mastra-app \
62+
--zone=us-west1-a \
63+
--format='get(networkInterfaces[0].accessConfigs[0].natIP)')
64+
65+
echo "VM External IP: $EXTERNAL_IP"
66+
67+
# Add VM IP to Cloud SQL authorized networks (replace existing IPs as needed)
68+
gcloud sql instances patch app-dev --authorized-networks=$EXTERNAL_IP
69+
```
70+
71+
### 6) Configure environment
5972
Create `.env` in the project root with required variables:
6073
```bash
6174
cat > .env << 'EOF'
6275
OPENAI_API_KEY=your_openai_key
6376
ANTHROPIC_API_KEY=your_anthropic_key
6477
EXA_API_KEY=your_exa_key
65-
DATABASE_URL=postgresql://user:pass@host:5432/db?sslmode=require
78+
79+
# GCP Cloud SQL PostgreSQL (update with your actual values)
80+
DATABASE_URL="postgresql://app_user:your_password@your_db_ip/app_db?sslmode=disable"
81+
82+
# CORS Configuration (replace YOUR_VM_IP with actual external IP)
83+
CORS_ORIGINS="http://localhost:4111,http://0.0.0.0:4111,http://YOUR_VM_IP:4111,*"
6684
6785
# Required for auth middleware
6886
MASTRA_JWT_SECRET=replace_with_a_strong_random_secret
@@ -72,20 +90,47 @@ NODE_ENV=production
7290
EOF
7391
```
7492

75-
### 7) Build and (optionally) apply migrations
93+
**Note:** For production, consider using `sslmode=require` with proper SSL certificates instead of `sslmode=disable`.
94+
95+
### 7) Build and apply migrations
7696
```bash
7797
# Build the app and prepare Prisma client in the output
7898
pnpm build
7999

80-
# If your database is new or migrations need to be applied
100+
# Apply database migrations
81101
npx prisma migrate deploy
102+
103+
# Generate Prisma client
104+
npx prisma generate
82105
```
83106

84107
### 8) Start the application
108+
109+
#### Option A: Development/Testing (foreground)
85110
```bash
86111
pnpm dev
87112
```
88113

114+
#### Option B: Production/Persistent (with PM2)
115+
```bash
116+
# Install PM2 globally
117+
sudo npm install -g pm2
118+
119+
# Start the app with PM2
120+
pm2 start "pnpm dev" --name app-playground
121+
122+
# Useful PM2 commands:
123+
pm2 list # View all processes
124+
pm2 logs app-playground # View logs
125+
pm2 restart app-playground # Restart the app
126+
pm2 stop app-playground # Stop the app
127+
pm2 delete app-playground # Remove from PM2
128+
129+
# Auto-restart PM2 processes on system reboot
130+
pm2 startup
131+
pm2 save
132+
```
133+
89134
The server listens on `0.0.0.0:4111`. In another terminal:
90135
```bash
91136
EXTERNAL_IP=$(gcloud compute instances describe mastra-app \
@@ -102,6 +147,13 @@ echo "http://$EXTERNAL_IP:4111/auth/login"
102147
- Auth-protected UI is served at `/auth/login` and the Web Automation Agent playground at `/agents/webAutomationAgent/chat/` after login.
103148

104149
### Troubleshooting
105-
- Prisma client errors: ensure you ran `pnpm build`. If needed, run `npx prisma generate` once, then `pnpm build` again.
106-
- Firewall: verify with `gcloud compute firewall-rules list --filter="name~allow-mastra-app"`.
107-
- Logs: if using PM2, run `pm2 logs mastra-app`; otherwise, observe terminal output from `pnpm dev`.
150+
- **Prisma client errors:** ensure you ran `pnpm build`. If needed, run `npx prisma generate` once, then `pnpm build` again.
151+
- **Firewall issues:** verify with `gcloud compute firewall-rules list --filter="name~allow-mastra-app"`.
152+
- **Database connection:** check that VM IP is authorized in Cloud SQL and `.env` has correct DATABASE_URL.
153+
- **Logs:**
154+
- PM2: `pm2 logs app-playground`
155+
- Foreground: observe terminal output from `pnpm dev`
156+
- **PM2 process management:**
157+
- Check status: `pm2 status`
158+
- Restart if needed: `pm2 restart app-playground`
159+
- Clear logs: `pm2 flush`
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
## Overview
2+
3+
We migrated to Google Cloud SQL PostgreSQL due to memory and storage limitations on our previous database. The setup uses a cost-effective shared-core instance suitable for development environments.
4+
5+
## Prerequisites
6+
7+
- Google Cloud SDK (`gcloud`) installed and authenticated
8+
- Access to the `nava-labs` GCP project
9+
- Appropriate IAM permissions for Cloud SQL
10+
11+
## Database Configuration
12+
13+
### Instance Details
14+
- **Instance Name:** `app-dev`
15+
- **Database Engine:** PostgreSQL 15
16+
- **Tier:** `db-g1-small` (1.7 GB RAM, shared-core)
17+
- **Region:** `us-central1`
18+
- **Storage:** 100GB SSD with automatic backups enabled
19+
- **IP Address:** `your_ip_address`
20+
21+
### Database & User
22+
- **Database Name:** `app_db`
23+
- **Username:** `app_user`
24+
- **Password:** `your_password`
25+
26+
## Setup Instructions
27+
28+
### 1. Verify GCP Project Configuration
29+
30+
```bash
31+
# Check current project
32+
gcloud config get-value project
33+
# Should return: nava-labs
34+
```
35+
36+
### 2. Create PostgreSQL Instance
37+
38+
```bash
39+
gcloud sql instances create app-dev \
40+
--database-version=POSTGRES_15 \
41+
--tier=db-g1-small \
42+
--region=us-central1 \
43+
--storage-type=SSD \
44+
--storage-size=100GB \
45+
--backup
46+
```
47+
48+
**Note:** PostgreSQL on Cloud SQL only supports custom tiers or shared-core tiers (not the standard predefined tiers like `db-n1-standard-*`).
49+
50+
### 3. Create Database
51+
52+
```bash
53+
gcloud sql databases create app_db --instance=app-dev
54+
```
55+
56+
### 4. Create Database User
57+
58+
```bash
59+
gcloud sql users create app_user \
60+
--instance=app-dev \
61+
--password=your_password
62+
```
63+
64+
### 5. Get Connection Information
65+
66+
```bash
67+
# Get the instance IP address
68+
gcloud sql instances describe app-dev \
69+
--format="value(ipAddresses[0].ipAddress)"
70+
```
71+
72+
### 6. Authorize Your IP Address
73+
74+
Before you can connect to the database, you need to add your current IP address to the authorized networks:
75+
76+
```bash
77+
# Get your current public IP address
78+
curl -s https://ipinfo.io/ip
79+
80+
# Add your IP to the authorized networks (replace YOUR_IP with the actual IP)
81+
gcloud sql instances patch app-dev --authorized-networks=YOUR_IP
82+
```
83+
84+
**Important:** When adding a new IP address, make sure to include any previously authorized IPs, otherwise they will be overwritten.
85+
86+
### 7. Update Environment Configuration
87+
88+
Update your `.env` file with the new database connection string:
89+
90+
```env
91+
# New GCP Cloud SQL PostgreSQL
92+
DATABASE_URL="postgresql://app_user:your_password@your_ip_address/app_db?sslmode=require"
93+
```
94+
95+
## Connection String Format
96+
97+
```
98+
postgresql://[username]:[password]@[host]:[port]/[database]?[parameters]
99+
```
100+
101+
For our setup:
102+
- **Username:** `app_user`
103+
- **Password:** `your_password`
104+
- **Host:** `your_ip_address`
105+
- **Port:** `5432` (default, omitted)
106+
- **Database:** `app_db`
107+
- **SSL Mode:** `require` (mandatory for Cloud SQL)
108+
109+
## Database Migration
110+
111+
After setting up the new database and authorizing your IP, run Prisma migrations to set up the schema:
112+
113+
```bash
114+
# Deploy existing migrations to the new database
115+
npx prisma migrate deploy
116+
117+
# Generate the Prisma client
118+
npx prisma generate
119+
120+
# Verify the schema is synchronized (optional)
121+
npx prisma db push --accept-data-loss
122+
```
123+
124+
**Note:** If you get a connection error, make sure you've completed step 6 (IP authorization) above.
125+
126+
## Environment Naming Convention
127+
128+
Following our multi-environment strategy:
129+
- **Development:** `app-dev` (current setup)
130+
- **Staging:** `app-staging` (future)
131+
- **Production:** `app-prod` (future)
132+
133+
## Cost Considerations
134+
135+
- **Tier:** `db-g1-small` is cost-effective for development
136+
- **Storage:** 100GB SSD provides good performance
137+
- **Backups:** Enabled for data safety
138+
- **Region:** `us-central1` offers good pricing
139+
140+
## Troubleshooting
141+
142+
### Common Issues
143+
144+
1. **"Only custom or shared-core instance Billing Tier type allowed for PostgreSQL"**
145+
- Use `db-g1-small` or `db-custom-X-Y` tiers, not `db-n1-standard-*`
146+
147+
2. **"Can't reach database server" or connection timeouts**
148+
- Ensure your IP is authorized: `gcloud sql instances patch app-dev --authorized-networks=YOUR_IP`
149+
- Verify SSL mode is set to `require`
150+
- Check that the instance is running: `gcloud sql instances describe app-dev`
151+
152+
3. **Prisma migration fails**
153+
- Make sure IP authorization is complete before running migrations
154+
- Verify the DATABASE_URL in your `.env` file is correct
155+
156+
### Useful Commands
157+
158+
```bash
159+
# List all SQL instances
160+
gcloud sql instances list
161+
162+
# Get instance details
163+
gcloud sql instances describe app-dev
164+
165+
# List databases in instance
166+
gcloud sql databases list --instance=app-dev
167+
168+
# List users in instance
169+
gcloud sql users list --instance=app-dev
170+
171+
# Connect via gcloud (for testing)
172+
gcloud sql connect app-dev --user=app_user --database=app_db
173+
```
174+
175+
## Security Notes
176+
177+
- Database password is stored in `.env` file (ensure it's in `.gitignore`)
178+
- SSL is required for all connections
179+
- Plan to use Cloud SQL Proxy for better security in production
180+
- IP whitelisting should be configured for production environments
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
-- CreateTable
2+
CREATE TABLE "public"."mastra_artifacts" (
3+
"id" TEXT NOT NULL,
4+
"sessionId" TEXT NOT NULL,
5+
"fileName" TEXT NOT NULL,
6+
"fileType" TEXT NOT NULL,
7+
"mimeType" TEXT NOT NULL,
8+
"size" INTEGER NOT NULL,
9+
"content" BYTEA NOT NULL,
10+
"metadata" JSONB NOT NULL DEFAULT '{}',
11+
"traceId" TEXT,
12+
"threadId" TEXT,
13+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
14+
"updatedAt" TIMESTAMP(3) NOT NULL,
15+
16+
CONSTRAINT "mastra_artifacts_pkey" PRIMARY KEY ("id")
17+
);
18+
19+
-- CreateIndex
20+
CREATE INDEX "mastra_artifacts_sessionId_idx" ON "public"."mastra_artifacts"("sessionId");
21+
22+
-- CreateIndex
23+
CREATE INDEX "mastra_artifacts_fileType_idx" ON "public"."mastra_artifacts"("fileType");
24+
25+
-- CreateIndex
26+
CREATE INDEX "mastra_artifacts_traceId_idx" ON "public"."mastra_artifacts"("traceId");
27+
28+
-- CreateIndex
29+
CREATE INDEX "mastra_artifacts_createdAt_idx" ON "public"."mastra_artifacts"("createdAt");

mastra-test-app/prisma/schema.prisma

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,24 @@ model HouseholdDependent {
6666
@@map("household_dependents")
6767
}
6868

69+
model PlaywrightArtifact {
70+
id String @id @default(cuid())
71+
sessionId String
72+
fileName String
73+
fileType String // 'screenshot' | 'trace' | 'session' | 'other'
74+
mimeType String
75+
size Int
76+
content Bytes
77+
metadata Json @default("{}")
78+
traceId String?
79+
threadId String?
80+
createdAt DateTime @default(now())
81+
updatedAt DateTime @updatedAt
82+
83+
@@index([sessionId])
84+
@@index([fileType])
85+
@@index([traceId])
86+
@@index([createdAt])
87+
@@map("mastra_artifacts")
88+
}
89+

mastra-test-app/src/mastra/agents/data-ops-agent.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,30 @@ import { anthropic } from '@ai-sdk/anthropic';
44
import { google } from '@ai-sdk/google';
55
import { databaseTools } from '../tools/database-tools';
66
import { storageTools } from '../tools/storage-tools';
7+
import { artifactTools } from '../tools/artifact-tools';
78

89
export const dataOpsAgent = new Agent({
910
name: 'Data Ops Agent',
10-
description: 'Agent specialized in database and Mastra storage queries (participants, threads, messages, traces).',
11+
description: 'Agent specialized in database and Playwright artifacts and Mastra storage queries (participants, threads, messages, traces).',
1112
instructions: `
1213
You are a concise data operations assistant. Use the provided tools to:
1314
- Query and manage participants/household records
1415
- Inspect Mastra threads, messages, and traces
16+
- Store and retrieve Playwright artifacts (screenshots, traces, session data)
1517
- Return small, readable result sets
18+
19+
The artifact tools allow you to:
20+
- Store files from disk as artifacts in the database
21+
- List and search stored artifacts
22+
- Retrieve artifacts by ID or session
23+
- Delete artifacts when no longer needed
1624
`,
1725
// model: google('gemini-2.5-pro'),
1826
model: anthropic('claude-sonnet-4-20250514'),
1927
tools: {
2028
...Object.fromEntries(databaseTools.map(t => [t.id, t])),
2129
...Object.fromEntries(storageTools.map(t => [t.id, t])),
30+
...Object.fromEntries(artifactTools.map(t => [t.id, t])),
2231
},
2332

2433
defaultStreamOptions: {

0 commit comments

Comments
 (0)