Installation Guide
Tours installs as a single Next.js application — there is no separate API server to set up. Install dependencies, point it at a PostgreSQL database, start the app, and finish the guided install wizard at /install. This page covers both the manual setup and the wizard, end to end, including the full environment-variable reference.
In a hurry? The Quick Start is the four-command version. This guide is the detailed one.
Prerequisites
| Requirement | Version / Notes |
|---|---|
| Node.js | 20+ (LTS recommended) |
| npm | 10+ (ships with Node) |
| PostgreSQL | Neon recommended — Tours uses the @neondatabase/serverless driver, so paste a Neon (or Neon-compatible) connection string. Local PostgreSQL works for development. |
| Object storage | Cloudflare R2 (or any S3-compatible bucket) — required for uploads in production |
| SMTP | Optional — only needed for transactional email |
Confirm your Node version before continuing:
node -v # must report v20 or higher
Step 1 — Install Dependencies
Unzip the download, then from the project root:
npm install
This also runs prisma generate (via the postinstall hook) to produce database client types. Runtime data access uses the tagged sql template, not an ORM — Prisma is only used for generated types and tooling.
Step 2 — Configure the Environment
Tours reads configuration from a .env file in the project root. The install wizard can create and write this file for you on a writable filesystem — it generates JWT_SECRET and CRON_SECRET automatically during the database step. On a read-only host (such as Vercel) you set the values manually instead.
To prepare it yourself, create .env with at least the core keys:
# Required — PostgreSQL connection (Neon recommended)
DATABASE_URL="postgresql://user:password@host/dbname?sslmode=require"
# Required — signs admin & customer session tokens (any long random string)
JWT_SECRET="replace-with-a-long-random-string"
# Recommended — AES-256-GCM key that encrypts integration secrets stored in the DB
SECRET_KEY="replace-with-a-long-random-string"
Generate strong secrets. Use something like
openssl rand -base64 48forJWT_SECRETandSECRET_KEY. SetSECRET_KEYonce, before connecting any integrations — if you change it after integration credentials have been saved, those encrypted values can no longer be decrypted.
Full Environment Variable Reference
These are the only environment variables Tours reads. Anything not listed here is not used by the app.
| Variable | Required? | Purpose |
|---|---|---|
DATABASE_URL |
Required | PostgreSQL connection string (Neon serverless driver). |
JWT_SECRET |
Required | Signs JWT session tokens (admin admin_token cookie + customer cookie). Auto-generated by the wizard if missing. |
SECRET_KEY |
Recommended | AES-256-GCM key encrypting integration secrets saved in the database. Falls back to JWT_SECRET if unset. |
JWT_EXPIRES_IN |
Optional | Token lifetime (e.g. 7d). |
CRON_SECRET |
Optional | Protects the /api/v1/cron endpoint. Auto-generated by the wizard. |
NEXT_PUBLIC_SITE_URL |
Optional | Public base URL for absolute links / SEO. Set by the wizard's site step. |
LICENSE_PUBLIC_KEY |
Optional | Override RS256 public key for license verification (a default is baked in). |
LICENSE_SERVER_URL |
Optional | License server (defaults to https://creative-cape.com). |
ADMIN_EMAIL |
Optional | Seed / bootstrap admin email (used by seed scripts). |
ADMIN_PASSWORD |
Optional | Seed / bootstrap admin password. |
NOTIFY_EMAIL |
Optional | Destination for system notifications. |
API_DOCS_USER |
Optional | Basic-auth user for the API docs page. |
API_DOCS_PASS |
Optional | Basic-auth password for the API docs page. |
R2_ENDPOINT |
Optional* | Cloudflare R2 endpoint (legacy fallback — storage is normally configured in admin). |
R2_ACCESS_KEY_ID |
Optional* | R2 access key (fallback). |
R2_SECRET_ACCESS_KEY |
Optional* | R2 secret key (fallback). |
R2_DEFAULT_BUCKET |
Optional* | R2 bucket name (fallback). |
R2_PUBLIC_URL |
Optional* | Public CDN URL for the bucket (fallback). |
PEXELS_API_KEY |
Optional | Stock-image search integration. |
WORLDVECTORLOGO_API_KEY |
Optional | Logo search integration. |
NODE_ENV |
Auto | Set by the runtime (development / production). |
VERCEL |
Auto | Set automatically on Vercel; used to detect a read-only filesystem. |
* The
R2_*variables are a fallback only. The recommended way to connect storage is Admin → Settings → Integrations → Storage, where keys are encrypted in the database withSECRET_KEY. See the Deployment Guide.
Step 3 — Initialise the Database
If you prefer to create the schema from the command line before running the wizard, use the init script (it reads DATABASE_URL from your .env):
npm run db:init
db:init runs two steps in order — the CMS tables (init-db), then the core / auth / vendor and Tours business schema (init-core). Related helper scripts:
| Script | What it does |
|---|---|
npm run db:init |
Both steps: init-db.ts (CMS tables) + init-core.ts (core, auth, vendor, and Tours business schema). |
npm run db:seed:core |
Seed baseline reference data. |
npm run db:seed:master |
Seed inclusion / itinerary master items. |
npm run db:seed:hero |
Seed hero-slider content for the storefront. |
npm run db:reset |
Reset the template database. |
The schema is idempotent and self-healing — it is created by
ensure*()helpers (CREATE TABLE IF NOT EXISTS,ALTER TABLE ... ADD COLUMN IF NOT EXISTS), not a migration framework. Running it again is safe. You can also skip this step entirely and let the install wizard create the schema during its database step.
Step 4 — Start the App
npm run dev
Open http://localhost:3000. On a fresh install (no DATABASE_URL and no .installed lock file) the app redirects to the install wizard at /install.
The first request to a freshly added or edited route can take a few seconds while the dev server compiles it on demand — that is normal, not a hang.
Step 5 — The Install Wizard (/install)
The wizard walks through six screens. It is the recommended path for a self-hosted Node setup, where it writes .env and creates the schema for you.
| Step | Screen | What happens |
|---|---|---|
| 1 | Welcome / Requirements | Checks your Node version and whether .env is writable. A read-only filesystem is flagged so you know to set values manually. |
| 2 | Database | Paste a Neon connection string (or enter host / port / database / user / password). The wizard tests the connection, writes DATABASE_URL (plus auto-generated JWT_SECRET and CRON_SECRET) to .env, creates the schema, and seeds settings / pages / templates. You can optionally tick install demo data. |
| 3 | License | Enter your CodeCanyon / creative-cape.com purchase code to activate against creative-cape.com. On a local / LAN host this is skipped automatically — the license activates on your live domain after deployment. |
| 4 | Admin account | Create your first super-admin (name, email, password — minimum 8 characters). They are linked to a full-access Administrator role. |
| 5 | Site settings | Set platform name, site URL, timezone, and default currency. The site URL is also written to NEXT_PUBLIC_SITE_URL. All of these can be changed later in the admin. |
| 6 | Done | The wizard drops a .installed lock file so the install gate stops redirecting, and surfaces your cron details. |
Read-only filesystem note: if
.envcannot be written (e.g. on Vercel), the wizard returns the exact values it would have written so you can add them as environment variables in your host's dashboard, then redeploy.
Restart Once After Finishing
After the wizard completes on a self-hosted setup, restart the app once (stop and re-run npm run dev / npm run start, or restart it in your hosting panel) so the newly written environment variables load fully. Then sign in.
Step 6 — First Admin Login
Go to /admin/login and sign in with the admin email and password you created in step 4. From there you can configure payments, storage, and theme, and switch on the add-ons your license entitles.
Verify the Install
- The storefront at
/renders with seeded content. /admin/loginaccepts your admin credentials.npm run type-checkpasses (runstsc --noEmit).- If uploads are needed, connect storage in Admin → Settings → Integrations → Storage before going live.
Next: ship it to production with the Deployment Guide, or pick a host with the Hosting Guide.
© CreativeCape Solutions · creative-cape.com · support@creative-cape.com