Running pcreative Commerce locally
Three processes and a database. On a clean machine, a few minutes from nothing to a browsable store.
apps/backend commerce engine :9000apps/admin our own panel :7001/adminthemes/growshop-premium storefront :30001. Infrastructure
Section titled “1. Infrastructure”docker compose up -d # Postgres :5434 (and a Redis only the old path uses)The ports are deliberately not the standard ones (5432/6379): that way you can have several stores up at once without them treading on each other.
2. Dependencies
Section titled “2. Dependencies”npm install # from the ROOT: this is a workspaces monorepo3. Backend
Section titled “3. Backend”cp apps/backend/.env.example apps/backend/.env# point DATABASE_URL at the docker-compose portcd apps/backendnpm run preparar # creates the schema (empty DB) or migrates, and prepares the shopnpm run seed # 6 categories and 24 demo productsnpm run pcc -- rescate alta admin@example.com # first panel access: prints the password oncenpm run dev:backend # :9000The seed does two things that are not cosmetic:
- It removes
pp_system_defaultfrom the region and switches on the real providers. That one is the engine’s test provider: it charges €0 and marks the order as paid. It is the quietest failure in a fresh install, because the shop appears to “work”. - It gives the two shipping methods different prices; out of the box both are €10.
Without SMTP_HOST the system starts anyway: emails are written to the log
instead of being sent. Configuring email is a go-live step, not a requirement
for bringing the backend up.
4. Storefront
Section titled “4. Storefront”cp themes/growshop-premium/.env.example themes/growshop-premium/.env.localNEXT_PUBLIC_COMMERCE_KEY is the sales channel’s publishable key. If you do not
have it to hand:
docker exec pcc-db psql -U pcreative -d pcreative_commerce \ -tAc "select token from api_key where type='publishable' limit 1"npm run dev:theme # :30005. Panel
Section titled “5. Panel”npm run dev:admin # :7001/adminUnder Themes you will see every folder in themes/ that has a valid
theme.json. Open one and the customiser form is generated from its
settings.schema.json: the panel does not know what settings a theme has until
it reads them, and that is exactly why it works the same for a Next theme, an
Astro one or a PHP one.
Saving writes themes/<id>/theme.override.json. In development the storefront
re-reads the theme on every request, so the change shows up on reload —
including derived colour scales, which recalculate themselves.
A section missing from the panel?
Section titled “A section missing from the panel?”You may be looking at a panel with sections that are not in this repository. That is on purpose: a store can add its own — integrations with its suppliers, bespoke reports — and those live in that installation, not in the product.
The panel discovers them by itself: the backend announces what it has at
GET /admin/capabilities and the menu adds them. Without that endpoint the
panel works exactly the same, with no errors.
Checks
Section titled “Checks”npm test # contracts: 130 tests, no backendnpm run theme -- validate themes/growshop-premiumnpm run theme -- info themes/growshop-premiumnpm run theme -- css themes/growshop-premium # the variables already resolvedTwo traps in this monorepo
Section titled “Two traps in this monorepo”React is pinned at the root. react and react-dom are in the root
package.json devDependencies on purpose. The engine drags in React 18 (for
the dashboard we keep disabled) and npm hoisted it to the root, where the
theme’s next also lives: the theme ended up with two Reacts and the build died
with minified error #31 (“object with keys {$$typeof, type…}”), which tells you
nothing about the cause. Pinning React 19 at the root leaves a single copy.
You do not need to — and should avoid — aliasing react in next.config:
that bypasses the react-server export conditions and breaks the Server
Components layer with Cannot read properties of null (reading 'useOptimistic').
Reading the cart is not a server action. carritoActual() lives in
lib/cart-read.ts and not in lib/cart.ts. A module marked "use server"
turns all of its exports into actions, and calling an action during render does
not mark the page as dynamic: Next was trying to prerender /carrito at build
time and failing. Mutations go in cart.ts; reads stay out of it.