Structure
Find your way around the Litestore repository and choose where new code belongs.
The repository has a fixed layout, and each new module or integration has a place it belongs. Following these conventions keeps your code where the next person will look for it.
Everything is in one project, so a storefront page can import a domain rule directly without crossing a package boundary.
Directory tree
Key conventions
Treat this layout as a set of rules. No script checks it, so reviewers do: a file in the wrong place gets copied by the next person who looks for an example.
Route folders
app/ contains Next.js convention files and nothing else:
page.tsx
layout.tsx
loading.tsx
error.tsx
route.tsUI for a specific route goes in modules/<area>/admin/ or modules/<area>/storefront/.
app/ contains a _components/ folder or any other underscore folder.Server actions
"use server" files live only in a module's admin/ or storefront/ folder, for example modules/orders/admin/actions.ts. Each admin action declares its permission with modulePermission or withAnyPermission from platform/permissions/procedures.ts.
Actions save data through the module's CRUD object, built on BaseCRUD in platform/crud/base-crud.ts. It handles soft delete, activity logging and cache invalidation in one step, so callers don't have to handle each of these themselves.
Queries
Read-only queries go next to the actions in queries.ts. Cached reads are tagged with a value from CACHE_TAGS in platform/cache.ts. When a write happens, it clears the same tag that the read was cached under, so the next read fetches fresh data.
Module folders
A business area keeps its rules at the root of its folder and its surface code in admin/ and storefront/. For example, the coupon rules are in modules/promotions/ and the coupon admin is in modules/promotions/admin/. Module rules never import from admin/ or storefront/; the surfaces import the rules.
Import boundaries
Server modules start with import "server-only". If a "use client" component imports one of them, directly or through another file, next build fails, so server code and database access can't end up in the browser bundle. Storefront and admin code also stay apart, and neither imports from the other.
Adding code
| You are adding | Where it goes |
|---|---|
| A storefront section | Pages don't store layout. If it's text and images, write it into a page's HTML content. Otherwise change the route, or PageContent and PageFeed in modules/storefront/pages/page-view.tsx if every page should get it. Storefront pages explains how pages render. |
| An admin entity | modules/<area>/admin/ (actions, queries, crud, schema, table, detail page) and a route under app/admin/. CRUD explains the persistence layer. |
| A reaction to an event | Write a handler in jobs/domain-events.ts. Events explains how. |
| A third-party integration | Put it in modules/integrations/, behind the existing interface. |
| A shared rule or format | Put a domain rule in the owning modules/<area>/ and infrastructure or a pure helper in platform/. Define each one in a single place and import it from there everywhere else. |
| A tuning value | A typed constant in platform/config/, with a one-line comment. |