Litestore · Developer guide

FAQ

Learn about the questions that come up most often when setting up, running, extending and evaluating Litestore, including what the repository does not claim to be.

Short answers, each checked against the code. Where a topic has a full page, the answer links to it.

The questions are grouped by what you are trying to do: get it running, operate it, change it, or decide whether to adopt it at all.

Setup

Why does every route return 500 with "Invalid environment variables"?

A required variable is unset.

env.ts validates with @t3-oss/env-nextjs at module load, not per request. That is why one missing value fails every route rather than only the route that needed it — the module never finishes loading.

The console output names the keys. REDIS_REST_URL and REDIS_REST_TOKEN are the pair most often missed: both are required even locally, though placeholder strings are enough in development. See Configuration.

Do I need Redis to develop locally?

No live instance.

checkRateLimit returns { success: true, remaining: 999 } before touching Redis when isDev is true, so nothing connects during local development.

The two variables still have to be set, because env.ts validates their presence, not their reachability. Production needs a real Upstash instance.

Does the repository have a migration history I can rely on?

Not for local setup.

prisma/migrations/ holds a baseline and a performance-index migration, and bun run db:deploy (prisma migrate deploy) applies them in production. That path is real.

But the README states directly that local setup uses db:push and that there is no committed migration history to treat as authoritative local bootstrap state. Bootstrap with:

bun run db:push

Then seed:

bun run db:seed

Note that the db:push script currently runs prisma migrate dev, not prisma db push — the script name and the README describe an intent the script body has drifted from.

Do I need Stripe to run the store?

No.

STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET are .optional() in env.ts, and the readiness panel marks payments non-critical.

Browsing and carts work without them. Taking payment is what switches off.

The magic link email never arrives. Where do I look?

Resend first. Check RESEND_API_KEY, and check that RESEND_SENDER_EMAIL is on a verified domain.

A down Redis is not the cause. checkRateLimit logs "Rate limiter error, failing open" and lets the request through, so rate limiting degrades rather than blocking sign-in.

Can I use MySQL or SQLite?

No.

The baseline migration writes Postgres-specific guarantees. It creates unique indexes on lower("email") and lower("slug"), and CHECK constraints such as order_amounts_refunded_not_over_total and stock_movement_quantity_math.

Those constraints are not decoration on top of application logic; they are where several of the guarantees actually live. A database that cannot express them would not enforce them.

Running it

Where do settings live — env or admin?

Secrets and infrastructure endpoints are environment variables, validated by env.ts.

Store identity, currency, thresholds and AI autonomy live in Settings in the admin, and change without a deploy.

The split follows from that: anything you would not want to redeploy to adjust is in the admin.

Does anything phone home?

No.

There is no licence check in the codebase and no variable pointing at a Litestore service.

Outbound traffic goes only to the integrations you configure.

How do I connect Claude or another assistant to my store?

Mint a ServiceApiKey carrying the admin:mcp scope in Settings → Developer, then point your MCP client at /api/mcp/admin with Authorization: Bearer <key>.

app/api/mcp/admin/route.ts rejects any key without that scope, so the scope is the access boundary rather than a label on the key.

Read tools answer from live data. Change tools mint approval cards you decide in the admin. See MCP servers.

Can more than one person use the admin?

Yes. Users carry roles, plus per-user grantedPermissions and deniedPermissions overrides.

An admin cannot grant a permission they do not hold themselves, which keeps the permission set from being escalated sideways.

Role or override edits emit a user_permissions_changed activity entry recording actor, target and what moved.

Changing it

How do I add a new section to the storefront?

Add the type to BLOCK_TYPES in lib/blocks/registry.ts. BLOCK_REGISTRY is declared satisfies Record<BlockType, BlockDefinition>, so typecheck fails until you add the definition.

The renderer is a separate step, and it is not compiler-enforced. The switch in components/web/blocks/block-renderer.tsx ends in default: return null, so a block with no case renders nothing instead of failing the build.

That is the step to remember: the type system will chase you through the registry, then stop. See Blocks.

How do I react to something happening — an order, a refund, a signup?

Bind a handler to the domain event.

domainEventFunctions is spread into the Inngest serve() call in app/api/inngest/route.ts, so a handler bound to an event is served from there without further wiring. See Events.

Why did my change fail a lint:discipline check?

scripts/check-discipline.ts enforces import boundaries, canonical patterns and budget ratchets. It is one of 25 scripts/check-*.ts checks.

The failure message names the rule and the file, so the check tells you which of the three it was. See The harness.

Is there a stable extension API?

No, and the README says so: this is "not a stable public extension API" and "not a polished framework".

You are editing a product codebase, not writing against a contract. Upstream changes can move the ground under a customization.

Can I remove modules I don't use?

Yes — it is your copy of the code.

Modules share the database and the registries, so delete from the registry outward. bun run typecheck will then list every site that referenced it.

Evaluating it

How big is it?

70 Prisma models, 56 domain events, 10 block types, and 41 admin task kinds.

25 architecture checks run in CI, over roughly 1,349 test cases across 154 Vitest files.

What kind of codebase am I adopting?

The README is direct about this: active, broad and usable, but "not a minimal starter".

The storefront and admin share one Next.js app, and cleanup of older abstractions and admin experiments is still underway.

Expect to read code rather than configure a framework.

What is out of scope?

Litestore is a single-merchant store you run yourself.

It does not include:

  • subscriptions and recurring billing
  • B2B quotes and company accounts
  • a plugin marketplace
  • multi-tenant SaaS hosting

On this page