Skip to content

Enable self-hosted deployment with BunMail, SMTP, and Docker fixes. - #3492

Closed
raedbrahem wants to merge 2 commits into
trycompai:mainfrom
1devspace:main
Closed

Enable self-hosted deployment with BunMail, SMTP, and Docker fixes.#3492
raedbrahem wants to merge 2 commits into
trycompai:mainfrom
1devspace:main

Conversation

@raedbrahem

@raedbrahem raedbrahem commented Jul 23, 2026

Copy link
Copy Markdown

Add BunMail REST and SMTP email transports with direct send fallback when Trigger.dev is unset, wire the API service into docker-compose, and fix Prisma TLS for local Postgres hostnames.

What does this PR do?

  • Fixes #XXXX (GitHub issue number)
  • Fixes COMP-XXXX (Linear issue number - should be visible at the bottom of the GitHub issue description)

Visual Demo (For contributors especially)

A visual demonstration is strongly recommended, for both the original and new change (video / image - any one).

Video Demo (if applicable):

  • Show screen recordings of the issue or feature.
  • Demonstrate how to reproduce the issue, the behavior before and after the change.

Image Demo (if applicable):

  • Add side-by-side screenshots of the original and updated change.
  • Highlight any significant change(s).

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. If N/A, write N/A here and check the checkbox.
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

How should this be tested?

  • Are there environment variables that should be set?
  • What are the minimal test data to have?
  • What is expected (happy path) to have (input and output)?
  • Any other important info that could help to test that PR

Checklist

  • I haven't read the contributing guide
  • My code doesn't follow the style guidelines of this project
  • I haven't commented my code, particularly in hard-to-understand areas
  • I haven't checked if my changes generate no new warnings

Summary by cubic

Enables self-hosted deployments with BunMail/SMTP email, a Dockerized API, and reliable local Postgres. Adds MinIO-backed S3, dctrl.ai cookie/portal URL support, and smoother Docker/Prisma builds.

  • New Features

    • Adds BunMail REST and SMTP transports with priority: BunMail → SMTP → Resend; sends directly when TRIGGER_SECRET_KEY is unset, with one‑click unsubscribe headers.
    • Introduces apps/api service in docker-compose (port 3333) with healthchecks and DB/env wiring; propagates NEXT_PUBLIC_API_URL to app and portal.
    • Adds MinIO and a bucket init job for local S3; wires portal S3 env (APP_AWS_*, FLEET_AGENT_BUCKET_NAME) to MinIO.
    • Supports .dctrl.ai cookie domain and centralizes portal links via PORTAL_URL/NEXT_PUBLIC_PORTAL_URL helper; updates invite emails and UI links.
    • Improves Docker builds: builds local packages/db first, uses tsx for seeding, increases Node memory; app runs on 3001 and portal on 3002. Adds nodemailer and @types/nodemailer to apps/api.
  • Migration

    • Email config (choose one):
      • BunMail: set BUNMAIL_API_URL, BUNMAIL_API_KEY, BUNMAIL_FROM.
      • SMTP: set SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS, SMTP_SECURE, SMTP_FROM.
      • Resend fallback: ensure RESEND_* vars are set.
    • URLs: set NEXT_PUBLIC_API_URL for app/portal; set PORTAL_URL (self‑host) or NEXT_PUBLIC_PORTAL_URL for portal links.
    • Local Postgres: service must be comp-postgres; DB URL uses sslmode=disable and PGSSLMODE=disable. comp-postgres is treated as local for Prisma TLS.
    • Optional Trigger.dev: leave TRIGGER_SECRET_KEY unset to send emails directly; set it to use the queued task path.
    • Optional MinIO: use the provided minio/minio-init services, or point APP_AWS_* to your S3 endpoint.
    • Docker: ensure the external network comp_network exists before docker compose up.

Written for commit 734cd98. Summary will update on new commits.

Review in cubic

Add BunMail REST and SMTP email transports with direct send fallback when Trigger.dev is unset, wire the API service into docker-compose, and fix Prisma TLS for local Postgres hostnames.
@vercel

vercel Bot commented Jul 23, 2026

