- ALLOWED_ORIGINS and NODE_ENV now read via $env/dynamic/private so Vite dev
server picks them up correctly from .env
- .env.example: document ALLOWED_ORIGINS with dev IP example
- .env: add http://192.168.0.94:5173 to ALLOWED_ORIGINS for local dev
- login/+server.ts: read env vars via $env/dynamic/private (works in Vite dev)
- auth.ts: requireAuth now takes secret as parameter instead of reading process.env
- authRequest.ts: new route-level helper that reads SESSION_SECRET from
$env/dynamic/private and passes it to requireAuth
- All admin routes updated to import authRequest from authRequest.ts
- SESSION_SECRET and PASSWORD_HASH moved out of config.json into env vars
- data.ts: AppConfig no longer holds secrets; loadConfig/loadData seed from
defaults/ on first run if data/ files are missing
- auth.ts: requireAuth/authRequest read SESSION_SECRET from process.env directly
- login/+server.ts: reads PASSWORD_HASH and SESSION_SECRET from process.env
- defaults/config.json: ships with image (no secrets)
- defaults/units.json: ships with image as initial unit data
- package.json: add dotenv dep; start/serve load .env via -r dotenv/config
- Dockerfile: copy defaults/ into image; data/ is PVC-only
- .env.example: documents required env vars for local dev
- Remove k8s/ — managed externally
- loadConfig(): if config.json missing, create data/ dir, write default config
with random sessionSecret and empty passwordHash, log instructions
- loadData(): throw clear error if units.json missing instead of crashing opaquely
- deployment.yaml: remove envFrom secretRef (SESSION_SECRET/PASSWORD_HASH not
read from env — config.json on PVC is the source of truth)
- Remove build-local.sh and old build-push.sh (crictl/scp/buildah workflow)
- New build-push.sh: docker build + push to registry.nerdrage.cloud/dickloads
- deployment.yaml: update image to registry.nerdrage.cloud/dickloads:latest, imagePullPolicy Always
- hooks.server.ts: replace empty stub with multi-origin CSRF guard
- Always allows humorunits.com and dickloads.com (+ www variants)
- ALLOWED_ORIGINS env var for additional origins (staging, preview)
- Dev: localhost:3000/4173/5173 auto-allowed when NODE_ENV != production
or ALLOWED_ORIGINS is unset — no config needed for local dev
- svelte.config.js: disable built-in single-origin CSRF check (we own it now)
trustProxy: true so X-Forwarded-Proto/IP are correct behind nginx-ingress
- login route: derive secure-cookie flag from X-Forwarded-Proto header so
session cookies are marked Secure even when Node sees plain HTTP from ingress
- deployment.yaml: add NODE_ENV=production and explicit ALLOWED_ORIGINS
- ⇅ button on each group header: sorts units alpha (labelPlural + symbol tiebreak) via order API
- ⚙ Settings moved to admin-header alongside Log out
- Unit type gets sortPosition?: number (1-based, optional)
- Converter sort: partitions pinned/floating, inserts pins at requested slots
Pins > length append at end; gaps fill naturally with floating items
- Admin unit form: Force position number input
- Unit ID rename: updates group.baseUnitId refs + {old-id:*} in all descriptions
- Group ID rename: updates unit.group refs + {old-id:*} in all descriptions
- Admin form ID fields unlocked; hint text updated
- renameIdInDescription() shared helper in both PUT handlers
- start.sh: builds and launches Node production server on 192.168.0.94:4078
- Multi-domain CSRF: not needed — SvelteKit natively passes when Origin matches Host
- hooks.server.ts: minimal stub with explanation
- svelte.config.js: reverted csrf experiment (not supported in this version)
Concurrent calls from rapid reloads or rapid saves could pile up,
each writing state on completion and potentially re-triggering more loads.
Guards ensure only one load is in flight at a time; extra calls are dropped.
- AppConfig gains yoloVisibility: 'auto' | 'never' (default: auto)
- Group gains alwaysShowLabel?: boolean
- YOLO toggle only renders when showYoloToggle is true (auto + >1 group)
- Group divider shows when >1 group OR alwaysShowLabel is set
- New /admin/api/config GET+PUT endpoint for yolo settings
- Admin: alwaysShowLabel checkbox in group form
- Admin: ⚙ Settings panel with YOLO label, description, and visibility controls
When a {id:description} reference forms a cycle, the back-reference
now expands to 'Label (symbol)' rather than being stripped.
So pound ↔ dickload renders as 'See dickload (dl)' and 'See pound (lb)'.
Two bugs:
1. Sentinel used double-underscore delimiters (__DESC:id__) — fragile regex
[^_]+ would break on IDs containing underscores, and Pass-1 output
containing sentinels would leak through Pass 2 unstripped.
2. After Pass 2 substitution, sentinels inside substituted text (from
Pass-1 output of the referenced id) were never cleaned up.
Fix: switch to null-byte delimiters (\x00DESC:id\x00) which cannot appear
in user text, and add a second .replace(SENTINEL_RE, '') pass to strip any
sentinels that survive after substitution (self-refs, nested cycles).
- selectUnit/selectGroup now async; call autoSaveCurrentForm before switching
- Enter in any form field (except textarea) triggers save
- Escape restores form to snapshot (discards unsaved changes)
- discardUnitForm/discardGroupForm helpers for snapshot restore