spomeni/local.md
2026-06-20 18:17:30 +02:00

4.5 KiB

Local Development Guide

Prerequisites

  • Node.js 20+
  • npm
  • PostgreSQL (running locally or via Docker)
  • A Contabo S3 bucket (or any S3-compatible storage)

1. Clone and Install

git clone <repo-url> && cd spomeniQR
npm install

2. Set Up Environment Variables

cp .env.example .env

Edit .env with your local values:

# Clerk - get from https://dashboard.clerk.com
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
CLERK_SECRET_KEY=sk_test_...

# Database - use localhost for local Postgres
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/monuments

# Contabo S3
S3_ENDPOINT=https://eu2.contabostorage.com
S3_REGION=eu-2
S3_ACCESS_KEY_ID=your-access-key
S3_SECRET_ACCESS_KEY=your-secret-key
S3_BUCKET_NAME=monuments-images

# App
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_APP_DOMAIN=localhost:3000

3. Set Up the Database

You need a PostgreSQL database. Options:

Start only the database:

docker compose up db -d

This starts PostgreSQL on port 5432 with user postgres, password postgres, database monuments.

Option B: Local PostgreSQL

Create the database manually:

createdb monuments

Update DATABASE_URL in .env to match your local PostgreSQL credentials.

4. Run Prisma Migrations

npx prisma migrate dev --name init

This creates the tables and generates the Prisma client.

5. Set Up Contabo S3

  1. Log into your Contabo Object Storage dashboard
  2. Create a bucket named monuments-images
  3. Set bucket policy to public read (monument images must be publicly accessible)
  4. Create an API key (access key + secret key)
  5. Note your endpoint and region (e.g. https://eu2.contabostorage.com, region eu-2)

Set the CORS policy on the bucket to allow browser uploads:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": { "AWS": ["*"] },
      "Action": ["s3:GetObject", "s3:PutObject"],
      "Resource": ["arn:aws:s3:::monuments-images/*"]
    }
  ]
}

Also set a CORS configuration:

[
  {
    "AllowedHeaders": ["*"],
    "AllowedMethods": ["GET", "PUT"],
    "AllowedOrigins": ["http://localhost:3000"],
    "ExposeHeaders": [],
    "MaxAgeSeconds": 3600
  }
]

6. Configure Clerk

  1. Go to Clerk Dashboard
  2. Create a new application
  3. Under Paths, set:
    • Sign-in: /sign-in
    • Sign-up: /sign-up
  4. Under API Keys, copy the publishable key and secret key to your .env
  5. Under Domains, add localhost:3000

7. Start Development Server

npm run dev

The app runs at http://localhost:3000.

8. Test Subdomain Routing Locally

Subdomain routing (eiffel-tower.testbed.mk) doesn't work on localhost. For local testing of subdomain pages:

  1. Direct URL: Visit http://localhost:3000/eiffel-tower (this simulates subdomain routing via the [subdomain] page route)

  2. Using /etc/hosts (optional, for realistic testing):

    sudo nano /etc/hosts
    # Add:
    127.0.0.1 eiffel-tower.testbed.mk
    127.0.0.1 testbed.mk
    

    Then add this to your .env:

    NEXT_PUBLIC_APP_DOMAIN=testbed.mk
    

    And modify middleware.ts temporarily to also check localhost in development.

  3. Using the X-Subdomain header directly (for curl testing):

    curl -H "X-Subdomain: eiffel-tower" http://localhost:3000/
    

9. Useful Commands

# Start dev server with hot reload
npm run dev

# Generate Prisma client (after schema changes)
npx prisma generate

# Create a new migration
npx prisma migrate dev --name your-migration-name

# Open Prisma Studio (DB GUI)
npx prisma studio

# Run linter
npm run lint

# Type check
npx tsc --noEmit

# Build for production
npm run build

10. Troubleshooting

"Prisma Client could not be generated"

npx prisma generate

Database connection refused

  • Make sure PostgreSQL is running: docker compose up db -d
  • Check DATABASE_URL in .env matches your DB credentials

Clerk authentication errors

  • Verify your Clerk keys in .env are correct
  • Ensure localhost:3000 is added as a domain in the Clerk dashboard

S3 upload fails

  • Check that the bucket exists and permissions are set
  • Verify the CORS configuration allows http://localhost:3000
  • Ensure the access key has both read and write permissions

Port 3000 already in use

# Kill whatever is on port 3000
lsof -ti:3000 | xargs kill -9
# Or use a different port
PORT=3001 npm run dev