Copy link
Copy Markdown

@raedbrahem is attempting to deploy a commit to the Comp AI Team on Vercel.

A member of the Team first needs to authorize it.

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@cubic-dev-ai cubic-dev-ai Bot left a comment

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.

7 issues found across 12 files

Confidence score: 2/5

  • In docker-compose.yml, the service env overrides point at Postgres host/credentials that do not exist in this repo’s DB setup, so self-hosted services are likely to fail at startup or crash-loop when they try to connect to the database — align these env values with the actual compose Postgres service definitions.
  • In apps/api/src/email/email-transport.ts, the SMTP path drops scheduledAt, which can send scheduled emails immediately and create user-facing timing/compliance issues — defer SMTP sends until scheduledAt or explicitly reject scheduled SMTP requests.
  • In apps/api/src/email/email-transport.ts (sendHtmlEmail), the BunMail branch omits headers and attachments, so unsubscribe headers and file attachments can be silently lost in production emails — forward both fields in the BunMail payload and add coverage for these cases.
  • docker-compose.yml now requires an external comp_network, and packages/db/src/ssl-config.ts lacks a regression test for the new Docker hostname, making local/self-hosted bring-up more fragile and harder to debug when networking or TLS behavior shifts — document/provision the network requirement and add the hostname SSL test case.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/db/src/ssl-config.ts">

<violation number="1" location="packages/db/src/ssl-config.ts:6">
P3: The new Docker hostname has no regression test, so an allowlist typo or later URL-parsing change can make self-hosted containers attempt TLS and fail to connect. Add a `resolveSslConfig('postgresql://u:p@comp-postgres:5432/x', {})` case asserting `undefined`.</violation>
</file>

<file name="docker-compose.yml">

<violation number="1" location="docker-compose.yml:40">
P1: The self-hosted services cannot connect to the repository's Postgres container: these overrides replace each service's env-file URL with a host and credentials that do not exist in the provided database compose setup. Use the actual database service/credentials or parameterize `DATABASE_URL` so deployments can supply their own connection string.</violation>

<violation number="2" location="docker-compose.yml:104">
P2: The `networks.default` overrides the project's default network to `comp_network` with `external: true`, which means this Docker network must already exist before `docker-compose up` will succeed. Running the compose file for the first time without a prior `docker network create comp_network` will fail with an opaque network-not-found error. Consider either dropping `external: true` so Docker Compose creates the network automatically, or adding a `docker network create` step to the project's setup documentation.</violation>
</file>

<file name="apps/api/src/email/email-transport.ts">

<violation number="1" location="apps/api/src/email/email-transport.ts:212">
P1: When BunMail is configured, the `sendHtmlEmail` function silently drops both `headers` and `attachments` from the outgoing email payload. This means the RFC 8058 one-click unsubscribe headers (`List-Unsubscribe` / `List-Unsubscribe-Post`) that both callers (`send-email.ts` and `trigger-email.ts`) explicitly build and pass through will not reach the BunMail API, breaking unsubscribe compliance for Gmail and other providers. Any attachments sent through the BunMail path are also silently discarded. Consider either adding `headers` and `attachments` support to the `sendViaBunMail` function and the BunMail API call, or documenting this as a known limitation so callers can handle it appropriately.</violation>

<violation number="2" location="apps/api/src/email/email-transport.ts:222">
P1: Scheduled emails are delivered immediately when SMTP is configured because this branch discards `scheduledAt`. Queue/defer SMTP sends until the requested time, or reject scheduled SMTP requests so users do not receive notifications early.</violation>
</file>

<file name="Dockerfile">

<violation number="1" location="Dockerfile:54">
P3: Docker builds can change unexpectedly because this resolves the latest global `tsx` outside the lockfile, and it bypasses the repository’s Bun-only dependency workflow. Use a pinned, Bun-managed `tsx` dependency instead.</violation>
</file>

<file name="apps/api/src/email/trigger-email.ts">

<violation number="1" location="apps/api/src/email/trigger-email.ts:75">
P3: The `console.log` on line 75 is the only informational log in this function, while the error path on line 95 uses `console.error`. In a NestJS application, consider using a structured `Logger` service for consistency, so that log levels and formatting are uniform across the codebase.</violation>
</file>

