Deployment verdict and scope
Band Licence currently supports:
- a teacher-controlled local pilot;
- a private-network host;
- an isolated public QR-profile process behind trusted HTTPS; and
- production-shaped Account Beta and Public Production start commands that deliberately fail closed when protected settings are incomplete.
The existence of the production workflow and public hostname does not mean public registration, native store release or subscription service is approved. Those stages require separate governance evidence.
This checklist covers the one supported shared SQLite shape: exactly one full teacher process plus, optionally, one separately isolated QR-only process on the same host and the same local-disk database. SQLite still permits only one write transaction at a time; the app enables WAL and a 10-second per-connection busy timeout, and begins top-level write transactions in immediate mode so the two approved processes can serialise short write contention. A busy timeout by itself cannot repair a deferred read-then-write transaction after its WAL snapshot becomes stale. Do not add replicas, start a second process of either role, put the database on a network/NAS/cloud-synchronised filesystem, or point the two roles at different database copies.
Roles and release authority
Name these roles before a shared deployment:
| Role | Responsibility |
|---|---|
| Release owner | Candidate identity, go/no-go, maintenance window and rollback |
| Application operator | Host configuration, runtime, reverse proxy and smoke tests |
| Database custodian | Backup, migration, restore rehearsal and recovery key |
| Security/privacy owner | Access, logging, incident and declaration review |
| School owner | Approved school/data scope and operational timing |
| Support owner | User notice, known issues and correction requests |
One person may hold more than one role during the pilot, but the record must show which decision they made. Public production should avoid a single-person account, signing or recovery dependency.
Environment separation
Maintain separate development, staging/account-beta and production:
- database path;
- backup directory;
- encryption and abuse-protection secrets;
- hostname and certificate;
- email/recovery provider configuration;
- mobile app identity and association records;
- reviewer/test accounts; and
- monitoring/alert destinations.
Never copy a production database into development. Use fictional demonstration data for store, support and training environments.
Protected shared-host configuration
The shared-host preflight enforces:
| Setting | Required production property |
|---|---|
| BAND_LICENCE_DEPLOYMENT_MODE | account-beta or public-production |
| BAND_LICENCE_APP_URL | Exact root HTTPS origin; not localhost, credentials, path, query or placeholder |
| BAND_LICENCE_TRUSTED_HTTPS | true only after trust from a separate normal browser |
| BAND_LICENCE_SECURE_COOKIES | true |
| BAND_LICENCE_AUTO_MIGRATE | false |
| BAND_LICENCE_INSTANCE_COUNT | 1; this is the single teacher-process count |
| BAND_LICENCE_PUBLIC_PROFILE_INSTANCE_COUNT | 0 or 1; never more than one QR-only process |
| BAND_LICENCE_SQLITE_CONCURRENCY_MODE | single-host-wal; an explicit declaration that both roles share one local-disk database |
| BAND_LICENCE_SQLITE_CONCURRENCY_EVIDENCE | Release-specific reference to the retained two-process rehearsal result |
| BAND_LICENCE_SQLITE_LOAD_EVIDENCE | Release-specific reference to reviewed production-shaped teacher-plus-QR load evidence |
| SQLITE_PATH | Explicit absolute live-database path |
| BACKUP_DIR | Explicit absolute path separate from the live database |
| BAND_LICENCE_RATE_LIMIT_SECRET | Unique non-placeholder secret, at least 32 characters |
| BAND_LICENCE_BACKUP_ENCRYPTION_KEY | Different protected secret, at least 32 characters |
| BAND_LICENCE_MONITOR_URL | Browser-trusted HTTPS origin |
| BAND_LICENCE_MONITORING_EVIDENCE | Release-specific reference to an exercised monitor/alert record |
| BAND_LICENCE_EMAIL_RECOVERY_READY | true only after delivery and recovery tests |
| BAND_LICENCE_PUBLIC_RELEASE_APPROVED | Required only for public-production after governance approval |
The start command also refuses to run when the production build, database file or backup directory is missing.
Run:
deploy\windows\Check Shared Host Readiness.cmdDo not echo protected environment values into CI logs or screenshots.
Architecture checks
Teacher service
- bind the Node process to loopback;
- put trusted HTTPS and access logging at the reverse proxy;
- expose ports 80/443 at the gateway, not port 3003;
- protect the SQLite and backup paths from web serving;
- run exactly one teacher process and use the same absolute local-disk SQLITE_PATH as the optional QR-only process;
- use secure cookies;
- keep the selected deployment mode accurate; and
- expose only the documented health information.
Public QR profiles
- run a separate process on port 3013 with BAND_LICENCE_PUBLIC_PROFILE_ONLY=true through pnpm start:public-profiles;
- run at most one such process, on the same host and SQLITE_PATH as the teacher process, and set BAND_LICENCE_PUBLIC_PROFILE_INSTANCE_COUNT=1 only when it is deliberately supervised;
- route only the approved profile hostname/path to that process;
- confirm /sign-in and every teacher/Administrator route return 404;
- keep the teacher service private where practicable;
- rate-limit public profile lookups;
- return only the token-bound QR profile boundary: progress and attendance are read-only, with only the documented unlocked-session practice-timer/tracking, sight-reading-result and friend-choice writes; and
- test revocation/expiry of QR profile sessions.
Reverse proxy
- final DNS points to the intended host;
- certificate issuance and renewal are monitored;
- HTTP redirects to HTTPS;
- forwarding headers are trusted only from the local proxy;
- request/body limits and timeouts are set;
- headers do not reveal unnecessary server detail;
- association endpoints are served without redirects;
- teacher and QR hosts route to the correct ports; and
- the backend ports are not reachable directly from the internet.
Candidate preparation
Record:
- full commit SHA and clean source status;
- Node 24.19.0 and pnpm 11.21.0, matching the current CI workflow;
- lockfile checksum;
- database schema version;
- build ID and portable archive SHA-256;
- change list, data impact and rollback classification;
- owner and maintenance window; and
- known issues and support notice.
Classify the change:
| Class | Examples | Release requirement |
|---|---|---|
| A — UI/read-only | Copy, styles, reports | Standard checks and smoke tests |
| B — server behaviour | Authentication, access, API, attendance mutation | Access/security tests and monitored window |
| C — schema/data | Table/column migration, repair | Rehearsal, protected backup, restore plan and compatibility review |
| D — infrastructure | Host, proxy, certificate, runtime, secrets | Staging rehearsal and independent connectivity test |
| E — privacy/mobile/billing | Permission, SDK, store, payment, public account | Governance/declaration approval before rollout |
Automated preflight
For every candidate:
pnpm install --frozen-lockfile
pnpm lint
pnpm typecheck
pnpm test
pnpm build
pnpm release:check
deploy\windows\Check Deployment Readiness.cmd
pnpm access:review
pnpm db:concurrency:rehearse
deploy\windows\Install Update.cmd
deploy\windows\Rehearse Database Restore.cmdThe pnpm build wrapper uses a disposable, pre-initialised database and turns automatic migration off before Next.js starts parallel workers. It ignores the ordinary application SQLITE_PATH; do not invoke next build directly. The Windows updater is the only documented exception: it explicitly selects and verifies its restored candidate copy under the operating-system temporary directory, never the live database.
For account beta also run:
deploy\windows\Check Account Beta Readiness.cmd
pnpm governance:check
deploy\windows\Check Shared Host Readiness.cmd
pnpm monitor:checkFor native/store-impacting changes also run:
pnpm native:foundation-check
pnpm mobile:check
pnpm store:documents-checkPublic/native release additionally requires the blocking evidence checks in Store Release Evidence and the policy and submission work in App Store and Play Store Readiness.
Current GitHub deployment path
The manually dispatched workflow at .github/workflows/deploy-band-licence-production.yml currently:
- checks out the exact commit on a Windows GitHub runner;
- installs the pinned Node and pnpm versions;
- installs from the lockfile;
- builds and runs the full automated test suite;
- constructs a portable tracked-source/runtime package without local databases, backups, secrets, logs or environment files;
- creates and records an archive SHA-256;
- sends the artifact to the self-hosted production runner;
- verifies the downloaded hash against preflight;
- queues a request for the separately installed privileged Windows deployment worker; and
- waits for success, failed-with-automatic-runtime-rollback or failed-safe maintenance status.
Important limitations:
- the workflow is manual, not an approval by itself;
- the privileged worker is installed host state and must be versioned, reviewed, backed up and tested separately;
- a successful artifact build does not verify external DNS, certificate, school approval or user workflows;
- the one-day artifact retention is not a long-term rollback archive; and
- database recovery remains separate from code-runtime rollback.
Retain the worker version, deployment log, status JSON, candidate checksum, previous runtime reference and health results in the release evidence.
Manual Windows update path
deploy/windows/Install-BandLicenceUpdate.ps1:
- verifies the archive and per-file checksums where available;
- verifies the package contains no database;
- checks disk space;
- creates and verifies a safety backup;
- stops Band Licence scheduled tasks;
- preserves data, backups, local files, releases, dependencies, build output and environment files while updating code;
- reinstalls from the lockfile;
- rebuilds and runs tests;
- restarts tasks; and
- checks teacher health plus public-profile route isolation.
This manual path does not promise automatic code rollback. On failure it preserves the database/backups and instructs the operator to restore the previous code package. Keep that package before starting.
Database migration sequence
For a schema-changing release:
- Announce and begin the maintenance window.
- Prevent new writes and stop the application processes.
- Record current runtime, schema and database file paths.
- Create an encrypted backup:
deploy\windows\Backup Database.cmd- Verify the newest backup:
deploy\windows\Verify Backup.cmd- Rehearse the migration against a temporary copy:
deploy\windows\Install Update.cmd- Confirm protected record counts, SQLite integrity and foreign keys pass.
- Confirm the new code’s rollback compatibility. If the schema is not backward-compatible, code-only rollback is unsafe.
- Apply deliberately:
deploy\windows\Install Update.cmd- Run deployment and database checks, including the two-process concurrency rehearsal, and retain their output.
- Start exactly one teacher process and confirm the live database reports WAL mode.
- If public QR access is enabled, start at most one QR-only process on the same host and exact same SQLITE_PATH.
- Exercise simultaneous short teacher and QR writes with fictional data, confirm neither request fails with SQLITE_BUSY, and retain the result.
- Perform smoke tests and preserve the pre-migration backup.
The migration command creates a timestamped pre-migration safety backup and then checks integrity, foreign keys and schema status. That does not replace the separate verified backup and restore rehearsal.
Deployment sequence
The canonical liveness, readiness and functional probes, along with the explicit emergency repair procedure, are documented in `PRODUCTION_HEALTH_AND_GUARDED_RECOVERY.md`. Routine releases use normal deployment. Guarded recovery is manual-only and does not relax backup, artifact, data-preservation, post-check or rollback requirements.
Before change
- candidate identity recorded;
- approvals complete for the change class;
- maintenance and support notice ready;
- current service/ports/health recorded;
- free space checked;
- newest protected backup verified;
- restore rehearsal current;
- previous compatible runtime retained;
- rollback trigger and owner named; and
- no live event depends on the app during the window.
During change
- block or drain writes;
- stop teacher and QR processes before migration;
- preserve diagnostic logs without copying secrets;
- verify artifact checksum;
- migrate once, deliberately;
- start the teacher process;
- start the QR process;
- reload/restart the HTTPS gateway only when needed; and
- do not open access until all smoke checks pass.
Smoke tests
- /api/health returns expected non-sensitive status;
- /sign-in loads through public HTTPS;
- secure account sign-in and sign-out work;
- correct accessible schools appear;
- direct cross-school access is refused;
- Dashboard, Students, Scheduling, Check-in, Attendance and Daily Review load;
- one fictional write/read/undo workflow succeeds in an approved test school;
- public QR profile opens through its public host;
- public QR host refuses /sign-in and teacher routes;
- backup status and schema version are correct;
- monitor check succeeds from an independent network; and
- no new critical error or failed-sign-in surge appears.
After change
- release time, operator, commit, build and schema recorded;
- smoke results attached;
- backup and restore references attached;
- monitoring observation window completed;
- user notice/support updated;
- previous runtime retained through the rollback window; and
- post-deployment review scheduled for high-risk changes.
Monitoring and auto-recovery
The repository currently includes a scheduled recovery workflow every five minutes and manual dispatch. It checks/restarts the teacher process, public QR process and HTTPS gateway on the self-hosted Windows environment and verifies route isolation.
Treat that as one recovery layer, not complete availability:
- GitHub Actions and the self-hosted runner can both be unavailable;
- repeated restart can hide a persistent application/database fault;
- a listening port is not proof that school workflows work;
- external DNS/certificate/network failure needs independent monitoring;
- a recovery action needs an alert and incident record; and
- restart must never create a second teacher process or a second QR-only process;
Define and record:
- uptime and route checks;
- database integrity and backup freshness;
- certificate-expiry warning;
- failed sign-in/rate-limit/security-event thresholds;
- disk space, host sleep/reboot and service state;
- alert destination and acknowledgement time;
- restart limit before escalation;
- recovery point objective and recovery time objective; and
- who can perform database restore.
Rollback decision matrix
| Failure | First safe action | Rollback |
|---|---|---|
| New runtime will not start before migration | Keep old runtime/data | Restore previous runtime |
| New runtime fails after backward-compatible migration | Stop new runtime | Restore previous runtime; keep database if compatible |
| Migration fails before verification | Keep app stopped; preserve failed DB | Restore pre-migration verified backup after diagnosis |
| Data writes occurred on new schema | Stop writes; assess data delta | Do not blindly restore; choose forward fix or approved point-in-time recovery |
| Public QR isolation fails | Remove public route/stop QR process | Restore previous proxy/runtime |
| Sign-in/access boundary fails | Disable broader access and native links | Restore previous runtime and revoke affected sessions |
| Certificate/DNS failure | Keep backend private | Restore proxy/DNS configuration; do not expose port 3003 |
| Privacy/child-safety incident | Stop affected feature/access | Follow incident plan; preserve evidence and notify owners |
Database restore is destructive to changes made after the selected backup. It is a last-resort, approved recovery—not the default response to a UI bug.
For a real restore:
- stop every writer;
- preserve a copy of the failed/current database;
- identify and verify the exact encrypted backup/key;
- use the guarded restore process;
- migrate the restored copy to the installed compatible code;
- check integrity, foreign keys and protected counts;
- run smoke tests before reopening; and
- record lost/re-entered transactions and affected users.
Local and private-network pilot
For the teacher-controlled pilot:
- run on a controlled computer;
- prevent sleep during lessons/rehearsals;
- use the hardware scanner where practical;
- back up and verify after live school use;
- keep a paper/manual attendance fallback; and
- do not describe self-signed local HTTPS as public production trust.
Private-network start:
pnpm start:private-networkThat ordinary command is audio-free. On an approved host where the local engine and every Lesson Notes governance gate have been checked, use the explicit opt-in instead:
pnpm lesson-notes:engine:check
pnpm start:private-network:lesson-notesUse local HTTPS only when secure-context browser features require it:
pnpm start:private-network:httpsDo not port-forward the full teacher app to the public internet.
Account Beta gate
Before inviting another teacher:
- trusted HTTPS and secure cookies;
- verified email delivery and password reset;
- formal role/access review;
- protected automatic backups and tested restore;
- monitored same-host SQLite service with one teacher process, at most one QR-only process, WAL, busy timeout, retained concurrency rehearsal and real production-shaped load evidence;
- support, correction, retention and deletion process;
- school approval and child-safety review;
- incident-response rehearsal;
- invite-only school-scoped accounts; and
- named operating and support owners.
Start only after preflight:
pnpm start:account-betaPublic Production gate
Do not set BAND_LICENCE_PUBLIC_RELEASE_APPROVED=true until:
- privacy policy and terms are final and published;
- public account deletion and correction work end to end;
- school/data-processing and child-safety approval are complete;
- retention, backup, monitoring and incident evidence is approved;
- role and school-boundary review has passed;
- subscription entitlements are tested before any payment provider;
- public registration, the future Student role (product label Player Account), Parent/Carer accounts and native access are separately approved; and
- the full governance gate contains real evidence.
The command intentionally fails closed:
pnpm start:public-productionDecision records
PDC-001 — Bounded same-host SQLite writers
Use exactly one teacher process plus at most one QR-only process on the same host and local-disk database. WAL, immediate write transactions and a 10-second busy timeout serialise their short write transactions; the timeout alone does not repair stale deferred snapshots, and these controls do not make SQLite horizontally scalable. Another process, host, replica or network filesystem requires a database architecture change and migration plan.
PDC-002 — Runtime address
Use server-only BAND_LICENCE_APP_URL. Do not rely on NEXT_PUBLIC_APP_URL, because it may be frozen into the build.
PDC-003 — Deliberate migrations
Disable automatic migration on shared hosts. Rehearse a temporary copy, verify a protected backup and apply with the application stopped.
PDC-004 — Separate public QR process
Expose narrow profile routes through port 3013; keep teacher/admin routes on the private teacher process.
PDC-005 — Runtime rollback is not database rollback
Retain previous code and protected backups separately. Choose rollback based on schema compatibility and writes since migration.
Evidence to retain
- release and change approvals;
- exact artifact and source hashes;
- CI/preflight output;
- retained
pnpm db:concurrency:rehearseoutput, production-shaped teacher-plus-QR load results and the exercised monitor/alert record; - protected environment review without secret values;
- backup, verification, restore rehearsal and migration status;
- deployed schema/build identity;
- proxy/DNS/certificate and route-isolation results;
- smoke and independent monitor results;
- automatic recovery/restart events;
- support and user notices;
- rollback or incident decisions; and
- post-release observation.
Related guides
- Database Migrations
- Protected Backups
- Self-hosted QR Profiles
- Access Review Checklist
- Governance Deployment Gate
- Incident Response Plan
Security references
- OWASP Application Security Verification Standard
- OWASP Mobile Application Security Verification Standard
- IETF RFC 9700: OAuth 2.0 Security Best Current Practice
References and platform requirements were checked 12 August 2026. Recheck before material infrastructure or store changes.