All posts

SOP: detect and remediate cross-connected Orbitype projects

Detect shared API keys or databases across Nuxt and Orbitype projects, stop unsafe writes, migrate clean data and prevent connector mix-ups.

Editorial illustration of two projects accidentally cross-connected to the wrong databases under a magnifying glass

Cross-connected Orbitype projects occur when two Nuxt applications reuse one API key, separate connectors point to the same database, or a credential labeled for one project actually opens another project’s content. The safe response is to freeze writes, verify the real SQL target with read-only checks, back up the data, create an isolated connector and migrate only records with confirmed ownership.

This SOP is based on an anonymized production incident. The clients are called Project A and Project B; domains, database IDs, key fragments, dates, row counts and legal content have been removed. Every command uses placeholders and contains no real credential.

The short answer

Project A → key A → connector A → database A
Project B → key B → connector B → database B

Before any write:
key fingerprint + current_database() + current_schema() + expected slugs

Repository names, Vercel project names and labels in a CMS dashboard are not isolation evidence. The useful evidence is the identity returned by the SQL session and whether the stored content belongs to that application. PostgreSQL documents that current_database() returns the current database and current_schema() returns the first schema in the search path.

What failed in the anonymized incident

Two failures reinforced each other:

  1. Project B’s local environment contained a credential associated with Project A.
  2. Project B’s original connector no longer resolved to a usable database.
  3. The reachable database contained records from both products.
  4. Both live sites looked plausible on their most visited routes because branding, navigation and components lived in each frontend.
  5. An SEO crawl found unexpected 404s and inconsistent routes before production showed an obvious homepage failure.

A correction based only on the home slug then wrote to the other project’s content. The rendering error was merely a symptom; the incident was a loss of data isolation.

Signals that must stop writes

SignalPossible meaningResponse
Another project’s copy appears in warnings or SSRForeign payload or incompatible schemaFreeze writes
Object props arrive as plain stringsSections were authored for another frontendVerify database and slugs
Canonical routes return unexpected 404sCMS inventory is incomplete or mixedCompare sitemap and slugs
Two environments produce the same key fingerprintCredential reuseRotate and audit
Different keys return the same databaseConnectors lack isolationSplit the destination
connector not found plus an empty dashboard fieldBroken or deleted connectorProvision a clean target
The live homepage looks fineOnly visited routes were testedDo not authorize writes

1. Contain the incident first

Disable seeds, schema installers, admin editors and one-off scripts. Do not run INSERT, UPDATE or DELETE until you know the current database and the owner of the affected records.

If an incorrect write already happened:

  1. stop new deployments and automation;
  2. preserve logs without copying secrets;
  3. restore a validated backup if production is affected;
  4. smoke-test core, sitemap and legal routes;
  5. rotate exposed credentials after the service is stable.

Making a translation helper tolerate unexpected strings may prevent an SSR crash, but it does not fix the wrong database target. Treat that change as rendering containment, not data remediation.

2. Identify keys without publishing them

Never paste API keys into chats, tickets, screenshots or runbooks. Instead of saving the value or its suffix, calculate a short SHA-256 fingerprint locally:

printf '%s' "$ORBITYPE_API_SQL_KEY" | shasum -a 256 | cut -c1-12

The fingerprint can reveal reuse without exposing part of the secret. Maintain a private registry containing:

FieldSafe example
ProjectProject A
Repositoryrepo-a
Key fingerprint12 SHA-256 characters
Database identitystored in a secret manager or private runbook
EnvironmentDevelopment, Preview or Production
Statusverified, migrating or retired

3. Run read-only identity checks

Use local environment variables and placeholders. Do not write the key value into the command:

curl --fail-with-body --silent --show-error "$ORBITYPE_API_SQL_URL" \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: $ORBITYPE_API_SQL_KEY" \
  --data '{"sql":"SELECT current_database() AS db, current_schema() AS schema"}'

Then inspect the inventory and a small content sample:

SELECT slug FROM pages ORDER BY slug LIMIT 100;

SELECT
  slug,
  left(title::text, 120) AS title_sample,
  json_array_length(sections) AS section_count
FROM pages
ORDER BY updated_at DESC
LIMIT 20;

Titles are not enough. Compare component names and prop shapes too. If Project A expects localized objects but receives flat strings or section types missing from its Vue catalog, it is probably reading foreign data.

Diagnosis matrix

