Installation
There are two ways to bring the system up, and both end in the same place: the wizard in your browser. That is the idea underneath — starting and configuring are different jobs. Starting can happen with Docker, with npm, or with a button in some cloud panel; configuring always happens the same way, and it happens without a terminal.
With Docker — recommended
Section titled “With Docker — recommended”docker compose -f docker-compose.full.yml up -dThat is it. It brings up four pieces: Postgres, the backend, the admin panel and the storefront.
- Storefront → http://localhost:3000
- Admin panel → http://localhost:7001/admin
The first run takes a few minutes, because it builds the three images and migrates the entire database. After that it starts in seconds. Opening the panel drops you into the wizard: four checks, your store name, your account and, if you want it, a demo catalogue so you can watch the whole loop work.
To follow the startup:
docker compose -f docker-compose.full.yml logs -f backendPutting it live
Section titled “Putting it live”Copy .env.docker.example to .env and change two things:
-
The domains (
TIENDA_URL,PANEL_URL,BACKEND_URL). CORS and the links in your emails are derived from these. -
The Postgres user and password. The examples are
pcreative, which is fine for trying it locally and not for a server.⚠️ If you are coming from an earlier install, the user was written into the volume the first time the database started and cannot be changed afterwards: put the one you already had in your
.env, or the backend will not be able to get into its own database.
You can leave the session secrets empty: the container generates a set on first run and keeps them in its volume. Set them by hand only if you are going to run several backend replicas — each one would generate its own, and sessions would stop being valid the moment a request landed on a different replica.
Change the .env, restart, done:
docker compose -f docker-compose.full.yml up -dNone of this forces an image rebuild, and that is not what you get by
default with Next: variables that reach the browser are baked in at build time,
so correcting a tax ID would mean rebuilding the whole panel. Here the server
reads its configuration at startup and hands it to the browser with each page
(apps/admin/src/lib/config.ts), which is the pattern Next documents for
“build once, deploy anywhere”. The same goes for the store name, the brand
colour and the tax details on your invoices.
The only thing still tied to build time is the storefront theme.
Changing the theme
Section titled “Changing the theme”Set TEMA=<folder under themes/> in the .env and rebuild the storefront:
docker compose -f docker-compose.full.yml build tiendadocker compose -f docker-compose.full.yml up -dThe panel reads the theme catalogue straight off disk (./themes is mounted),
so nothing needs rebuilding on that side.
What is stored, and where
Section titled “What is stored, and where”Four volumes, and it is worth knowing which is which before deleting any of them:
| Volume | What is in it |
|---|---|
db |
The database. Everything. |
static |
Images uploaded from the panel. |
datos |
Generated secrets and the publishable key. |
Without Docker — on your own server
Section titled “Without Docker — on your own server”What Docker does under the hood, by hand. You need Node 22 or later and a Postgres.
npm ci # ALWAYS ci, never installnpm run build -w @pcreative/commerce-backend # compiles to apps/backend/dist
cd apps/backendcp .env.example .env # DATABASE_URL and little elsenpm run preparar # installs or migrates, and prepares the shopnpm start # runs the compiled buildpreparar looks at the database and decides on its own: if it is empty it
creates the whole schema (173 tables, with nothing else installed); if it
already has things, it applies whatever is missing. Either way it leaves the
shop ready to sell: the store row, a sales channel and the publishable key the
storefront needs to talk to it. It is idempotent — you can run it on every
start, which is exactly what the container does.
Then the setup wizard in the browser, same as with Docker.
Behind a process manager or a load balancer
Section titled “Behind a process manager or a load balancer”The server has two health endpoints, and they are not the same thing:
/salud→ 200 as long as the process responds. For “is it alive?”./listo→ 200 only if it can serve customers. It switches to 503 the moment shutdown begins, and also if any plugin failed to load at startup — a server selling at a different price is not ready.
The process manager watches /salud to decide whether to restart; the load
balancer watches /listo to decide whether to send traffic. The other way
round loses requests: a balancer watching /salud keeps sending customers to a
server that is already leaving, and a manager watching /listo kills the
process while it finishes a payment. With PCC_MARGEN_CIERRE_MS=5000 the
server waits that long between flagging /listo and closing the port, so the
balancer can step aside.
For development
Section titled “For development”Same, without compiling and reloading on save:
docker compose up -d # Postgres onlynpm cicd apps/backend && npm run dev # tsx watchcd apps/admin && npm run devWhat is not there yet
Section titled “What is not there yet”- An
npx create-pcreative-commercecommand for people who would rather not know Docker exists. Today it would be a thin wrapper around the above. - Deploy buttons for Coolify, Railway or DigitalOcean.
- Shared hosting. And this one is not coming: Node is not installed on the €3 hosting plans where half of WooCommerce lives. It is the structural disadvantage against PHP, and a better installer does not fix it.