diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 46c5638..83dbf74 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -1,14 +1,17 @@ #!/bin/sh set -e -# Fix /data permissions — Docker volumes are mounted as root by default -chown -R nextjs:nodejs /data +if [ -n "$TURSO_DATABASE_URL" ]; then + echo "Turso database configured — skipping local migrations." +else + # Fix /data permissions — Docker volumes are mounted as root by default + chown -R nextjs:nodejs /data 2>/dev/null || true -# Run Prisma migrations as nextjs user -echo "Running database migrations..." -DATABASE_URL="${DATABASE_URL:-file:/data/leadflow.db}" \ - su-exec nextjs node node_modules/prisma/build/index.js migrate deploy \ - --schema ./prisma/schema.prisma 2>&1 || echo "Migration warning (may already be up to date)" + echo "Running SQLite migrations..." + DATABASE_URL="${DATABASE_URL:-file:/data/leadflow.db}" \ + su-exec nextjs node node_modules/prisma/build/index.js migrate deploy \ + --schema ./prisma/schema.prisma 2>&1 || echo "Migration warning (may already be up to date)" +fi echo "Starting LeadFlow..." exec su-exec nextjs node server.js diff --git a/prisma/turso-schema.sql b/prisma/turso-schema.sql new file mode 100644 index 0000000..9e31b3f --- /dev/null +++ b/prisma/turso-schema.sql @@ -0,0 +1,102 @@ +-- LeadFlow schema for Turso (combined migrations) +-- Apply with: turso db shell < prisma/turso-schema.sql + +CREATE TABLE IF NOT EXISTS "ApiCredential" ( + "id" TEXT NOT NULL PRIMARY KEY, + "service" TEXT NOT NULL, + "value" TEXT NOT NULL, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL +); +CREATE UNIQUE INDEX IF NOT EXISTS "ApiCredential_service_key" ON "ApiCredential"("service"); + +CREATE TABLE IF NOT EXISTS "Job" ( + "id" TEXT NOT NULL PRIMARY KEY, + "type" TEXT NOT NULL, + "status" TEXT NOT NULL DEFAULT 'pending', + "config" TEXT NOT NULL DEFAULT '{}', + "totalLeads" INTEGER NOT NULL DEFAULT 0, + "emailsFound" INTEGER NOT NULL DEFAULT 0, + "error" TEXT, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL +); + +CREATE TABLE IF NOT EXISTS "LeadResult" ( + "id" TEXT NOT NULL PRIMARY KEY, + "jobId" TEXT NOT NULL, + "companyName" TEXT, + "domain" TEXT, + "contactName" TEXT, + "contactTitle" TEXT, + "email" TEXT, + "confidence" REAL, + "linkedinUrl" TEXT, + "source" TEXT, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY ("jobId") REFERENCES "Job" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE TABLE IF NOT EXISTS "Lead" ( + "id" TEXT NOT NULL PRIMARY KEY, + "domain" TEXT, + "companyName" TEXT, + "contactName" TEXT, + "contactTitle" TEXT, + "email" TEXT, + "linkedinUrl" TEXT, + "phone" TEXT, + "address" TEXT, + "sourceTab" TEXT NOT NULL, + "sourceTerm" TEXT, + "sourceJobId" TEXT, + "serpTitle" TEXT, + "serpSnippet" TEXT, + "serpRank" INTEGER, + "serpUrl" TEXT, + "emailConfidence" REAL, + "status" TEXT NOT NULL DEFAULT 'new', + "priority" TEXT NOT NULL DEFAULT 'normal', + "notes" TEXT, + "tags" TEXT, + "country" TEXT, + "headcount" TEXT, + "industry" TEXT, + "description" TEXT, + "companyType" TEXT, + "topics" TEXT, + "salesScore" INTEGER, + "salesReason" TEXT, + "offerPackage" TEXT, + "approved" INTEGER NOT NULL DEFAULT 0, + "approvedAt" DATETIME, + "capturedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "contactedAt" DATETIME, + "updatedAt" DATETIME NOT NULL +); +CREATE INDEX IF NOT EXISTS "Lead_domain_idx" ON "Lead"("domain"); +CREATE INDEX IF NOT EXISTS "Lead_status_idx" ON "Lead"("status"); +CREATE INDEX IF NOT EXISTS "Lead_sourceTab_idx" ON "Lead"("sourceTab"); +CREATE INDEX IF NOT EXISTS "Lead_capturedAt_idx" ON "Lead"("capturedAt"); +CREATE INDEX IF NOT EXISTS "Lead_email_idx" ON "Lead"("email"); +CREATE INDEX IF NOT EXISTS "Lead_approved_idx" ON "Lead"("approved"); +CREATE INDEX IF NOT EXISTS "Lead_companyType_idx" ON "Lead"("companyType"); + +CREATE TABLE IF NOT EXISTS "LeadEvent" ( + "id" TEXT NOT NULL PRIMARY KEY, + "leadId" TEXT NOT NULL, + "event" TEXT NOT NULL, + "at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY ("leadId") REFERENCES "Lead" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); +CREATE INDEX IF NOT EXISTS "LeadEvent_leadId_idx" ON "LeadEvent"("leadId"); + +CREATE TABLE IF NOT EXISTS "SearchHistory" ( + "id" TEXT NOT NULL PRIMARY KEY, + "query" TEXT NOT NULL, + "region" TEXT NOT NULL, + "searchMode" TEXT NOT NULL, + "executedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP +); +CREATE INDEX IF NOT EXISTS "SearchHistory_searchMode_idx" ON "SearchHistory"("searchMode"); +CREATE INDEX IF NOT EXISTS "SearchHistory_executedAt_idx" ON "SearchHistory"("executedAt");