Skip to content

Feature: page access groups with RBAC-based visibility control#727

Open
Plattenspatz wants to merge 1 commit into
rajnandan1:mainfrom
Plattenspatz:feature/page-access-groups
Open

Feature: page access groups with RBAC-based visibility control#727
Plattenspatz wants to merge 1 commit into
rajnandan1:mainfrom
Plattenspatz:feature/page-access-groups

Conversation

@Plattenspatz

Copy link
Copy Markdown

Summary

This PR adds access groups to Kener — a flexible, RBAC-based mechanism to control who can see which status pages. It enables multi-tenant setups where different customers or teams only see their own pages.

Instead of a simple public/internal toggle, access groups provide a unified model: a built-in public group controls whether a page is publicly visible, while custom groups (e.g. customer-a, customer-b) restrict access to users whose role includes that group. This keeps things simple for basic setups (everything is public by default) while supporting complex scenarios when needed.

Motivation

This was built for a multi-tenant use case: a single Kener instance serving status pages for multiple customers, where each customer should only see their own pages. Currently, all pages are visible to everyone who knows the URL.

Resolves #725.
Related to #714 and #697 — this PR takes a different approach by building on the RBAC system (v4.0.23) rather than adding a binary internal/public flag. The public access group replaces the need for a separate page_is_internal field, and the same mechanism handles both public visibility and per-user filtering.

How It Works

Access groups on pages

Each page can have one or more access groups assigned. Two system groups exist by default:

  • public — pages with this group are visible to everyone without login (current default behavior)
  • admin — roles with this group can see all pages regardless of their groups
    Custom groups (e.g. customer-a) are created by admins and assigned to pages and roles as needed.

Access check logic

Page has "public" group?
  → Yes: visible to everyone
  → No: user logged in?
    → No: redirect to sign-in
    → Yes: user's role has "admin" group?
      → Yes: visible
      → No: any overlap between page groups and role groups?
        → Yes: visible
        → No: 404 (not 403, to avoid revealing the page exists)

Example

Page "customer-a-status"     → groups: [customer-a]
Page "customer-b-status"     → groups: [customer-b]
Page "shared-infra"          → groups: [customer-a, customer-b]
Page "public-status"         → groups: [public]
 
Role "Customer A Viewer"     → page scope: [customer-a]
Role "Admin"                 → page scope: [admin]  (built-in)
  • Customer A users see customer-a-status, shared-infra, and public-status
  • Customer B users see customer-b-status, shared-infra, and public-status
  • Admins see everything
  • Anonymous visitors see only public-status

What's Included

Database

  • New migration adding three tables: access_groups, page_access_groups (page ↔ group), role_access_groups (role ↔ group)
  • System groups public and admin are seeded automatically and cannot be deleted
  • All existing pages get the public group on migration (backward compatible — nothing changes for existing installations)
  • The admin role gets the admin group on migration

Backend

  • Access check in page routes — (kener)/+page.server.ts and (kener)/[page_path]/+page.server.ts
  • Page switcher API filters pages by user's access (api-server/pages/get.ts)
  • Site setting autoPublicPages — when enabled (default), newly created pages automatically get the public group
  • 9 new repository methods for access group CRUD and assignment

Admin UI

  • Page edit: Access Groups card with checkboxes to assign groups to a page
  • Roles page: "Page Access" button per role, opening a sheet to select which groups the role can view
  • Roles page: Group management (create/delete custom groups) within the same sheet
  • Site Configuration: "Auto-public new pages" toggle

REST API (/api/v4/)

  • GET /api/v4/pages and GET /api/v4/pages/{path} — response includes access_groups array
  • POST /api/v4/pages — accepts optional access_groups array (falls back to auto-public setting when omitted)
  • PATCH /api/v4/pages/{path} — accepts access_groups array to replace current assignments (omitting it leaves groups unchanged)
  • GET /api/v4/access-groups — list all access groups
  • POST /api/v4/access-groups — create a new access group

Backward Compatibility

This PR is fully backward compatible:

  • All existing pages receive the public group during migration, so they remain visible to everyone
  • All existing roles work unchanged — the built-in admin/editor/member roles continue to function as before
  • The admin role automatically gets the admin group, giving it access to all pages
  • No existing API contracts are broken — access_groups is an additive field in API responses

Files Changed

Area Files Changes
DB 1 new migration 3 tables, system group seeds, backward-compat migration
Backend 5 modified, 1 new Access check, page switcher filter, repository methods, permission mapping
Admin UI 3 modified Page edit card, role sheet, site config toggle
API 3 modified, 1 new GET/POST/PATCH with access_groups, new access-groups endpoint
Types 2 modified API interfaces, site data keys

Total: ~1,130 lines added across 18 files.

Testing

Tested on two independent instances (fresh install + existing installation with data) covering:

  • Public/private page visibility for anonymous and authenticated users
  • Role-based access filtering with custom groups
  • Shared pages across multiple groups
  • Page switcher filtering
  • Admin override via admin group
  • Auto-public setting (on/off)
  • API operations (create, update, list with access groups)
  • System group protection (cannot delete public/admin)
  • Backward compatibility (existing pages remain public after migration)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: Per-user page access restrictions for internal pages

1 participant