feat: refine ISAC design and prepare production deployment
Validate and deploy production / validate (push) Successful in 18s
Validate and deploy staging / validate (push) Successful in 18s
Validate and deploy production / deploy (push) Successful in 1m1s
Validate and deploy staging / deploy (push) Successful in 28s

This commit is contained in:
JB
2026-07-26 12:25:47 -04:00
parent 75faef50b8
commit 2e868d86ff
153 changed files with 64660 additions and 264 deletions
+76 -6
View File
@@ -1,4 +1,4 @@
# Container and staging deployment
# Container, staging, and production deployment
SHD.build is packaged as a Node 24 container using the official SvelteKit Node
adapter. The image contains application code, migration and notification
@@ -197,8 +197,78 @@ volume containing the embedded database and uploads.
## Production promotion
Production should use a separate compose project, volume, database filename,
runtime environment, port, and deployment workflow. Do not point staging and
production at the same embedded database or storage volume. Once staging is
proven, the same container image can be tagged for production so promotion does
not rebuild application code.
Production uses a separate compose project, volume, database filename, runtime
environment, port, and deployment workflow:
- Public origin: `https://shd.build`
- Reverse-proxy upstream: host port `3102`
- Deployment directory: `/opt/shd-build-production`
- Database: `/app/data/shd-build-production.db`
- Persistent volume: `shd-build-production-data`
Routine pushes never import or replace production data. The production deploy
stops only its application and scheduler, creates a timestamped JSON backup,
applies repeatable migrations, restarts, and verifies database health. Never
run `docker compose down --volumes` against production.
Add these repository Action secrets:
- `DOTENV_PRIVATE_KEY_PRODUCTION`, matching the ignored local `.env.keys`
- `SCHEDULER_TOKEN_PRODUCTION`, a long random value used only by the internal
scheduler endpoint
Optional repository variables are `PRODUCTION_DEPLOY_PATH` (default
`/opt/shd-build-production`) and `PRODUCTION_PORT` (default `3102`). The
`deploy-production.yml` workflow deploys production on pushes to `main` and
manual dispatches using the trusted `stage-deploy` host runner.
Prepare the host directory once from an interactive SSH session:
```sh
sudo install -d -o jb -g jb -m 0750 /opt/shd-build-production
```
Generate the scheduler secret locally without printing it into a shared log,
then enter it directly in Gitea's repository-secret form. Do not commit it or
reuse the staging scheduler token.
### Initial production bootstrap
The one-time production bootstrap clones current development data and uploads.
Stop this project's development server before creating the bundle:
```sh
npm run production:bootstrap:export
```
Copy the resulting ignored JSON bundle to the deployment host over SSH, then:
```sh
/opt/shd-build-production/bootstrap-production.sh \
/secure/path/shd-production-bootstrap-YYYY-MM-DDTHH-MM-SSZ.json
```
The importer verifies the bundle target, creates a production safety backup,
and refuses to replace a production database containing users, builds, audit
events, or proposals. Remove the remote transfer copy after verification.
### Pull production ISAC data into development
Manually run **Export production ISAC data** in Gitea Actions and download its
`shd-production-isac-data` artifact. Stop the local development server, then:
```sh
npm run isac:import -- /path/to/isac-production.json --confirm-replace-isac-data
```
The importer creates a complete local database backup and an ISAC-only snapshot
before replacing canonical game data. It leaves accounts, content, proposals,
notifications, settings, and audit history untouched.
### Pull production ISAC data into staging
Manually run **Replace staging ISAC data from production** in Gitea Actions.
The workflow exports a consistent production snapshot, restarts production,
then stops staging and imports it. The staging importer creates both full and
ISAC-only safety backups before replacement. This is intentionally manual and
never runs as part of either deployment.
+71 -4
View File
@@ -202,6 +202,9 @@ The canonical tokens live in `src/app.css` under `:root`.
| Main text | `--shd-text` | `#ecebe5` |
| Muted text | `--shd-text-muted` | `#858b8d` |
| SHD action orange | `--shd-orange` | `#f6a821` |
| Telemetry text floor | `--shd-type-telemetry` | `12px` |
| Supporting copy floor | `--shd-type-supporting` | `14px` |
| Ordinary body floor | `--shd-type-body` | `16px` |
| Adaptive display scale | `--shd-display-scale` | `1` by default; stepped on high-resolution desktops |
### High-resolution display scaling
@@ -228,11 +231,31 @@ Use the spacing tokens for new components. Prefer `8px`, `12px`, and `20px` gaps
## Typography
- The current UI stack is `Arial, Helvetica, sans-serif`.
SHD.build self-hosts two intentional type voices through Fontsource packages:
- **Barlow** is the operational family for display headings, navigation,
controls, data, labels, metadata, and general interface copy. Use the shared
`--shd-font-sans` token instead of declaring local sans-serif stacks.
- **Source Serif 4** is the editorial family for explanations, introductions,
guide-like prose, and longer descriptive passages. Use
`--shd-font-editorial`; do not apply it to controls, tables, metrics, or
telemetry labels.
Only the used Barlow weights (400, 600, 700, 800, and 900) and Source Serif 4
weights (400 and 600) are loaded. Both families are self-hosted, preserve
fallback stacks, and render immediately without a third-party font request.
The two-voice rule remains semantic: Barlow operates the system; Source Serif 4
explains it.
- Page and module headings are uppercase, heavy, and tightly spaced.
- Eyebrows and table labels use 7–10px text with 1–2px letter spacing.
- Body and form text should normally remain between 9–12px in dashboards.
- Public/editorial copy may use Georgia for a restrained field-manual character.
- Short operational labels, metadata, statuses, and compact actions use the
shared 12px telemetry floor. Their tracking must not exceed `0.1em`.
- Supporting descriptions use at least 14px with normal tracking. Ordinary
body and form copy uses the 16px body floor.
- High-resolution workspace scaling never justifies smaller source sizes:
density comes from spacing, connected borders, tone, and weight.
- Public/editorial copy uses Source Serif 4 for its restrained field-manual
character and stays within a 45–75 character reading measure.
- Never use low-contrast tiny text for information required to complete a task.
## Layout patterns
@@ -390,6 +413,11 @@ squeezed beside long module headings on mobile.
- The administrative system is named ISAC. Separate navigation into explicit
operational domains such as User Operations and Data Management; visibility
must reflect server-provided capabilities.
- ISAC module navigation uses complete, game-facing names such as `Weapons`,
`Talents`, and `OS Protocols`. Do not expose internal abbreviations such as
`WPN`, `TLNT`, or `OSPR`. Canonical game icons may supplement visible labels
inside module content and editor controls, but the navigation rail must not
invent iconography merely to replace clear language.
- User Operations shows every supported authentication method as operational
metadata: local credentials, verified email, passkeys, Discord, and planned
providers. Identity-removal controls require `users.identities`, create audit
@@ -1472,3 +1500,42 @@ selection changes, and background refreshes. Toasts automatically dismiss
according to severity, remain keyboard dismissible, use `status` or `alert`
semantics, and disable entrance motion with reduced motion. On mobile they span
the safe viewport width below the header without obscuring navigation.
### ISAC progressive disclosure
The ISAC rail shows every module the current operator is authorized to access,
but groups modules behind collapsible operational categories. The category
containing the current route opens on first use; subsequent open and closed
choices are remembered locally for that browser. Searching the rail temporarily
reveals matching modules across all authorized categories without changing the
remembered category state.
Use the compact command-status strip for persistent system, access, environment,
and data-mode context. These values remain textual and must not rely on color
alone. Registry search remains available for a single page of results, while
page navigation and row-count controls appear only when the result set spans
multiple pages. This keeps expert lookup fast without presenting inactive
controls to contributors and first-time Oversight operators.
Sidebar category headers are real buttons with `aria-expanded` and controlled
navigation regions. Search fields have visible or accessible labels, keyboard
focus uses Signal Orange, and collapsed state must remain understandable
without motion.
### ISAC mutation consequence
Every writable game-data module states what Save will do before the operator
opens an editor, and the statement remains visible while the editor is open.
The message is derived from effective permissions rather than copied into each
module:
- `OVERSIGHT REVIEW` means saving creates a proposal and does not change live
data until Oversight approves it.
- `DIRECT PUBLISH` means the change becomes live immediately and creates an
append-only audit event.
Pair the short state label with a complete consequence sentence. Contributors
must not have to infer this behavior from their role name, data-mode color, or a
success message shown after saving. Read-only operators do not see a mutation
statement because their mutation controls are absent. At narrow widths the
message becomes its own compact row above the module toolbar.
+11 -27
View File
@@ -90,35 +90,19 @@ This guard prevents accidental merging or overwriting of contributor data.
Stop the application before backup or restore so the embedded database file is
not locked by another process.
## Low-downtime development migrations
## Development database maintenance
The development database is a shared working data source: contributors may be
entering ISAC records while application development continues. Database changes
therefore use a prepared migration window rather than taking the server down at
the beginning of implementation.
The development database remains valuable persistent data, but it is no longer
served to outside contributors and does not require a low-downtime migration
window. Stop only this project's development server before backup, export,
restore, migration, or other work requiring exclusive access. Create and verify
a JSON backup, perform the prepared operation, verify schema state and critical
record counts, then restart and health-check the application. Prefer additive,
repeatable migrations and preserve the verified backup if maintenance fails.
Before the window, finish the code and idempotent migration, batch related
schema changes, identify verification queries, and run `npm run check` plus
`npm run build` while the server remains available. Prefer additive,
backward-compatible tables and safely defaulted or nullable columns. Coordinate
with known contributors so the stop does not interrupt an unsaved submission.
The offline window is deliberately narrow:
1. Inspect running processes and stop only this project's development server.
2. Run and verify `npm run db:backup`.
3. Run the already-prepared migration.
4. Verify expected schema state, record counts, and critical entities.
5. Restart the development server immediately.
6. Confirm a basic page or health check, then perform extended browser and
regression testing with the service online.
Code editing, builds, formatting, documentation review, and noncritical UI
testing do not belong inside this window. Destructive, data-rewriting, or
long-running migrations require a separately communicated maintenance window
and a verified recovery plan. Every migration handoff reports the backup path,
migration outcome, successful server restart, critical checks, and the
approximate offline interval when available.
Production and staging remain shared persistent environments and retain the
deployment, backup, synchronization, and maintenance safeguards documented in
`docs/DEPLOYMENT.md`.
# ISAC audit and compensating reversals