Run locally
Run the site on your machine with pnpm dev on port 3000, the minimum env it needs, the superadmin sign-in, and what to change if you use another port.
Outcome: pnpm dev serves the site at http://localhost:3000, you sign in as the superadmin, and /dashboard shows the admin menu.
What it needs
| Item | Where it comes from |
|---|---|
Node.js 22.23.4 |
.node-version |
pnpm 12.16.1 |
packageManager in package.json; corepack enable makes it the one used here |
| Dependencies | pnpm install |
.env.local |
cp .env.example .env.local, filled by the setup skills |
DATABASE_URL with every migration applied |
skill setup-database |
BETTER_AUTH_SECRET, 32 characters or more |
skill setup-auth (the agent generates it) |
| One sign-in method | Google (skill setup-auth) or email codes (skill setup-email) |
DATABASE_URL and BETTER_AUTH_SECRET are enough for the site to start. Without a sign-in method nobody can sign in, the superadmin included: there is no password sign-in.
NEXT_PUBLIC_SITE_URL stays http://localhost:3000 locally, as in .env.example.
Steps
1. Database and owner account
Agent: runs setup-database: writes DATABASE_URL, applies the migrations with pnpm db:migrate, then creates the owner:
pnpm create-superadmin you@example.com
This creates a user with the role superadmin and a verified email, or promotes the existing user with that email.
You: name the email you sign in with.
2. Start the app
You or Agent:
pnpm dev
Open http://localhost:3000. The home page is ShipAgent's own landing page until the agent replaces it with yours (ask it to "turn this into my product"; it follows skills/reference/quick-start.md).
3. Sign in as the superadmin
You: open the sign-in dialog and use the superadmin email, either:
- Google, with the same address. A Google account is linked to an existing user with the same email.
- Email code or magic link, once
setup-emailhas passed.
Then open /dashboard. As superadmin you see the admin pages: overview, users, orders, credits, coupons, feedback, blog, glossary and R2 files. Every user sees billing, orders, credit history, team, settings and feedback.
The AI demos at /ai-demo/chat, /ai-demo/image and /ai-demo/video are open to admins only, so your provider keys are not spent by visitors.
Ports
| Port | What | Notes |
|---|---|---|
| 3000 | the app (pnpm dev) |
every default assumes it: NEXT_PUBLIC_SITE_URL, the Google origin and redirect URI, the R2 CORS rule, stripe listen --forward-to localhost:3000/api/stripe/webhook, and the check scripts' default --url |
| 4983 | Drizzle Studio (pnpm db:studio), a table browser for your database |
Drizzle's default; it opens in the browser at local.drizzle.studio |
If port 3000 is taken, Next.js starts on the next free port (3001) and prints it. Sign-in then fails, because the site is no longer at the origin it trusts. Either free port 3000, or move everything to the new port:
NEXT_PUBLIC_SITE_URL=http://localhost:3001in.env.local, then restartpnpm dev.- Add
http://localhost:3001andhttp://localhost:3001/api/auth/callback/googleto the Google client. pnpm tsx scripts/check-storage.ts --origin http://localhost:3001 --apply-corsfor uploads.stripe listen --forward-to localhost:3001/api/stripe/webhook.- Pass
--url http://localhost:3001tocheck-auth.ts,check-stripe.ts --fireandcheck-ai.ts.
Other commands
| Command | What it does |
|---|---|
pnpm lint |
type check (tsc --noEmit); there is no ESLint |
pnpm test |
unit tests in tests/ |
pnpm build |
production build with next build (Vercel uses this one) |
pnpm db:migrate |
apply new migrations from lib/db/migrations/ |
pnpm db:studio |
browse the database |
pnpm stripe:bootstrap |
dry run of the Stripe products and prices from config/pricing.ts; --write creates them |
The agent runs pnpm lint and pnpm test before it reports any code change as done.
When it fails
| What you see | Cause | Fix |
|---|---|---|
DATABASE_URL environment variable is not set from create-superadmin |
.env.local has no DATABASE_URL |
run setup-database |
| Pages fail with a missing table | migrations not applied to this database | pnpm db:migrate, then pnpm tsx scripts/check-database.ts |
Sign-in does nothing or /api/auth/ok answers 500 |
BETTER_AUTH_SECRET missing or shorter than 32 characters |
ask the agent to run setup-auth step 1, then restart pnpm dev |
| No sign-in method works | neither Google nor email is set up | setup-auth or setup-email |
| No email code arrives | DEFAULT_ADMIN_EMAIL or RESEND_API_KEY missing, or the domain is not verified |
setup-email |
| Signed in, but no admin menu | you signed in with another email than the superadmin's | pnpm create-superadmin <that email>, sign out and in again |
| A key you just added has no effect | the app reads .env.local at startup; NEXT_PUBLIC_* values are fixed when it starts |
restart pnpm dev |
Missing API key: X is not configured for Y in an AI demo |
the running app does not see the provider key | put it in .env.local, restart pnpm dev |