Implemented. Sign in, then open Experience or Skills to:

- Add, edit, and delete experience entries and project links.
- Manage skill categories and individual skill labels.
- Edit the skills introduction and “How I work” text.
Changes save directly to Supabase—no code edits or Git push needed. Existing content is preserved.
This commit is contained in:
StormRunner06106
2026-09-13 10:03:21 -07:00
parent 6e3779e500
commit 404e0dc16d
25 changed files with 1337 additions and 82 deletions
+12 -2
View File
@@ -75,11 +75,13 @@ Reading the journal is public and independent of the admin session. Journal list
Use **+ Section** in the editor to add a section heading and opening paragraph. Section headings receive the same divider and uppercase drop cap as the starter articles, with formatting visible in the editor. Existing H2 headings use this styling automatically.
The media picker supports drag-and-drop or file browsing, a live banner preview with the article title and subtitle, file-size and format checks, and duplicate detection by file name and size. Uploads have individual progress, cancel, and retry controls; a failed file does not stop the remaining queue. Retry or remove pending/failed uploads before publishing. Use the up/down controls to set the order of additional photos and files. Replacing a banner keeps the previous image until the replacement uploads successfully.
The media picker supports drag-and-drop or file browsing, a live banner preview with the article title and subtitle, file-size and format checks, and duplicate detection by file name and size. Uploads have individual progress, cancel, and retry controls; a failed file does not stop the remaining queue. Retry or remove pending/failed uploads before publishing. Drag an attachment row with a mouse, or briefly hold its grip handle on a touch screen, to change the order of additional photos and files. Keyboard users can focus the handle, press Space to pick up a file, use the arrow keys to move it, and press Space to drop or Escape to cancel. The new order is persisted when the article is saved. Build the frontend and run `.venv/Scripts/python.exe -m scripts.test_attachment_reordering` to verify mouse, touch, keyboard, cancellation, and order persistence in an isolated browser test (requires Playwright and Microsoft Edge). Replacing a banner keeps the previous image until the replacement uploads successfully.
The publisher accepts a banner image (JPEG, PNG, WebP, or GIF, up to 8 MB) and up to ten additional photos or files (20 MB each). The banner appears in the journal thumbnail and behind the article title and subtitle with a readability overlay; additional photos and downloadable files appear below the body. Uploads require an admin session. New uploads use Dropbox by default. The Supabase article's `banner` and each item in `attachments` contain `storage: "dropbox"` and `dropbox_file_id: "id:..."`, alongside their names, sizes, media types, and stable website URLs.
The `article_media` table stores the upload-ID-to-Dropbox-ID mapping, including uploads not yet attached to a published article. The public `/api/uploads/{upload_id}` route retrieves bytes from Dropbox by ID, so article rows never contain expiring temporary links or access tokens. Original local uploads continue to work until migrated. Removing an attachment or deleting an article does not delete its stored file.
The `article_media` table stores the upload-ID-to-Dropbox-ID mapping, including uploads not yet attached to a published article. The public `/api/uploads/{upload_id}` route retrieves bytes from Dropbox by ID, so article rows never contain expiring temporary links or access tokens. Original local uploads continue to work until migrated. Saving an attachment removal or banner replacement deletes the unused file from Dropbox and removes its upload record and any local migration backup. Deleting an article also cleans up its uploaded files. Files referenced by another article are retained.
Removal intent is stored in the private `article_media_deletions` table before the article write. Cleanup runs after a successful save/delete and retries pending work at backend startup and every 60 seconds; Dropbox outages do not lose deletion requests. Cleanup checks published references before deleting anything. In local mode, the queue lives in `backend/data/media-deletions.json`. The form tracks uploads removed before publishing as well; removals take effect when the form is successfully submitted. Apply the current schema to existing Supabase projects before running this version. Article writes and cleanup are serialized within the backend process; run a single backend worker for this workflow.
For an existing Supabase project, run `bash scripts/setup_supabase.sh --schema-only` to add the nullable `banner` and default-empty `attachments` columns before running the updated backend. Existing articles remain compatible.
@@ -102,6 +104,14 @@ To move existing published media to Dropbox, preview with `.venv/Scripts/python.
For offline development only, set `JOURNAL_MEDIA_STORAGE=local`. Local files and legacy uploads use `JOURNAL_UPLOAD_DIR` (default `backend/data/uploads`). Dropbox uploads with Supabase configured do not require local file storage. If running without Supabase, upload metadata remains in that local directory and needs persistent storage.
## Edit experience and skills
Sign in with the existing admin password, then open **Experience** or **Skills** (also linked from the admin account menu). Experience supports adding, editing, and deleting roles, companies, locations, dates, summaries, highlights, technologies, and project links. Entries are displayed newest first by start date. Skills supports category CRUD, adding/removing individual skill labels, card colors, and editing the introduction and “How I work” principles. Press Enter in a label field to add it. Saves update the public website without code edits or Git pushes. Delete actions require confirmation; canceled dialogs leave published content unchanged.
Experience and skills live in the private Supabase `portfolio_content` table. Apply `backend/supabase/schema.sql` to existing projects, then run `.venv/Scripts/python.exe -m backend.seed_portfolio` once to copy the existing JSON content. Rerunning the seeder preserves content already saved in Supabase. All mutation endpoints require the same admin authentication as articles; reads remain public. Writes use version checks to avoid losing concurrent document updates. Configured Supabase failures are reported rather than falling back to outdated JSON. Local development without Supabase writes to the experience/skills JSON files.
Validation: `.venv/Scripts/python.exe -m unittest backend.test_portfolio_content`. After building the frontend, run `.venv/Scripts/python.exe -m scripts.test_portfolio_editors` for isolated browser coverage (requires Playwright and Microsoft Edge), including CRUD, public visibility, mobile forms, and keeping drafts through session recovery.
## Supabase article storage
The runtime backend needs two values from **Supabase Dashboard → Settings → API Keys**: