Skip to main content
Skip to content

Last updated on 4 June 2026

Installation Guide — UI06 PulseCare HealthTech

Prerequisites

  • Node.js 20+ (LTS recommended)
  • pnpm 9+ (this kit uses pnpm as the package manager)
  • A code editor with TypeScript support (VS Code recommended)
  • An active internet connection on first install (Google Fonts are loaded at build time)

Licence Key

Before running the kit, add your licence key to licence.json:

json
{
  "key": "TE-XXXX-XXXX-XXXX",
  "domain": "yourdomain.com"
}

Your key is in your account at templateempire.io/account.

Setup

bash
# 1. Install dependencies
pnpm install

# 2. Copy environment variables
cp .env.example .env.local

# 3. Start development server
pnpm run dev

Open http://localhost:3000 in your browser.

Environment Variables

Create .env.local from .env.example:

env
# Site URL (used for OG images, canonical URLs)
NEXT_PUBLIC_SITE_URL=http://localhost:3000

# Analytics (optional)
NEXT_PUBLIC_ANALYTICS_ID=

Build for Production

bash
pnpm run build

This generates a static export in the out/ directory (configured via next.config.ts).

Phase Gate Commands

Run these before every release:

bash
pnpm run typecheck    # TypeScript strict check
pnpm run lint         # ESLint
pnpm run build        # Production build
pnpm audit --omit=dev --audit-level=high  # Dependency audit
pnpm run dev          # Manual smoke test

Security Headers

Empire UI kits are static exports (output: 'export') — they emit HTML/CSS/JS with no runtime server, so the app sends no HTTP response headers of its own. Set security headers at your host/CDN (per-host examples below).

Set headers in your host's config, not next.config.ts headers(). For a static export, next.config headers() is inert on a generic static host (S3, nginx, GitHub Pages) — it does anything only on Vercel, so relying on it is a false sense of security. Your host's native config (vercel.json, a _headers file, an nginx block — below) is explicit, portable, and what the examples here use.

Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Strict-Transport-Security: max-age=31536000; includeSubDomains
  • CSP script-src'unsafe-inline' is required by the inline theme-flash-prevention script (it runs before hydration, so it can't be externalised without a flash); 'unsafe-eval' by some animation-library code paths. A static export can't issue per-request CSP nonces. To harden, try removing 'unsafe-eval' and test (modern GSAP/Three.js often don't need it), and replace the inline theme script with a hashed/external one to drop 'unsafe-inline'.
  • Optional Google Analytics — if you wire up NEXT_PUBLIC_GA_ID, GA is blocked by the CSP above unless you add its origins: https://www.googletagmanager.com https://www.google-analytics.com to script-src, https://www.google-analytics.com to img-src, and https://www.google-analytics.com https://analytics.google.com https://region1.google-analytics.com to connect-src.
  • connect-src is 'self' only — add the specific origins your app actually calls (e.g. the GA hosts above). Avoid a blanket https:: it lets an XSS exfiltrate to any origin.
  • Clickjackingframe-ancestors 'self' blocks cross-origin framing and supersedes the legacy X-Frame-Options; unlike XFO it takes an allow-list (e.g. frame-ancestors 'self' https://your-other-site.com) if you embed your own site. X-XSS-Protection is intentionally omitted (deprecated; CSP replaces it).
  • HSTSincludeSubDomains enforces HTTPS on every subdomain for the full max-age; only keep it if all your subdomains are HTTPS.

The public Empire UI demos deliberately ship no frame protection so our preview tooling + storefront can embed them. Your production site isn't embedded — keep frame-ancestors 'self' (above).

Per host

Vercelvercel.json at the project root:

json
{
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        { "key": "Content-Security-Policy", "value": "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'" },
        { "key": "X-Content-Type-Options", "value": "nosniff" },
        { "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" },
        { "key": "Permissions-Policy", "value": "camera=(), microphone=(), geolocation=()" },
        { "key": "Strict-Transport-Security", "value": "max-age=31536000; includeSubDomains" }
      ]
    }
  ]
}

Netlify / Cloudflare Pages — put a _headers file in public/ (Next.js copies it into the out/ build output; don't edit out/ directly — it's regenerated each build):

/*
  Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'
  X-Content-Type-Options: nosniff
  Referrer-Policy: strict-origin-when-cross-origin
  Permissions-Policy: camera=(), microphone=(), geolocation=()
  Strict-Transport-Security: max-age=31536000; includeSubDomains

nginx — inside your server { } block:

nginx
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

After deploying, verify with securityheaders.com or DevTools → Network → Headers.

Troubleshooting

Port already in use

bash
npx kill-port 3000
pnpm run dev

Tailwind styles not applying

Make sure you have postcss.config.mjs with the @tailwindcss/postcss plugin configured.

TypeScript errors after install

bash
pnpm run typecheck

Fix any errors before proceeding. The project uses strict: true in tsconfig.


Template Empire — Halbon Labs