Establish content/ as the source of truth for editable content and
back-fill it from the existing detail pages, per U1 of the no-code CMS
plan.
- docs/content-model.md: front-matter schema (EN/MK/SI), body_format
html-vs-markdown, content/events -> projects/ output mapping.
- tools/migrate_pages_to_content.py: bs4/yaml extractor; pulls title,
subtitle, category, ISO date (from ARTICLE_DATES), hero image+caption;
preserves the article body PLUS trailing sibling sections (event
galleries) verbatim as body_format: html. Reports unparseable pages
instead of emitting half-formed files.
- content/**: 51 files (17 entries x EN/MK/SI), 0 skips.
- tools/tests/test_migrate_roundtrip.py: 12 characterization tests
(structured fields, news-has-no-subtitle, event gallery/lightbox
preserved, Cyrillic UTF-8 round-trip, every page parses).
- .gitignore: ignore __pycache__/ and *.pyc.
U1 is unblocked and standalone. U2 (render content -> pages) is next;
U5/U6 remain blocked on Open Question Q1 (Gitea<->GitHub topology).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Gallery flow:
- Album covers now open the photo lightbox directly (full album set), while
the title/"Read the story" link opens the article. Previously the whole card
linked to the article and photos were only at the bottom of it.
- Each album carries its full photo set in a hidden js-lightbox grid; added
main.js support for [data-lightbox-target] cover triggers.
- Added the missing main.js include on the gallery page (its lightbox, mobile
menu and language switcher never ran before).
- Lightbox gained an optional "Read the story ->" button (data-project-url /
data-project-label) shown only for gallery albums.
Watermark:
- Baked a subtle "(c) msosorg.com" watermark (bottom-right, sized per image)
into 114 of our own event/community photos. Stock/partner/logo/icon images
excluded. Clean originals backed up to images/_originals/ (git-ignored); the
script always re-derives from them so re-runs never stack.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Proactive security & health pass. No live/exploitable vulnerabilities were
found; these changes remove information-disclosure surfaces and add
standard hardening.
- Remove publicly-downloadable 1.1 MB full source dump (code_export.txt)
and stray empty l.php; add code_export.txt to .gitignore.
- Exclude dev files/folders (*.sh, *.py, docs/, templates/, tools/,
README.md) from the rsync deploy so they never reach the live server.
- .htaccess: add X-Frame-Options, Referrer-Policy, Permissions-Policy,
and a report-only Content-Security-Policy; add defense-in-depth deny
block for dev/VCS files (robots.txt & sitemap.xml left served).
- .htaccess: fix root redirect to canonical msosorg.com + /en/.
- Swap 4 project-page YouTube embeds to youtube-nocookie.com so no
Google cookies are set before consent (GDPR).
- Add rel="noopener" to 30 team social links on the About Us pages.
- Harden esc() in my-route.js to also escape single quotes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add branded 1200x630 og-default.jpg; article pages use their hero as
og:image, others use the default
- Wire the existing (previously unlinked) favicon set into every page
- Add branded 404.html with root-absolute paths + noindex
- Emit Article + localized BreadcrumbList JSON-LD on all article pages
- Convert 74 heavy served photos to WebP (28MB -> 8.5MB, -70%), rewrite
references, add loading=lazy/decoding=async to below-fold images and
fetchpriority=high to heroes (protect LCP)
- Stop tracking images/original/ (458MB of unused source masters; kept on
disk, gitignored) and ignore .playwright-mcp/
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>