Skip to main content

Local Development

This guide covers everything you need to run Soku locally, from initial setup to debugging production-like issues on your machine.

Prerequisites

Before starting, make sure you have:

  • Node.js 22 (see engines in root package.json; use nvm use if you have an .nvmrc)
  • pnpm 9.x installed globally (npm install -g pnpm)
  • A populated .env.local file in apps/web/ (see Environment Setup below)
  • Firebase project credentials for Auth and Firestore
  • Stripe test-mode API keys (for subscription flows)

Starting the Dev Server

The root pnpm dev command uses Turborepo to start all services in parallel:

pnpm dev

This runs:

  1. The Next.js web app (apps/web)
  2. The Firebase Functions emulator (apps/functions)

Both processes stream logs to the same terminal. Turbo handles orchestration so you do not need multiple terminal tabs.

Individual Services

If you only need part of the stack:

CommandWhat it starts
pnpm dev:webNext.js web app only
pnpm dev:functionsFirebase Functions emulator only

Ports and URLs

ServiceURLDefault Port
Next.js web apphttp://localhost:30003000
Firebase Functions emulatorhttp://localhost:50015001
Firestore emulatorhttp://localhost:80808080
Storage emulatorhttp://localhost:91999199

Environment Setup

The web app requires several environment variables. Create apps/web/.env.local with:

Required Variables

# Firebase (client-side)
NEXT_PUBLIC_FIREBASE_API_KEY=
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=
NEXT_PUBLIC_FIREBASE_PROJECT_ID=
NEXT_PUBLIC_FIREBASE_APP_ID=

# Firebase (server-side / Admin SDK)
FIREBASE_SERVICE_ACCOUNT_KEY= # JSON string or path

# Stripe
STRIPE_SECRET_KEY= # sk_test_...
STRIPE_WEBHOOK_SECRET= # whsec_...
STRIPE_STARTER_PRICE_ID=
STRIPE_PRO_PRICE_ID=
STRIPE_AGENCY_PRICE_ID=
STRIPE_STARTER_YEARLY_PRICE_ID=
STRIPE_PRO_YEARLY_PRICE_ID=
STRIPE_AGENCY_YEARLY_PRICE_ID=

Optional Variables

NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID=
TIKTOK_CALLBACK_URL= # Production callback URL for TikTok OAuth

Verifying Environment Variables

Hit the debug endpoint to check which variables are present without revealing their values:

GET http://localhost:3000/api/debug-env

This returns a list of variable names with a present: true/false flag. It never exposes actual secret values.

Hot Reload Behavior

Next.js 16 provides Fast Refresh out of the box:

  • React components: Edits to .tsx files hot-reload in the browser with state preserved.
  • Server components / API routes: Changes trigger a server restart. The browser refetches automatically.
  • Tailwind CSS: Class changes appear instantly via Fast Refresh.
  • Environment variables: Changes to .env.local require a full restart (Ctrl+C then pnpm dev).

Firebase Functions running through the emulator also watch for file changes and restart automatically.

Error Handling in Development

When NODE_ENV=development (the default for next dev), API routes return detailed error responses including stack traces. This makes debugging straightforward:

{
"error": "Error creating checkout session",
"details": "Missing required parameters: planId",
"stack": "Error: Missing required parameters...\n at POST (/app/api/...)"
}

In production, error responses omit stack traces and internal details.

Platform-Specific Dev Tips

TikTok Desktop Auth Flow

TikTok's OAuth has a special desktop flow that behaves differently from mobile:

  1. Append ?desktop=1 to the TikTok auth start URL when testing locally.
  2. The callback is handled by a proxy route at /api/tiktok/callback because TikTok's desktop app has restrictions on redirect URIs.
  3. The callback handler automatically serves TikTok's verification .txt files when probed.
  4. Make sure TIKTOK_CALLBACK_URL matches your deployed URL for production. For local development, the proxy route handles the flow.

Social Integrations

Use the Settings page in the app to connect social platform integrations. The app uses Firebase Functions start endpoints and redirects back to your current URL when the OAuth flow completes.

Common Commands

CommandDescription
pnpm devStart all services in parallel via Turbo
pnpm dev:webStart only the Next.js web app
pnpm dev:functionsStart only the Firebase Functions emulator
pnpm buildProduction build (all packages)
pnpm testRun unit tests with coverage
pnpm lintRun ESLint across the monorepo
pnpm typecheckRun TypeScript type checking
pnpm checkLint + typecheck + test (pre-push quality gate)
pnpm ciFull CI pipeline: lint, typecheck, test, build
pnpm deploy-functionsDeploy all Firebase Functions
pnpm deploy-function --function=<name>Deploy a single Firebase Function
pnpm sync:schemaBuild and sync the shared schema package

Debugging Tips

Inspecting API Routes

Use curl or a tool like Postman to test API routes directly:

# Check environment variables
curl http://localhost:3000/api/debug-env

# Test authenticated route (replace TOKEN with a Firebase ID token)
curl -X POST http://localhost:3000/api/auth/session \
-H "Content-Type: application/json" \
-d '{"idToken": "TOKEN"}'

Stripe Webhook Testing

To test Stripe webhooks locally, use the Stripe CLI to forward events to your Functions emulator:

stripe listen --forward-to http://localhost:5001/<project-id>/us-central1/stripeWebhook

The CLI prints a webhook signing secret (whsec_...) that you should set as STRIPE_WEBHOOK_SECRET in your Functions environment.

Firebase Emulator UI

When running the Firebase emulators, the Emulator UI is available at http://localhost:4000. It provides a visual interface for inspecting Firestore documents, Auth users, and Storage files.

Common Issues

ProblemSolution
Missing Firebase environment variablesEnsure all NEXT_PUBLIC_FIREBASE_* vars are set in .env.local
Session cookie not being setCheck that __session cookie is visible in DevTools; ensure the session API route is running
Stripe webhook errorsVerify STRIPE_WEBHOOK_SECRET matches the secret from stripe listen
Port already in useKill the existing process on port 3000 or 5001, then restart
HMR not workingClear .next cache: rm -rf apps/web/.next and restart