Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 39 additions & 21 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ WORKDIR /app
COPY package.json bun.lock ./

# Copy package.json files for all packages (exclude local db; use published @trycompai/db)
COPY packages/auth/package.json ./packages/auth/
COPY packages/billing/package.json ./packages/billing/
COPY packages/company/package.json ./packages/company/
COPY packages/db/package.json ./packages/db/

COPY packages/kv/package.json ./packages/kv/
COPY packages/ui/package.json ./packages/ui/
COPY packages/email/package.json ./packages/email/
Expand All @@ -26,28 +31,29 @@ COPY apps/portal/package.json ./apps/portal/
RUN PRISMA_SKIP_POSTINSTALL_GENERATE=true bun install --ignore-scripts

# =============================================================================
# STAGE 2: Ultra-Minimal Migrator - Only Prisma
# STAGE 2: Migrator - built from local db source (not published npm package)
# =============================================================================
FROM oven/bun:1.2.8 AS migrator
FROM deps AS migrator

WORKDIR /app

# Copy local Prisma schema and migrations from workspace
COPY packages/db/prisma ./packages/db/prisma

# Create minimal package.json for Prisma runtime (also used by seeder)
RUN echo '{"name":"migrator","type":"module","dependencies":{"prisma":"^6.14.0","@prisma/client":"^6.14.0","@trycompai/db":"^1.3.4","zod":"^3.25.7"}}' > package.json
# Copy full local db package source (schema, scripts, seed data, prisma files)
COPY packages/db ./packages/db

# Install ONLY Prisma dependencies
RUN bun install
# Build local db package: generates Prisma Client from local schema files
# AND builds the combined dist/schema.prisma - both from source, not npm
RUN cd packages/db && bun run build

# Ensure Prisma can find migrations relative to the published schema path
# We copy the local migrations into the published package's dist directory
RUN cp -R packages/db/prisma/migrations node_modules/@trycompai/db/dist/
# Install Node.js (Bun's WASM engine has a known crash bug with Prisma 7's
# query compiler - see https://github.com/prisma/prisma/issues/28805 and
# https://github.com/oven-sh/bun/issues/17146). Run seed under Node instead.
RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates \
&& curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \

@cubic-dev-ai cubic-dev-ai Bot Jul 23, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: A changed or compromised NodeSource setup response executes arbitrary code as root during migrator builds because this mutable remote script is piped directly to bash. Use a pinned Node base/stage or verify a checksummed/signed artifact before execution.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Dockerfile, line 51:

<comment>A changed or compromised NodeSource setup response executes arbitrary code as root during migrator builds because this mutable remote script is piped directly to `bash`. Use a pinned Node base/stage or verify a checksummed/signed artifact before execution.</comment>

