A reusable Next.js (App Router) + TypeScript + Tailwind starter for building multi-tenant client websites that begin with mostly static content and can later evolve to dynamic CMS-driven experiences. Includes:
- DevContainer for consistent developer onboarding.
- Environment variable validation.
- Multi-tenant-ready contact endpoint scaffold.
- Accessible form components.
- Testing setup (Jest + Testing Library).
- Tailwind design token starter (CSS variables for tenant themes).
- Install VS Code + Dev Containers extension.
- Clone repository:
git clone <repo-url> raihsuite-web-starter cd raihsuite-web-starter
- Open folder in VS Code; choose "Reopen in Container".
- Copy
env.exampleto.envand fill in values. - Run:
pnpm dev
- Visit
http://localhost:3000.
| Script | Description |
|---|---|
pnpm dev |
Start local development server |
pnpm build |
Production build |
pnpm start |
Start production server locally |
pnpm lint |
ESLint (errors fail) |
pnpm format |
Prettier formatting |
pnpm typecheck |
TypeScript type checking |
pnpm preflight |
Validate required environment variables |
pnpm test |
Run Jest tests |
Defined in env.example:
TENANT_ID– identifies tenant (used for theming, tagging enquiries).RAISUITE_API_BASE– base URL for Raisuite ERP API.RAISUITE_API_KEY– secret API key for server-side usage only.TURNSTILE_SECRET– optional (Cloudflare Turnstile CAPTCHA).
Validation occurs via src/lib/env.ts. The contact route fails early if variables are missing.
POST /api/contact
- Accepts
name,email,message. - Validates with Zod.
- Rate limit placeholder (in-memory).
- TODO: Add Turnstile (Cloudflare) verification.
- TODO: Replace mock forwarding with real fetch to Raisuite ERP.
- Place original template files in a temporary folder (e.g.
templates/source-reference/). - Identify repeating sections (hero, features, testimonials) → convert into React components under
src/components/. - Inline scripts that only animate can usually become CSS transitions or
framer-motionusage. - For static assets (images, fonts), move into
public/. - Replace global CSS with Tailwind classes incrementally; keep original stylesheet until fully replaced.
- Current approach uses CSS variables (
--color-brand). - Future: Map
TENANT_IDto a theme object and inject variables at runtime inlayout.tsx(or middleware when customizing per request). - Optionally integrate a design token file exporting Tailwind
theme.extendoverrides.
Possible approach:
- Add route handlers or server actions calling a headless CMS.
- Use incremental static regeneration (
fetchwithnext: { revalidate: 60 }) or dynamic rendering. - Implement preview mode (if using Next.js preview API with a secret token).
- Basic test example located in
src/__tests__/contactForm.test.tsx. - Extend coverage for new components as you add them.
- TODO: Add accessibility tests (axe-core) & Playwright for e2e in future.
- Form inputs link labels with
htmlFor. - Error messages have
role=\"alert\"andaria-describedby. - TODO: Add automated axe checks.
- Cloudflare Pages can build Next.js directly; for advanced edge features, evaluate
@cloudflare/next-on-pages(if required for middleware). - Ensure environment variables set in Cloudflare dashboard.
- Use branch protections with GitHub Actions (optional) before allowing deployments.
- Build command:
npx @cloudflare/next-on-pages@latest - Output directory:
.vercel/output/static - Root directory:
/ - Build system version:
3 (latest) - Node compatibility: enable
nodejs_compat(via Pages UI) or addwrangler.toml:
name = "raihsuite-web-starter"
compatibility_date = "2024-11-01"
compatibility_flags = ["nodejs_compat"]Environment variables (Production):
TENANT_IDRAISUITE_API_BASERAISUITE_API_KEYTURNSTILE_SECRET(optional)
Local parity:
pnpm install --frozen-lockfile
node scripts/preflight-env.mjs
pnpm build:pagesRedeploy checklist:
- Ensure output dir is
.vercel/output/static(no leading slash) - Add required environment variables in Pages → Settings → Environment variables
- Trigger a new deploy
Current rate limiting is not production-safe (in-memory). Replace with:
- Cloudflare KV / Durable Objects
- Redis (if using external store)
- Add per-IP & per-tenant counters and exponential backoff or captcha requirement after threshold.
Always:
- Validate input.
- Avoid returning upstream error details.
- Log minimal PII (extend log scrubbing when needed).
- Implement Turnstile CAPTCHA integration.
- Add proper multi-tenant theme mapping.
- Add CMS data fetching example.
- Move rate limiting to durable store.
- Add Playwright E2E tests.
- Add Git hooks (Husky) for pre-commit lint & format.
- Create a feature branch.
- Run
pnpm preflightbefore pushing. - Include tests for new components or endpoints.
- Open PR; run local
pnpm typecheck && pnpm lint && pnpm testbefore requesting review.
Internal proprietary starter (adjust if open-sourcing later).