Skip to content

feat(admin): granular access control, custom roles, and the real logo - #363

Merged
pratyush618 merged 5 commits into
mainfrom
feat/granular-rbac
Sep 22, 2026
Merged

pratyush618 merged 5 commits into
mainfrom
feat/granular-rbac

Conversation

@kartikeya-27

Copy link
Copy Markdown
Contributor

Members table was overlapping itself

.row-member declares minmax(0, 1fr) 104px 140px 92px minmax(0, 320px) with a 16px gap — 720px of tracks and gaps before the name column gets anything. The page was in .content-form, which caps the container at 720px and then takes 48px of padding out of it, so the 1fr track resolved to zero and every column printed on top of the one before it.

The members page is a list, not a column of form fields. It moves to .content-narrow, and the invite panel stays the thing that constrains itself.

Granular access

A super admin can now say exactly what one person may do, and write roles of their own to say it once instead of five times.

Schema. The permission catalogue moves to @byteveda/db/constants so it can back a real Postgres enum — admin_permission, fifteen resource.verb values — rather than a text[] that any typo fits into. A new admin_custom_roles table holds roles somebody wrote: a key, a label, a description, and a permission array. admin_users gains custom_role_id and two override columns.

Resolution. role (or custom role) → + extra_permissions → − denied_permissions, in catalogue order. Denied is applied last and wins over the role and over a contradicting extra, which is the only ordering that makes "take this away" mean it. members.manage is stripped at every write and at resolution, so nothing stored can carry the grant that grants grants.

Overrides are a diff, not a snapshot. The dialog sends the permissions the operator ticked; the server computes the difference against the role and stores that. Move somebody to another role later and everything nobody touched by hand follows the new role.

Deleting a role does not delete access. The built-in role column is kept underneath a custom role rather than cleared, so the foreign key's set null drops the member back onto something. Tidying up a role should not be a way to lock the last editor out of the console.

Interface

  • Each member row gets an Access button. The dialog holds the role picker (built-in and custom), the inbox scope, and a permission matrix grouped by resource — each tick with a sentence saying what it hands over, and an added / removed flag wherever the grant differs from the role.
  • A Roles panel lists the four built-in roles (locked, with the reason) alongside the custom ones. New and Edit open the same matrix.
  • The row shows +2 −1 when somebody's grant no longer matches their role.

Two of the three controls that lived in the table row have moved into the dialog. A role, a scope and fifteen permissions were never going to fit beside a name — the version that tried is the bug at the top of this description.

Logo

Mark was an inline bracket glyph that needed an accent tile behind it to be legible, and was never the logo. It now renders BrandMark, the artwork the public sites ship. The tile comes off with the glyph. Reaches the rail, the login sheet, the error page and both subscription pages.

apps/admin's vitest config learns to resolve a static image import the way next build does — reading the real dimensions out of the PNG header — otherwise any test rendering a page with the logo on it throws inside next/image.

Checks

pnpm -r typecheck clean. 232 admin tests and 51 db tests pass, including nine new ones covering custom roles, override precedence and the reserved grant. next build clean. Biome at baseline.

Not visually verified — /members is behind GitHub OAuth. The layout fix is confirmed by track arithmetic.

Migration 0009_custom_roles has not been applied anywhere. apps/admin's build runs db:deploy first, so deploying carries it; locally it is pnpm --filter @byteveda/db db:deploy.

🤖 Generated with Claude Code

kartikeya-27 and others added 4 commits September 22, 2026 10:58
The bracket glyph was a stand-in that needed an accent tile to be
legible. BrandMark is the artwork the public sites ship, so the tile
comes off with it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The row's columns add up to more than the 720px `.content-form` allows,
so the name track collapsed to zero and every column printed on top of
its neighbour. A list belongs in `.content-narrow`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The permission list moves to constants so it can back a Postgres enum,
and a super admin can now write roles of their own — bounded to the
same catalogue the built-in ones use.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A super admin picks a role, a mail scope and per-resource permissions
in one dialog, and can write custom roles from the same matrix. A
member's exceptions are stored as a diff, so changing their role still
moves everything nobody touched by hand.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
byteveda-site Ready Ready Preview Sep 22, 2026 5:44am UTC
byteveda-site-academy Ready Ready Preview Sep 22, 2026 5:44am UTC
byteveda-site-admin Ready Ready Preview Sep 22, 2026 5:44am UTC
byteveda-site-flexiq Ready Ready Preview Sep 22, 2026 5:44am UTC

drizzle-kit writes these unformatted; every snapshot already in the
tree has been through Biome.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@pratyush618
pratyush618 merged commit d81b10a into main Sep 22, 2026
16 checks passed
@pratyush618
pratyush618 deleted the feat/granular-rbac branch September 22, 2026 06:19

This branch was successfully deployed

4 active deployments
Preview – byteveda-site-flexiq 352b8c88 Deployed Sep 22, 2026 by vercel[bot]
Preview – byteveda-site-admin 352b8c88 Deployed Sep 22, 2026 by vercel[bot]
Preview – byteveda-site 352b8c88 Deployed Sep 22, 2026 by vercel[bot]
Preview – byteveda-site-academy 352b8c88 Deployed Sep 22, 2026 by vercel[bot]
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.

2 participants