Add PUT /admin/api/groups/:id/rename (owner role) which re-points the group's routes, migrates the per-group webhook secret (tenant:{id}) and pending invites, and records an audit entry. The group editor's id field is now editable and the console renames first, then persists remaining edits under the new id.
The GitHub App Setup URL now lands on /auth/github/install, which renders a choice page: bind the installation to a new inst-{id} group or to an existing group the signed-in user owns (owner role re-checked on POST /auth/github/install/bind). Adds an App-JWT helper (getInstallationAccount) to name the auto-created group, audit entries, a console toast, and keeps the installation.created webhook fallback.
Add POST /webhook/{groupId} with per-group secrets (KV tenant:{groupId}), a custom provider (X-WebHooker-Signature HMAC, arbitrary JSON -> custom events through the route pipeline), and GitHub App installation isolation (Group.installationId) with automatic provisioning on installation.created (inst-{id} groups or binding matching owners groups). Includes WebhookPanel admin UI, custom route template, docs and 157 passing tests.
The root catch-all page ([...slug].vue) redirected every unknown URL to
/admin, and the worker fell back to the SPA for any path — so no matter
what page was opened, the URL ended up at baseurl/admin.
- Extract the console into ConsolePage.vue; the active tab now mirrors
the URL path: /admin (groups), /admin/groups, /admin/logs, /admin/audit
(tab switches use router.replace; unknown slugs render 404)
- admin.vue and admin/[slug].vue become thin wrappers
- Delete the root [...slug].vue catch-all redirect
- server.ts: notFound serves ASSETS (SPA + _nuxt chunks) only for
/admin-prefixed paths; every other unknown URL returns a JSON 404