CMS & Websites
135 features · 19 subsystems
Every tenant (FIPJP, continental, national federation), region, and club gets their own website with a unique URL and full CMS capabilities. The CMS is a core differentiator — replacing the fragmented, outdated websites that federations and clubs manage today.
Multi-Site Platform
F18.01- F18.01.01 Shipped
One site per tenant/club/region with unique URL
✅ PL-F1801a - F18.01.02 Shipped
Platform subdomain (e.g., norrbotten-bk.petanque-life.com)
✅ PL-F1801a - F18.01.03 Shipped
Custom domain support (e.g., www.norrlandbk.se) with auto-SSL
✅ PL-F1801a - F18.01.04 Shipped
Site creation wizard (pick template, set branding, go live)
✅ PL-F1801a - F18.01.05 Shipped
Site activation/deactivation
✅ PL-F1801b - F18.01.06 Shipped
Tenant-scoped site management (federation admin manages federation site + club sites)
✅ PL-F1801b - F18.01.07 Shipped
Site directory (find federation/club websites)
✅ PL-F1801b - F18.01.08 Shipped
Path-prefix routing — child OrgNode-CmsSites kan mountas under förälderns domän (www.svenskboule.se/<distrikt>/); 1–3 nivåer; reserverar systemslugs; canonical URL pekar på path-formen
✅ PL-T233
Page Builder
F18.02- F18.02.01 Shipped
Drag-and-drop page builder with content blocks
✅ PL-F1802a - F18.02.02 Shipped
Block types: text, image, gallery, video, map, embed, form, columns
✅ PL-F1802a - F18.02.03 Shipped
Dynamic data blocks: ranking table, results, calendar, club directory, venue map
✅ PL-F1802a - F18.02.04 Shipped
Page templates library (homepage, about, contact, competition, news)
✅ PL-F1802a - F18.02.05 Shipped
Custom page creation with SEO-friendly URLs — PL-F1802b
✅ PL-F1802b - F18.02.06 Shipped
Page versioning and draft/publish workflow — PL-F1802b
✅ PL-F1802b - F18.02.07 Shipped
Page scheduling (publish at future date) — PL-F1802b
✅ PL-F1802b - F18.02.08 Shipped
Reusable block components (header, footer, sidebar) — PL-F1802b
✅ PL-F1802b
Theme & Branding Engine
F18.03- F18.03.01 Shipped
Per-site theming (colors, fonts, logo) — PL-F1803a
✅ PL-F1803a - F18.03.02 Shipped
Pre-built theme templates (modern, classic, sport, minimal) — PL-F1803a
✅ PL-F1803a - F18.03.03 Shipped
Header/footer layout customization — PL-F1803a
✅ PL-F1803a - F18.03.04 Shipped
Custom CSS injection (for advanced users) — PL-F1803a
✅ PL-F1803a - F18.03.05 Shipped
Responsive design (mobile-first) — PL-F1803b
✅ PL-F1803b - F18.03.06 Shipped
Dark mode support — PL-F1803b
✅ PL-F1803b - F18.03.07 Shipped
Federation brand inheritance (club sites can inherit national branding) — PL-F1803b
✅ PL-F1803b - F18.03.08 Shipped
Default-tema: bottle-green + ivory, Fraunces display + Inter body, shadcn-parity med www — PL-T109
✅ PL-T109
Blog & News
F18.04- F18.04.01 Shipped
Article creation with rich text editor — PL-F1804a
✅ PL-F1804a - F18.04.02 Shipped
Categories and tags — PL-F1804a
✅ PL-F1804a - F18.04.03 Shipped
Featured image and excerpt — PL-F1804a
✅ PL-F1804a - F18.04.04 Shipped
Article scheduling (publish at future date) — PL-F1804a
✅ PL-F1804a - F18.04.05 Shipped
Multi-author support — PL-F1804b
✅ PL-F1804b - F18.04.06 Shipped
News feed aggregation (pull news from parent federation) — PL-F1804b
✅ PL-F1804b - F18.04.07 Shipped
RSS feed generation — PL-F1804b
✅ PL-F1804b - F18.04.08 Shipped
Comment system (moderated) — PL-F1804b
✅ PL-F1804b
Navigation & Structure
F18.05- F18.05.01 Shipped
Menu builder (custom navigation) — PL-F1805
✅ PL-F1805 - F18.05.02 Shipped
Auto-generated pages (rankings, calendar, results — pulled from API) — PL-F1805
✅ PL-F1805 - F18.05.03 Shipped
Breadcrumb navigation — PL-F1805
✅ PL-F1805 - F18.05.04 Shipped
Search within site — PL-F1805
✅ PL-F1805 - F18.05.05 Shipped
Sitemap generation (XML for search engines) — PL-F1805
✅ PL-F1805 - F18.05.06 Shipped
Footer customization (links, contact info, social media) — PL-F1805
✅ PL-F1805
Media Library
F18.06- F18.06.01 Shipped
Image upload and management per site — PL-F1806a
✅ PL-F1806a - F18.06.02 Shipped
Automatic image optimization (resize, compress, WebP) — PL-F1806a
✅ PL-F1806a - F18.06.03 Shipped
Document upload (PDF, Word) — PL-F1806a
✅ PL-F1806a - F18.06.04 Shipped
Video embedding (YouTube, Vimeo, direct upload) — PL-F1806a
✅ PL-F1806a - F18.06.05 Shipped
Photo gallery creation
✅ PL-F1806b - F18.06.06 Shipped
CDN delivery for all media
✅ PL-F1806b - F18.06.07 Shipped
Storage quota per site
✅ PL-F1806b - F18.06.08 Shipped
Public + lösenordsskyddad media via blob storage (Azure) — PL-T234
✅ PL-T234
Forms & Interaction
F18.07- F18.07.01 Shipped
Form builder (contact, feedback, registration interest) — PL-F1807
✅ PL-F1807 - F18.07.02 Shipped
Form submissions management (view, export, notify) — PL-F1807
✅ PL-F1807 - F18.07.03 Shipped
Email notification on form submission — PL-F1807
✅ PL-F1807 - F18.07.04 Shipped
Anti-spam protection (captcha) — PL-F1807
✅ PL-F1807 - F18.07.05 Shipped
Event RSVP / sign-up forms — PL-F1807
✅ PL-F1807
SEO & Analytics
F18.08- F18.08.01 Shipped
Per-page meta titles and descriptions — PL-F1808
✅ PL-F1808 - F18.08.02 Shipped
Open Graph images for social sharing — PL-F1808
✅ PL-F1808 - F18.08.03 Shipped
Structured data (JSON-LD: SportOrganization, Event, etc.) — PL-F1808
✅ PL-F1808 - F18.08.04 Shipped
Analytics integration (privacy-respecting, e.g., Plausible/Umami) — PL-F1808
✅ PL-F1808 - F18.08.05 Shipped
Page performance monitoring — PL-F1808
✅ PL-F1808 - F18.08.06 Shipped
Search engine indexing control (robots.txt, canonical URLs) — PL-F1808
✅ PL-F1808
Multi-Language Sites [DONE] `PL-F1809`
F18.09- F18.09.01 Shipped
Multi-language page content (parallel versions per language)
✅ PL-F1809 - F18.09.02 Shipped
Language switcher in navigation
✅ PL-F1809 - F18.09.03 Shipped
Default language per site
✅ PL-F1809 - F18.09.04 Shipped
Translation workflow (flag pages needing translation)
✅ PL-F1809 - F18.09.05 Shipped
hreflang tags for SEO
✅ PL-F1809
Role-Based Editing [DONE] `PL-F1810`
F18.10**PL-F1810: F18.10 Role-Based Editing** — Implemented:
How it works- F18.10.01 Shipped
Federation editor role (manages federation site) — PL-F1810
✅ PL-F1810 - F18.10.02 Shipped
Club editor role (manages club site only) — PL-F1810
✅ PL-F1810 - F18.10.03 Shipped
Region editor role (manages region landing page) — PL-F1810
✅ PL-F1810 - F18.10.04 Shipped
Content approval workflow (draft > review > publish) for larger federations — PL-F1810
✅ PL-F1810 - F18.10.05 Shipped
Audit trail on all content changes — PL-F1810
✅ PL-F1810 - F18.10.06 Shipped
Content scheduling permissions (who can publish immediately vs. schedule) — PL-F1810
✅ PL-F1810
Dynamic Data Integration
F18.11**PL-F1811a: F18.11 Dynamic Data Integration del 1/2** — Implemented:
How it works- F18.11.01 Shipped
Ranking table widget (auto-updated)
✅ PL-F1811a - F18.11.02 Shipped
Competition calendar widget
✅ PL-F1811a - F18.11.03 Shipped
Recent results widget
✅ PL-F1811a - F18.11.04 Shipped
Club directory widget
✅ PL-F1811a - F18.11.05 Shipped
Venue map widget
✅ PL-F1811a - F18.11.06 Shipped
Live score widget (during competitions) — PL-F1811b
✅ PL-F1811b - F18.11.07 Shipped
Player profile widget — PL-F1811b
✅ PL-F1811b - F18.11.08 Shipped
Federation statistics widget (member count, club count, etc.) — PL-F1811b
✅ PL-F1811b - F18.11.09 Shipped
Upcoming events widget — PL-F1811b
✅ PL-F1811b - F18.11.10 Shipped
Sponsor banner widget — PL-F1811b
✅ PL-F1811b
Theme & Customization
F18.12**PL-F1812b: F18.12 CMS theme och customization del 2/2** — Implemented:
How it works- F18.12.01 Shipped
Theme gallery with live preview — PL-F1812a
✅ PL-F1812a - F18.12.02 Shipped
Per-club color scheme presets — PL-F1812a
✅ PL-F1812a - F18.12.03 Shipped
Custom CSS injection enhancements (variables, scoping, validation) — PL-F1812a
✅ PL-F1812a - F18.12.04 Shipped
Logo upload with auto-sizing (8 variants) — PL-F1812a
✅ PL-F1812a - F18.12.05 Shipped
Header/footer layout selection — PL-F1812b
✅ PL-F1812b - F18.12.06 Shipped
Page width and content max-width configuration — PL-F1812b
✅ PL-F1812b - F18.12.07 Shipped
Font pair selection (heading + body) — PL-F1812b
✅ PL-F1812b - F18.13.01 Shipped
Enhanced per-page meta title/description with configurable title templates, length limits, auto-description, SEO preview and audit endpoints
✅ PL-F1813a - F18.13.02 Shipped
Enhanced Open Graph tags with og:locale and og:locale:alternate for multi-language sites plus article-specific OG properties
✅ PL-F1813a - F18.13.03 Shipped
Dedicated Twitter Card support with site-level defaults, per-page creator handle, separate twitter:image:alt, and card type fallback
✅ PL-F1813a - F18.13.04 Shipped
Schema.org SportsClub structured data with sport="Pétanque", logo, sameAs social profiles, and memberOf federation hierarchy
✅ PL-F1813a - F18.13.05 Shipped
Auto-generated sitemap.xml for CMS sites with lastmod, changefreq, priority, and xhtml:link hreflang alternates for multi-language sites
✅ PL-F1813b - F18.13.06 Shipped
Enhanced robots.txt per CMS instance with crawl-delay, custom disallow/allow patterns, user-agent rules, and sitemap reference
✅ PL-F1813b - F18.13.07 Shipped
Enhanced canonical URLs with language-aware resolution (default uses clean path, non-default includes prefix) and canonical+alternates endpoint
✅ PL-F1813b - F18.13.08 Shipped
hreflang link tags for all available language versions plus x-default pointing to default language with partial translation awareness
✅ PL-F1813b
Custom Domains via Caddy reverse proxy [DONE] `PL-T232`
F18.14**PL-T232 — Caddy reverse proxy ersätter Cloudflare for SaaS** som plattformens primära väg för CMS-custom domains. Den tidigare Cloudflare-implementationen (PL-T046) lämnas som vilande alternativ i `services/cloudflare_saas.py`.
How it works- F18.14.01 Shipped
Custom hostname-registrering via CustomDomain-modell — PL-T232
✅ PL-T232 - F18.14.02 Shipped
CNAME/TXT-valideringsflöde med dig-baserad DNS-lookup — PL-T232
✅ PL-T232 - F18.14.03 Shipped
Automatisk TLS-provisionering via Caddy + Let's Encrypt HTTP-01 — PL-T232
✅ PL-T232 - F18.14.04 Shipped
/public/domains/cert-allowed-gate mot Let's Encrypt-abuse — PL-T232
✅ PL-T232 - F18.14.05 Shipped
Admin-UI för domänhantering med CNAME-target proxy.web.petanque.life — PL-T232
✅ PL-T232 - F18.14.06 Shipped
Plattform-subdomän-konvention <slug>.web.petanque.life — PL-T232 (auto-DNS via PL-T235)
✅ PL-T232
Premium UX (dual-mode adaptive, SSR-prestanda, editorial) [DONE] `PL-T158`
F18.15**PL-T158: F18.15 web/ premium-UX** — Implemented:
How it works- F18.15.01 Shipped
Dual-mode adaptive shell (mobile drawer + bottom-nav / desktop full nav)
✅ PL-T158 - F18.15.02 Shipped
Editorial display-skala (Fraunces opsz, ss01)
✅ PL-T158 - F18.15.03 Shipped
PetanqueImage AVIF/WebP/JPEG + focal-point + lazy/priority
✅ PL-T158 - F18.15.04 Shipped
TenantBrandStyle SSR CSS-var-injektion + auto-accent
✅ PL-T158 - F18.15.05 Shipped
SSR-prestanda + canonical + hreflang + Lighthouse-budget
✅ PL-T158 - F18.15.06 Shipped
JSON-LD Organization + WebSite per tenant page
✅ PL-T158 - F18.15.07 Shipped
Sitemap + robots med tenant-noindex-respekt
✅ PL-T158 - F18.15.08 Shipped
Skip-to-content + axe-baseline + focus-visible
✅ PL-T158 - F18.15.09 Shipped
Editorial footer + språkväxlare med session-minne
✅ PL-T158 - F18.15.10 Shipped
Shared ThemeProvider + HtmlThemeBridge
✅ PL-T158
Ministry-report PDF-template-engine [DONE] `PL-T223`
F18.16Multi-language PDF-template-resolution för `MinistryImpactReport`. Template
- F18.16.01 Shipped
MinistryReportTemplate-config per (tenant_id, funder_type, lang) med pdf_template_ref + required_sections + value_assumptions
✅ PL-T223 - F18.16.02 Shipped
Template-resolution med fallback-kedja (exact/en/tenant-default/no_template) och audit-warning vid fallback
✅ PL-T223 - F18.16.03 Shipped
PDF 1.4-wrapper utan extern dependency, deterministisk för testbarhet
✅ PL-T223 - F18.16.04 Shipped
Multi-lang PDF-export med X-Template-Resolution-header för spårbarhet
✅ PL-T223
Club inquiry CMS form-shortcode [DONE] `PL-T222`
F18.17Klubbsidor på `web/`-CMS:et exponerar ett intresseanmälnings-formulär som
- F18.17.01 Shipped
ClubInquiryFormBlock-komponent på web/, lokaliserade etiketter (en/sv/fr/es), default inquiry_type per shortcode-prop
✅ PL-T222 - F18.17.02 Shipped
Honeypot-fält (website, off-screen) + Cloudflare-Turnstile-integration via /public/config/turnstile-key
✅ PL-T222 - F18.17.03 Shipped
Block-registrering i BlockRenderer så CMS-sidor renderar type: "club_inquiry_form"
✅ PL-T222 - F18.17.04 Shipped
Public POST-endpoint /clubs/{club_id}/inquiries med rate-limit 10/h per IP och 5-min dedup på (email, club_id, subject)
✅ PL-T222
Open-Source Continuity Layer [DONE] `PL-T230`
F18.18> Spec-källa anger "F18.10 Open-Source Continuity Layer" — F18.10 är dock
- F18.18.01 Shipped
Audit-script tools/audit/audit-template-portability.mjs blockerar web/-merges om template/block importerar @/lib/api, @/lib/auth, @/lib/sse, @/lib/booking, next/headers, next/server eller läser process.env.PL_* (whitelist via tools/audit/portability-allowlist.json med obligatorisk reason)
✅ PL-T230 - F18.18.02 Shipped
Mirror-header-injicering tools/generators/inject-mirror-headers.mjs (idempotent, bevarar "use client"/"use server"-pragmas, två header-typer för portabel resp. allowlistad fil)
✅ PL-T230 - F18.18.03 Shipped
Sync-script tools/generators/sync-templates-to-oss-repo.mjs med --init (engångs-bootstrap av OSS-repot) + --sync (subtree-push från monorepo); type-only imports till @/lib/api skrivs om till ./types-relativa imports; manifest-snapshot .oss-mirror-manifest.json i OSS-targeten + tools/.state/oss-mirror-state.json i monorepot
✅ PL-T230 - F18.18.04 Shipped
Sys-endpoint GET /sys/oss-templates/status returnerar manifest-snapshot + GitHub-stats (stars, open issues, latest 5 release-tags) — gate:ad via require_any_sys_role(SYS_SECURITY,SYS_ENGINEER), cache-header private, max-age=300
✅ PL-T230 - F18.18.05 Shipped
Sys-endpoint POST /sys/oss-templates/sync enqueue:ar mirror-sync som background-job, returnerar job_id (HTTP 202) — gate:ad via require_sys_role(SYS_ENGINEER) + require_fresh_auth(300), sys.oss_templates.sync.enqueue audit-rad
✅ PL-T230 - F18.18.06 Shipped
Sys-vy views/sys/oss-templates-status (sys/app/(dashboard)/oss-templates-status.tsx) — hero med last-synced-at/commit/by, GitHub-stats-panel, mirrored-files-tabell, skipped-allowlist-lista, "Sync now"-knapp (fresh-auth via lib/api.ts); typed klient sys/src/lib/oss-templates.ts; sidebar-länk under Styrning-gruppen
✅ PL-T230 - F18.18.07 Shipped
Strategi-doc docs/business/oss-strategy.md (varför MIT, varför separat repo, copyright, risk-bedömning, Continuity Promise-formulering) + arkitektur-doc docs/engineering/architecture/03b-continuity-layer.md (3-lagers-modell, two-mechanism-jämförelse mot PL-T227/T228); pricing-rad i docs/business/business-model.md
✅ PL-T230 - F18.18.08 Shipped
Allowlist-baserad undantagsmodell tools/audit/portability-allowlist.json (4 type-only @/lib/api-templates + 25 non-portable blocks med per-block reason-fält) som audit-scriptet enforce:ar — saknad reason = audit-fail
✅ PL-T230
CMS access control: gated pages per group + grupp-modell [DONE] `PL-T205`
F18.19CMS-sidor och enskilda block kan begränsas till tre access-nivåer
- F18.19.01 Shipped
CmsAccessGroup-Beanie-dokument tenant-scopad med slug/name/kind/auto_category/auto_entity_id/member_user_ids/member_count/last_synced_at/is_active + uniqueness på (tenant_id, slug)
✅ PL-T205 - F18.19.02 Shipped
CmsPage utökad med access_level ∈ {public, members, groups}, allowed_group_ids[], preview_for_anonymous: dict[lang, str], block_access per ContentBlock
✅ PL-T205 - F18.19.03 Shipped
Auto-group-katalog (9 kategorier) seedas via POST /admin/cms-access/seed; per-grupp-sync via POST /admin/cms-access/{id}/sync; bulk-sync via POST /admin/cms-access/sync
✅ PL-T205 - F18.19.04 Shipped
Custom-grupp-CRUD /tenant/groups med audit-trail (cms.access_group_created/updated/deleted/members_added/member_removed); 409 vid radering av grupp som refereras av page
✅ PL-T205 - F18.19.05 Shipped
services.cms_access.evaluate_page_access returnerar AccessDecision ∈ {allow, require_login, denied_not_member, denied_not_in_group}; evaluate_block_access är ren (utan I/O) för per-block-gating i SSR
✅ PL-T205 - F18.19.06 Shipped
Public CMS-endpoints (/public/sites/{id}/pages, /public/sites/{id}/pages/{slug}) filtrerar listor och redacterar block enligt viewer; gated sidor läcker inte i sitemap eller söklistor
✅ PL-T205 - F18.19.07 Shipped
GET /me/groups med tenant_id/user_id/group_ids[]/is_active_member/hash (sha256 över sorterade group_ids, 32 chars) — SSR cache-key-segment
✅ PL-T205 - F18.19.08 Shipped
web/-SSR resolveViewerAccess() läser petanque_member_token-cookie + forwardar bearer; getPageBySlug byter till cache: "no-store" när auth-header skickas; AccessGatePlaceholder renderar 3 deny-decisions med i18n-preview
✅ PL-T205 - F18.19.09 Shipped
Admin-UI: /(dashboard)/cms/access-groups (lista, filter på kind/slug, seed/sync-knappar) + /(dashboard)/cms/access-groups/[id] (detalj — auto read-only, custom edit/add/remove/delete) + /(dashboard)/cms/access-groups/new (skapa custom)
✅ PL-T205 - F18.19.10 Shipped
42 backend-tester (tests/test_pl_t205_cms_access.py) över modellinvarianter, custom-CRUD, auto-seeding, access-evaluation, user-groups-payload och HTTP-routes
✅ PL-T205
No features match your filters.