feat: refine ISAC design and prepare production deployment
This commit is contained in:
+76
-6
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user