About this template
Image Lite
Image Lite is a focused AI image generator built with TanStack Start and the ShipAny SaaS engine. It combines a public text/reference-image generator with accounts, credits, subscriptions, My Creations, RBAC, and an admin console.
Stack
- TanStack Start, Vite 8, Nitro, React 19, and TypeScript
- Tailwind CSS 4 and shadcn/ui v4
- TanStack Query, Router, Form, and Table
- better-auth, Drizzle ORM, and Paraglide JS
- SQLite for local development; PostgreSQL, MySQL, Turso, or Cloudflare D1 in production
- Cloudflare Workers, D1, R2, and Hyperdrive support
Local development
Requirements
- Node.js 22+
- pnpm 10+
- OpenSSL
Enable pnpm through Corepack if necessary:
corepack enable
1. Install and configure
pnpm install
cp .env.example .env.development
Generate two independent secrets:
openssl rand -base64 32
openssl rand -base64 32
Put the first value in AUTH_SECRET and the second in
CONFIG_ENCRYPTION_KEY inside .env.development. Never commit that file.
2. Prepare the local database
pnpm db:setup
pnpm db:push
pnpm rbac:init \
[email protected] \
--admin-password=choose-a-local-password
db:push directly synchronizes the development database and may be
destructive. Do not use it against a production database.
3. Start the app
pnpm dev
Open:
- App: http://localhost:3000
- Sign in: http://localhost:3000/sign-in
- Admin: http://localhost:3000/admin
After signing in as the administrator, configure AI, storage, payments, email, OAuth, and analytics under Admin → Settings. Provider credentials belong in the admin settings; environment variables are only fallback values.
Debugging and verification
| Command | Purpose |
|---|---|
pnpm dev |
Start Vite on port 3000 with hot reload |
pnpm build |
Build the production client and Nitro server |
pnpm start |
Run the generated Node server from .output/ |
pnpm format:check |
Check formatting without changing files |
pnpm db:studio |
Inspect the current database in Drizzle Studio |
pnpm db:push |
Sync schema changes to a development database |
pnpm db:generate |
Generate reviewable production migration SQL |
pnpm db:migrate |
Apply migrations to a direct database connection |
Use .env.development as the single local environment file. Conflicting
values in .env.local can override it and commonly cause database or auth
origin problems.
Before pushing code, run:
pnpm format:check
pnpm build
To test the generated Node bundle locally:
pnpm build
pnpm start
Common local problems
| Symptom | Fix |
|---|---|
| Database tables are missing | Run pnpm db:setup and pnpm db:push |
| Sign-in reports an invalid origin | Keep VITE_APP_URL=http://localhost:3000 |
| Image generation is unavailable | Configure an AI provider in Admin → Settings |
| Reference-image upload fails | Configure public R2/S3 storage in Admin → Settings |
| Admin returns 403 after assigning a role | Sign out and sign in again |
Environment variables
The committed .env.example intentionally contains only the local essentials.
| Variable | Required | Notes |
|---|---|---|
VITE_APP_URL |
Yes | Public URL used by auth, callbacks, and SEO |
VITE_APP_NAME |
Yes | Product name shown in the UI |
DATABASE_PROVIDER |
Yes | sqlite, postgresql, mysql, turso, or d1 |
DATABASE_URL |
Local/Node | Direct database connection string |
AUTH_SECRET |
Yes | Generate with openssl rand -base64 32 |
CONFIG_ENCRYPTION_KEY |
Recommended | Encrypts secrets saved from Admin → Settings |
Only public browser-visible values may use the VITE_ prefix. Never expose
database credentials, API keys, or auth secrets through VITE_* variables.
Database changes
For development:
pnpm db:push
For production, generate and review a migration before applying it:
pnpm db:generate
# Review the SQL under drizzle/.
pnpm db:migrate
src/config/db/schema.ts and drizzle/ are working files and are ignored by
Git. The committed dialect templates live under src/config/db/.
Deploy to Cloudflare Workers
Cloudflare Workers with D1 is the default deployment target. Production image upload also requires R2 or another public S3-compatible storage provider; a Worker has no persistent writable filesystem.
Recommended deployment
In a compatible coding-agent environment, run:
/deploy-cloudflare
The project deployment skill performs the build, creates or reuses D1 or Hyperdrive, applies migrations, seeds RBAC, uploads secrets, configures the production URL, deploys, and smoke-tests the result. It always asks before the final production deployment. Run it again for subsequent releases.
Manual D1 deployment
1. Authenticate and create the working config
npx wrangler login
cp wrangler.example.jsonc wrangler.jsonc
npx wrangler d1 create image-lite-db
In the ignored wrangler.jsonc, replace the D1 placeholder with the returned
database ID. Keep the binding name DB, DATABASE_PROVIDER set to d1, and
migrations_dir set to drizzle.
2. Set the production URL
Create the ignored .env.production:
VITE_APP_URL=https://image-lite.<your-subdomain>.workers.dev
VITE_APP_NAME=Image Lite
DATABASE_PROVIDER=d1
Set the same VITE_APP_URL and VITE_APP_NAME in wrangler.jsonc vars.
They must match because the URL is used during both build and runtime.
For a custom domain, add this to wrangler.jsonc and use the same domain for
VITE_APP_URL:
"routes": [{ "pattern": "images.example.com", "custom_domain": true }]
The domain or its parent zone must already exist in the Cloudflare account.
3. Generate and apply migrations
DATABASE_PROVIDER=d1 pnpm db:setup
DATABASE_PROVIDER=d1 pnpm db:generate
npx wrangler d1 migrations apply image-lite-db --remote
Review the generated SQL under drizzle/ before applying it.
4. Seed RBAC
Remote D1 is accessed through a Worker binding, so seed a local Wrangler D1 and import only the RBAC rows:
npx wrangler d1 migrations apply image-lite-db --local
LOCAL_D1=$(find .wrangler/state -name "*.sqlite" -path "*d1*" | head -1)
DATABASE_PROVIDER=sqlite DATABASE_URL="file:$LOCAL_D1" pnpm rbac:init
sqlite3 "$LOCAL_D1" ".dump role permission role_permission" \
| grep "^INSERT INTO" \
| sed 's/^INSERT INTO/INSERT OR IGNORE INTO/' \
> /tmp/image-lite-rbac.sql
npx wrangler d1 execute image-lite-db \
--remote \
--file=/tmp/image-lite-rbac.sql
Manual RBAC seeding requires the sqlite3 CLI.
5. Add Worker secrets and deploy
openssl rand -base64 32 | npx wrangler secret put AUTH_SECRET
openssl rand -base64 32 | npx wrangler secret put CONFIG_ENCRYPTION_KEY
pnpm cf:deploy
Never put secrets in wrangler.jsonc vars. After the first deployment,
synchronize the exact deployed URL in .env.production and wrangler.jsonc,
then run pnpm cf:deploy again if the URL changed.
6. Finish production setup
-
Sign up through
/sign-up. -
Promote the first administrator with
/deploy-cloudflare --admin=<email>. For a fully manual deployment, run:npx wrangler d1 execute image-lite-db --remote --command=" INSERT OR IGNORE INTO user_role (id, user_id, role_id) SELECT lower(hex(randomblob(16))), u.id, r.id FROM user u, role r WHERE u.email = '[email protected]' AND r.name = 'super_admin' " -
Sign out and sign back in.
-
Configure AI and R2 under Admin → Settings.
-
Verify
/and/api/config/publicreturn HTTP 200.
For live Worker errors:
npx wrangler tail
PostgreSQL with Hyperdrive
When using an existing PostgreSQL database:
-
Create Hyperdrive with
npx wrangler hyperdrive create image-lite --connection-string="$DATABASE_URL". -
Set
DATABASE_PROVIDERtopostgresqlinwrangler.jsonc, removed1_databases, and add a Hyperdrive binding named exactlyHYPERDRIVE. -
Load a local
.env.productioncontaining the direct PostgreSQL URL, then prepare and migrate the schema:set -a . ./.env.production set +a DATABASE_PROVIDER=postgresql pnpm db:setup DATABASE_PROVIDER=postgresql pnpm db:generate DATABASE_PROVIDER=postgresql pnpm db:migrateReview the generated SQL before running
db:migrate. -
Run
pnpm rbac:initagainst the direct PostgreSQL connection. -
Add Worker secrets and deploy with
pnpm cf:deploy.
The PostgreSQL connection string is a secret. Do not place it in
wrangler.jsonc vars; Hyperdrive supplies it at runtime.
Deploy to a Node server
Use PostgreSQL, MySQL, or Turso for multi-instance production. SQLite is only suitable for one instance with persistent storage.
- Create
.env.productionwith the production URL, database provider and connection,AUTH_SECRET, andCONFIG_ENCRYPTION_KEY. - Run
NODE_ENV=production pnpm db:setup. - Generate and review migrations with
NODE_ENV=production pnpm db:generate. - Apply them with
NODE_ENV=production pnpm db:migrate. - Seed roles with
NODE_ENV=production pnpm rbac:init. - Build with
NODE_ENV=production pnpm build. - Start with
NODE_ENV=production PORT=3000 pnpm start.
Run the server behind TLS and pass production secrets through the hosting
platform rather than committing .env.production.
Project layout
src/blocks/ Landing-page sections
src/components/ Reusable UI and shadcn primitives
src/core/ Auth, database, AI, payments, email, and storage
src/modules/ Business services
src/routes/ Pages and API routes
messages/ English and Chinese translations
wrangler.example.jsonc Cloudflare configuration template
License
Proprietary software. See LICENSE.
Built with ShipAny.
