@zindua/create-app
v1.3.0
Published
Scaffold a Next.js auth app. Run: npx @zindua/create-app@latest my-app — setup wizard in browser
Maintainers
Readme
@zindua/create-app
SaaS-ready Next.js authentication starter powered by Zindua. OTP by email or WhatsApp, optional password register/login, i18n, and server-side @zindua/sdk. No SMTP. Delivery goes through zindua.run.
Install
npx @zindua/create-app@latest my-appDo not use npm i @zindua/create-app to create a project. That only installs the CLI into node_modules inside your current folder. It does not scaffold an app.
Always pin @latest so you get the newest template and CLI:
npx @zindua/create-app@latest <command>Prerequisites
- Node.js 18+ and npm.
- A Zindua account with a project and API key (
znd_test_…for local dev,znd_live_…for production). - At least one delivery channel connected in the dashboard (email and/or WhatsApp).
- An OTP template on Zindua (default slug:
otp-verificationwith{{code}}).
Step-by-step: create your app
Step 1. Scaffold the project
From the directory where you want the new folder:
npx @zindua/create-app@latest my-appReplace my-app with your project name (letters, numbers, ., _, - only). This creates ./my-app/ with a complete Next.js App Router app and placeholder .env.local.
init does the same thing:
npx @zindua/create-app@latest init my-appNo terminal wizard. The CLI does not ask for your API key in the console.
Step 2. Install dependencies
cd my-app
npm installStep 3. Start the dev server
npm run devOpen http://localhost:3000. You are redirected to /setup — a browser setup wizard that walks you through:
- API key verification (calls Zindua)
- OTP channel and template language
- UI locale, template (corporate or minimal), auth mode, optional Neon URL
- Save to
.env.local
When setup finishes, restart the dev server (Ctrl+C, then npm run dev again). Next.js loads environment variables at startup.
After restart, open http://localhost:3000 — you land on /en, /fr, or /es based on your choices.
Step 4. Prepare Zindua (dashboard)
In zindua.run → your project:
- Channels: connect email (Gmail, Outlook, SMTP, etc.) and/or WhatsApp.
- Templates: create
otp-verificationwith variable{{code}}. Optional:{{appName}}. - Login alert (optional): if you enable login alerts in the wizard, create template
new-login-alertwith{{appName}},{{device}},{{ip}},{{time}}.
Step 5. Optional: Neon database
If you chose password auth in the wizard, DATABASE_URL is already in .env.local. Push the schema:
npm run db:pushYou can also add DATABASE_URL manually later for persisted sessions, audit logs, and OTP storage.
Password register/login (AUTH_MODE=password or both) requires DATABASE_URL.
Step 6. Test the OTP flow
- Enter email or phone (depending on
ZINDUA_OTP_CHANNEL). - Receive the code via Zindua.
- Verify on
/[locale]/verify. - Land on
/[locale]/success(protected byproxy.ts).
Check delivery logs in your Zindua dashboard.
Step 7. Deploy
Deploy to Vercel, Railway, or any Node host. Set the same variables as server-side secrets (not NEXT_PUBLIC_*). Use a live API key in production. Point APP_URL to your public URL.
Production: configure .env.local (or host secrets) manually — the browser wizard only runs in development.
Auth modes
Set AUTH_MODE in .env.local:
| Value | Behavior |
|-------|----------|
| otp | OTP only (default) |
| password | Email + password register and login |
| both | Tabs on login: OTP and password |
Password routes:
- Register UI:
/[locale]/register - API:
POST /api/auth/register,POST /api/auth/login-password
Login alert email
After a successful sign-in (OTP, register, or password login), optionally notify the user:
ZINDUA_LOGIN_ALERT_ENABLED=true
ZINDUA_LOGIN_ALERT_TEMPLATE=new-login-alertCreate the matching email template in Zindua. The send is fire-and-forget and does not block login.
Commands for an existing project
Run these inside your app folder (cd my-app).
Switch UI template (corporate or minimal)
Changes layout and styles only. Does not overwrite .env.local or your auth logic.
npx @zindua/create-app@latest templatePick corporate (split orange panel) or minimal (single column). The choice is stored in .zindua/template.json.
Update auth engine from the latest package
Syncs server routes, lib/, store/, and related files from the npm package. Keeps .env.local untouched.
npx @zindua/create-app@latest updateUse this after releasing a new @zindua/create-app version to pull bug fixes and new API routes. To refresh UI only, use template instead.
Diagnose configuration
npx @zindua/create-app@latest doctorChecks .env.local, API key reachability, and common misconfigurations.
What you get
- Next.js 16 App Router, Tailwind v4,
@zindua/sdk(server-only) - Browser setup wizard at
/setup(development only) - UI templates:
corporateorminimal(switch anytime withtemplate) - i18n routes:
/en,/fr,/eswith locale switcher - Zustand auth flow (credentials → OTP → success)
- API routes:
send-otp,verify-otp,register,login-password,logout - Optional Drizzle + Neon: users, sessions, OTP codes, audit logs, devices
- Rate limiting on OTP send, httpOnly session cookie,
proxy.tsroute guard - No SMTP. All delivery through Zindua.
Environment reference
| Variable | Required | Default | Notes |
|----------|----------|---------|-------|
| ZINDUA_SETUP_COMPLETE | Dev | false | Set true by wizard when done |
| ZINDUA_API_KEY | Yes | n/a | From Dashboard → Projects |
| ZINDUA_APP_NAME | No | MyApp | Used in templates as {{appName}} |
| ZINDUA_TEMPLATE_SLUG | No | otp-verification | OTP template slug |
| ZINDUA_OTP_CHANNEL | No | email | email or whatsapp |
| ZINDUA_OTP_LANG | No | en | Template language for Zindua API |
| ZINDUA_DEFAULT_LOCALE | No | en | UI locale: en, fr, es |
| AUTH_MODE | No | otp | otp, password, or both |
| ZINDUA_LOGIN_ALERT_ENABLED | No | false | true to send post-login alert |
| ZINDUA_LOGIN_ALERT_TEMPLATE | No | new-login-alert | Alert template slug |
| APP_URL | Yes | n/a | Public app URL |
| AUTH_SESSION_SECRET | Yes | n/a | Long random string |
| DATABASE_URL | For password | n/a | Neon Postgres connection string |
Security
ZINDUA_API_KEYstays on the server. Never useNEXT_PUBLIC_for secrets.@zindua/sdkis only imported inapp/api/**andlib/. Client components call your own/api/auth/*routes.- Rotate the API key in the dashboard if it was ever exposed.
- Replace in-memory OTP storage with Postgres (
DATABASE_URL) or Redis before high traffic.
Command cheat sheet
# Create project (recommended)
npx @zindua/create-app@latest my-app
# Same as my-app
npx @zindua/create-app@latest init
# Inside an existing project
npx @zindua/create-app@latest template # switch corporate | minimal UI
npx @zindua/create-app@latest update # sync auth engine, keep .env.local
npx @zindua/create-app@latest doctor # diagnose setup