# V11 Enterprise QMS Full-stack quality management system — Next.js 15 (pages router) + Prisma + **SQLite**, packaged as a **single Docker container** for self-hosting on Unraid. Starts from zero data and learns as your team uses it. > **Status — partial build.** The implemented modules are: authentication, the first-build > **Form builder** (admin), **Fill / Report an issue** (production), **Nonconformances + Resolutions > library** (QC), **Client release / Shipments**, **Client issues / Quality escapes**, and the > **living Shipping standard**. The remaining nav items (Admin dashboard, Users, Audit trail, > Settings, QC dashboard, CAPA, Audits, Documents, Risk, Suppliers, Standards, My submissions, > Management dashboard & Reports) are wired into navigation but render a "Coming soon" placeholder — > the data model for them already exists in `prisma/schema.prisma`. ## Roles & access | Role | Access | |------|--------| | **Admin** | Everything: form builder, users, settings, audit trail | | **QC** | CAPA, audits, NCRs, resolutions, documents, risk, suppliers, standards, shipping standard | | **Production** | Fill first-build forms, report issues | | **Production lead** | Production + client release, client issues, shipping standard, NCRs | | **Logistics lead** | Client release, client issues, shipping standard, NCRs | | **Management** | Read-only dashboards and reports | Only **Admin / Production lead / Logistics lead** can email a client release package. --- ## Deploy on Unraid (the intended setup) CI/CD: push to Gitea → Gitea Actions builds the image → pushes to `registry.alwisp.com/jason/qms:latest` → install/Force-update from the Unraid Docker GUI. ### 1. Build & push (automatic) `.gitea/workflows/docker-build.yml` builds and pushes the image to `registry.alwisp.com//:latest` on every push to `main`. It needs two repo secrets: `REGISTRY_USER` and `REGISTRY_TOKEN`. ### 2. Run on Unraid Either `docker compose up -d` with the bundled [`docker-compose.yml`](docker-compose.yml), or add a container in the Unraid Docker GUI with the equivalent settings: | Setting | Value | |---|---| | Repository | `registry.alwisp.com/jason/qms:latest` | | Network | **Custom: br0** — assign a free IP in `10.2.0.0/24` | | Volume | `/mnt/user/appdata/qms` → `/data` | | `DATABASE_URL` | `file:/data/qms.db` | | `NEXT_PUBLIC_APP_URL` | `http://:3000` | | `ADMIN_EMAIL` / `ADMIN_PASSWORD` / `ADMIN_NAME` | first-run admin (created only if no admin exists) | | `SMTP_*` (optional) | enables outbound email; omit to keep notifications in-app only | On first start the container runs `prisma db push` (creates `/data/qms.db`), then `create-admin` (creates the admin from `ADMIN_*` only if none exists), then serves on port `3000`. The SQLite file lives entirely in the mapped volume, so the container is disposable — update by pulling a new image. The app is reached at `http://:3000`. Sign in with the admin credentials and change the password. --- ## Local development ```bash npm install cp .env.example .env # DATABASE_URL defaults to file:./dev.db npm run db:push # create the SQLite schema npm run create-admin # seed the first admin from ADMIN_* in .env npm run dev # http://localhost:3000 ``` Useful scripts: `npm run build`, `npm run start`, `npm run db:studio`. --- ## Why SQLite (not Postgres) This deploy targets a single self-contained container, so the schema was converted from PostgreSQL to SQLite. SQLite (via Prisma) supports neither native enums nor `Json`/scalar-list columns, so: - former enums are stored as `String` and validated in app code (union types in [`types/index.ts`](types/index.ts)); - former `Json` columns (`AuditLog.before/after`, `FormSubmission.data`, `QualityStandard.specs`) and the `FormField.options` list are stored as **JSON-encoded strings**, (de)serialised at the DB boundary (see [`lib/forms.ts`](lib/forms.ts)). ## Project structure ``` /pages /api ← backend API routes (auth, forms, submissions, ncrs, escapes, shipments, …) /admin /qc /fill /management ← role-scoped pages /components ← layout shell, shared UI kit, form field renderer /lib ← prisma client, auth/session, email, form (de)serialisation helpers /prisma ← schema.prisma (SQLite) /scripts ← create-admin.js (first-run bootstrap) Dockerfile · docker-compose.yml · docker-entrypoint.sh · .gitea/workflows/build.yml ``` > `init-source/` holds the original delivery (base snapshot + fix/update overlays) for provenance; > it is excluded from the build and the image.