{"id":"69c47403296e9ae113723a5e","title":"2026 03 25 Issue 197","path":"how-to/committee/release-notes/2026-03-25-issue-197","contentMarkdown":"# 25-Mar-2026 — navbar access levels, external committee file URLs, and unreferenced page fix [#197](https://github.com/nbarrett/ngx-ramblers/issues/197)\n\n## [build 564](https://github.com/nbarrett/ngx-ramblers/actions/runs/23569609083) — [commit 4536544](https://github.com/nbarrett/ngx-ramblers/commit/45365443ff211334d9203600d5d4a23cb85d82ca)\n\n_____\n\n### Navbar access-level visibility control\n- Navbar items now support an `accessLevel` field (`public`, `loggedInMember`, `committee`, `hidden`)\n- Items are filtered from the navbar based on the current user's permissions\n- `PageAccessGuard` on dynamic routes prevents direct navigation to restricted pages\n- When a user logs out while on a restricted page, they are redirected to the home page\n- Access level column added to **Pages Within Navbar** table in System Settings\n- Migration backfills all existing navbar items with `accessLevel: \"public\"`\n- Environment seed data includes access levels (Admin defaults to `committee`)\n### System config refresh on login/logout\n- `SystemConfigService` now refreshes configuration on `MEMBER_LOGIN_COMPLETE` and\n`MEMBER_LOGOUT_COMPLETE` events so permission-gated data (e.g. Brevo email details)\nis reloaded when auth state changes\n### External URL support for committee files\n- `CommitteeDisplayService.fileUrl()` detects remote URLs via `isRemoteUrl()` and\nreturns them unchanged\n- Committee file entries can reference external PDFs that have yet to be migrated to\ninternal S3 storage\n- `committeeFileSlug()` generates a kebab-case slug from file title and event date\n### Committee file notification improvements\n- Send notification URL now uses slug-based query params instead of MongoDB IDs\n(e.g. `?committee-file=agenda-december-12-2024&source-page=council/meetings/2024-12-12`)\n- Email \"view on our site\" link now uses the source page path with an absolute URL\n- `PageService.titleFromPath()` converts paths to human-readable titles (with unit tests)\n- Source page title derived from path and passed through to email template\n- FA icons added to Edit, Send Email, Delete, Confirm Delete, Cancel, and Back buttons\n- Null guard on `toMemberFilterSelection` when mailing list is not yet loaded\n### Unreferenced page detection fix\n- Pages referenced by an album-index inside a shared fragment were incorrectly shown\nas unreferenced\n- `collectNestedAlbumIndexes` now resolves shared fragment references and checks them\nfor album-index rows","contentHtml":"<h1>25-Mar-2026 — navbar access levels, external committee file URLs, and unreferenced page fix <a href=\"https://github.com/nbarrett/ngx-ramblers/issues/197\">#197</a></h1>\n<h2><a href=\"https://github.com/nbarrett/ngx-ramblers/actions/runs/23569609083\">build 564</a> — <a href=\"https://github.com/nbarrett/ngx-ramblers/commit/45365443ff211334d9203600d5d4a23cb85d82ca\">commit 4536544</a></h2>\n<hr>\n<h3>Navbar access-level visibility control</h3>\n<ul>\n<li>Navbar items now support an <code>accessLevel</code> field (<code>public</code>, <code>loggedInMember</code>, <code>committee</code>, <code>hidden</code>)</li>\n<li>Items are filtered from the navbar based on the current user&#39;s permissions</li>\n<li><code>PageAccessGuard</code> on dynamic routes prevents direct navigation to restricted pages</li>\n<li>When a user logs out while on a restricted page, they are redirected to the home page</li>\n<li>Access level column added to <strong>Pages Within Navbar</strong> table in System Settings</li>\n<li>Migration backfills all existing navbar items with <code>accessLevel: &quot;public&quot;</code></li>\n<li>Environment seed data includes access levels (Admin defaults to <code>committee</code>)</li>\n</ul>\n<h3>System config refresh on login/logout</h3>\n<ul>\n<li><code>SystemConfigService</code> now refreshes configuration on <code>MEMBER_LOGIN_COMPLETE</code> and\n<code>MEMBER_LOGOUT_COMPLETE</code> events so permission-gated data (e.g. Brevo email details)\nis reloaded when auth state changes</li>\n</ul>\n<h3>External URL support for committee files</h3>\n<ul>\n<li><code>CommitteeDisplayService.fileUrl()</code> detects remote URLs via <code>isRemoteUrl()</code> and\nreturns them unchanged</li>\n<li>Committee file entries can reference external PDFs that have yet to be migrated to\ninternal S3 storage</li>\n<li><code>committeeFileSlug()</code> generates a kebab-case slug from file title and event date</li>\n</ul>\n<h3>Committee file notification improvements</h3>\n<ul>\n<li>Send notification URL now uses slug-based query params instead of MongoDB IDs\n(e.g. <code>?committee-file=agenda-december-12-2024&amp;source-page=council/meetings/2024-12-12</code>)</li>\n<li>Email &quot;view on our site&quot; link now uses the source page path with an absolute URL</li>\n<li><code>PageService.titleFromPath()</code> converts paths to human-readable titles (with unit tests)</li>\n<li>Source page title derived from path and passed through to email template</li>\n<li>FA icons added to Edit, Send Email, Delete, Confirm Delete, Cancel, and Back buttons</li>\n<li>Null guard on <code>toMemberFilterSelection</code> when mailing list is not yet loaded</li>\n</ul>\n<h3>Unreferenced page detection fix</h3>\n<ul>\n<li>Pages referenced by an album-index inside a shared fragment were incorrectly shown\nas unreferenced</li>\n<li><code>collectNestedAlbumIndexes</code> now resolves shared fragment references and checks them\nfor album-index rows</li>\n</ul>\n"}