# Changelog

All notable changes to website-impl are documented here.
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
Not versioned until production deployment — see `.ontology/state.ncl` for current `deployment-readiness` state.

## [Unreleased]

### Changed — Server Restructuring & on+re migration (2026-04-06)
- **Server restructured** to rustelo template pattern (app.rs, run.rs, shell.rs, resources.rs, theme.rs) — custom auth stack removed
- **Auth removed**: JWT, OTP, WebSocket hot-reload, user dashboard, server_fns.rs, database/auth.rs — `auth-system` dimension regressed to `build-time-only`
- **Project showcase pages** added: kogral, vapora, rustelo, syntaxis, typedialog, secretumvault, stratumiops, provisioning, ontoref, work_request, services
- **Post viewer simplified**: client.rs and html_generator.rs removed, only mod.rs remains
- **CSS scripts moved** from `scripts/` to `scripts/build/` subdirectory
- **on+re migration**: `state.ncl` — new `build-time-only` state in auth-system, deployment-readiness pre-production description updated, transition blockers updated
- **on+re migration**: `core.ncl` — hydration-strategy artifact paths corrected, auth-rbac-impl updated (build-time only), user-dashboard updated (removed, FTL preserved), css-asset-pipeline script paths updated, new `project-showcase-pages` node added
- **ADR-001** (website-impl): Server Template Restructuring — auth removal constraints captured

### Added — Architecture Self-Description (2026-03-14)
- **on+re protocol** integrated: `.ontology/` + `adrs/` + `reflection/` in place
- `.ontology/core.ncl` — knowledge graph as Rustelo Service consumer: axioms (`rustelo-consumer`, `bilingual-content`), tensions (hydration complexity, build-time vs runtime), project nodes (build-time codegen impl, hydration strategy, cache layer, NCL config, custom routing impl, auth RBAC, user dashboard, CSS asset pipeline)
- `.ontology/state.ncl` — four tracked dimensions: `deployment-readiness` (development → **pre-production**), `hydration-stability` (stabilized → **zero-mismatch**), `auth-system` (**operational**), `css-pipeline` (**correct**)
- `.ontology/gate.ncl` — `hydration-parity` (Low permeability, Challenge protocol), `content-integrity` (Medium, Observe protocol), `rbac-correctness` (Low, Challenge protocol)
- `.ontology/manifest.ncl` — Service manifest with EndUser, Developer, Agent consumption modes; `rustelo-browse` operational mode for cross-project framework capability browsing
- `reflection/` — backlog, constraints, defaults, qa, schema; modes: `integrity-check`, `sync-ontology`, `validate-content`, `validate-hydration`
- `adrs/adr-001-ncl-over-toml.ncl` — NCL (Nickel) over TOML for site configuration
- `adrs/adr-002-hydration-strategy.ncl` — SsrTranslator in both SSR+WASM targets; 6 hard/soft constraints including `menu-registry-language-keyed`, `reactive-closure-copy-only`, `spa-content-id-not-slug`
- `adrs/adr-003-ws-rbac-hot-reload.ncl` — WebSocket broadcast for RBAC hot-reload without server restart; 3 constraints (`content-module-always-compiled`, `chrono-non-optional`, `server-enforcement-primary`)

### Added — User Dashboard (2026-03-03)
- 5-tab authenticated user area: Perfil, Marcadores, Mensajes, Notas, Recursos
- DB migrations `005_user_dashboard_{postgres,sqlite}.sql`: `user_messages`, `user_notes`, `user_resources` tables
- `database/auth.rs`: `MessageRow`, `NoteRow`, `ResourceRow` + 7 query methods
- `server_fns.rs`: 7 server functions (`UserMessage`, `UserNote`, `UserResource`)
- `otp_service.rs` + `otp_adapter.rs`: trait + full implementation for all 7 methods
- `site/rbac.ncl`: 7 endpoint allow rules for `user` group
- `site/i18n/locales/{en,es}/pages/user.ftl`: ~20 new i18n keys per language
- `crates/pages/src/user/unified.rs`: 5-tab dashboard rewrite with signal-safety patterns

