Troubleshooting

Concrete symptoms and fixes for the issues you're most likely to hit when running Tours. Each entry follows a problem → cause → fix shape: match the symptom, confirm the cause, apply the fix, and check the relevant logs if it persists.

Symptom Index

Symptom Likely cause Section
Can't reach / connect to the database Wrong DATABASE_URL or no SSL Database
"relation does not exist" / missing tables Schema not provisioned Database
Install Wizard never appears DATABASE_URL already set or already installed Install Wizard
Public License Banner / admin License Gate showing Domain not activated or grace lapsed Licensing
Premium add-on shows as locked No entitlement and no purchase code Licensing
Uploads fail (SignatureDoesNotMatch) Wrong storage secret key Storage
Images upload but don't display Wrong public base URL Storage
Emails not arriving SMTP not configured/active Email
A route 404s despite existing Stale dev route table (Turbopack) Dev Server
Build fails on deploy Node version or missing env var Build & Env
App reads as "unlicensed" after moving domains License bound to the old domain Licensing

Database

Can't reach the database

  • Cause: an incorrect DATABASE_URL, a missing SSL parameter, or the database refusing connections from your host. Tours connects to PostgreSQL through @neondatabase/serverless.
  • Fix:
    • Verify the DATABASE_URL host, user, password, and database name.
    • Append ?sslmode=require for Neon and most managed Postgres providers.
    • Confirm the database accepts connections from your host/IP.
    • For app runtime on Neon, use the pooler host; for pg_dump/pg_restore, use the direct (unpooled) host.
ENV
DATABASE_URL="postgresql://user:pass@host/db?sslmode=require&channel_binding=require"

Missing tables / "relation does not exist"

  • Cause: you imported a partial database or skipped the wizard, so an ensure*Schema() provisioning step hasn't run for that table.
  • Fix: re-open /install and complete the Database step, which (re)creates the required tables idempotently. The schema is self-healing — tables are created on demand — so completing the Database step against your database resolves this.

Install Wizard

The wizard at /install doesn't appear (redirects away)

  • Cause: the installer gate keys off DATABASE_URL and an installed lock. If DATABASE_URL is already present, the app treats the database as configured and may skip past early steps; if installation already completed, /install is closed.
  • Fix: to re-run from scratch, point the app at a fresh database and clear the install lock, then reload /install.

The wizard can't save my settings on Vercel

  • Cause: Vercel's filesystem is read-only, so the wizard cannot write a .env file.
  • Fix: on read-only hosts the installer surfaces the values (such as DATABASE_URL and a generated JWT_SECRET) for you to add as Vercel project environment variables manually, then redeploy. The database schema is still created over the serverless connection.

Licensing

Public License Banner or admin License Gate is showing

  • Cause: the installation isn't in an active licensed state. Common reasons and their fixes:
Reason Fix
Unactivated Enter your purchase code in the Install Wizard's License step or in Admin → License.
Grace lapsed The license server was unreachable; run Admin → License → Recheck once connectivity is restored.
Domain mismatch The purchase code is active on another domain — deactivate it there to release the seat, then activate here.
Dev host localhost, *.localhost, *.test, and private LAN ranges never require a license and never show the banner.

You can inspect the public, non-secret state at GET /api/license/status (returns state, type, entitlements, and a message — no purchase code or domain).

A premium add-on shows as locked

  • Cause: the add-on is neither covered by a license entitlement nor activated with a per-add-on purchase code — or it's unlocked but the admin toggle hasn't been switched on.
  • Fix:
    • Confirm the entitlement is present in Admin → License (or GET /api/license/status): a match is */all, the channel id, or the exact <channel>:<provider> key.
    • Or activate the add-on's purchase code in Admin → Add-ons.
    • Remember the two-gate model: unlocking only makes the add-on available — you still flip the admin toggle to switch it on.
    • Free providers (email:smtp, analytics:ga4, payments:cod/bank/paypal, storage:r2, video:youtube/vimeo) never require a key.

App reads as "unlicensed" after moving domains

  • Cause: the license is bound to your domain. After moving, the previously activated record won't match the new host.
  • Fix: activate the new domain (Install Wizard or Admin → License). If you're retiring the old domain, Deactivate it first to release the seat.

Storage

Uploads fail with SignatureDoesNotMatch

  • Cause: the stored storage secret key is wrong (or the token was rotated). This is configuration, not code. Uploads go server-side to Cloudflare R2 (or any S3-compatible storage) via the AWS S3 SDK.
  • Fix: re-enter your credentials in Admin → Settings → Storage — endpoint/account, access key, secret, and bucket. The upload route surfaces the underlying storage error (not a generic 500), so the cause is diagnosable in the response/logs.

Images upload but don't display

  • Cause: the stored public base URL is wrong, not publicly reachable, or the raw object key was saved instead of the public URL.
  • Fix:
    • Confirm the bucket's public URL / custom domain in Admin → Settings → Storage is correct and publicly reachable.
    • Confirm the bucket exists and the key has read/write permission on it.
    • Ensure the stored value is the public URL, not the raw object key.

Email

Emails not arriving (verification, reset, notifications)

  • Cause: SMTP isn't configured or activated. Tours sends mail with nodemailer over an SMTP integration configured in the database, not an env var.
  • Fix:
    • Configure and activate SMTP in Admin → Settings → Email (SMTP is the free email provider and needs no license key).
    • Verify the host, port, username, password, and from-address.
    • To avoid spam folders, set SPF/DKIM/DMARC records for your sending domain and use a verified from-address.

Dev Server

A route returns 404 even though it exists and typechecks

  • Cause: Turbopack de-registers neighboring routes when a route folder is added or moved in dev — a stale route table, not a code bug.
  • Fix: touch the affected page.tsx/route.ts, or restart npm run dev for a clean route table. Note that the first request to a freshly added/edited route can take several seconds (on-demand compilation) — that's not a hang.

Build & Env

Build fails on deploy

  • Cause: an unsupported Node version or a missing environment variable.
  • Fix:
    • Node version: Tours requires Node 20+. Set the host's Node version accordingly.
    • Missing env var: confirm DATABASE_URL is present at build/runtime; on Vercel also set JWT_SECRET and NEXT_PUBLIC_SITE_URL.
    • Read the platform build log — a missing variable or Node version mismatch is named directly there.

Triage Order

A quick order that resolves most problems:

  1. Read the host/platform logs — the error usually names the fix.
  2. Confirm env values: DATABASE_URL, JWT_SECRET, and (on Vercel) NEXT_PUBLIC_SITE_URL.
  3. Confirm in-app integration config: storage and SMTP credentials in the admin panel.
  4. Verify connectivity: database reachable, storage bucket reachable and public.
  5. Redeploy / restart, then hard-refresh the browser.

If a problem persists after triage, open a ticket at creative-cape.com or email support@creative-cape.com with your purchase code, version, environment, and reproduction steps. See the Support Policy for what's covered.


© CreativeCape Solutions · creative-cape.com · support@creative-cape.com