diff --git a/.claude/settings.json b/.claude/settings.json
new file mode 100644
index 0000000..e10da22
--- /dev/null
+++ b/.claude/settings.json
@@ -0,0 +1,20 @@
+{
+ "permissions": {
+ "allow": [
+ "Bash(docker compose *)",
+ "Bash(grep -E '^\\\\.env$|^\\\\.env' .gitignore)",
+ "Bash(curl -s -o /dev/null -w \"%{http_code}\\\\n\" http://127.0.0.1:8090/)",
+ "Bash(docker rm *)",
+ "Bash(powershell.exe -NoProfile -Command \"netsh interface ipv4 show excludedportrange protocol=tcp\")",
+ "Bash(curl -s -o /dev/null -w \"app :8080 -> %{http_code}\\\\n\" http://127.0.0.1:8080/)",
+ "Bash(curl -s -o /dev/null -w \"phpliteadmin :8091 -> %{http_code}\\\\n\" http://127.0.0.1:8091/)",
+ "Bash(curl -s http://127.0.0.1:8080/)",
+ "Bash(curl -s -o /dev/null -w \"app :9092 -> %{http_code}\\\\n\" http://127.0.0.1:9092/)",
+ "Bash(curl -s -o /dev/null -w \"phpliteadmin :9091 -> %{http_code}\\\\n\" http://127.0.0.1:9091/)",
+ "Bash(curl -s http://127.0.0.1:9092/)",
+ "Bash(curl -s http://127.0.0.1:9092/locations)",
+ "Bash(curl -s http://127.0.0.1:9092/items)",
+ "Bash(grep -E '\\\\.env$|\\\\.sqlite$|storage/')"
+ ]
+ }
+}
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..30cf57e
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,10 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Ignored default folder with query files
+/queries/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/laravel-idea.xml b/.idea/laravel-idea.xml
new file mode 100644
index 0000000..bd941a4
--- /dev/null
+++ b/.idea/laravel-idea.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..d6a57ee
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/php.xml b/.idea/php.xml
new file mode 100644
index 0000000..0960256
--- /dev/null
+++ b/.idea/php.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/phpunit.xml b/.idea/phpunit.xml
new file mode 100644
index 0000000..4f8104c
--- /dev/null
+++ b/.idea/phpunit.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/warehouse.iml b/.idea/warehouse.iml
new file mode 100644
index 0000000..64ad165
--- /dev/null
+++ b/.idea/warehouse.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/deploy-raspberry-pi.md b/docs/deploy-raspberry-pi.md
new file mode 100644
index 0000000..412b0c6
--- /dev/null
+++ b/docs/deploy-raspberry-pi.md
@@ -0,0 +1,62 @@
+# Raspberry Pi deployment
+
+This app can run directly on a Raspberry Pi with **nginx + php-fpm** instead of Docker.
+
+## What the script does
+
+`scripts/deploy-raspi.sh` runs from your local machine and connects over SSH to the Pi. On the Pi it will:
+
+- install `nginx`, `git`, `composer`, and PHP 8.2 packages
+- clone or update the repository
+- create/update `.env`
+- install Composer dependencies
+- prepare the default SQLite database
+- run migrations
+- create an nginx vhost that serves `public/`
+- create a `systemd` service for `php command.php queue:work`
+
+## Assumptions
+
+- the Raspberry Pi is running a Debian/Raspberry Pi OS style distro with `apt`
+- your SSH user can run `sudo`
+- the repository is reachable from the Pi over Git/SSH or HTTPS
+- you want the app at `/var/www/warehouse`
+- you are fine using the app's default **SQLite** setup
+
+## Basic usage
+
+From this repo on your local machine:
+
+```bash
+chmod +x scripts/deploy-raspi.sh
+scripts/deploy-raspi.sh pi@raspberrypi.local git@github.com:YOUR_USER/warehouse.git DietPi.ntp.kentcommunications.com
+```
+
+Arguments:
+
+- argument 1: SSH target, for example `pi@192.168.1.50`
+- argument 2: Git clone URL the Pi can access
+- argument 3: nginx `server_name` value, optional, defaults to `DietPi.ntp.kentcommunications.com`
+
+## Useful environment overrides
+
+```bash
+DEPLOY_REF=main \
+DEPLOY_PATH=/var/www/warehouse \
+PHP_VERSION=8.2 \
+scripts/deploy-raspi.sh pi@raspberrypi.local git@github.com:YOUR_USER/warehouse.git DietPi.ntp.kentcommunications.com
+```
+
+## After deploy
+
+- browse to `http://DietPi.ntp.kentcommunications.com`
+- check nginx with `sudo systemctl status nginx`
+- check php-fpm with `sudo systemctl status php8.2-fpm`
+- check the queue worker with `sudo systemctl status warehouse-queue.service`
+
+## Notes
+
+- the app serves from `public/`, so the nginx root must stay pointed there
+- low-stock emails are always queued in this app, so the queue worker service matters in production
+- this script sets up **HTTP only**; add TLS separately with `certbot` or another reverse-proxy setup if you want HTTPS
+- if you prefer MySQL instead of SQLite, update `.env` and the script before rerunning it
\ No newline at end of file
diff --git a/readme.md b/readme.md
index 16a7c31..8837475 100644
--- a/readme.md
+++ b/readme.md
@@ -37,3 +37,7 @@ Note: host ports `9092`/`9091` map to the app's internal `80`/`8081` — the hos
## Framework guide
This app is built on a small custom MVC framework in `framework/`. See [docs/framework.md](docs/framework.md) for how routing, controllers, views, models/migrations, validation, sessions, caching, queues, and the CLI commands all work.
+
+## Raspberry Pi deployment
+
+If you want to run this app directly on a Raspberry Pi with `nginx` and `php-fpm`, see [docs/deploy-raspberry-pi.md](docs/deploy-raspberry-pi.md) and use `scripts/deploy-raspi.sh`.
diff --git a/scripts/deploy-raspi.sh b/scripts/deploy-raspi.sh
new file mode 100644
index 0000000..f216312
--- /dev/null
+++ b/scripts/deploy-raspi.sh
@@ -0,0 +1,125 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+if [ "$#" -lt 2 ] || [ "$#" -gt 3 ]; then
+ echo "Usage: scripts/deploy-raspi.sh [domain]"
+ exit 1
+fi
+
+ssh_host="$1"
+repo_url="$2"
+domain="${3:-DietPi.ntp.kentcommunications.com}"
+deploy_path="${DEPLOY_PATH:-/var/www/warehouse}"
+deploy_ref="${DEPLOY_REF:-main}"
+php_version="${PHP_VERSION:-8.2}"
+
+ssh "$ssh_host" bash -s -- "$repo_url" "$domain" "$deploy_path" "$deploy_ref" "$php_version" <<'REMOTE'
+set -euo pipefail
+
+repo_url="$1"
+domain="$2"
+deploy_path="$3"
+deploy_ref="$4"
+php_version="$5"
+owner="$(id -un)"
+group="$(id -gn)"
+php_fpm_service="php${php_version}-fpm"
+php_fpm_socket="/run/php/${php_fpm_service}.sock"
+
+set_env() {
+ file="$1"
+ key="$2"
+ value="$3"
+ if grep -q "^${key}=" "$file"; then
+ sed -i "s|^${key}=.*|${key}=${value}|" "$file"
+ else
+ printf '%s=%s\n' "$key" "$value" >> "$file"
+ fi
+}
+
+sudo apt-get update
+sudo apt-get install -y git nginx composer \
+ "php${php_version}" "php${php_version}-cli" "php${php_version}-fpm" \
+ "php${php_version}-mbstring" "php${php_version}-xml" \
+ "php${php_version}-curl" "php${php_version}-zip" \
+ "php${php_version}-sqlite3" "php${php_version}-mysql"
+
+sudo mkdir -p "$(dirname "$deploy_path")"
+if [ ! -d "$deploy_path/.git" ]; then
+ sudo git clone --branch "$deploy_ref" --single-branch "$repo_url" "$deploy_path"
+ sudo chown -R "$owner:$group" "$deploy_path"
+else
+ git -C "$deploy_path" fetch --prune origin
+ git -C "$deploy_path" checkout "$deploy_ref"
+ git -C "$deploy_path" reset --hard "origin/$deploy_ref"
+fi
+
+cd "$deploy_path"
+if [ ! -f .env ] && [ -f .env.example ]; then cp .env.example .env; fi
+set_env .env APP_ENV prod
+set_env .env DB_CONNECTION sqlite
+set_env .env DB_SQLITE_PATH "$deploy_path/database/database.sqlite"
+
+composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader --ignore-platform-reqs
+
+mkdir -p storage/framework/views database
+touch database/database.sqlite
+sudo chgrp -R www-data storage database
+sudo chmod -R g+rwX storage database
+sudo find storage database -type d -exec chmod 2775 {} \;
+sudo chmod 664 database/database.sqlite
+
+php command.php migrate
+
+sudo tee /etc/systemd/system/warehouse-queue.service >/dev/null </dev/null <