# Deployment and recovery

Requires PHP 8.2+, PDO SQLite, sessions and image metadata support. Document root must be `shop/public` only. `app`, `bin` and `var` must never be publicly served. `PURENEST_SHOP_DATA` can override the private storage directory (default `shop/var`). The PHP service needs write access only to private storage and its session directory. Source/assets remain root-owned.

On this host the app is `/var/www/purenest-shop`, PHP runs as `purenestshop`, socket `/run/php/purenest-shop-fpm.sock`, private data `/var/www/purenest-shop/var`, session/log files `/var/lib/purenest-shop`. Service: `purenest-shop-fpm`. Apache virtual host: `shop.purenesteggs.com`. TLS uses a separate Let's Encrypt certificate. Existing brand website is independent.

The deployment folder contains host-specific examples. `install.sh` is for initial HTTP bootstrap only: do not blindly rerun after HTTPS configuration, because it would replace the virtual host. For application updates, back up first, update only app/bin/public, then reload the shop PHP service if necessary. Never overwrite `var` or sessions with local test files.

## Owner password reset
Run as the shop service user, supplying a new password on stdin rather than in command arguments or shell history:

`php bin/shop.php owner owner`

Minimum 14 characters. On this server, PHP CLI uses the same isolated extensions as the PHP service: `php8.2 -n -d extension=pdo.so -d extension=/opt/purenest-php/usr/lib/php/20220829/pdo_sqlite.so`.

## Backups
Use `bin/shop.php backup /private/new-backup.sqlite` as the shop user; this uses SQLite VACUUM INTO for a consistent snapshot, including active WAL contents. Back up `var/uploads` alongside it, and store off-server encrypted backups. Do not copy only the active .sqlite file while writes are in progress.

For restore: close the storefront, stop `purenest-shop-fpm` and pause `/etc/cron.d/purenest-shop`; preserve current data as a rollback copy; restore the snapshot as `var/shop.sqlite` and matching uploads; remove stale WAL/SHM files only while stopped; set ownership `purenestshop:purenestshop`, directory 0700 and database/files 0600. Start the service, restore the cron file, test private login/catalogue/order views and only then reopen the storefront. Do not restore the development test database to production.

Scheduler command: `bin/shop.php fulfilments`. Daily cron configuration is in `deploy/fulfilments`. Monitor service and Apache logs and the last successful scheduler timestamp in admin. HTTPS renewal is managed by Certbot.

Tests: `php tests/commerce.php`; concurrency uses an empty temporary `PURENEST_SHOP_DATA` directory. Browser tests use an isolated localhost preview and must never be aimed at production with their write/test-order steps.

## Grocery redesign migration
Back up before updating app/bin/public. The idempotent bootstrap migration adds catalogue publication and SEO fields without replacing existing tables. `php bin/publish-catalogue.php` is a one-time rollout command: it publishes the first white/brown 6/12 packs, writes introductory product descriptions and enables browse-only visibility while explicitly closing orders. It does not create prices, stock or orders. Do not remove its completion setting or rerun it to reset an operational store. Preserve the database and uploaded images on future deployments.

Additional checks: `php tests/seo.php`; `tests/redesign.mjs` targets the isolated local preview on port 8797, not production.