<file context>
@@ -26,28 +31,29 @@ COPY apps/portal/package.json ./apps/portal/
+# query compiler - see https://github.com/prisma/prisma/issues/28805 and
+# https://github.com/oven-sh/bun/issues/17146). Run seed under Node instead.
+RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates \
+    && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
+    && apt-get install -y nodejs \
+    && rm -rf /var/lib/apt/lists/* \
</file context>
Fix with cubic

&& apt-get install -y nodejs \
&& rm -rf /var/lib/apt/lists/* \
&& npm install -g tsx

# Run migrations against the combined schema published by @trycompai/db
RUN echo "Running migrations against @trycompai/db combined schema"
CMD ["bunx", "prisma", "migrate", "deploy", "--schema=node_modules/@trycompai/db/dist/schema.prisma"]
CMD ["sh", "-lc", "cd packages/db && bunx prisma migrate deploy"]

# =============================================================================
# STAGE 3: App Builder
Expand All @@ -68,8 +74,13 @@ COPY --from=deps /app/node_modules ./node_modules
# `--ignore-scripts` so packages/db's postinstall was skipped; we run
# it explicitly here so `next build` can resolve the generated runtime
# + types when it imports @prisma/client.
RUN cd packages/db && node scripts/combine-schemas.js \
&& node scripts/generate-prisma-client-js.js
# Build local workspace packages in dependency order (db first, others depend on it)
RUN cd packages/db && bun run build
RUN cd packages/auth && bun run build
RUN cd packages/company && bun run build
RUN cd packages/billing && bun run build

RUN cd apps/app && bun run db:getschema

# Ensure Next build has required public env at build-time
ARG NEXT_PUBLIC_BETTER_AUTH_URL
Expand Down Expand Up @@ -104,7 +115,7 @@ COPY --from=app-builder /app/apps/app/.next/static ./apps/app/.next/static
COPY --from=app-builder /app/apps/app/public ./apps/app/public

EXPOSE 3000
CMD ["node", "apps/app/server.js"]
CMD ["node", "--max-old-space-size=8192", "apps/app/server.js"]

# =============================================================================
# STAGE 5: Portal Builder
Expand All @@ -119,14 +130,21 @@ COPY apps/portal ./apps/portal

# Bring in node_modules for build and prisma prebuild
COPY --from=deps /app/node_modules ./node_modules
# Build local workspace packages in dependency order (db first, others depend on it)
RUN cd packages/db && bun run build

RUN cd packages/auth && bun run build
RUN cd packages/company && bun run build
RUN cd packages/billing && bun run build

# Pre-combine schemas for portal build
RUN cd packages/db && node scripts/combine-schemas.js
RUN cp packages/db/dist/schema.prisma apps/portal/prisma/schema.prisma
RUN cd apps/portal && bun run db:getschema

# Ensure Next build has required public env at build-time
ARG NEXT_PUBLIC_BETTER_AUTH_URL
ARG NEXT_PUBLIC_API_URL
ENV NEXT_PUBLIC_BETTER_AUTH_URL=$NEXT_PUBLIC_BETTER_AUTH_URL \
NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL \
NEXT_TELEMETRY_DISABLED=1 NODE_ENV=production \
NEXT_OUTPUT_STANDALONE=true \
NODE_OPTIONS=--max_old_space_size=6144
Expand All @@ -147,6 +165,6 @@ COPY --from=portal-builder /app/apps/portal/.next/static ./apps/portal/.next/sta
COPY --from=portal-builder /app/apps/portal/public ./apps/portal/public

EXPOSE 3000
CMD ["node", "apps/portal/server.js"]
CMD ["node", "--max-old-space-size=8192", "apps/portal/server.js"]

# (Trigger.dev hosted; no local runner stage)
13 changes: 13 additions & 0 deletions apps/api/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,16 @@ SECURITY_HUB_GOVCLOUD_ACCESS_KEY_ID=
SECURITY_HUB_GOVCLOUD_SECRET_ACCESS_KEY=
# Optional: only set when using temporary GovCloud credentials. Leave unset for long-lived IAM user keys.
# SECURITY_HUB_GOVCLOUD_SESSION_TOKEN=

# SMTP (optional — if SMTP_HOST is set, Resend is ignored)
SMTP_HOST=
SMTP_PORT=587
SMTP_USER=
SMTP_PASS=
SMTP_SECURE=false
SMTP_FROM=noreply@yourdomain.com

# BunMail (optional — REST email API; takes priority over SMTP/Resend)
BUNMAIL_API_URL=
BUNMAIL_API_KEY=
BUNMAIL_FROM=noreply@yourdomain.com
2 changes: 2 additions & 0 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@
"react-dom": "^19.1.0",
"reflect-metadata": "^0.2.2",
"resend": "^6.4.2",
"nodemailer": "^6.10.1",
"@types/nodemailer": "^6.4.17",
"rxjs": "^7.8.1",
"safe-stable-stringify": "^2.5.0",
"stripe": "^20.4.0",
Expand Down
4 changes: 2 additions & 2 deletions apps/api/prisma/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { PrismaPg } from '@prisma/adapter-pg';

const globalForPrisma = global as unknown as { prisma?: PrismaClient };

const LOCAL_HOSTNAMES = new Set(['localhost', '127.0.0.1', '::1']);
const LOCAL_HOSTNAMES = new Set(['localhost', '127.0.0.1', '::1', 'comp-postgres']);

@cubic-dev-ai cubic-dev-ai Bot Jul 23, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The LOCAL_HOSTNAMES set and SSL configuration helpers (isLocalhostUrl, stripSslMode) are duplicated across 4 files instead of being centralized. This diff required adding 'comp-postgres' to all 4 locations identically — a pattern that is fragile and prone to drift between environments. Consider exporting the shared hostname set and helpers from packages/db/src/ssl-config.ts (which already exports resolveSslConfig) and importing them in the apps' prisma client files, or aligning the apps to use @trycompai/db's client directly.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/prisma/client.ts, line 6:

<comment>The `LOCAL_HOSTNAMES` set and SSL configuration helpers (`isLocalhostUrl`, `stripSslMode`) are duplicated across 4 files instead of being centralized. This diff required adding `'comp-postgres'` to all 4 locations identically — a pattern that is fragile and prone to drift between environments. Consider exporting the shared hostname set and helpers from `packages/db/src/ssl-config.ts` (which already exports `resolveSslConfig`) and importing them in the apps' prisma client files, or aligning the apps to use `@trycompai/db`'s client directly.</comment>

<file context>
@@ -3,7 +3,7 @@ import { PrismaPg } from '@prisma/adapter-pg';
 const globalForPrisma = global as unknown as { prisma?: PrismaClient };
 
-const LOCAL_HOSTNAMES = new Set(['localhost', '127.0.0.1', '::1']);
+const LOCAL_HOSTNAMES = new Set(['localhost', '127.0.0.1', '::1', 'comp-postgres']);
 
 function stripSslMode(connectionString: string): string {
</file context>
Fix with cubic


function stripSslMode(connectionString: string): string {
const url = new URL(connectionString);
Expand Down Expand Up @@ -61,7 +61,7 @@ function createPrismaClient(): PrismaClient {
}
// Strip sslmode from the connection string to avoid conflicts with the explicit ssl option
const url = ssl !== undefined ? stripSslMode(rawUrl) : rawUrl;
const adapter = new PrismaPg({ connectionString: url, ssl });
const adapter = new PrismaPg({ connectionString: url, ssl: ssl ?? false });
return new PrismaClient({
adapter,
transactionOptions: {
Expand Down
3 changes: 3 additions & 0 deletions apps/api/src/auth/auth.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ function getCookieDomain(): string | undefined {
if (baseUrl.includes('trycomp.ai')) {
return '.trycomp.ai';
}
if (baseUrl.includes('dctrl.ai')) {
return '.dctrl.ai';
}
return undefined;
}

Expand Down
Loading