ResultLikely diagnosis
Same fingerprint and same databaseA key was copied between projects
Different fingerprints and same databaseSeparate connectors share one destination
Key A opens Project B slugsMiswired connector or misleading label
Key B returns connector not foundRevoked credential or broken connector
Distinct databases and coherent contentIsolation looks correct; still verify ownership

4. Why production can look healthy

Each deployment ships its own layout, navigation, styles and component catalog. The CMS responds only to the requested slug. A compatible homepage may therefore render while less-visited pages return 404, use the wrong meaning for a slug or contain sections the frontend cannot render.

Local, Preview and Production can also use different values. Vercel states that environment-variable changes apply only to new deployments, so a healthy live site does not prove that a local file reaches the same database.

Useful passive checks include:

  • crawling canonical routes after every go-live;
  • comparing the sitemap, an expected-route allowlist and the CMS inventory;
  • alerting on slugs from an unrelated product;
  • verifying database identity before every write-capable job.

5. Back up and classify before migration

Create a complete, verifiable backup. With direct PostgreSQL access, use the backup method approved by your provider; PostgreSQL documents regular backups plus pg_dump and pg_restore. If the SQL API is the only access path, export affected tables to encrypted storage outside the repository.

Classify every row:

  • approved: clearly owned by the destination project;
  • excluded: clearly owned by the sibling project;
  • review required: ownership is uncertain;
  • legal or sensitive: requires explicit human review.

Prefer an allowlist of expected slugs over “copy everything except these pages.” A denylist can silently reintroduce another client’s legal pages, SEO metadata or settings.

6. Provision a clean target and migrate

If the connector cannot be repaired:

  1. create a new Orbitype project or connector;
  2. confirm that the dashboard shows a valid database;
  3. generate a new credential;
  4. run current_database() and current_schema();
  5. confirm that pages is missing or empty;
  6. install the versioned schema;
  7. import approved records only;
  8. verify counts, slugs, the homepage and component types.

If an INSERT returns an HTTP error, query for the row before retrying. A failed response does not always prove that the transaction was rolled back; blind retries can produce duplicate or constraint errors.

7. Cut over without losing rollback

Update Development, Preview and Production deliberately. Nuxt keeps credentials out of the browser when they are declared in private server runtime configuration; see the official useRuntimeConfig guidance.

For Vercel:

  1. add the new key to the intended environment;
  2. create a new deployment;
  3. smoke-test home, business, sitemap and legal routes;
  4. confirm that reads reach the new database;
  5. keep the old destination temporarily available for rollback;
  6. revoke the old key after every environment is verified.

Vercel’s secret rotation guide likewise recommends keeping the old credential active until the new deployments have been tested.

8. Add a gate before every seed

The strongest control is to reject writes by default:

async function assertSafeCmsTarget(options: {
  expectedDatabase: string
  allowNonEmpty: boolean
}) {
  const identity = await sql(
    "SELECT current_database() AS db, current_schema() AS schema",
  )

  if (identity[0].db !== options.expectedDatabase) {
    throw new Error("CMS target does not match the expected project")
  }

  const result = await sql("SELECT count(*)::int AS n FROM pages")
  if (result[0].n > 0 && !options.allowNonEmpty) {
    throw new Error("CMS target is not empty; seeding requires review")
  }
}

For a non-empty target, require an interactive confirmation and display sample slugs. Store the expected identity in protected configuration rather than hardcoding a production identifier in a public repository.

Pre-write checklist

  • Key fingerprint compared with sibling projects.
  • current_database() and current_schema() verified.
  • Slugs and section shapes match the repository.
  • Complete backup stored outside the repository.
  • Legal records reviewed by a person.
  • New target is empty or explicitly approved.
  • Rollback plan is documented.
  • Vercel was redeployed after changing variables.
  • Old key is revoked only after smoke testing.

Frequently asked questions

How can I tell whether two Orbitype projects share a database?

Compare one-way key fingerprints and run current_database() with every credential. Different keys can still reach the same database, so inspect slugs, titles and component types as well.

What should I do before correcting content?

Freeze writes, identify the real target, create a backup and classify record ownership. Do not use an UPDATE against the home slug as a diagnostic test.

Will rotating the key repair a broken connector?

Not necessarily. If the connector does not resolve to a valid database, create a clean target, migrate approved data, cut environments over and rotate credentials afterward.

How do I prevent a seed from affecting another project?

Run a blocking gate that validates identity, table state and sample slugs. An installer or seed must never write merely because it found a key in the environment.

The same server-only secret and layered validation principles apply to form integrations; see the related Orbitype, Vercel and SendGrid SOP.

// stuck on something similar?

Let's debug it together

Book a call More posts