nmemmert d6acf85252 Fix Save Draft always showing Unsaved after save
The snapshot was set from buildSiteContentForSave(form) which runs
normalizeSiteContentForAdmin and rebuilds study objects, producing a
JSON string that never matched the raw form state. isDirty therefore
stayed true permanently after every save.

Fix by capturing JSON.stringify(form) before the fetch and using that
as the snapshot, so isDirty correctly clears on success.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-16 11:54:39 -04:00
2026-06-09 11:30:36 -04:00
2026-06-09 11:30:36 -04:00
2026-04-27 11:26:01 -04:00
2026-05-18 08:27:24 -04:00
2026-06-08 10:24:37 -04:00
2026-06-16 09:33:35 -04:00
2026-06-04 10:12:13 -04:00
2026-06-16 09:33:35 -04:00

Siteforge

This project is a React + TypeScript portfolio app built with Vite.

It is designed to showcase two categories of work:

  • Websites
  • Apps

The app now supports:

  • Dynamic cards generated from a project data source
  • Built vs Hosted filters
  • A dedicated About page route for each project
  • An admin editor route to update cards and About pages
  • A per-project README summary block on each project page
  • Embedded Spotify podcast player on the home section

Run locally

npm install
npm run dev:full

dev:full starts both:

  • Vite frontend (http://localhost:5173)
  • Admin content API (http://localhost:4173)

Build for production

npm run build

Run in container

Pull image directly:

docker pull ghcr.io/nmemmert/siteforge:latest
docker run -d --name siteforge-app -p 4173:4173 -v ./data:/app/data ghcr.io/nmemmert/siteforge:latest

Run with Docker Compose:

docker compose pull
docker compose up -d

Admin auth:

  • Set ADMIN_PASSWORD on the server/container to protect /admin and admin stats/maintenance endpoints.
  • Without ADMIN_PASSWORD, admin login is disabled until configured.
  • Optional: set CACHE_PURGE_WEBHOOK_URL to enable one-click cache purge from Admin Operations.
  • Optional: set DEPLOY_WEBHOOK_URL to enable one-click deploy trigger from Admin Operations.
  • Optional: set BUILD_COMMIT, BUILD_NUMBER, and DEPLOYED_AT to display deployment status in Admin.

The app will be available at http://localhost:4173.

Persistent admin saves:

  • Admin updates are written to data/admin-content.json.
  • Admin drafts are written to data/admin-content-draft.json.
  • Built-in page hit stats are written to data/hit-stats.json.
  • Detailed visitor analytics are written to data/visitor-stats.json.
  • Backup snapshots are written to data/backups/.
  • Uploaded admin assets are stored in data/uploads/ and served at /uploads/*.
  • docker-compose.yml mounts ./data into the container at /app/data.
  • This keeps all admin-managed data after container restarts/rebuilds/updates.

Where to edit content

  • Project domain data and ownership: src/data/projects.ts
  • Portfolio rendering logic: src/App.tsx
  • Portfolio UI styles: src/App.css
  • Global theme variables: src/index.css

Routes

  • Site home: /
  • Start Here: /start-here
  • Questions: /questions
  • Privacy: /privacy
  • Terms: /terms
  • Admin editor: /admin
  • Admin draft preview: /preview

Admin editing

  • Open /admin to edit homepage content, links, archived studies, Q&A moderation, and analytics.
  • Use Operations to manage SEO metadata, sitemap paths, legal page text, redirect rules, and podcast highlights.
  • Use Operations to upload/delete hosted image assets for use in content and social cards.
  • Use Save Draft, Preview Draft, and Publish Draft for a safer publish workflow.
  • Saved edits are written to data/admin-content.json through the API server.
  • Built-in stats in /admin include page hits plus visitor details (IP, country/state/county/city, returning visitors, and recent visitor log).
  • Site Stats in /admin includes a Bible Questions inbox sourced from contact form submissions marked as Bible Question.
  • Analytics cookies are consent-based. Visitors can accept or decline tracking from the site banner.
  • Admin now includes maintenance actions: Export JSON, Backup Now, Prune Old Data, and Clear Analytics.
  • Admin also supports restoring from a backup snapshot from /admin.
  • The server creates startup + daily backup snapshots and retains recent backups automatically.
  • Operations can trigger optional Purge Cache and Trigger Deploy webhooks.

Deployment note:

  • To keep Admin saves working on the internet, deploy with the Node API (server.js) and writable server storage for data/.

Titus study download gate:

  • The site now gates Titus study downloads behind a name/email form.
  • Default source file is A_Study_of_Titus.pdf in the project root.
  • Override source path with TITUS_STUDY_FILE (relative to project root or absolute).
  • Override downloaded filename with TITUS_STUDY_DOWNLOAD_NAME.
  • When the form checkbox is left enabled (default), contacts are synced to Resend using the same contact sync flow as the contact form.

Useful container commands:

docker compose logs -f
docker compose down

Update to latest image:

docker compose pull
docker compose up -d

Notes

  • The current project cards are sample placeholders.
  • Most metadata was scanned from live pages.
  • Skywatch currently uses a manual fallback description due to a 401 response during automated scan.
S
Description
No description provided
Readme 31 MiB
Languages
TypeScript 47%
JavaScript 26.6%
CSS 15%
HTML 10.9%
Shell 0.4%