CORS & Connection Issues

Cross-origin rejections between the Next.js and Express processes, internal changeops pool problems, and the product-layer connection/TLS pitfalls that bite when the IDE opens live pools against external engines.

CORS Between Frontend and Backend

The backend derives its allowed origin from CLIENT_URL. Because the frontend (3000) and backend (5002) are different origins, any response lacking a matching Access-Control-Allow-Origin is dropped by the browser. When credentialed requests are involved, the allowed origin must be an exact literal — wildcards are not honored with credentials.

Symptom: Static UI renders but every dynamic panel is empty; Console shows blocked by CORS policy; Network shows /api/ calls as (failed) with no ACAO header on the response.

The exact-match requirement — each of these is a distinct origin and will fail if it is not what the browser actually sends:

Browser originCLIENT_URLResult
http://localhost:3000http://localhost:3000OK
http://localhost:3000http://localhost:3000/Fails — trailing slash
http://localhost:3000http://127.0.0.1:3000Fails — host literal differs
http://localhost:3000https://localhost:3000Fails — scheme differs
http://myhost.local:3000http://localhost:3000Fails — use the real hostname

Verify without a browser by sending the preflight the client would send:

curl -s -D- -o /dev/null -X OPTIONS http://localhost:5002/api/health \\
  -H "Origin: http://localhost:3000" \\
  -H "Access-Control-Request-Method: GET" | grep -i access-control

Absence of Access-Control-Allow-Origin in that response means the sent Origin did not match CLIENT_URL. Change CLIENT_URL, restart the backend, hard-refresh. Behind a reverse proxy, ensure the proxy preserves the original Host/scheme so the browser origin and CLIENT_URL agree.

Internal changeops Pool

The changeops pool underpins auth, connections, scripts, releases, and audit. Its failure modes are distinct from the live pools the IDE opens against user databases.

Authentication / role errors

Symptom: password authentication failed for user, or no pg_hba.conf entry for host. Resolution: reconcile DB_DEVOPS_DB_USER/DB_DEVOPS_DB_PASSWORD (or the legacy DB_* fallbacks) against the role, and confirm the server's pg_hba.conf admits the app's source address with a compatible method. Test with the exact credentials the container resolves, from inside the container, to rule out host-vs-container network differences.

Pool exhaustion

Symptom: Requests intermittently stall then fail with a connection-acquisition timeout under load; latency climbs while the DB itself is idle.

Cause: All pooled connections are checked out. The pool is bounded by DB_POOL_MAX (default 20), with DB_IDLE_TIMEOUT_MS (30000) and DB_CONNECTION_TIMEOUT_MS (2000) governing reclamation and acquisition wait.

Resolution: Raise DB_POOL_MAX only up to what the Postgres max_connections budget allows across all app replicas (replicas × pool must not exceed the server ceiling). If acquisition timeouts dominate, a short DB_CONNECTION_TIMEOUT_MS is surfacing real saturation, not causing it — fix the saturation (slow queries holding connections, or too few connections for concurrency) rather than just lengthening the timeout.

External Database Connections (IDE) — Product-Layer Pitfalls

All dialects route through the singleton DatabaseConnectionManager. The recurring issues are TLS negotiation and auth-plugin mismatches, not the engines themselves.

DialectSymptomCause / resolution
PostgreSQLConnection hangs or no pg_hba.conf entry against a managed instanceManaged Postgres (RDS/Azure/Cloud SQL) requires TLS. Enable SSL in the connection's settings; the server refuses non-TLS sessions at the pg_hba layer.
MySQL / MariaDBER_NOT_SUPPORTED_AUTH_MODEMySQL 8 defaults to caching_sha2_password. Either enable TLS (required to transmit that auth type) or move the account to mysql_native_password.
SQL ServerTLS/handshake failure against on-box or Edge instancesSet the encrypt / trust-server-certificate options to match the instance. For named instances use host\\INSTANCE or an explicit port. Each connection opens its own pool — a test connection closing must not tear down a live one.
MongoDBSRV hostname will not resolve, or Authentication failedmongodb+srv:// depends on DNS SRV/TXT resolution from the app host; the auth database (usually admin) must be specified when it differs from the target DB.

A connection that hangs ~15–30s and then fails is a network-reachability problem (allow-list / security group / route), not credentials — credential errors return promptly. Resolve reachability at the infra layer before touching connection settings.

Docker Networking for Live Pools

When the container connects to a database on the host, localhost resolves to the container itself. Use the correct host reference:

ScenarioHost to use
Docker Desktop (macOS/Windows)host.docker.internal
Linux, bridge networkbridge gateway (default 172.17.0.1)
Linux, host network modelocalhost
Same Docker Compose projectthe service name