Pre-launch hardening, QA fixes, and a new offline help assistant for the MSOS site. All verified in a headless browser; every changed page loads with zero console errors.
🔒 Security
Remove publicly-downloadable source dump + stray l.php; exclude dev files from deploy
## Summary
Pre-launch hardening, QA fixes, and a new offline help assistant for the MSOS site. All verified in a headless browser; every changed page loads with zero console errors.
### 🔒 Security
- Remove publicly-downloadable source dump + stray `l.php`; exclude dev files from deploy
- Add security headers (X-Frame-Options, Referrer-Policy, Permissions-Policy, report-only CSP) + dev-file deny block
- Fix root redirect to canonical `msosorg.com`; 4 YouTube embeds → `youtube-nocookie`; `rel=noopener` on social links
### 🩺 Health / a11y / SEO
- Fix Timeline pages (broken stylesheet/hero paths) and a broken gallery image
- Add width/height to 1039 images (CLS) + responsive `img` safety net; preload homepage hero; Font Awesome non-blocking
- Newsletter `aria-label`, My Route `<h1>`, 6 meta descriptions
- Keyboard/screen-reader-accessible mobile menu; remove unwired homepage "Play video" button
### 🤖 Offline "Ask MSOS" assistant (no API, $0)
- In-browser search + curated multilingual answers; detects the language of the *question*; suggested-question chips; one-time disclaimer
- Privacy-safe GA4 `assistant_query` analytics (consent-gated) + `docs/GA4-ASSISTANT-REPORT.md` guide
- Search index auto-rebuilds on every deploy (CI step)
### Notes / follow-ups
- MK/SI curated answers + meta descriptions are machine-drafted — **proofread before launch**
- CSP is report-only; set HSTS at the host; content placeholders tracked in `docs/PRE-LAUNCH-CHECKLIST.md`
- Blog pages have the assistant widget in the working tree but are left with the in-progress blog content (not in this PR)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
- Fixed 3 SI event posts that were missing their </article> and </main> tags
- Replaced all punctuation em-dashes and spaced en-dashes (435 across 64 files)
with commas; normalized a SI date range to a hyphen to match EN/MK
- Verified the new Gallery + in-post gallery content is fully translated in
EN/MK/SI (headings, titles, links, nav labels) with no English leftovers
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>
Site-wide health pass (excludes in-progress blog work). Verified with a
local server + headless browser: Timeline, homepage and gallery pages load
with zero console errors and no layout distortion.
Render bugs
- Timeline page (en/mk/si): fix ../../../ paths that overshot the site root,
so the main stylesheet and hero image load again.
- Meet Student Slovenia 2023 (en/mk/si): remove a <figure> referencing
event3-photo-11.png, an image that was never uploaded (broken image).
Performance
- Add intrinsic width/height to 1039 raster <img> tags to prevent layout
shift (CLS); 450 SVGs correctly skipped. Add a global
`img { max-width:100%; height:auto }` safety net so aspect ratio is
preserved and images never overflow.
- Preload the homepage hero (LCP) image on en/mk/si.
- Load Font Awesome non-blocking (media=print/onload swap) with a <noscript>
fallback, on 225 pages.
Accessibility
- Add aria-label to 57 unlabeled newsletter email inputs.
- Add an sr-only <h1> to the three "My Route" pages (had no h1).
- Add an .sr-only utility class.
SEO
- Add meta descriptions to legal/msos-hub/support pages (en/mk/si).
Note: MK/SI meta descriptions are machine-drafted and should be proofread
by a native speaker before considering them final.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The mobile hamburger is a <div class="mobile-menu-icon"> with a click
handler, so it worked on tap but was invisible to keyboard and screen-reader
users. Expose it as a button in main.js: role="button", tabindex="0",
aria-label, aria-expanded toggling, and Enter/Space activation. Verified in
a headless browser (focusable, Enter opens, aria state flips).
Also adds docs/PRE-LAUNCH-CHECKLIST.md (dev-only, excluded from deploy):
inventory of remaining content placeholders for the public launch.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The homepage "Every Student Has a Story" section had a <button class=
"play-button"> with no handler and no video wired to it — clicking did
nothing. Remove the dead button; keep the team photo and section copy.
The story video can be wired back in later.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A privacy-friendly help widget that answers visitor questions from the
site's own content and links to the full page — runs 100% in the browser,
no API, no server, no per-token cost.
- tools/build_search_index.py: parses every EN/MK/SI page into ~720
heading-level chunks per language -> assistant/index-<lang>.json
(lazy-loaded only when the chat is opened; gzips to ~80 KB).
- assistant.js: dependency-free BM25 search + multilingual stopword
filtering + a curated short-answer layer for common questions, plus an
accessible chat widget (role=dialog, keyboard, aria). CSP-safe (self only).
- assistant.css: scoped .msa-* styles in the site's teal palette;
responsive (full-screen panel on mobile).
- Injected on 208 pages (blog WIP excluded; picks it up when that lands).
Verified in a headless browser across EN/MK/SI: curated answers, search
fallback with correct ranking (rare terms win), correct deep links,
Cyrillic + Slovene diacritics, and zero console errors. Curated MK/SI
answers are machine-drafted — proofread before launch.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addresses real gaps found in testing (a Macedonian question on an English
page returned nothing):
- Detect the language of the QUESTION (Cyrillic -> MK; Slovene markers -> SI;
else the page language) and load that language's index + curated answers.
Fixes cross-language questions.
- Expand curated multilingual intents (now incl. enrolment/eVŠ, deadlines,
health, "what is MSOS", etc.) with stem keywords for better paraphrase
matching. MK/SI answers machine-drafted — proofread before launch.
- Suggested-question chips on open (localized) to guide users.
- Privacy-safe analytics: fire a GA4 'assistant_query' event ONLY after the
visitor accepts cookies (q text, result type, question vs page language) so
the team can see real FAQs and unanswered questions.
- Move the widget to bottom-left on pages with the floating "Become a member"
CTA so they never overlap. Design polish (chips, typing dots, launcher pulse).
- CI: rebuild the search index on every deploy (setup-python + build script)
so the assistant stays in sync with content automatically. Build script is
now path-portable (no hardcoded path).
Verified in a headless browser: MK-on-EN now answers correctly, chips work,
analytics event fires only with consent, become-a-member offset applies,
zero console errors.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add a subtle disclaimer under the greeting (EN/MK/SI): "automated guide,
can make mistakes — check the linked page for official steps." Shown once,
not on every message, so it sets expectations without clutter. Persistent
footer disclaimer stays.
- docs/GA4-ASSISTANT-REPORT.md: step-by-step for registering the custom
dimensions and building the "top questions" + "unanswered questions"
explorations in GA4 (dev-only doc, not deployed).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Pre-launch hardening, QA fixes, and a new offline help assistant for the MSOS site. All verified in a headless browser; every changed page loads with zero console errors.
🔒 Security
l.php; exclude dev files from deploymsosorg.com; 4 YouTube embeds →youtube-nocookie;rel=noopeneron social links🩺 Health / a11y / SEO
imgsafety net; preload homepage hero; Font Awesome non-blockingaria-label, My Route<h1>, 6 meta descriptions🤖 Offline "Ask MSOS" assistant (no API, $0)
assistant_queryanalytics (consent-gated) +docs/GA4-ASSISTANT-REPORT.mdguideNotes / follow-ups
docs/PRE-LAUNCH-CHECKLIST.md🤖 Generated with Claude Code
Site-wide health pass (excludes in-progress blog work). Verified with a local server + headless browser: Timeline, homepage and gallery pages load with zero console errors and no layout distortion. Render bugs - Timeline page (en/mk/si): fix ../../../ paths that overshot the site root, so the main stylesheet and hero image load again. - Meet Student Slovenia 2023 (en/mk/si): remove a <figure> referencing event3-photo-11.png, an image that was never uploaded (broken image). Performance - Add intrinsic width/height to 1039 raster <img> tags to prevent layout shift (CLS); 450 SVGs correctly skipped. Add a global `img { max-width:100%; height:auto }` safety net so aspect ratio is preserved and images never overflow. - Preload the homepage hero (LCP) image on en/mk/si. - Load Font Awesome non-blocking (media=print/onload swap) with a <noscript> fallback, on 225 pages. Accessibility - Add aria-label to 57 unlabeled newsletter email inputs. - Add an sr-only <h1> to the three "My Route" pages (had no h1). - Add an .sr-only utility class. SEO - Add meta descriptions to legal/msos-hub/support pages (en/mk/si). Note: MK/SI meta descriptions are machine-drafted and should be proofread by a native speaker before considering them final. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>