Commit Graph

114 Commits

Author SHA1 Message Date
Falkan
231eacc27c fix: adminPath TTL cache in hooks.ts instead of read-once at startup
Previous approach read config.json once at module load time. If the PVC
wasn't fully mounted yet, it fell back to 'admin' and stayed there for
the lifetime of the process. New approach caches for 5 seconds and re-reads
on expiry, so it recovers from startup races and picks up changes without
requiring a restart.
2026-03-20 01:57:06 -04:00
Falkan
7239ca6d5a debug: log reroute calls in hooks.ts 2026-03-20 01:56:15 -04:00
Falkan
f10e4a6cbe debug: log adminPath at startup in hooks.ts 2026-03-20 01:53:25 -04:00
Falkan
ea08258ad4 debug: log hash/secret/password lengths in login route 2026-03-20 01:18:51 -04:00
Falkan
ae7ad0073b fix: trim whitespace from PASSWORD_HASH and SESSION_SECRET env vars 2026-03-20 01:17:04 -04:00
Falkan
258b0f5065 fix: default adminPath is boss, not admin 2026-03-20 00:59:32 -04:00
Falkan
d4b8a9a646 fix: brand name Dick Loads -> Dickloads 2026-03-20 00:55:57 -04:00
Falkan
5ec1222720 fix: remove debug logging from login route; fix .env.example formatting
- Remove console.log debug lines added during password troubleshooting
- .env.example: restore correct formatting, add note about $ escaping with
  single quotes + backslashes for bcrypt hashes