### Fixed — NavMenu Auth & RBAC (2026-03-03)
- `AuthControls` moved inline in `UnifiedNavMenu` (desktop + mobile) — no longer a fixed overlay
- `navmenu/unified.rs`: auth strings (`nav-sign-in`, `nav-sign-out`, `nav-dashboard`) computed inside reactive closures via `UnifiedI18n::new` — reactive to language changes
- `site/rbac.ncl`: authenticated `user` group allow rules for assets, `track_page_view*`, `server_update_display_name*`
- `database/auth.rs`: `parse_sqlite_datetime()` helper handles both RFC3339 and `%Y-%m-%d %H:%M:%S` — fixes OTP login panic on SQLite `datetime('now')` format

### Added — RBAC Hot-Reload via WebSocket (2026-03-01)
- `site/rbac.ncl` file-watch triggers in-process server reload of `AUTH_PATTERNS`
- New patterns broadcast over WebSocket to all connected WASM clients
- WASM receives broadcast and updates reactive signal — UI gates update without page reload
- `content` module compiled unconditionally (no feature gate); `chrono` made non-optional

### Fixed — CSS Asset Pipeline (2026-03-05)
- `scripts/build-css-bundles.js`: reads from correct source (`site/assets/styles/`, not cache)
- `scripts/download-highlight-css.js`: output to `site/public/assets/styles/` (was `public/styles/`)
- `scripts/download-highlightjs-copy-css.js`: output path fixed + converted to ES modules
- `scripts/copy-css-assets.js`: excludes `.DS_Store`, `.toml`, and `themes/` directory from public sync
- `package.json`: `highlightjs-copy:css` added to build pipeline
- `site/config/assets.ncl`: all CSS paths corrected from `/styles/` → `/assets/styles/`

### Fixed — Hydration: SPA PostViewer Cold-Cache 404 (2026-02-26)
- `item.id ≠ item.slug` for some posts — HTML files are named after `item.id`, not `item.slug`
- On cold SPA navigation: `load_content_index` returned `[]` → fallback used `url_slug` as filename → 404
- Fix: `AsyncContentUpdater::resolve_and_fetch_content` fetches `index.json`, matches `item.slug == url_slug`, then uses `item.id` for the file path
- `_content_memo` gated to `#[cfg(not(target_arch = "wasm32"))]` — was firing in WASM with wrong language

### Fixed — Hydration: WASM FTL Registry (2026-02-26)
- `FTL_REGISTRY` was never populated in WASM — all translations fell through to SSR-embedded data (initial language only)
- `crates/client/build.rs`: generates `ftl_registry_fn.rs` with `include_str!` for every `.ftl` file (46 entries for en+es)
- `crates/client/src/lib.rs`: calls `populate_wasm_ftl_registry()` at WASM startup — populates registry before any component renders
- Language switching now works correctly in WASM: `get_parsed_ftl_for_language("en")` finds all `en_*` keys

### Fixed — Hydration: Page Cache Empty HashMap (2026-02-26)
- All 15 `*Client` cache components passed `HashMap::new()` as `lang_content` — caused `HtmlContent` empty `inner_html` → tachys `<!>` placeholder → cursor desync → hydration panic
- `target/rustelo-cache/pages/page_*.rs` `*Client` components: replaced `HashMap::new()` with `SsrTranslator` + `build_page_content_patterns`
- `build_page_generator.rs` template updated — future regenerations produce structurally identical code for both targets

### Fixed — Hydration: Menu Registry Key Mismatch (2026-02-26)
- `MENU_REGISTRY` keyed `"main"` in WASM init; `get_menu(lang)` looks up by `"en"`/`"es"` → 0 items in WASM vs 6 in server
- `crates/server/build.rs` + `crates/client/build.rs`: now insert per-language keys (`"en"`, `"es"`) from `config.ncl` routes
- `navmenu/unified.rs`: `lang_signal.get_untracked()` in SSR to suppress tracking-context warning

### Added — Configuration-Driven Routing (2026-02-25)
- `routing.rs` fully rewritten: uses `ROUTE_TABLE` (BTreeMap from NCL config) — no hardcoded paths
- `build.rs`: reads `site/config/routes/*.ncl`, generates `route_table.rs` + `RouteComponent` enum
- `lib.rs`: `#![recursion_limit = "512"]` added for complex generated types

### Added — NCL Configuration (2026-02-09)
- Route configuration migrated from `*.toml` to `site/config/routes/*.ncl`
- RBAC rules in `site/rbac.ncl` with typed contracts
- Asset configuration in `site/config/assets.ncl`
- Reusable schemas in `site/schemas/` for content, menus, footer, themes
- Bilingual menus in single NCL file (eliminated en.toml/es.toml duplication)
