cleanup
This commit is contained in:
@@ -4,9 +4,13 @@ A single-container, self-hosted Manufacturing Resource Planning (MRP) app built
|
||||
|
||||
## Status
|
||||
|
||||
**Step 1 of the build plan** is in this commit: repo scaffold, Prisma schema, Docker build, and authentication (admin email + password; operator name + 4-digit PIN with 12h device session). Everything downstream — project / assembly / part CRUD, QR generation, operator scan flow, PDF travelers, fasteners & POs, dashboards, STEP viewer, QC — is planned but not yet implemented.
|
||||
Steps 1 – 3 of the build plan are in this repo:
|
||||
|
||||
See [`docs/BUILD-PLAN.md`](docs/BUILD-PLAN.md) for the sequenced roadmap.
|
||||
- **1.** Scaffold + auth (admin email/password, operator name/4-digit PIN with 12 h device session, PIN lockout, audited sessions).
|
||||
- **2.** Admin CRUD (users, machines, operation templates, projects / assemblies / parts) with content-addressed STEP / PDF / DXF / SVG file uploads.
|
||||
- **3.** Operation authoring with per-operation QR tokens (192-bit, base64url).
|
||||
|
||||
Planned (not yet shipped): operator scan flow → PDF traveler print → fasteners & POs → dashboard → STEP viewer → QC records → OpenAPI docs + backups. See [`docs/BUILD-PLAN.md`](docs/BUILD-PLAN.md).
|
||||
|
||||
## Core concepts
|
||||
|
||||
@@ -25,30 +29,61 @@ See [`docs/BUILD-PLAN.md`](docs/BUILD-PLAN.md) for the sequenced roadmap.
|
||||
- bcryptjs for password / PIN hashing
|
||||
- Zod for input validation and environment parsing
|
||||
|
||||
## Deployment
|
||||
|
||||
The primary deployment target is **Unraid**, using an image built by a **Gitea Actions** runner on every push to `main` and pulled from the private registry at **`registry.alwisp.com`** into Unraid's Docker GUI.
|
||||
|
||||
```
|
||||
push to main ─► Gitea Actions (docker-build.yml) ─► registry.alwisp.com
|
||||
(docker build + push) <owner>/<repo>:latest
|
||||
│
|
||||
▼
|
||||
Unraid Docker tab ─► pull / force-update
|
||||
```
|
||||
|
||||
Two deploy paths are supported; pick one:
|
||||
|
||||
- **`docker pull`** — Unraid pulls a prebuilt image the Gitea runner already tagged. Fastest, this is what the runner is for.
|
||||
- **`docker build`** — Unraid clones this repo and builds the image locally, no registry required.
|
||||
|
||||
See [`docs/DEPLOY.md`](docs/DEPLOY.md) for the full, click-by-click Unraid GUI walkthrough (template fields, volume mapping, env vars, update flow, backups).
|
||||
|
||||
### TL;DR Unraid install
|
||||
|
||||
1. **Docker tab → Add Container**.
|
||||
2. **Repository**: `registry.alwisp.com/<owner>/<repo>:latest` (the owner/repo path matches `${{ gitea.repository }}` from the workflow).
|
||||
3. **Network Type**: Bridge. **Port**: host `3000` → container `3000`.
|
||||
4. **Path**: host `/mnt/user/appdata/mrp-qrcode` → container `/data`.
|
||||
5. **Variables** (required):
|
||||
- `APP_URL` = the public HTTPS URL your reverse proxy serves (`https://mrp.yourdomain.tld`)
|
||||
- `APP_SECRET` = a ≥32-char secret (`openssl rand -base64 48`)
|
||||
- `BOOTSTRAP_ADMIN_EMAIL`, `BOOTSTRAP_ADMIN_PASSWORD`, `BOOTSTRAP_ADMIN_NAME`
|
||||
6. Apply. The container runs migrations, creates the bootstrap admin on first boot, and comes up on `:3000`.
|
||||
|
||||
## Local development
|
||||
|
||||
Prerequisites: Node 20+, npm.
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# edit .env and set APP_SECRET to at least 32 random chars
|
||||
# edit .env: set APP_SECRET to >=32 random chars
|
||||
npm install
|
||||
npx prisma migrate dev --name init
|
||||
npx prisma migrate deploy
|
||||
npm run db:seed # creates the bootstrap admin from .env
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Visit http://localhost:3000 and sign in as the bootstrap admin.
|
||||
Visit <http://localhost:3000> and sign in as the bootstrap admin.
|
||||
|
||||
## Docker / Unraid deployment
|
||||
## CI: Gitea Actions
|
||||
|
||||
See [`docs/DEPLOY.md`](docs/DEPLOY.md). In short:
|
||||
Image builds are driven by `.gitea/workflows/docker-build.yml`. On every push to `main` the runner:
|
||||
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
1. Logs into `registry.alwisp.com` with the `REGISTRY_USER` / `REGISTRY_TOKEN` repo secrets.
|
||||
2. Runs `docker build -t registry.alwisp.com/${{ gitea.repository }}:latest .`
|
||||
3. Pushes the `:latest` tag.
|
||||
|
||||
The container runs `prisma migrate deploy` on every start and creates a bootstrap admin on first boot if none exists. All persistent state lives in the `/data` volume (`app.db` + `uploads/` + `backups/`).
|
||||
Point Unraid at `registry.alwisp.com/<owner>/<repo>:latest` and use **Check for Updates / Force Update** (or the *CA Auto Update Applications* plugin) to roll new builds.
|
||||
|
||||
## Environment
|
||||
|
||||
@@ -57,15 +92,16 @@ All env vars are documented in [`.env.example`](.env.example). `APP_SECRET` must
|
||||
## Project layout
|
||||
|
||||
```
|
||||
app/ Next.js routes (UI + /api/*)
|
||||
app/ Next.js routes (UI + /api/v1/*)
|
||||
components/ Shared React components
|
||||
lib/ env, prisma, auth, session, password, audit, request helpers
|
||||
lib/ env, prisma, auth, session, password, qr, audit, request helpers
|
||||
prisma/ schema.prisma + migrations/
|
||||
scripts/ seed.ts and future ops scripts
|
||||
docker/ entrypoint.sh
|
||||
docs/ Project docs (DEPLOY, BUILD-PLAN, ARCHITECTURE)
|
||||
.gitea/workflows/ Gitea Actions (docker-build.yml → registry.alwisp.com)
|
||||
```
|
||||
|
||||
## Not in this repo
|
||||
|
||||
The top-level `AGENTS.md`, `SKILLS.md`, `hubs/`, and `skills/` directories are the coding-agent instruction suite this project was started from. They are reference material for AI assistants and are not shipped in the Docker image (they are listed in `.dockerignore`).
|
||||
The top-level `AGENTS.md`, `SKILLS.md`, `hubs/`, and `skills/` directories are the coding-agent instruction suite this project was started from. They are reference material for AI assistants, are listed in `.dockerignore`, and are not shipped in the Docker image.
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env sh
|
||||
# Pull latest source from Gitea, rebuild the local image, and restart the
|
||||
# container. Intended for the "Unraid builds locally" deploy path documented
|
||||
# in docs/DEPLOY.md §5. Run it on the Unraid host, not inside the container.
|
||||
#
|
||||
# Usage:
|
||||
# SRC_DIR=/mnt/user/appdata/mrp-qrcode-src \
|
||||
# IMAGE=mrp-qrcode:local \
|
||||
# CONTAINER=mrp-qrcode \
|
||||
# docker/rebuild.sh
|
||||
#
|
||||
# Wire it up as a User Scripts plugin cron job to get poor-man's CI.
|
||||
|
||||
set -eu
|
||||
|
||||
SRC_DIR="${SRC_DIR:-/mnt/user/appdata/mrp-qrcode-src}"
|
||||
IMAGE="${IMAGE:-mrp-qrcode:local}"
|
||||
CONTAINER="${CONTAINER:-mrp-qrcode}"
|
||||
BRANCH="${BRANCH:-main}"
|
||||
|
||||
cd "$SRC_DIR"
|
||||
|
||||
echo "[rebuild] fetching $BRANCH"
|
||||
git fetch --prune origin "$BRANCH"
|
||||
git checkout "$BRANCH"
|
||||
git reset --hard "origin/$BRANCH"
|
||||
|
||||
echo "[rebuild] building $IMAGE"
|
||||
docker build -t "$IMAGE" .
|
||||
|
||||
echo "[rebuild] restarting $CONTAINER"
|
||||
if docker inspect "$CONTAINER" >/dev/null 2>&1; then
|
||||
docker restart "$CONTAINER"
|
||||
else
|
||||
echo "[rebuild] container $CONTAINER not found — create it from the Unraid GUI first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[rebuild] done"
|
||||
+228
-64
@@ -1,98 +1,262 @@
|
||||
# Deploying on Unraid
|
||||
|
||||
The MRP app is a single Docker container that stores everything (SQLite database + uploaded files + backups) under a single `/data` volume.
|
||||
The MRP app is a single Docker container that stores everything (SQLite database + uploaded files + backups) under a single `/data` volume. This guide walks through installing it on an Unraid server using the **Docker GUI**, with images coming from a **Gitea Actions** runner that rebuilds on every push and publishes to `registry.alwisp.com`.
|
||||
|
||||
## 1. Prepare environment
|
||||
You can skip the registry and have Unraid build locally — both paths are documented below.
|
||||
|
||||
Pick a host directory on your Unraid array (example: `/mnt/user/appdata/mrp-qrcode/`). This will hold the database and uploaded files, and will survive container upgrades.
|
||||
---
|
||||
|
||||
Generate a strong app secret:
|
||||
## Architecture at a glance
|
||||
|
||||
```bash
|
||||
node -e "console.log(require('crypto').randomBytes(48).toString('base64url'))"
|
||||
```
|
||||
git push main ─► Gitea Actions (.gitea/workflows/docker-build.yml)
|
||||
│
|
||||
├── docker login registry.alwisp.com
|
||||
├── docker build -f Dockerfile .
|
||||
└── docker push registry.alwisp.com/<owner>/<repo>:latest
|
||||
│
|
||||
▼
|
||||
Unraid Docker tab ──► pull image
|
||||
│
|
||||
▼
|
||||
Container: /data volume, :3000, reverse-proxied
|
||||
```
|
||||
|
||||
## 2. docker-compose (recommended)
|
||||
---
|
||||
|
||||
Create `.env` next to `docker-compose.yml`:
|
||||
## 1. Prerequisites
|
||||
|
||||
```env
|
||||
APP_URL=https://mrp.yourdomain.tld
|
||||
APP_SECRET=<paste-the-secret-from-step-1>
|
||||
BOOTSTRAP_ADMIN_EMAIL=you@yourdomain.tld
|
||||
BOOTSTRAP_ADMIN_PASSWORD=<a-strong-password>
|
||||
BOOTSTRAP_ADMIN_NAME=Your Name
|
||||
```
|
||||
- **Unraid** 6.11+ with the Docker service enabled.
|
||||
- A **subdomain** (e.g. `mrp.yourdomain.tld`) pointed at Unraid through your existing reverse proxy (SWAG, Nginx Proxy Manager, Caddy, Traefik, Zoraxy — whichever you already use). The subdomain is what operators will scan into from their phones.
|
||||
- A Gitea server hosting this repo with:
|
||||
- Actions enabled, runner online
|
||||
- Two repo secrets: `REGISTRY_USER` and `REGISTRY_TOKEN` with push rights to `registry.alwisp.com`
|
||||
- The workflow at `.gitea/workflows/docker-build.yml` (already committed)
|
||||
|
||||
Then:
|
||||
If you don't have the CI path, skip to [§5: Unraid builds locally](#5-alternative-unraid-builds-locally).
|
||||
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
---
|
||||
|
||||
The container will:
|
||||
## 2. Prepare the data directory on Unraid
|
||||
|
||||
1. Create `/data/uploads` and `/data/backups` inside the volume.
|
||||
2. Run `prisma migrate deploy`.
|
||||
3. Create the bootstrap admin if no admin exists.
|
||||
4. Start the web server on port 3000.
|
||||
|
||||
## 3. Bind the `/data` volume to host storage (Unraid)
|
||||
|
||||
If you prefer a host bind mount over the named volume, replace the `volumes:` block in `docker-compose.yml` with:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- /mnt/user/appdata/mrp-qrcode:/data
|
||||
```
|
||||
|
||||
Make sure the host directory is owned by UID 1001 (the `nextjs` user inside the container):
|
||||
Create the appdata folder. Unraid conventionally uses `/mnt/user/appdata/<app>`:
|
||||
|
||||
```bash
|
||||
mkdir -p /mnt/user/appdata/mrp-qrcode
|
||||
chown -R 1001:1001 /mnt/user/appdata/mrp-qrcode
|
||||
```
|
||||
|
||||
## 4. Reverse proxy / subdomain
|
||||
UID 1001 is the `nextjs` user inside the container (`Dockerfile` creates it). Getting this wrong is the #1 cause of "can't write to /data" errors at first boot.
|
||||
|
||||
Point your reverse proxy (SWAG, Nginx Proxy Manager, Caddy, Traefik — whatever is already on your Unraid) at `http://<container-ip>:3000` and terminate TLS there.
|
||||
|
||||
`APP_URL` must match the externally reachable URL — it is embedded in QR code payloads and used for absolute links. If operators scan a card and land on `http://10.x.x.x:3000`, their phone probably cannot reach that IP; always set `APP_URL` to the public subdomain.
|
||||
|
||||
## 5. Backups
|
||||
|
||||
The container does not yet run automatic backups. Until step 9 of the build plan ships, back up `/data` with your Unraid backup strategy:
|
||||
|
||||
- `/data/app.db` (SQLite file)
|
||||
- `/data/app.db-wal` and `/data/app.db-shm` if present (SQLite WAL sidecars)
|
||||
- `/data/uploads/`
|
||||
|
||||
A safe way to snapshot a live SQLite DB is:
|
||||
Generate a secret you will paste into the `APP_SECRET` env var:
|
||||
|
||||
```bash
|
||||
docker exec mrp-qrcode sqlite3 /data/app.db ".backup '/data/backups/app-$(date +%F).db'"
|
||||
openssl rand -base64 48
|
||||
```
|
||||
|
||||
## 6. Upgrades
|
||||
Keep it somewhere safe. Changing it logs every existing session out.
|
||||
|
||||
---
|
||||
|
||||
## 3. Gitea Actions: auto-build the image
|
||||
|
||||
The workflow at [`.gitea/workflows/docker-build.yml`](../.gitea/workflows/docker-build.yml) triggers on every push to `main`. It runs in `catthehacker/ubuntu:act-latest` and does exactly:
|
||||
|
||||
```yaml
|
||||
- docker/login-action@v3 # registry.alwisp.com, REGISTRY_USER / REGISTRY_TOKEN
|
||||
- docker build -t registry.alwisp.com/${{ gitea.repository }}:latest .
|
||||
- docker push registry.alwisp.com/${{ gitea.repository }}:latest
|
||||
```
|
||||
|
||||
`${{ gitea.repository }}` expands to `<owner>/<repo>`, so the published image path is:
|
||||
|
||||
```
|
||||
registry.alwisp.com/<owner>/<repo>:latest
|
||||
```
|
||||
|
||||
**One-time repo setup**:
|
||||
|
||||
1. Gitea repo → **Settings → Actions → Runners** — confirm your runner is online and labelled `ubuntu-latest`.
|
||||
2. Gitea repo → **Settings → Secrets** — add:
|
||||
- `REGISTRY_USER` — a user that can push to `registry.alwisp.com`
|
||||
- `REGISTRY_TOKEN` — that user's password or personal access token
|
||||
|
||||
**Pull credentials on Unraid** (required if the registry is private):
|
||||
|
||||
```bash
|
||||
git pull
|
||||
# As root on Unraid
|
||||
docker login registry.alwisp.com -u <user> -p <token>
|
||||
```
|
||||
|
||||
Credentials are stored in `/root/.docker/config.json`; Unraid reuses them automatically on pull.
|
||||
|
||||
---
|
||||
|
||||
## 4. Install on Unraid (Docker GUI, `docker pull` path)
|
||||
|
||||
1. Open the Unraid web UI → **Docker** tab → **Add Container**.
|
||||
2. Fill the template. Bold fields matter; the rest can stay default:
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| **Name** | `mrp-qrcode` |
|
||||
| **Repository** | `registry.alwisp.com/<owner>/<repo>:latest` |
|
||||
| **Network Type** | `Bridge` |
|
||||
| **Console shell command** | `sh` |
|
||||
| **Privileged** | Off |
|
||||
| **Icon URL** (optional) | point at any PNG you host; public/icon.png in the repo is a reasonable pick |
|
||||
|
||||
3. **Port mapping** — *Add another Path, Port, Variable, Label or Device* → *Port*:
|
||||
|
||||
| Name | Container Port | Host Port | Protocol |
|
||||
|---|---|---|---|
|
||||
| Web UI | `3000` | `3000` (or any free port) | TCP |
|
||||
|
||||
4. **Volume mapping** — *Add* → *Path*:
|
||||
|
||||
| Name | Container Path | Host Path | Access |
|
||||
|---|---|---|---|
|
||||
| Data | `/data` | `/mnt/user/appdata/mrp-qrcode` | Read/Write |
|
||||
|
||||
5. **Environment variables** — *Add* → *Variable* for each:
|
||||
|
||||
| Key | Required | Example | Notes |
|
||||
|---|---|---|---|
|
||||
| `APP_URL` | ✅ | `https://mrp.yourdomain.tld` | Public URL; baked into QR payloads. |
|
||||
| `APP_SECRET` | ✅ | *(paste from §2)* | ≥32 chars. Signs sessions + QR tokens. |
|
||||
| `BOOTSTRAP_ADMIN_EMAIL` | ✅ on first boot | `you@yourdomain.tld` | Only used if no admin exists. |
|
||||
| `BOOTSTRAP_ADMIN_PASSWORD` | ✅ on first boot | *(strong password)* | Change in the UI after login. |
|
||||
| `BOOTSTRAP_ADMIN_NAME` | | `Plant Manager` | Display name. |
|
||||
| `ADMIN_SESSION_HOURS` | | `8` | Admin cookie TTL. |
|
||||
| `OPERATOR_SESSION_HOURS` | | `12` | Operator device TTL. |
|
||||
| `PIN_MAX_ATTEMPTS` | | `5` | Lockout threshold. |
|
||||
| `PIN_LOCKOUT_MINUTES` | | `15` | Lockout window. |
|
||||
|
||||
`DATABASE_URL` and `UPLOAD_DIR` are pre-set inside the image (`file:/data/app.db` and `/data/uploads`). Do not override them unless you really mean it.
|
||||
|
||||
6. **Apply**. Unraid pulls the image, starts the container, and the entrypoint:
|
||||
1. Creates `/data/uploads` and `/data/backups` if missing.
|
||||
2. Runs `prisma migrate deploy`.
|
||||
3. Creates the bootstrap admin if no admin exists yet.
|
||||
4. Starts Next.js on `:3000`.
|
||||
|
||||
7. Check the log (click the container icon → **Logs**). You should see `✓ Ready on http://0.0.0.0:3000`.
|
||||
|
||||
8. Point your reverse proxy at `http://<unraid-ip>:3000` with your TLS cert, and browse to `https://mrp.yourdomain.tld/login/admin`.
|
||||
|
||||
### Updates
|
||||
|
||||
Every push to `main` produces a new `:latest` image at `registry.alwisp.com/<owner>/<repo>`.
|
||||
|
||||
- **Manual pull**: Docker tab → container row → **Force update** (Unraid does `docker pull` then recreates the container).
|
||||
- **Automated**: install the *CA Auto Update Applications* plugin from Community Applications and let it pull fresh `:latest` on a schedule.
|
||||
|
||||
The `/data` volume is preserved across recreations. Migrations run automatically on start; if a release adds a new Prisma migration, it will apply once on first boot of the new image.
|
||||
|
||||
### Pinning (optional)
|
||||
|
||||
The current `docker-build.yml` only publishes `:latest`. If you want immutable tags for rollback, extend the workflow to also push `${{ gitea.sha }}` or a release tag, then point the Unraid **Repository** field at the pinned tag (e.g. `registry.alwisp.com/<owner>/<repo>:v0.4.0`). Rollback becomes a one-field change + **Apply**.
|
||||
|
||||
---
|
||||
|
||||
## 5. Alternative: Unraid builds locally (`docker build` path)
|
||||
|
||||
If you don't want a registry at all, Unraid can build from a local clone of the repo.
|
||||
|
||||
1. On Unraid:
|
||||
|
||||
```bash
|
||||
mkdir -p /mnt/user/appdata/mrp-qrcode-src
|
||||
cd /mnt/user/appdata/mrp-qrcode-src
|
||||
git clone https://<your-gitea-host>/<owner>/<repo>.git .
|
||||
docker build -t mrp-qrcode:local .
|
||||
```
|
||||
|
||||
2. In the Docker GUI template (§4), set:
|
||||
- **Repository**: `mrp-qrcode:local`
|
||||
- Everything else identical.
|
||||
|
||||
3. To update: `git pull && docker build -t mrp-qrcode:local . && docker restart mrp-qrcode`.
|
||||
|
||||
A tiny convenience script lives at `docker/rebuild.sh` if you want to cron it.
|
||||
|
||||
---
|
||||
|
||||
## 6. Alternative: `docker compose` on the Unraid CLI
|
||||
|
||||
The repo also ships a `docker-compose.yml` for users who prefer CLI. This path bypasses the Unraid GUI entirely — state goes to a Docker-managed volume instead of `/mnt/user/appdata/…`, unless you override the mount.
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# edit .env with real APP_URL, APP_SECRET, bootstrap admin creds
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
Migrations run automatically on start. Before major upgrades, snapshot the DB as above.
|
||||
To mount `/data` under `/mnt/user/appdata/mrp-qrcode` instead of the named volume, change `docker-compose.yml`:
|
||||
|
||||
## 7. First-login checklist
|
||||
```yaml
|
||||
volumes:
|
||||
- /mnt/user/appdata/mrp-qrcode:/data
|
||||
```
|
||||
|
||||
1. Sign in at `/login/admin` with the bootstrap credentials.
|
||||
2. Change your password (admin settings — shipping in a later step).
|
||||
3. Create your operators (each gets a name and a 4-digit PIN).
|
||||
4. Add your machines.
|
||||
5. Create operation templates for repetitive steps.
|
||||
6. Create your first project.
|
||||
and `chown -R 1001:1001 /mnt/user/appdata/mrp-qrcode` first.
|
||||
|
||||
## Troubleshooting
|
||||
---
|
||||
|
||||
- **`APP_SECRET must be at least 32 chars`** — the container refuses to start without one. Regenerate as shown in step 1.
|
||||
- **`migrations/` is empty** — run `npx prisma migrate dev --name init` locally once, commit the generated `prisma/migrations/` directory, rebuild the image.
|
||||
- **Healthcheck failing** — `docker logs mrp-qrcode` and check DB permissions on `/data`.
|
||||
## 7. Reverse proxy notes
|
||||
|
||||
`APP_URL` must match the externally reachable URL — it is embedded in QR code payloads and used for absolute links on traveler cards. If operators scan a card and land on `http://10.x.x.x:3000`, their phone probably cannot reach that IP; always set `APP_URL` to the public subdomain.
|
||||
|
||||
Minimal Nginx Proxy Manager config:
|
||||
|
||||
- Domain: `mrp.yourdomain.tld`
|
||||
- Scheme: `http`, Forward host: `<unraid-ip>`, Forward port: `3000`
|
||||
- Block Common Exploits: on
|
||||
- Websockets: on (Next.js hot reload uses them in dev; in prod they're unused but harmless)
|
||||
- SSL: request a Let's Encrypt cert; Force SSL + HTTP/2 on.
|
||||
|
||||
---
|
||||
|
||||
## 8. Backups
|
||||
|
||||
The container does not yet run automatic backups (shipping in step 10 of the build plan). Until then, your Unraid backup strategy should cover:
|
||||
|
||||
- `/mnt/user/appdata/mrp-qrcode/app.db` (SQLite file)
|
||||
- `/mnt/user/appdata/mrp-qrcode/app.db-wal` and `app.db-shm` if present
|
||||
- `/mnt/user/appdata/mrp-qrcode/uploads/` (STEP / PDF / DXF / SVG assets)
|
||||
|
||||
A safe live snapshot of SQLite (works while the app is running):
|
||||
|
||||
```bash
|
||||
docker exec mrp-qrcode sqlite3 /data/app.db \
|
||||
".backup '/data/backups/app-$(date +%F).db'"
|
||||
```
|
||||
|
||||
Cron it nightly via **User Scripts** plugin.
|
||||
|
||||
---
|
||||
|
||||
## 9. First-login checklist
|
||||
|
||||
1. Sign in at `https://mrp.yourdomain.tld/login/admin` with the bootstrap email + password you set in step 4.
|
||||
2. **Users** → change your own password; create operators (each gets a name + 4-digit PIN).
|
||||
3. **Machines** → add your shop equipment (NCT punch, press brake, rivet, weld, …).
|
||||
4. **Operation templates** → pre-author your common recipes so they appear in the operation picker later.
|
||||
5. **Projects** → create your first project, add assemblies, add parts, upload STEP / drawing / cut files.
|
||||
6. **Operations** on each part → author steps, reorder, verify QR tokens appear in the table.
|
||||
|
||||
Step 4 of the build plan (the operator scan flow) lands next; until then, the QR tokens are visible and tested but not yet scannable to an operator view.
|
||||
|
||||
---
|
||||
|
||||
## 10. Troubleshooting
|
||||
|
||||
| Symptom | Fix |
|
||||
|---|---|
|
||||
| `APP_SECRET must be at least 32 chars` on start | Regenerate via `openssl rand -base64 48` and paste into the env var. |
|
||||
| `EACCES` / permission errors writing to `/data` | `chown -R 1001:1001 /mnt/user/appdata/mrp-qrcode` on the host. |
|
||||
| Healthcheck failing | `docker logs mrp-qrcode` — usually a missing env var or a broken reverse proxy. |
|
||||
| Unraid won't pull the image | Run `docker login registry.alwisp.com` on the host with the same user/token the runner uses. Confirm the repo name matches `${{ gitea.repository }}` exactly (case-sensitive). |
|
||||
| Migrations didn't run | The entrypoint calls `prisma migrate deploy`. Logs will show which migration failed. Don't manually touch `_prisma_migrations`. |
|
||||
| QR codes link to `localhost` | `APP_URL` was left at default. Update the env var and restart the container. |
|
||||
| Can't log in after redeploy | `APP_SECRET` changed → every session cookie is invalid. Log in again. |
|
||||
|
||||
Reference in New Issue
Block a user