2026-03-20 00:23:16 -04:00
Falkan
d40b76e8f2 fix: use $env/dynamic/private in hooks.server.ts for CSRF allowlist
- 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
2026-03-20 00:12:40 -04:00
Falkan
6198c58055 fix: use $env/dynamic/private for SESSION_SECRET and PASSWORD_HASH
- 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
2026-03-20 00:11:07 -04:00
Falkan
029b7854aa content: about and contact page copy 2026-03-20 00:03:36 -04:00
Falkan
da8c527b61 fix: increase tooltip max-width from 280px to 420px to reduce wrapping 2026-03-20 00:01:52 -04:00
Falkan
5480bb246c refactor: move sessionSecret+passwordHash to env vars, seed data/ from defaults/
- 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
2026-03-19 23:54:37 -04:00
Falkan
5b89585505 feat: first-run config.json auto-generation on blank PVC
- 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)
2026-03-19 23:40:20 -04:00
Falkan
2c5d267d84 chore: clean up build scripts — simple docker build+push to registry.nerdrage.cloud
- 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
2026-03-19 23:00:00 -04:00
Falkan
337b722cf2 fix: multi-domain CSRF allowlist, trustProxy for nginx-ingress TLS termination
- 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
2026-03-19 13:18:21 -04:00
Falkan
8d2b838d84 chore: add build-local.sh for manual node import via crictl 2026-03-19 02:09:13 -04:00
Falkan
1e7331d4fc fix: use crictl image import instead of ctr for proper CRI registration 2026-03-19 02:02:43 -04:00
Falkan
e70949009f fix: imagePullPolicy IfNotPresent instead of Never 2026-03-19 01:58:48 -04:00
Falkan
c588949411 fix: tag image as localhost/humor-units to avoid docker.io expansion 2026-03-19 01:55:39 -04:00
Falkan
112336397b fix: qualify image as localhost/humor-units:latest for kubelet 2026-03-19 01:54:47 -04:00
Falkan
cffaaea26d fix: use OCI archive workflow instead of registry — scp + ctr import on each node 2026-03-19 01:33:47 -04:00
Falkan
8e739f4077 fix: use NodePort for registry — resolvable from node host network 2026-03-19 01:27:16 -04:00
Falkan
5901ba92e8 fix: --ignore-scripts in production stage avoids svelte-kit not found 2026-03-19 01:17:07 -04:00
Falkan
e5ff5a90c5 fix: build-push.sh — push via port-forward, tag with in-cluster registry address 2026-03-19 01:08:02 -04:00
Falkan
177b15920f chore: in-cluster registry manifest, build-push.sh script 2026-03-19 01:00:54 -04:00
Falkan
e6a023e14a chore: add Dockerfile and k8s deployment manifests 2026-03-19 00:42:31 -04:00
Falkan
cd0482bade feat: tooltip viewport clamping — shifts minimally to keep bounding box in view 2026-03-19 00:27:01 -04:00
Falkan
d1500c6ac3 fix: tooltip tracks current mouse position, opens at cursor 2026-03-19 00:24:20 -04:00
Falkan
7dec5272b1 revert: tooltip positioning back to 52fc0b8 (pre-viewport-clamping) 2026-03-19 00:20:37 -04:00
Falkan
15b5871eb9 fix: tooltip positioning without rAF — measure synchronously via ready class 2026-03-19 00:16:49 -04:00
Falkan
65f760a254 fix: tooltip positioning — measure after rAF, shift up minimally to fit 2026-03-19 00:05:09 -04:00
Falkan
c13db8b826 fix: tooltip flips above cursor when it would clip viewport bottom 2026-03-18 23:58:40 -04:00
Falkan
52fc0b826f fix: tooltip respects newlines via white-space: pre-wrap 2026-03-18 23:49:24 -04:00
Falkan
248df8d552 chore: add auto-generated ID backlog item 2026-03-18 23:36:54 -04:00
Falkan
8bdde05ca7 chore: add BACKLOG.md 2026-03-18 23:07:05 -04:00
Falkan
1dd2f0c5d3 feat: optgroup dividers in unit dropdown, matching group order and visibility 2026-03-18 23:00:07 -04:00
Falkan
a44551d4bc fix: settings button size in admin header 2026-03-18 22:44:45 -04:00
Falkan
cd34fd27a1 fix: uniform sizing for admin header buttons 2026-03-18 22:40:48 -04:00
Falkan
61d1d49f4b feat: sort-alpha button per group, settings in header, sortPosition pin
- ⇅ 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
2026-03-18 22:16:44 -04:00
Falkan
8ec935d238 fix: alpha sort by labelPlural primary, symbol secondary
Handles ties like 'Barrel (US fluid)' vs 'Barrel (US dry)'
2026-03-18 21:13:17 -04:00
Falkan
1c6dc7984a chore: add build:watch and serve scripts, install nodemon 2026-03-18 20:52:21 -04:00
Falkan
1308b1f96f feat: editable unit/group IDs with full cascade
- 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
2026-03-18 20:46:36 -04:00
Falkan
7d79284fd7 feat: start.sh for production server, hooks.server.ts stub, svelte.config cleanup
- 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)
2026-03-18 20:30:34 -04:00
Falkan
8dbc625c68 fix: in-flight guards on loadData/loadConfig, remove duplicate loadConfig
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.
2026-03-18 20:21:15 -04:00
Falkan
4c2fe9b3ad fix: replace $effect with onMount for initial data load
$effect re-runs on any reactive state change — loadData/loadConfig both
write state, creating an infinite loop that hung the page under load.
2026-03-18 20:18:30 -04:00
Falkan
b020b74c31 feat: yoloVisibility config, alwaysShowLabel on groups, site settings panel
- 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
2026-03-18 20:15:45 -04:00
Falkan
2c27edc487 fix: cycle references resolve to Label (symbol) instead of empty
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)'.
2026-03-18 19:59:33 -04:00
Falkan
d332cc135e fix: description placeholder sentinel leaking to output
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).
2026-03-18 19:51:01 -04:00
Falkan
1204ede140 feat: Enter to save, Escape to discard, auto-save on unit/group selection
- 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
2026-03-18 19:42:56 -04:00