Tip: instead of fixing issues one by one fix them all with cubic

Re-trigger cubic

Comment thread docker-compose.yml
- apps/app/.env
environment:
PGSSLMODE: disable
DATABASE_URL: postgresql://comp:comp@comp-postgres:5432/comp?sslmode=disable

@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.

P1: The self-hosted services cannot connect to the repository's Postgres container: these overrides replace each service's env-file URL with a host and credentials that do not exist in the provided database compose setup. Use the actual database service/credentials or parameterize DATABASE_URL so deployments can supply their own connection string.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docker-compose.yml, line 40:

<comment>The self-hosted services cannot connect to the repository's Postgres container: these overrides replace each service's env-file URL with a host and credentials that do not exist in the provided database compose setup. Use the actual database service/credentials or parameterize `DATABASE_URL` so deployments can supply their own connection string.</comment>

<file context>
@@ -30,17 +30,43 @@ services:
       - apps/app/.env
+    environment:
+      PGSSLMODE: disable
+      DATABASE_URL: postgresql://comp:comp@comp-postgres:5432/comp?sslmode=disable
     restart: unless-stopped
     healthcheck:
</file context>
Fix with cubic

}

if (isSmtpConfigured()) {
return sendViaSmtp({

@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.

P1: Scheduled emails are delivered immediately when SMTP is configured because this branch discards scheduledAt. Queue/defer SMTP sends until the requested time, or reject scheduled SMTP requests so users do not receive notifications early.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/email/email-transport.ts, line 222:

<comment>Scheduled emails are delivered immediately when SMTP is configured because this branch discards `scheduledAt`. Queue/defer SMTP sends until the requested time, or reject scheduled SMTP requests so users do not receive notifications early.</comment>

<file context>
@@ -0,0 +1,243 @@
+  }
+
+  if (isSmtpConfigured()) {
+    return sendViaSmtp({
+      from: fromAddress,
+      to: toAddress,
</file context>
Fix with cubic

}

if (isBunMailConfigured()) {
return sendViaBunMail({

@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.

P1: When BunMail is configured, the sendHtmlEmail function silently drops both headers and attachments from the outgoing email payload. This means the RFC 8058 one-click unsubscribe headers (List-Unsubscribe / List-Unsubscribe-Post) that both callers (send-email.ts and trigger-email.ts) explicitly build and pass through will not reach the BunMail API, breaking unsubscribe compliance for Gmail and other providers. Any attachments sent through the BunMail path are also silently discarded. Consider either adding headers and attachments support to the sendViaBunMail function and the BunMail API call, or documenting this as a known limitation so callers can handle it appropriately.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/email/email-transport.ts, line 212:

<comment>When BunMail is configured, the `sendHtmlEmail` function silently drops both `headers` and `attachments` from the outgoing email payload. This means the RFC 8058 one-click unsubscribe headers (`List-Unsubscribe` / `List-Unsubscribe-Post`) that both callers (`send-email.ts` and `trigger-email.ts`) explicitly build and pass through will not reach the BunMail API, breaking unsubscribe compliance for Gmail and other providers. Any attachments sent through the BunMail path are also silently discarded. Consider either adding `headers` and `attachments` support to the `sendViaBunMail` function and the BunMail API call, or documenting this as a known limitation so callers can handle it appropriately.</comment>

<file context>
@@ -0,0 +1,243 @@
+  }
+
+  if (isBunMailConfigured()) {
+    return sendViaBunMail({
+      from: fromAddress,
+      to: toAddress,
</file context>
Fix with cubic

Comment thread docker-compose.yml
networks:
default:
name: comp_network
external: true

@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 networks.default overrides the project's default network to comp_network with external: true, which means this Docker network must already exist before docker-compose up will succeed. Running the compose file for the first time without a prior docker network create comp_network will fail with an opaque network-not-found error. Consider either dropping external: true so Docker Compose creates the network automatically, or adding a docker network create step to the project's setup documentation.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docker-compose.yml, line 104:

<comment>The `networks.default` overrides the project's default network to `comp_network` with `external: true`, which means this Docker network must already exist before `docker-compose up` will succeed. Running the compose file for the first time without a prior `docker network create comp_network` will fail with an opaque network-not-found error. Consider either dropping `external: true` so Docker Compose creates the network automatically, or adding a `docker network create` step to the project's setup documentation.</comment>

<file context>
@@ -49,14 +75,30 @@ services:
+networks:
+  default:
+    name: comp_network
+    external: true
</file context>
Fix with cubic

| { rejectUnauthorized: false };

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.

P3: The new Docker hostname has no regression test, so an allowlist typo or later URL-parsing change can make self-hosted containers attempt TLS and fail to connect. Add a resolveSslConfig('postgresql://u:p@comp-postgres:5432/x', {}) case asserting undefined.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/db/src/ssl-config.ts, line 6:

<comment>The new Docker hostname has no regression test, so an allowlist typo or later URL-parsing change can make self-hosted containers attempt TLS and fail to connect. Add a `resolveSslConfig('postgresql://u:p@comp-postgres:5432/x', {})` case asserting `undefined`.</comment>

<file context>
@@ -3,7 +3,7 @@ export type SslConfig =
   | { rejectUnauthorized: false };
 
-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 isLocalhostUrl(connectionString: string): boolean {
</file context>
Fix with cubic

Comment thread Dockerfile
&& curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
&& apt-get install -y nodejs \
&& rm -rf /var/lib/apt/lists/* \
&& npm install -g tsx

@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.

P3: Docker builds can change unexpectedly because this resolves the latest global tsx outside the lockfile, and it bypasses the repository’s Bun-only dependency workflow. Use a pinned, Bun-managed tsx dependency instead.

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

<comment>Docker builds can change unexpectedly because this resolves the latest global `tsx` outside the lockfile, and it bypasses the repository’s Bun-only dependency workflow. Use a pinned, Bun-managed `tsx` dependency instead.</comment>

<file context>
@@ -26,28 +31,29 @@ COPY apps/portal/package.json ./apps/portal/
+    && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
+    && 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
</file context>
Fix with cubic

};

if (!process.env.TRIGGER_SECRET_KEY) {
console.log(

@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.

P3: The console.log on line 75 is the only informational log in this function, while the error path on line 95 uses console.error. In a NestJS application, consider using a structured Logger service for consistency, so that log levels and formatting are uniform across the codebase.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/email/trigger-email.ts, line 75:

<comment>The `console.log` on line 75 is the only informational log in this function, while the error path on line 95 uses `console.error`. In a NestJS application, consider using a structured `Logger` service for consistency, so that log levels and formatting are uniform across the codebase.</comment>

<file context>
@@ -30,16 +60,26 @@ export async function triggerEmail(params: {
+    };
+
+    if (!process.env.TRIGGER_SECRET_KEY) {
+      console.log(
+        'TRIGGER_SECRET_KEY not set; sending email directly via configured transport',
+      );
</file context>
Fix with cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment

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.

4 issues found across 8 files (changes from recent commits).

Confidence score: 2/5

  • In apps/api/src/auth/auth.server.ts, comp-app.dctrl.ai and comp-portal.dctrl.ai are not included in Better Auth trustedOrigins/API CORS checks, so self-hosted clients can receive the cookie but still fail cross-origin auth flows — add both hosts to the trusted origins and CORS allowlist paths used by auth.
  • In docker-compose.yml, TRUST_APP_URL is set to the employee portal host even though the API uses it as the base for trust-site/access links, which can send users to the wrong destination and break trust-portal journeys — point TRUST_APP_URL to the trust app domain and verify generated links end-to-end.
  • In docker-compose.yml, using minio/minio:latest adds upgrade drift risk across environments, and in packages/email/emails/policy-acknowledgment-digest.tsx the extra trailing-slash replace is dead code that can obscure intent — pin MinIO to a release tag and remove the redundant replace for predictability and clarity.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/api/src/auth/auth.server.ts">

<violation number="1" location="apps/api/src/auth/auth.server.ts:45">
P1: Default self-hosted dctrl clients cannot complete cross-origin auth/CORS: `comp-app.dctrl.ai` and `comp-portal.dctrl.ai` receive the shared cookie but remain absent from Better Auth `trustedOrigins` and API CORS checks when `AUTH_TRUSTED_ORIGINS` is unset. Add the dctrl origins/pattern alongside this cookie-domain support, or require and provide `AUTH_TRUSTED_ORIGINS` in the deployment config.</violation>
</file>

<file name="docker-compose.yml">

<violation number="1" location="docker-compose.yml:65">
P1: Trust portal links generated by the API are pointed at the employee portal host. `TRUST_APP_URL` is consumed as the base for trust-site and access URLs, but this compose change sets it to `https://comp-portal.dctrl.ai`; recipients will be sent links such as `https://comp-portal.dctrl.ai/<friendlyUrl>/access/<token>`, which can route to the wrong application. The deployment should set `TRUST_APP_URL` to the actual trust portal URL (or leave it unset if `PORTAL_URL` is the intended trust host) and verify the corresponding route exists.</violation>

<violation number="2" location="docker-compose.yml:108">
P3: The MinIO service uses `minio/minio:latest` which is not pinned to a specific version. `latest` can change unexpectedly and break the compose setup. Consider pinning to a specific release tag (e.g., `minio/minio:RELEASE.2024-01-01T00-00-00Z`) for reproducible deployments.</violation>
</file>

<file name="packages/email/emails/policy-acknowledgment-digest.tsx">

<violation number="1" location="packages/email/emails/policy-acknowledgment-digest.tsx:65">
P3: The trailing-slash replacement applied to `getPortalBaseUrl()` is redundant because the helper already strips trailing slashes internally. The `.replace(//+$/, '')` wrapping on line 64 is guaranteed to be a no-op, which adds unnecessary indirection and makes the code slightly harder to read. Consider removing the outer `.replace()` and using the return value of `getPortalBaseUrl()` directly.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

if (baseUrl.includes('trycomp.ai')) {
return '.trycomp.ai';
}
if (baseUrl.includes('dctrl.ai')) {

@cubic-dev-ai cubic-dev-ai Bot Jul 27, 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.

P1: Default self-hosted dctrl clients cannot complete cross-origin auth/CORS: comp-app.dctrl.ai and comp-portal.dctrl.ai receive the shared cookie but remain absent from Better Auth trustedOrigins and API CORS checks when AUTH_TRUSTED_ORIGINS is unset. Add the dctrl origins/pattern alongside this cookie-domain support, or require and provide AUTH_TRUSTED_ORIGINS in the deployment config.

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

<comment>Default self-hosted dctrl clients cannot complete cross-origin auth/CORS: `comp-app.dctrl.ai` and `comp-portal.dctrl.ai` receive the shared cookie but remain absent from Better Auth `trustedOrigins` and API CORS checks when `AUTH_TRUSTED_ORIGINS` is unset. Add the dctrl origins/pattern alongside this cookie-domain support, or require and provide `AUTH_TRUSTED_ORIGINS` in the deployment config.</comment>

<file context>
@@ -42,6 +42,9 @@ function getCookieDomain(): string | undefined {
   if (baseUrl.includes('trycomp.ai')) {
     return '.trycomp.ai';
   }
+  if (baseUrl.includes('dctrl.ai')) {
+    return '.dctrl.ai';
+  }
</file context>
Fix with cubic

Comment thread docker-compose.yml
DATABASE_URL: postgresql://comp:comp@comp-postgres:5432/comp?sslmode=disable
PORTAL_URL: https://comp-portal.dctrl.ai
NEXT_PUBLIC_PORTAL_URL: https://comp-portal.dctrl.ai
TRUST_APP_URL: https://comp-portal.dctrl.ai

@cubic-dev-ai cubic-dev-ai Bot Jul 27, 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.

P1: Trust portal links generated by the API are pointed at the employee portal host. TRUST_APP_URL is consumed as the base for trust-site and access URLs, but this compose change sets it to https://comp-portal.dctrl.ai; recipients will be sent links such as https://comp-portal.dctrl.ai/<friendlyUrl>/access/<token>, which can route to the wrong application. The deployment should set TRUST_APP_URL to the actual trust portal URL (or leave it unset if PORTAL_URL is the intended trust host) and verify the corresponding route exists.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docker-compose.yml, line 65:

<comment>Trust portal links generated by the API are pointed at the employee portal host. `TRUST_APP_URL` is consumed as the base for trust-site and access URLs, but this compose change sets it to `https://comp-portal.dctrl.ai`; recipients will be sent links such as `https://comp-portal.dctrl.ai/<friendlyUrl>/access/<token>`, which can route to the wrong application. The deployment should set `TRUST_APP_URL` to the actual trust portal URL (or leave it unset if `PORTAL_URL` is the intended trust host) and verify the corresponding route exists.</comment>

<file context>
@@ -59,6 +60,10 @@ services:
       DATABASE_URL: postgresql://comp:comp@comp-postgres:5432/comp?sslmode=disable
+      PORTAL_URL: https://comp-portal.dctrl.ai
+      NEXT_PUBLIC_PORTAL_URL: https://comp-portal.dctrl.ai
+      TRUST_APP_URL: https://comp-portal.dctrl.ai
+      NEXT_PUBLIC_APP_URL: https://comp-app.dctrl.ai
     volumes:
</file context>
Suggested change
TRUST_APP_URL: https://comp-portal.dctrl.ai
TRUST_APP_URL: https://comp-trust.dctrl.ai
Fix with cubic

Comment thread docker-compose.yml
logging: *default-logging

minio:
image: minio/minio:latest

@cubic-dev-ai cubic-dev-ai Bot Jul 27, 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.

P3: The MinIO service uses minio/minio:latest which is not pinned to a specific version. latest can change unexpectedly and break the compose setup. Consider pinning to a specific release tag (e.g., minio/minio:RELEASE.2024-01-01T00-00-00Z) for reproducible deployments.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docker-compose.yml, line 108:

<comment>The MinIO service uses `minio/minio:latest` which is not pinned to a specific version. `latest` can change unexpectedly and break the compose setup. Consider pinning to a specific release tag (e.g., `minio/minio:RELEASE.2024-01-01T00-00-00Z`) for reproducible deployments.</comment>

<file context>
@@ -98,7 +103,42 @@ services:
     logging: *default-logging
+
+  minio:
+    image: minio/minio:latest
+    container_name: comp-minio
+    command: server /data --console-address ":9001"
</file context>
Suggested change
image: minio/minio:latest
image: minio/minio:RELEASE.2024-05-10T22-45-00Z
Fix with cubic


const portalBase = (
process.env.NEXT_PUBLIC_PORTAL_URL ?? 'https://portal.trycomp.ai'
getPortalBaseUrl()

@cubic-dev-ai cubic-dev-ai Bot Jul 27, 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.

P3: The trailing-slash replacement applied to getPortalBaseUrl() is redundant because the helper already strips trailing slashes internally. The .replace(//+$/, '') wrapping on line 64 is guaranteed to be a no-op, which adds unnecessary indirection and makes the code slightly harder to read. Consider removing the outer .replace() and using the return value of getPortalBaseUrl() directly.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/email/emails/policy-acknowledgment-digest.tsx, line 65:

<comment>The trailing-slash replacement applied to `getPortalBaseUrl()` is redundant because the helper already strips trailing slashes internally. The `.replace(//+$/, '')` wrapping on line 64 is guaranteed to be a no-op, which adds unnecessary indirection and makes the code slightly harder to read. Consider removing the outer `.replace()` and using the return value of `getPortalBaseUrl()` directly.</comment>

<file context>
@@ -61,7 +62,7 @@ export const PolicyAcknowledgmentDigestEmail = ({
 
   const portalBase = (
-    process.env.NEXT_PUBLIC_PORTAL_URL ?? 'https://portal.trycomp.ai'
+    getPortalBaseUrl()
   ).replace(/\/+$/, '');
   const subjectText = computePolicyAcknowledgmentDigestSubject(orgsWithPolicies);
</file context>
Fix with cubic

@raedbrahem raedbrahem closed this Jul 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants