Built in public
Changelog
سجل التغييرات
Every single thing shipped on this site — OWASP headers, referee signals, poule sheets, scholarship forms, AI translation, Arabic RTL layout, door-check QR, 150 iterations of "what would a real federation website actually do?". The log is public because the work is.
Iterations
234
Log entries
222
Days
3
Features
117
feature · 117 ux · 25 api · 24 seo · 6 multi-role · 6 feed · 4
Thu, 23 Apr 2026 · 69 entries
- iter234api/api/public/coaches JSON mirrors the existing coaches.csvfilters team by /coach|مدرب/i, strips email/phone, exposes id/nameEn+Ar/roleEn+Ar/photo/bio/certificationLevel/joinedAt. Verified 200 count=1 (Hisham Karshod)
- iter233uxsurface iter-232 per-athlete Results CSV + JSON downloads as ghost-buttons next to Passport PDF on /athletes/{slug} (bilingual labels, fa-table + fa-brackets-curly icons)verified both links render on jana-al-sharji prod
- iter232api/athletes/{slug}/results.csv + results.json per-athlete match-history endpoints (item #24 missing-features); slug→athleteId via readAthletes + resultsForAthlete + medalTally; unknown slug 404, empty roster returns header-only CSV / count=0 JSON
- iter231uxglobal '/' keybind focuses first search input on any public page (GitHub/Notion style, skips when typing in input/textarea/contenteditable); focuses+selects
- iter230maintenancesmoke.sh extended with 12 filter permutations from iters 225-229 (weapon, club, year, tag, q, limit, medal, types=)61→73 endpoints, 73/73 green against prod
- iter229api/api/public/results ?athleteSlug (or athleteId) + ?medal + ?year + ?weapon + ?limit (1-500, default 200) filters; store currently empty so all permutations return 200 count=0
- iter228syncrefresh content/loop-log.txt from 197 to 227footer 'Built in public · N iterations shipped' + /changelog + /changelog.rss.xml + /changelog.atom.xml all bump in one ship
- iter227api/api/public/news ?year= date-prefix + ?q= NFD-normalised substring match + ?limit=1-200 (default 50). Verified 22 total → 5 from 2025 → 1 matching 'bahrain' → 3 capped by limit
- iter226api/api/public/events ?year=YYYY date-prefix match + ?tag= case-insensitive exact match; verified 8 total → 3 from 2025, 2 international, 1 composed
- iter225api/api/public/athletes ?weapon=foil|epee|sabre (NFD) + ?club=substring + ?active=0 filters; exposes discipline+gender on each row. Verified 13 total → 7 foil + 6 epee, 3 Salalah by club
- iter224uxricher ShareButton titles on athlete/event/news/club detail pages (athlete: name+category+discipline+club; event: title+date+tag; news: title+date; club: name+cityall suffixed 'Oman Fencing')
- iter223api/api/public/search/suggest?types= mirrors iter-222 filter on the typeahead endpointverified q=al types=athlete returns 8 athletes vs 4 types mixed unfiltered
- iter222api/api/public/search?types=a,b,c filter (comma-separated allowlist of athlete/event/news/club/committee; unknown vals dropped; empty keeps all)verified q=jana types=athlete narrows from 5 mixed to 1 athlete
- iter221discoverability/.well-known/change-password 302 to /login for W3C password-manager discovery (Bitwarden, Apple Passwords, 1Password, Chrome leaked-password flow); fencing.om is OTP so redirect to re-authentication page
- iter220maintenancescripts/smoke.sh 61-endpoint smoke suite (discovery/feeds/registries/entities/aggregates/search/detail/pages, HTTP code + content-type substring check, exits non-zero on any mismatch, 61/61 green against prod now)
- iter219refactorDRY spotlight picker into src/lib/spotlight.ts todaySpotlight(); /api/public/spotlight + SpotlightFeature both delegateguaranteed same pick (API and homepage both return Salma Al Daghishi today); -35 net lines
- iter218uxSpotlightFeature on homepage surfaces iter-217 athlete-of-day (same FNV-1a hash ensures page pick matches API pick; renders between Stats and About with photo + discipline badge + category + club)
- iter217api/api/public/spotlight athlete-of-the-day (FNV-1a(yyyy-mm-dd) mod active-roster, same pick all day, rotates at UTC midnight)today's pick: Salma Al Daghishi
- iter216discoverabilityfooter bottom bar surfaces /now (iter 206) + /developers (iter 170) alongside Privacy/Terms/CoC/Security
- iter215ux'Jump to' anchor pills on /committee (President + board-members grid anchor + CSV download, star/users/file-csv icons, EN+AR)
- iter214uxclient-side filter on /clubs index (name+city search, NFD-normalised, shown/total counter); mirrors iter-213 committee filter
- iter213uxclient-side filter input above /committee board grid (NFD-normalised, live shown/total count pill, empty-state msg, no network roundtrip)
- iter212export/coaches.csv (head coach + certified coaches filtered by coach|مدرب role pattern, NO email/phone, 600s cache) registered in feeds.json catalog and /developers docs
- iter211seo/sitemap-images.xml Google image sitemap (event photos + news covers + athlete photos grouped by page URL with image:title context, schema 1.1, 1h cache); listed in sitemap.xml index
- iter210ux/committee member cards get id={member.id} + scroll-mt-24 so /committee#tm_president deep-links work; matches iter-201 /api/public/committee/{id} URL contract
- iter209api/api/public/sitemap.json (100 static pages + 51 dynamic news/events/athletes/clubs URLs deduped+sorted, 150 total, each with relative path + absolute URL, 600s cache)
- iter208ux/now page gets JSON snapshot + .ics subscribe + News RSS pill row (mirrors iter-178 news index pattern, surfaces structured siblings)
- iter207api/api/public/now JSON sibling to /now page (eventsThisWeek + upcomingNext5 with inDays + recentNews 7d + recentResults 30d, 300s cache, registered in /api/public)
- iter206ux/now 'what's on this week' snapshot page (4 sections: This Week events / Recent News 7d / Coming Up Next 5 + day count / Recent Results 30d; empty-state pills with deep links; sitemap daily-changefreq)
- iter205uxNewsFeature on homepage (3 latest news cards inserted after Events before Gallery, mirrors /news index card style with date badge + line-clamp-2 title + RTL-aware arrow, 'All news' link in header)
- iter204docs/developers refreshed with all endpoints shipped since iter 170 (+committee/{id}, +disciplines, +changelog, +feeds.json, +new Search group with full+suggest, +atom feeds, +per-event ICS, +per-club CSV/JSON, +openapi.json)
- iter203api/api/openapi.json refreshed to v1.1.0 (15→21 paths) covering committee/{id} disciplines changelog feeds.json search search/suggest shipped since iter 171
- iter202api/api/public/search/suggest?q= typeahead endpoint (max 8 title-only results, 30s cache, NFD scoring); search.ts moved to search/index.ts to allow sibling; registered in /api/public
- iter201api/api/public/committee/[id] per-member JSON (President's record returns full safe-fields, unknown 404, list endpoint moved committee.ts → committee/index.ts to allow [id].ts sibling); per-entity detail set complete across athletes (166), events (167), news+clubs (168), committee (201)
- iter200MILESTONE/api/public/search?q=&limit=N cross-entity search (athletes+news+events+clubs+committee, NFD-normalised exact>prefix>substring scoring, news falls back to body scan, snippet+score per hit, 60s cache, registered in /api/public)
- iter199a11yaria-current='page' + green tint on active Nav item (top + mobile drawer); active when pathname === target OR startsWith target+/, so /news/<slug> still highlights News
- iter198ux'Built in public · N iterations shipped' centered footer line on every public page (reads max iter from content/loop-log.txt at module load, links to /changelog, EN+AR; +log refresh to keep number current)
- iter197feed/changelog.atom.xml Atom 1.0 sibling to iter-188 RSS (100 entries, autodiscovered on /changelog via head slot, entry in /api/public/feeds.json catalog)
- iter196api/api/public/feeds.json catalog (24 feeds across 8 MIME types: rss/atom/json/xml/calendar/csv/plain/opensearch)entity tag + format + description + absoluteUrl per entry, 1h cache, registered in /api/public
- iter195feed/news.atom.xml Atom 1.0 sibling to RSS (per-entry xml:lang, proper id/published/updated, author block, 600s cache) + Base.astro adds <link rel=alternate type=application/atom+xml> alongside the RSS link
- iter194uxreading-time badge on /news index cards (precomputed in frontmatter from readNewsArticle, 200wpm EN/180wpm AR, EN 'X min'/AR 'X د' next to date)
- iter192ux+fixborn/age badge on athlete profile when birthYear present (3 athletes today: israa-al-siyabi, ahmed-keskes, ali-al-busaidi); iter 192 IIFE pattern silently dropped by Astro template parser, iter 193 fixed by computing ageEoY in frontmatter and using plain {athlete.birthYear && (...)} expression
- iter191api/clubs/<slug>/athletes.json sibling to iter-190 per-club CSV (same tolerant club-name match, returns club identity + roster array, 404 on unknown, 600s cache)
- iter190export/clubs/<slug>/athletes.csv per-club roster CSV (tolerant club-name match handles 'Quriyat'/'Quryat' transliteration variants, NFD-normalised, strips 'club' word) + Roster CSV card surfaced on /clubs/[slug] alongside venue + how-to-join
- iter189seoBase.astro gains <slot name='head'/> + /changelog adds <link rel=alternate rss> for iter-188 changelog.rss.xml so feed readers auto-detect it
- iter188feed/changelog.rss.xml RSS 2.0 of last 100 shipped iterations (parses content/loop-log.txt) + RSS+JSON CTA pills under /changelog intro (mirrors iter 178 news pattern)
- iter187api+syncrefresh in-repo content/loop-log.txt (was 1 day stale, now reflects iter 186) + new /api/public/changelog JSON feed parsing same file (?limit=N, max 500) registered in /api/public; 175 entries indexed
- iter186api/api/public/disciplines reference endpoint (3 weapons foil/épée/sabre with EN+AR names, target area, scoring rules, pageUrl) registered in /api/public, 24h cache
- iter185uxShareButton on /clubs/[slug] completes detail-page set (news + events + athletes + clubs all have prev/next nav AND share button)
- iter184refactor+uxextract ShareButton.astro reusable component (data-attr + idempotent document-level handler binding via data-bound flag); /news/[slug] + /events/[slug] swap to component (-80 lines); /athletes/[slug] gains share button above prev/next nav
- iter183uxshare button on /events/[slug] mirrors iter-182 news (navigator.share native + clipboard fallback + transient flash, EN+AR)
- iter182uxshare button on /news/[slug] (navigator.share native dialog on mobile/PWA, navigator.clipboard fallback with 'Link copied'/'تم النسخ' transient flash, EN+AR)
- iter181uxreading-time estimate badge in /news/[slug] meta strip ('X min read' EN @200wpm + 'قراءة X دقيقة' AR @180wpm; hidden when body empty; AR badge uses flex-ar helper for proper display:flex on lang=ar)
- iter180ux/clubs index gets CSV + JSON API + Leaderboard pill row (completes listing-page export pattern across news 178 athletes+events 179 clubs 180)
- iter179ux/athletes + /events index pages get JSON API export pill next to existing CSV/ICS pills (mirrors iter 178 news pattern)
- iter178ux/news index gets RSS + Email + JSON API CTA strip surfacing /news.rss.xml + /#newsletter + /api/public/news (3 pills below search row, EN+AR, hover green-ofc)
- iter177ux'Add to calendar' button on /events/[slug] surfaces iter-176 per-event ICS endpoint (calendar-plus icon, download attribute, EN+AR labels, leads the CTA strip above 'Full medal table' and 'All athletes')
- iter176feed/events/<id>.ics per-event iCalendar export (RFC 5545 line-folding+escape, X-WR-CALNAME=event title, 600s cache, CORS *) sibling to /events.ics whole-calendar feed
- iter175uxprev/next nav on /clubs/[slug] (alphabetical EN sort)completes detail-page nav set across news (172) events (173) athletes (174) clubs (175)
- iter174uxprev/next nav on /athletes/[slug] completes the trio (news iter 172 + events iter 173 + athletes iter 174); active roster sorted alphabetically by EN name, edge entries single card, RTL-aware
- iter173uxprev/next event navigation on /events/[slug] mirrors iter 172 news pattern (sorted by date newest-first, RTL-aware arrows, line-clamp-2 titles, edge events single card)
- iter172uxprev/next article navigation on /news/[slug]grid 2-col older+newer cards, RTL-aware arrows, line-clamp-2 titles, hover green-ofc border; edge articles show single card
- iter171api/api/openapi.json OpenAPI 3.1 descriptor (15 paths: entities+aggregates+ops, slug/id path params, envelope schema, Health schema, CC BY 4.0 license, contact [email protected]) registered in /api/public index, 1h cache
- iter170docs/developers public API + feeds documentation page (bilingual; Registry/Entities/Feeds/Discovery tables; 14 JSON endpoints + 7 CSV/RSS/ICS + 6 discovery files; curl example; cache+CORS notes); added to sitemap-pages.xml
- iter169export/committee.csv (id, nameEn, nameAr, roleEn, roleAr, isBoard, joinedAtNO email/phone; 7 active members) completing CSV export set with athletes/clubs/events/results; text/csv attachment, 600s cache, CORS *
- iter168api/api/public/news/[slug] (slug, titleEn/Ar, date, coverPhoto, bodyEn/Ar, url) + /api/public/clubs/[slug] (slug, names, city, notes, public contact, url)both 404 on unknown, 600s cache, completing per-entity detail pattern with iters 166 (athletes) and 167 (events)
- iter167api/api/public/events/[id] individual event JSON (id, titleEn/Ar, date, tag/Ar, photo, descEn/Ar, url)404 on unknown, 600s cache, for partner embeds and calendar integrations
- iter166api/api/public/athletes/[slug] individual athlete JSON (id, slug, nameEn/Ar, discipline, category, gender, club, photo, bioEn/Ar, medals, highlights, FIE fields)matches by slug OR id, 404 on unknown/inactive, 600s cache, for partner embeds and share-card generators
- iter165seorobots.txt rewritten: old blanket Disallow /api/ hid public JSON feeds from crawlers; now explicit Allow /api/public /api/health /.well-known/ and explicit Disallow /board /my /account /admin /api/admin /api/auth /api/board /api/my /api/ai /api/committee
Wed, 22 Apr 2026 · 30 entries
- iter164seo/opensearch.xml OpenSearch 1.1 descriptor (EN + AR, 16/32/192 icons, search template /search?q=) + <link rel='search'> in Base.astro so browsers (Firefox/Chrome/Safari) can add fencing.om as a built-in search engine
- iter163api/api/public/latest combined one-call feed (5 latest events + 5 latest news + 10 latest results) 300s cache, so widgets don't chain 3 API calls; registered in /api/public index
- iter162api+seo/api/public/upcoming (future events only, sorted soonest first, 600s cache, registered in /api/public index) + sitemap-pages dedup /partners and /hall-of-fame were each listed twice
- iter161api/api/public/committee (7 active members, id/nameEn/Ar/roleEn/Ar/photo/bioEn/Ar/isBoard/joinedAt sorted by order)email/phone deliberately omitted, private contact only via rate-limited /api/committee/contact; registered in /api/public index
- iter160seositemap-pages.xml now indexes all 19 /tools/* routes (door-check-qr first-aid floor-captain kit-check penalty-tracker risk-assessment session-plan share-card training-load training-log training-plan weekly-digest added to the existing 7); 20 total tool entries
- iter159fix/athletes/[slug] second missing import streakForAthlete (same file)all 13 athlete profile pages now return 200 (slugs that don't exist return 302 to /athletes, by design)
- iter158fix/athletes/[slug] 500missing import pctLast30Days from lib/training, caught by module-audit agent
- iter157seositemap-pages.xml now covers 24 previously-missing public routes (/activity /changelog /announcements /league /contact /coach-corner /beginner-pathway /lessons /glossary /rules-summary /scoring /spectator-info /referee-signals /target-areas /mental-game /strength /stretches /nutrition /statistics /achievements /medals /scholarship /security /code-of-conduct) so crawlers finally discover them
- iter156api+footer/api/public/results endpoint (last 200 tournament results with athlete names, medal, placing, level, source) + footer now links /code-of-conduct + /security alongside /privacy + /terms in both EN and AR
- iter155fix/api/public/stats breakdown zeros (discipline is 'Foil'/'Épée'/'Sabre' capitalized+accented; gender is 'Male'/'Female' capitalized; normalise to lowercase ASCII before matching) + sum athlete.medals.{gold,silver,bronze} to top-level medals block
- iter154api/api/public/clubs (8 clubs) + /api/public/stats (counts + weapon/gender breakdown) CORS * 600s cache, registered in /api/public index
- iter153governance/code-of-conduct bilingual 8-section page (who, values, expectations, prohibited, safeguarding, anti-doping, enforcement, agreement) linked to /safeguarding /anti-doping /decisions
- iter152ops/humans.txt + /api/health (uptime probe with intentionally minimal surface: no PID/mem/SHA)
- iter151securityRFC 9116 /.well-known/security.txt + bilingual /security responsible-disclosure page (scope, how-to-report, in/out-of-scope, safe harbour, acknowledgments) thematic followup to pass-2 codex fixes
- codexcodex challenge mode found 4 real concurrency bugs (P1 role-requests lost-update race; P2 pending-changes same; P2 rate-limit bypass via cancelOwn splice; P2 athletes.json last-write-wins) + 2 bonus bugs (double-approval guard, ClaimWizard duplicate note fields) ALL FIXED with withFileLock wrappers, status='cancelled' marking, updateAthlete atomic helper, disabled hidden panels · 20 unit + 7+42+11 E2E all green on prod
- crud11-case write-path CRUD suite added (claim+approve, bio+approve, medical direct, emergency direct, camp registration, newsletter, permission gates x3, rate limit, UI /my)snapshot+restore rig keeps prod data pristine · surfaced real API bug fixed: notify() was awaited and blocked redirects; switched to fire-and-forget across /api/my/claim + /api/board/approvals · 60 total E2E assertions passing on live prod
- deep11-case depth-audit spec added (mobile overflow, Arabic CSS hide, identity menu, ⌘K switcher, sidebar active, app grid integrity)zero real bugs found; initial false-positive on Arabic h1 traced to Playwright :has-text matching hidden descendants · 49 total E2E assertions green
- modulesauthenticated module sweep 31/31 greenevery /board module + /my + /admin pages verified (HTTP 200 + expected text + no console errors + no failed requests) using production admin session · test harness committed at tests/e2e/module-sweep.spec.ts + scripts/module-sweep.sh
- icons6 broken Tabler refs replaced (polls:chart-bar, approvals:checks, contracts:contract, overview empty:circle-check, settings head-coach:user-star) audited 5699 glyphs · 20 unit + 7 E2E green
- i18nadmin Arabic labels were display:none because global.css never un-hid .ar-onlyadded display:revert rules matching Base.astro parity; every Arabic label across /board /my sidebar topbar role cards approvals app grid module header now renders · 20 unit + 7 E2E green
- admin-shell/my migrated onto Admin layout (user-heart icon, ModuleHeader, same topbar as /board) + full mobile pass (responsive topbar, chip collapse, tile sizing, welcome hero break-words) · 20 unit + 7 E2E green
- boardOdoo-style app launcher on /board home (no sidebar, category-tinted tile grid, staggered fade-in) + ModuleHeader with back-arrow and ⌘K-searchable app switcher sheet · 20 unit + 7 E2E green
- boardBoardMemberCard on /my (4-up KPIs + next-meeting hero + open-actions list) + tab-bar edge fades + auto-scroll active into view · 20 unit + 7 E2E green
- ui-uxApp Store polish across /board + /my: IdentityChip, My.astro shell, sidebar stripe, role-card unification, ApprovalsList field diff, design tokens + motion primitives · 20 unit + 7 E2E green
- multi-roleMyFamilyCard for staff-who-are-parents + Playwright E2E 7/7 green
- multi-roleRefereeCard live (availability direct, cert renewal banner)
- multi-roleSecretaryCard live (club-edit + announcement submit, write-through on approve)
- multi-roleParentCard live (per-child AthleteCards, add-child CTA)
- multi-roleAthleteCard live (medical direct, emergency direct, profile via approvals)
- multi-roleclaim+approve flow deployed (OTP dispatch, /my shell, ClaimWizard, Approvals tab, notifications, role-requests+pending-changes stores)
Tue, 21 Apr 2026 · 123 entries
- iter150featureFINALE · Changelog/changelog (public log of all 150 sprint iters, grouped by day, kind filters, sprint-complete hero) · SPRINT 150/150 COMPLETE
- iter149featureActivity timeline/activity (unified news/events/results/media timeline, 4 time buckets, kind filter chips)
- iter148featureHomepage video embedVideoFeature block after Gallery (click-to-load youtube-nocookie, lazy poster, subscribe CTA)
- iter147featureCamp registration backend/camps/register form + /api/camps/register POST (JSON store + coaching@ email, 5 camps seeded)
- iter146featureShare-card generator/tools/share-card (1200x630 social card, live SVG preview, 5 accents, PNG+SVG download)
- iter145featureCoach certification/coaches/certification (5-level pathway Assistant→FIE Master + directory of 8 certified coaches)
- iter144featureInter-club league/league (weighted points: medal value × event level multiplier, live from results)
- iter143featurePersonal training plan/tools/training-plan (4-week generator by weapon/level/days/goal; skill/strength/sparring/recovery)
- iter142featureAlumni & legends page/athletes/alumni (6 curated pioneers + auto-merge with inactive athletes + add-your-name CTA)
- iter141featureWeekly digest preview/tools/weekly-digest (email-ready template, live next event + YTD medals + latest 3 news, copy HTML button)
- iter140featureAnnouncements page/announcements with 6 seeded notices (policy/club/competition/safeguarding/governance), type filter chips, CTA
- iter139featurePenalty tracker tool/tools/penalty-tracker (cards by fencer, auto-escalate 2nd yellow, CSV export)
- iter138featureTraining-load tool/tools/training-load (sRPE, weekly load, ACWR, monotony, strain; localStorage, seed data)
- iter137featureDoor-check QR tool/tools/door-check-qr (A4 printable badge, live form, goqr.me render)
- iter136featureCoach corner blog/coach-corner with 6 seeded posts (technique/mental/parents/career) + pitch CTA
- iter135featureContact page/contact with 6-department mailto routing (general/press/coaching/clubs/scholarship/safeguarding)
- iter134featureNews archive TOC/news/archive grouped by year+month with jump-to-year chips
- iter133feature404 polishsearch form + Off-the-piste copy + sitemap link
- iter132featureHuman sitemap/sitemap (74 links across 12 themed sections)
- iter131featureHomepage coach CTA blockdark-gradient section between About and AthletesFeature, buttons to /lessons + /coaches + /beginner-pathway
- iter130featureRules summary infographic/rules-summary (9 emoji cards: hit/priority/length/3 cards/safety/piste/salute + cross-links)
- iter129featureBeginner pathway/beginner-pathway (6-step visit→signup→basics→base→first-comp→squad, timeline chips, cross-links)
- iter128featurePrintable calendar/calendar-print (A4 portrait, year-grouped events with date tiles, past strike-through, tape-to-wall format)
- iter127featureScholarship programme/scholarship (commitment/coverage/eligibility/application/confidentiality/funding + confidential email CTA)
- iter126featureClubs CSV export/clubs.csv (slug/name/city/active/gold/silver/bronze/score/url) + link on /club-leaderboard
- iter125featureReferee signals poster/referee-signals (10 signals across 5 categories, emoji icons, bilingual descriptions)
- iter124featureStrength program/strength (4 blocks: lower/specific/core/weapon-arm, weekly schedule, safety caveats)
- iter123featureTraining log tool/tools/training-log (weekly 7-day table: session/min/RPE/notes/mood + reflections, A4 portrait)
- iter122featureTarget areas/target-areas (inline SVG silhouettes for foil/épée/sabre with green-shaded valid zones + off-target notes)
- iter121featureIndividual lessons/lessons (4 tiers trial/foundation/performance/group + request form posting to /api/contact)
- iter120featureSpectator info/spectator-info (7 sections: what to expect, seat, etiquette, dress, photo, kids, Qs + quick-links)
- iter119featureScoring explainer/scoring (6 sections: electric box, target, priority, bout length, cards, spectator shortcut)
- iter118featureMatch-day kit checklist/tools/kit-check (28 items, 6 categories: weapons/armour/clothing/hydration/paperwork/extras, A4 portrait print)
- iter117featureFencing glossary/glossary (20 EN+AR terms, live search filter, letter-jump chips, empty-state)
- iter116featureMental game/mental-game (pre-bout routine, box breathing, reset after lost touch, focus cues, sleep, when to seek help) + cross-links
- iter115featureInjury-prevention stretches/stretches (6 warm-up + 7 cool-down with reps/holds/focus + 5 red-flag signals)
- iter114featureAthlete nutrition/nutrition (6 EN+AR sections: hydration/pre/match-day/recovery/Ramadan/supplements + medical disclaimer)
- iter113featureFloor captain checklist/tools/floor-captain (22-point running order, 5 phases, A4 portrait print)
- iter112featureTournament registration/register (auto-populated event dropdown, athlete/contact/medical/consent fields, POST /api/contact, 48h confirmation)
- iter111featureFirst-aid checklist/tools/first-aid (23-point medical readiness: personnel/equipment/venue/paperwork, tick-boxes, sign-line, A4 portrait)
- iter110featureAchievements feed/achievements (unified newest-first stream of milestones + medals grouped per event, cross-links to history/HoF/results)
- iter109featureRisk assessment template/tools/risk-assessment (8 pre-filled hazards, L×S scoring, L/M/H colour chips, inline editable, A4 landscape print)
- iter108featureSession plan tool/tools/session-plan (6 phase blocks w/ minute totals, inline editable, A4 print, pre-filled template)
- iter107featurePublic statistics dashboard/statistics (8 headline cards + medal-by-type/weapon/year charts, live-computed from existing data)
- iter106featureSitemap catch-up14 new URLs in sitemap-pages.xml (8 club details + 3 tools + 7 pages added across iters 65-103)
- iter105featureEvent runsheet tool/tools/runsheet (day-of-show timeline builder, inline editable rows, A4 landscape print, pre-filled template) + Tools hub Ready
- iter104featureSearch filter pillsper-type result counts, auto-dim empty types, updates on every query
- iter103featureClub detail pages/clubs/[slug] dynamic routes, SportsTeam JSON-LD, filtered athlete grid, quick-links to training/venues/join
- iter102featureEvents tag filterdynamic pill row above card grid, filters by event.tag, empty-state, client-side
- iter101featureSponsor application/partners/apply (5-tier pricing, full form w/ tier+budget+goals, honeypot, POST to /api/contact) + /partners CTA updated
- iter100featureMILESTONE Homepage medal tickerbilingual animated marquee of 20 recent medals (emoji + athlete + event + year), reduced-motion safe, RTL-aware
- iter99featureHomepage testimonialrotating bilingual pull-quote (President/HeadCoach/Board), dark section between Gallery and Instagram
- iter98featureResults medal chartstacked horizontal bars per year (G/S/B) with counts + totals + legend
- iter97featureNewsletter archive/newsletter-archive (empty-state w/ live sub count + what-to-expect + inline subscribe form)
- iter96featureDrills category filter6-pill client-side filter (Footwork/Point/Distance/Parry/Tactics/Conditioning) above card grid
- iter95featureEvents CSV export/events.csv (id/date/title/tag/photo/url) + CSV button on /events
- iter94featureAthletes CSV export/athletes.csv (id/slug/name/weapon/category/club/photo/url cols) + link on /athletes filter bar
- iter93featureResults CSV export/results.csv endpoint + Download CSV button on /results, extracted resultsData lib for reuse
- iter92featureParents FAQ/parents (10 EN+AR questions: age/safety/time/cost/academics/supervision/mixed/travel/quitting/talent + trial CTAs)
- iter91featureAthlete comparison/tools/compare?a=&b= SSR, side-by-side G/S/B + intl + recent date + profile link, hub promoted Ready
- iter90featureClub medal leaderboard/club-leaderboard (weighted rank by level+medal, G/S/B + athletes + intl + score cols, medal-coloured position chips)
- iter89featureBout slip generator/tools/bout-slip (printable DE match slip, red/green score boxes, card cols, signatures, 2 per A4) + promote Ready
- iter88featureResults filtersyear + medal + search across athlete/event/discipline, count indicator, reset button, auto-hide empty year blocks
- iter87featureVenue directory/venues (8 club venues, EN+AR address, parking, Google/Waze/Apple maps links)
- iter86featureHomepage partners stripOOC/MCSY/FIE/FCA tiles above footer, bilingual, links out + to /partners
- iter85featureSitemap index split/sitemap.xml is now sitemapindex with 4 child sitemaps (pages/news/events/athletes), 48 pages + dynamic entries, hreflang alternates
- iter84featureHomepage next-event countdownlive days/hrs/min/sec to soonest upcoming event, bilingual, calendar CTAs
- iter83featureAdvanced athlete filters/athletes category + club selectors + name search, match count, reset button, empty-state
- iter82featureNews archive filters/news year pill filters + EN/AR search, count indicator, empty-state reset link
- iter81featureFAQ rich searchlive client-side EN+AR filter, match counter, clear button, empty-state CTA, auto-expand matches
- iter80featureWeapon check tool/tools/weapon-check (11-point FIE safety checklist per fencer, printable cards, CSV template) + promote Ready
- iter79featurePoule sheet generator/tools/poule-sheet (NxN printable grid, canonical FIE bout order pools 4-10, V/M/TS/TR/Ind cols, A4 landscape) + promote Ready
- iter78featureBout timer/tools/bout-timer (FIE 3x3min + priority, red/green scoreboard, 10s chime, kbd shortcuts) + promote Ready on hub
- iter77featureTools hub/tools (pool + bracket ready, 4 'soon' tools placeholders, tool-request CTA)
- iter76featureDE bracket generator/tools/bracket (cross-seed order, auto power-of-2 with BYEs, 8-128 tables, CSV/copy/print)
- iter75featurePool assignment tool/tools/pools (client-side snake/sequential/random seeding from paste roster, CSV/print/copy)
- iter74featureJoin OFC funnel/join (5-step onboarding with cross-links to clubs/fees/safeguarding/anti-doping/rankings)
- iter73featureTraining times/training (weekly grid across 9 club sessions with days/time/group)
- iter72featureEquipment guide/equipment (3 weapons + 6-item FIE-standard safety kit + where-to-buy)
- iter71featureFees & licences/fees (6 tiers: athlete/club/coach/ref/event/hardship, transparent OMR pricing)
- iter70featureCookie notice/cookies (detailed table of 4 cookies + purpose + lifetime + type)
- iter69featureNational rankings/rankings (auto-computed by weapon from results, weighted score tables)
- iter68featureDrill library/drills (6 drills across footwork/point/distance/parry/tactics/conditioning + submit-drill CTA)
- iter67featureCamps & programmes/camps (6 tiers: U12/U15/U20/Sen/Ref/Coach + registration CTA)
- iter66featureReferees & officials/referees licensed list + 4-step pathway + clinic CTA
- iter65featureCoaches directory/coaches pulls coach-role team members + certification CTA
- iter64featureVolunteer signup/volunteer (6 role cards, form with honeypot + checkbox interests + phone, POST to /api/contact, toast on success)
- iter63featurePartners & sponsors/partners (4 tiers w/ accent gradients: governing/international/regional/academic, partnership CTA)
- iter62featureHall of Fame/hall-of-fame (weighted medal score by level+medal, top-24 cards w/ gold/silver/bronze, landmark firsts timeline)
- iter61featureAccessibility statement/accessibility (WCAG 2.1 AA commitment, 10 features, 3 known limitations, testing/review process, feedback CTA)
- iter60featureTerms of use/terms (10 EN+AR sections) + footer Privacy/Terms links in bottom bar
- iter59featurePrivacy policy/privacy (10 EN+AR sections: what, why, sharing, retention, rights, cookies, minors, security)
- iter58featureSafeguarding policy/safeguarding (7 sections, standards of behaviour, screening, reporting, ROP 9999 callout, Safeguarding Officer CTA)
- iter57featureAnti-doping page/anti-doping (WADA Code, testing, TUE, whereabouts, education, sanctions, confidential reporting CTA)
- iter56featurePress kit/press (fact sheet, EN+AR boilerplate, 8 downloads inc RSS/ICS/JSON API, media contact)
- iter55featurePublic JSON API/api/public + /events + /news + /athletes (CORS *, 5-min cache) for press/ministry integration
- iter54featureEvents .ics calendar feed/events.ics VEVENTs with RFC 5545 folding, Asia/Muscat TZ, subscribe CTA on /events
- iter53featureNews RSS feed/news.rss.xml (40 items, enclosures for cover photos, stripped-md descriptions) + autodiscovery <link> in Base
- iter52featureElections module/elections mandate+countdown+eligibility+8-step timeline+secretariat CTA, bilingual, JSON-LD breadcrumb
- iter51featureAGM minutes archive/agm (year-grouped completed meetings filtered by AGM/General Assembly keywords, empty-state + next-AGM call-out, cross-links bylaws/events)
- iter50featureConstitution & bylawspublic /bylaws page with 10 EN+AR articles, sticky ToC, JSON-LD breadcrumb, footer quick link
- iter49featureNewsletter sign-upfooter form posting to /api/newsletter/subscribe (honeypot, IP rate-limit, re-sub, /unsubscribe token) + /admin/newsletter list + CSV export
- iter48featureToast notificationswindow.toast(msg,kind) + auto-promote ?saved/?deleted/?error URL params into toast + scrub URL
- iter47featureKeyboard shortcuts/ search, ? help, Esc close, g+letter jump to Overview/Team/Meetings/Actions/Polls/Decisions/Updates/News/Events
- iter46featureSite-wide search/search UI + /api/search across athletes/results/news/events/decisions/policies + / keyboard shortcut
- iter45featurePublic /decisions logministry-transparency view of every board decision, year filter, outcome chips, cross-links governance + committee
- BATCH 3 (10 parallel sub-agents)Time-box timer + Chair private notes + Action sub-tasks + Role delegation + Member-at-risk + Growth log + Training attendance + Injury tracker + Coach private notes + Athlete goals
- iter34featurePublic /org-chart pagehierarchical board tree from team.json with Organization JSON-LD for SEO
- iter33featureBoard term trackertermStartsAt/EndsAt/Notes on TeamMember + Overview alert card when terms expire within 90d
- iter32featureAction escalation 14d14+ days overdue fires WA+email to every admin + tags action as 'escalated'
- iter31featureAthlete passport PDFGET /athletes/<slug>.passport — credit-card-sized ID card with photo, name EN+AR, weapon, born, ref, medals, QR
- iter30featureHybrid Zoom/Teams/Meet linkvideoUrl/videoProvider field + Join button on meeting page + WA reminder includes link
- iter29featureQuorum checker ribbongreen/amber/red status on scheduled meetings, defaults to majority of active board members
- iter28featureGroups & sub-committees/board?t=sub-committees + 4 seed committees + admin CRUD
- BATCH 2 (10 parallel sub-agents)Conflicts + Selections + Disciplinary + MoYC + Correspondence + Contracts + Letter generator + Insurance + Grants + Budget+Expenses · all merged + tabs wired
- BATCH (10 parallel sub-agents)Decisions register + Agenda templates + Meeting RSVP + Read-receipts + AI board-chat + Discussions + Surveys + PWA + Governance hub + Motions
- iter5featureDigital Board Packet PDF/admin/meetings/<id>.packet + buttons on both meeting views · plans/master.md + wave-a detail shipped
- iter4featureeSignatures (Boardable parity #2)/admin/signature + /api/board/signature + draw canvas + stamp upload + signing event log
- iter3featurePolls & async voting (board-committee Boardable parity)/board?t=polls + /api/board/poll + auto WA to eligible voters on create
- iter2planning100 missing features catalogued in docs/100-missing-features.md · 9 clusters × 8-12 features each · loop will work through these
- iter2featureAthlete Results & Medal Tracker/admin/results + /medals + Result type + medalLeaderboard
- iter1securityOWASP baseline headers (HSTS/CSP/XFO/XCTO/Referrer/Permissions) via sequence middleware · commit 9092e55
- iter0cron 7,27,47 * * * *22-minute cadence · iteration 0 = kickoff
Sprint complete
150 iterations, one site. The next phase is whatever clubs, athletes, coaches and the board actually ask for. If something here is wrong or missing, tell us — [email protected].
Raw log also available as plain text on GitHub. Site source: fencing.om monorepo.