Skip to content

Frontend Admin Specification

Related documentation: Frontend Implementation · Frontend Applications · Frontend Tasks · Backend Admin · Backend Admin API · Backend Auth · Backend Core

Detailed specification for Frontend-Kisum-Admin

Section titled “Detailed specification for Frontend-Kisum-Admin”

Audience: frontend engineers, backend engineers, product, QA, operations
Status: mixed runtime + target specification
Scope: this page defines what the Admin frontend must do, what screens it must expose, what backend endpoints it must call, what actions platform staff may perform, and how the Admin UI must behave in the new Kisum architecture.

This page mixes current runtime with target Admin frontend contract.

  • it documents what is already implemented now and what the Admin app must still become
  • it treats Backend-Kisum-Admin as the only backend the browser should call for platform-admin work
  • it assumes Backend-Kisum-Admin orchestrates into Core, Auth, and module backends such as Backend-Kisum-Venues

Implemented now:

  • React Router 7 + React 19 SPA
  • platform-staff auth/bootstrap
  • live route groups for dashboard, artists, contacts, admin-users, app-users, venues, and settings
  • venue cutover to Venue-backed Admin APIs
  • artist-company request review surface

Still not safe to document as fully complete:

  • some package/catalog areas still exist in code but are not fully part of the active route tree
  • this page still contains target-state sections below; treat them as TODO unless the current route tree already exposes them
Frontend-Kisum-Admin never calls Core or Auth directly for platform-control work.
Frontend-Kisum-Admin always calls Backend-Kisum-Admin.
Backend-Kisum-Admin orchestrates Core and Auth.

Frontend-Kisum-Admin is the platform staff control-plane application.

It exists to answer:

What should platform staff be able to operate safely from the UI?

The Admin frontend must expose:

  • commercial catalog management
  • company lifecycle management
  • platform-user management
  • tenant-user and membership management
  • session visibility and revocation
  • delegation governance
  • payment-provider operational configuration
  • approval workflows
  • artist management
  • market-directory contacts management
  • venue management
  • file-management utilities
  • AI helper utilities

The Admin frontend is not the product tenant app. It is the staff-facing operating console for the platform.

For venue management:

  • Frontend-Kisum-Admin calls Backend-Kisum-Admin
  • Backend-Kisum-Admin calls Backend-Kisum-Venues
  • the browser must not call Backend-Kisum-Venues directly

Admin venue pages should use numeric venue_id as the stable route identity.


The Admin frontend may:

  • authenticate platform staff
  • show staff-only navigation
  • load company, package, module, add-on, membership, and session data
  • submit create, patch, put, approve, reject, activate, deactivate, assign, revoke, and delete actions
  • show access-sensitive controls based on platform-admin capabilities
  • render audit-meaningful confirmation flows for destructive actions

The Admin frontend must not:

  • call Core directly from the browser
  • call Auth directly from the browser for control-plane operations
  • compute entitlements locally
  • compute effective tenant access locally
  • decide delegation truth locally
  • decide session truth locally
  • persist platform control-plane truth in browser state as if it were authoritative

Only platform staff.

Accepted platform roles:

  • PLATFORM_SUPERADMIN
  • PLATFORM_ADMIN
  • PLATFORM_MODERATOR

The Admin frontend must call:

  • POST /auth/login
  • POST /auth/refresh
  • POST /auth/logout
  • GET /auth/me

for authentication and identity bootstrap only.

For platform control-plane operations, the browser must call:

  • Backend-Kisum-Admin

using:

Authorization: Bearer <access_token>

Admin frontend authentication is still Auth-backed, but control-plane data access is Admin-backed.

That means:

Browser -> Auth for sign-in/session bootstrap
Browser -> Admin backend for platform work
Admin backend -> Auth/Core server-to-server

The Admin frontend must:

  • restore session on reload
  • refresh access token when needed
  • redirect to sign-in when session is invalid
  • clear privileged UI state on sign-out
  • never keep stale privileged data after logout

4. Primary route groups the Admin frontend must expose

Section titled “4. Primary route groups the Admin frontend must expose”

The Admin frontend should expose these major route groups:

  • /dashboard
  • /packages
  • /modules
  • /addons
  • /companies
  • /platform-users
  • /users
  • /companies/:companyId/users
  • /companies/:companyId/memberships
  • /business-units/:businessUnitId/memberships
  • /sessions
  • /delegation-rules
  • /payment-providers
  • /approvals
  • /artists
  • /contacts
  • /venues
  • /files
  • /ai
  • /settings

The current local Frontend-Kisum-Admin already contains route groups for:

  • dashboard
  • artists
  • contacts
  • admin-users
  • app-users
  • venues
  • settings

There are also package-related route files in the repository, but they are not yet part of the active route tree.

The final route tree must align with the Admin control-plane model, even if the current route tree is still older and incomplete.


The Admin frontend sidebar should expose at least these navigation groups:

  • Dashboard
  • Companies
  • Packages
  • Modules
  • Add-ons
  • Payment Providers
  • Platform Users
  • Users
  • Company Memberships
  • Sessions
  • Delegation Rules
  • Approvals
  • Artists
  • Contacts
  • Venues
  • Files
  • AI Tools
  • Profile
  • Settings

The Admin frontend now includes a dedicated Market-directory contact section:

  • /contacts
  • /contacts/companies/:id
  • /contacts/people/:id

This area is for Market companies, Market people, and their relations. It must use Backend-Kisum-Admin only, through the Admin Market-directory proxy namespace, not direct browser calls to Market and not the Core tenant-company namespace under /companies.


The Admin dashboard should be an operating summary, not just a generic landing page.

It should show:

  • total companies
  • pending companies or approval items
  • active packages
  • active modules
  • active add-ons
  • connected users
  • active sessions
  • payment-provider status summary
  • recent admin actions or warnings

The dashboard may aggregate from:

  • GET /api/v1/admin/session-stats
  • GET /api/v1/admin/approvals
  • GET /api/v1/admin/companies
  • GET /api/v1/admin/packages
  • GET /api/v1/admin/modules
  • GET /api/v1/admin/addons

The dashboard should prefer a future dashboard aggregation endpoint if one is added, but these are the minimum source endpoints.


The Admin frontend must provide full package catalog management.

  • package list
  • package detail
  • package create
  • package edit

7.2 Trial + Audience controls (2026-05-20)

Section titled “7.2 Trial + Audience controls (2026-05-20)”

The shared app/features/catalog/components/catalog-commercial-fields.tsx component (reused by both package and add-on drawers) exposes the new Core catalog columns introduced in the Trial Flags + Persona Pricing release:

  • Audience (segmented control: Promoter / Venue / Artist / Vendor — expanded to four values in the 2026-05-21 Base/Addon Modules Rework). Maps to packages.audience / addons.audience. Drives which marketing-site /pricing persona tab the row appears under. Required for every catalog row.
  • Trial enabled (switch). Maps to packages.trial_enabled / addons.trial_enabled. When false, self-serve signup MUST collect a card up front (routes through System-Kisum-Checkout’s Xendit flow). When true, signup provisions the row as status='trial' for trial_days with no card required.
  • Trial days (number input). Maps to *.trial_days. Disabled by the UI when the trial switch is off, to prevent stale numbers ending up in Core when the switch is flipped back on later.

Both package-form-drawer.tsx and addon-form-drawer.tsx send these three fields on every create + patch, hydrate them from the detail GET, and reset them on close.


16. Frontend implementation checklist by route and screen

Section titled “16. Frontend implementation checklist by route and screen”

This section is the execution checklist for Frontend-Kisum-Admin.

It translates the Admin frontend specification into concrete route groups, screen expectations, API dependencies, and implementation rules.

  • the browser must call only Backend-Kisum-Admin for platform-control work
  • the browser may call Auth only for login, refresh, logout, and GET /auth/me
  • all create, update, assign, approve, reject, activate, deactivate, and delete flows should use right-side drawers unless the object is large enough to require a full detail page
  • list pages must follow the existing admin-users and app-users/companies visual and behavioral patterns
  • use headless + Tailwind and existing app primitives; do not introduce a second component system
  • when an Admin endpoint is documented but not yet live, the UI should fail gracefully with a clear unavailable state
  • Artists and Venues must remain visually and behaviorally consistent with the current app; do not redesign them as part of this work

Use these existing screens as the style and interaction reference:

  • admin-users
    • reference for user tables, filters, status indicators, and row actions
  • app-users/companies
    • reference for company list/detail structure, large-form editing flows, and multi-section information layouts
  • /signin
  • /signout
  • dashboard shell layout
  • keep the existing sign-in and sign-out behavior Auth-backed
  • ensure the app shell blocks non-platform users
  • use GET /auth/me to bootstrap platform-staff identity
  • remove direct browser use of Auth /internal/* control-plane routes
  • centralize all Admin API calls under one Admin API client
  • add a consistent unavailable-error view for not-yet-live Admin endpoints
  • /dashboard

Provide the control-plane overview for platform staff.

  • GET /api/v1/admin/session-stats
  • GET /api/v1/admin/approvals
  • GET /api/v1/admin/companies
  • GET /api/v1/admin/packages
  • GET /api/v1/admin/modules
  • GET /api/v1/admin/addons
  • keep the dashboard as an operational summary, not a generic landing page
  • show connected users and active sessions
  • show pending approvals
  • show company totals
  • show package, module, and add-on totals
  • show payment-provider status when the backend supports it
  • add loading, empty, and failure states for each major widget
  • /companies
  • /companies/:companyId

Platform-admin control over company master data and company commercial lifecycle.

  • GET /api/v1/admin/companies
  • POST /api/v1/admin/companies
  • GET /api/v1/admin/companies/{id}
  • PATCH /api/v1/admin/companies/{id}
  • POST /api/v1/admin/companies/{id}/approve
  • POST /api/v1/admin/companies/{id}/reject
  • POST /api/v1/admin/companies/{id}/activate
  • POST /api/v1/admin/companies/{id}/deactivate
  • GET /api/v1/admin/companies/{id}/subscription
  • POST /api/v1/admin/companies/{id}/package
  • POST /api/v1/admin/companies/{id}/addons
  • DELETE /api/v1/admin/companies/{id}/addons/{addonId}
  • GET /api/v1/admin/companies/{id}/entitlements
  • GET /api/v1/admin/companies/{id}/history
  • build a company list screen using the same table behavior as the current company/admin user screens
  • support filters, pagination, loading state, and empty state
  • build a company detail page for large read-only or mixed-action views
  • use drawers for create and edit
  • split company UI into sections:
    • master identity
    • profile
    • addresses
    • social links
    • documents
    • subscription
    • add-ons
    • entitlements
    • commercial history
  • expose approve, reject, activate, and deactivate actions with explicit confirmations
  • show the difference between company master data and company commercial state
  • keep company users and memberships linked from the company page
  • /packages
  • /packages/:packageId

Platform-admin management of package catalog entries.

  • GET /api/v1/admin/packages
  • POST /api/v1/admin/packages
  • GET /api/v1/admin/packages/{id}
  • PATCH /api/v1/admin/packages/{id}
  • PUT /api/v1/admin/packages/{id}/modules
  • build package list screen
  • build package detail screen
  • use drawers for create and edit
  • show package metadata, activation state, and linked modules
  • allow package-module mapping in a controlled multi-select flow
  • display warnings when changing package-module composition affects downstream entitlements
  • add clear empty and unavailable states if the backend route is not live yet
  • /modules
  • /modules/:moduleId

Platform-admin management of module catalog entries.

  • GET /api/v1/admin/modules
  • POST /api/v1/admin/modules
  • GET /api/v1/admin/modules/{id}
  • PATCH /api/v1/admin/modules/{id}
  • build module list screen
  • build module detail screen
  • use drawers for create and edit
  • show key, name, type, description, and activation state
  • surface the relationship between modules and packages/add-ons
  • make module status easy to audit visually
  • /addons
  • /addons/:addonId

Platform-admin management of add-on catalog entries.

  • GET /api/v1/admin/addons
  • POST /api/v1/admin/addons
  • GET /api/v1/admin/addons/{id}
  • PATCH /api/v1/admin/addons/{id}
  • PUT /api/v1/admin/addons/{id}/modules
  • build add-on list screen
  • build add-on detail screen
  • use drawers for create and edit
  • show linked module composition
  • make activation state explicit
  • support replace-style module mapping
  • /platform-users
  • /platform-users/:userId

Platform-staff administration of platform roles and staff accounts.

  • GET /api/v1/admin/platform-users
  • POST /api/v1/admin/platform-users
  • GET /api/v1/admin/platform-users/{userId}
  • PATCH /api/v1/admin/platform-users/{userId}
  • DELETE /api/v1/admin/platform-users/{userId}
  • GET /api/v1/admin/platform-users/{userId}/context
  • POST /api/v1/admin/platform-users/{userId}/revoke-all
  • POST /api/v1/admin/platform-users/invitations
  • replace direct Auth /internal/users browser calls with Admin API calls
  • keep the current admin-users table pattern
  • support filters:
    • approval status
    • global role
    • status
    • sort
  • add create-user drawer
  • add edit-user drawer
  • add invite-platform-user drawer
  • add revoke-all confirmation flow
  • build a user detail page or side panel with:
    • core identity
    • global role
    • approval status
    • account state
    • context output
  • /users
  • /users/:userId

Global platform-admin visibility into all tenant users, not scoped to a single company.

  • GET /api/v1/admin/users
  • move the current app-user global list pattern to the Admin API
  • keep this directory separate from platform users
  • support approval-status filtering
  • support paging and row click to detail
  • clearly label this screen as global tenant users, not company users

This distinction must be explicit in the frontend because both data sets are shown in Admin and they are not interchangeable.

A user screen is centered on the person/account.

These screens answer questions like:

  • who is this person
  • what is their email and full name
  • is their account active
  • do they have a platform role
  • what sessions do they have

User screens are account-directory screens.

They are useful for:

  • platform user administration
  • global tenant user administration
  • user detail pages
  • session visibility
  • revoke-all actions

In UI terms:

  • a user usually appears once in a list
  • the row represents the identity
  • the primary columns are email, full name, status, approval state, and global role

Membership screens are scoped-access screens

Section titled “Membership screens are scoped-access screens”

A membership screen is centered on the assignment of that user into a scope.

That scope can be:

  • a company
  • a business unit

These screens answer questions like:

  • does this user belong to this company
  • does this user belong to this business unit
  • what role do they have in that scope
  • what module grants and permission grants apply there
  • what delegation limits apply there

Membership screens are access-administration screens.

They are useful for:

  • company role management
  • business-unit role management
  • module-grant editing
  • permission-grant editing
  • delegation configuration

In UI terms:

  • a membership row represents one scoped assignment
  • the same user can appear multiple times across different scopes
  • the primary columns are scope, role, active state, grants, and delegation summary

This is the main frontend reason the two views must stay separate.

Example:

User
- Marco
- marco@kisum.io
Memberships
- Company C1 -> ADMIN
- Business Unit BU7 -> APPROVER
- Business Unit BU9 -> MEMBER

That is still one user, but multiple access assignments.

So:

  • the user table may show Marco once
  • the membership tables may show multiple rows tied to Marco

Use a users screen when the main task is:

  • finding people
  • inspecting identity/account state
  • opening user detail
  • checking sessions

Use a memberships screen when the main task is:

  • assigning access
  • changing tenant roles
  • editing scoped grants
  • editing delegation in tenant scope

Use this rule everywhere:

  • users = person/account view
  • memberships = company or business-unit access view

If a page mixes both, render them as separate sections or tabs, not as one ambiguous table.

  • /companies/:companyId/users
  • /companies/:companyId/memberships

Manage the company-scoped user access layer from the Admin control plane.

  • GET /api/v1/admin/companies/{companyId}/users
  • GET /api/v1/admin/companies/{companyId}/memberships
  • POST /api/v1/admin/companies/{companyId}/memberships
  • build a company-user list
  • build a company-membership list
  • show each user’s tenant role, status, module grants, permission grants, and delegation settings where available
  • use a drawer for create/update membership
  • support module-grant and permission-grant editing in one flow
  • make delegation configuration visible inside the membership editor
  • surface which company page the membership belongs to
  • /companies/:companyId/business-units
  • /companies/:companyId/business-units/:businessUnitId
  • /companies/:companyId/business-units/:businessUnitId/users
  • /companies/:companyId/business-units/:businessUnitId/memberships

Manage business-unit master data and BU-scoped access from the Admin control plane.

  • GET /api/v1/admin/companies/{companyId}/business-units
  • POST /api/v1/admin/companies/{companyId}/business-units
  • GET /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}
  • PATCH /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}
  • DELETE /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}
  • GET /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}/users
  • GET /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}/memberships
  • POST /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}/memberships
  • provide a BU master list inside the company detail flow
  • provide a right-side drawer for create BU
  • provide a BU detail/read view scoped under the parent company
  • provide a right-side drawer for patch BU
  • provide a delete/deactivate confirmation flow scoped under the parent company
  • show name, code, slug, status, and metadata fields for each BU
  • provide a BU user list
  • provide a BU membership editor drawer
  • show the relationship between company membership and BU membership
  • keep BU scope visually distinct from company-wide scope
  • /sessions
  • /companies/:companyId/sessions
  • optional user-linked session views under user detail pages

Operational visibility into connected users and active sessions.

  • GET /api/v1/admin/sessions
  • GET /api/v1/admin/session-stats
  • GET /api/v1/admin/companies/{companyId}/sessions
  • POST /api/v1/admin/platform-users/{userId}/revoke-all
  • build a global sessions table
  • build dashboard counters from session-stats
  • support filters:
    • approval status
    • platform vs tenant users
    • user
    • company
  • show columns:
    • user
    • role
    • IP
    • device
    • user agent
    • created at
    • last used at
    • expires at
  • support company-scoped session view
  • link session information from user detail views where appropriate
  • explain in the UI that this is active-session presence, not realtime socket presence
  • /delegation-rules
  • /delegation-rules/:ruleId

Govern what tenant actors are allowed to delegate to other users.

  • GET /api/v1/admin/delegation-rules
  • POST /api/v1/admin/delegation-rules
  • PATCH /api/v1/admin/delegation-rules/{id}
  • build delegation-rule list
  • build create/edit drawers
  • clearly separate:
    • what a user can do
    • what that user can delegate to others
  • support editing:
    • grantable modules
    • grantable permissions
    • canManageUsers
    • canBuyAddons
  • include strong helper text and warnings, because this screen is easy to misunderstand
  • /payment-providers

Operational configuration for Stripe, Xendit, or future region-specific providers.

  • GET /api/v1/admin/payment-providers
  • POST /api/v1/admin/payment-providers/stripe
  • POST /api/v1/admin/payment-providers/xendit
  • build provider summary screen
  • build configuration drawers or panels for each provider
  • show provider status by region or deployment scope
  • use confirmation flows for secret-bearing changes
  • never expose secrets back into the browser after initial submission
  • /approvals
  • /approvals/:approvalId

Platform-admin approval and rejection workflows.

  • GET /api/v1/admin/approvals
  • GET /api/v1/admin/approvals/{id}
  • POST /api/v1/admin/approvals/approve
  • POST /api/v1/admin/approvals/reject
  • keep approvals as a first-class operational module
  • support approval list and detail
  • use confirmation UI for approve/reject actions
  • require explicit rejection reasons when the backend supports them
  • file upload affordances inside relevant flows
  • optional /files operational utility view if needed
  • POST /api/v1/admin/files/upload
  • keep file upload available for company, approval, and operational flows
  • standardize upload progress, success, and failure UX
  • expose returned file metadata clearly to the caller flow
  • /ai
  • POST /api/v1/admin/ai/gemini
  • provide a staff-only AI utility surface
  • show request/response clearly
  • mark generated output as assistive, not authoritative
  • existing artist routes
  • do not redesign
  • keep current routes and patterns
  • only align API client usage if required by backend changes
  • existing venue routes
  • new: /venues/requests — admin queue for tenant-submitted venue takeover + creation requests
  • venue detail (/venues/:id) gains a Revert takeover action when ownershipStatus === "active"

16.20.1 Agency / Management Requests (2026-05-25)

Section titled “16.20.1 Agency / Management Requests (2026-05-25)”

Admin review surface for agency provisioning requests submitted by tenants from Frontend-Kisum-Artists’s /settings/agency page. Mirror of the venue-requests pattern with one simplification: no proof-of-ownership file (the Artists provisioning flow doesn’t accept file uploads).

User-facing label: “Agency / Management Requests” (renamed from “Artist Company Requests” on 2026-05-25 to match the agency/management/label vocabulary tenants actually use). Underlying URL, route file path, feature folder name, API endpoints and query keys all keep the artist-company-requests slug — the rename is label-only.

  • new: /artists/company-requests — admin queue for tenant-submitted artists-company takeover + creation requests, labelled “Agency / Management Requests” in nav + page header
  • existing /artists IA tweaked so its isActive predicate excludes /artists/company-requests (the new sibling)
  • new app/features/artist-company-requests/ mirroring app/features/venue-requests/:
    • types/index.tsArtistCompanyRequest, ArtistCompanyRequestKind, ArtistCompanyRequestStatus, ArtistCompanyCreationSpec (no ProofOfOwnership)
    • api/artist-company-requests.ts — 4 client functions hitting /admin/artist-company-requests/* via adminApiClient
    • 2 TanStack Query hooks (use-artist-company-requests-query, use-artist-company-request-query) — 30s stale, no refetch on focus
    • 3 components: list (status + kind filters, table with row click → drawer), detail drawer (header + requester + target-or-spec + decision; Approve / Reject in footer when status === 'pending'), decision dialog (confirmation with optional decisionNotes textarea, Sonner toast on success/error)
  • the page must call only Backend-Kisum-Admin (/api/v1/admin/artist-company-requests*); never call Backend-Kisum-Artists directly
  • show kind (takeover / creation) and status (pending / approved / rejected / revoked) prominently
  • no proof viewer — the Artists provisioning flow has no file upload, so the drawer omits the proof section entirely
  • approve / reject must accept optional decisionNotes so the tenant sees the rejection reason in their own /settings/agency history
  • on approve the upstream side-effect is destructive-ish (binds the requesting Auth org to the agency; writes an artists_company_claims row; flips companies.claimed=TRUE) but no type-to-confirm is needed because there’s no equivalent to “revert takeover” today — only the pending → approved transition
  • mutation cache invalidation: both the list key (ARTIST_COMPANY_REQUESTS_QUERY_KEY) and the single key ([...ARTIST_COMPANY_REQUEST_QUERY_KEY, id])
  • do not redesign existing venue routes
  • the new /venues/requests page must call only Backend-Kisum-Admin (/api/v1/admin/venue-requests*); never call Backend-Kisum-Venues directly
  • show kind (takeover / creation) and status (pending / approved / rejected / revoked) prominently
  • proof-of-ownership files must be opened through the BFF GET /api/v1/admin/venue-requests/{id}/proof-url route, which returns a short-lived presigned S3 URL; the bucket itself stays private
  • approve / reject must accept optional decisionNotes so the tenant gets context in their own /settings/venue view
  • the Revert takeover action must use a destructive-pattern dialog: type-to-confirm the venue name + required reason note (min 10 chars, shown to the tenant in the revoked request’s decision_notes)
  • when the BFF returns 409 VENUE_HAS_TENANT_DATA, the dialog must show the per-table counts (spaces, bookings, deposits, contracts, events, availability_blocks, checklists) inline so admins can coordinate cleanup before retrying
  • /settings
  • keep settings/profile behavior consistent with current app shell
  • avoid mixing platform operational configuration with personal profile settings unless clearly separated

Recommended implementation order:

  1. app shell and Admin API client migration
  2. platform users
  3. users
  4. company users and memberships
  5. sessions
  6. packages
  7. modules
  8. add-ons
  9. companies
  10. delegation rules
  11. payment providers
  12. keep approvals/files/AI aligned

Artists and Venues should remain stable while the rest of the control-plane surface is updated.

  • package-to-module mapping editor

Each package screen should show:

  • package key
  • name
  • description
  • status
  • lifecycle state
  • included modules
  • allowed add-ons
  • upgrade and downgrade notes if defined
  • GET /api/v1/admin/packages
  • POST /api/v1/admin/packages
  • GET /api/v1/admin/packages/{packageId}
  • PATCH /api/v1/admin/packages/{packageId}
  • DELETE /api/v1/admin/packages/{packageId}
  • PUT /api/v1/admin/packages/{packageId}/modules
{
"key": "basic",
"name": "Basic",
"description": "Basic subscription that enables the core application",
"isActive": true,
"priceMinor": 99.00,
"currency": "USD",
"billingInterval": "monthly",
"taxCode": "digital_services",
"taxInclusive": false,
"trialDays": 14,
"regionPricing": [
{
"region": "SG",
"currency": "SGD",
"priceMinor": 129.00
}
],
"moduleKeys": ["basic"]
}

Package UI must:

  • prevent duplicate keys visually where possible
  • require explicit module selection
  • show which modules are currently mapped
  • require commercial fields like price, currency, and billing interval
  • collect price as the final decimal amount such as 199 or 199.00
  • send priceMinor as that same decimal value, so 199.00 stays 199.00
  • explain that packages are commercial bundles, not permission sets
  • never present package assignment as direct user access

The Admin frontend must provide commercial module management.

  • module list
  • module detail
  • module create
  • module edit
  • module key
  • name
  • type
  • description
  • active state
  • packages that include it
  • add-ons that include or depend on it
  • GET /api/v1/admin/modules
  • POST /api/v1/admin/modules
  • GET /api/v1/admin/modules/{moduleId}
  • PATCH /api/v1/admin/modules/{moduleId}
  • DELETE /api/v1/admin/modules/{moduleId}
{
"key": "finance",
"name": "Finance",
"type": "addon",
"description": "Finance module",
"isActive": true
}

Module UI must:

  • explain that modules are capability boundaries
  • not confuse modules with packages
  • not confuse modules with add-ons
  • surface where a module is used in the commercial catalog

The Admin frontend must provide add-on catalog management.

  • add-on list
  • add-on detail
  • add-on create
  • add-on edit
  • add-on-to-module mapping editor
  • add-on key
  • name
  • description
  • active state
  • compatible packages
  • compatible standalone modules
  • mapped capability modules if applicable
  • GET /api/v1/admin/addons
  • POST /api/v1/admin/addons
  • GET /api/v1/admin/addons/{addonId}
  • PATCH /api/v1/admin/addons/{addonId}
  • DELETE /api/v1/admin/addons/{addonId}
  • PUT /api/v1/admin/addons/{addonId}/modules
{
"key": "live-ticket-sales",
"name": "Live Ticket Sales",
"description": "Live ticket sales in your events",
"isActive": true,
"priceMinor": 49.00,
"currency": "USD",
"billingInterval": "monthly",
"taxCode": "digital_services",
"taxInclusive": false,
"trialDays": 7,
"moduleKeys": ["finance"]
}

Add-on UI must:

  • explain that add-ons are optional commercial extensions
  • clearly show compatibility
  • collect price as the final decimal amount such as 79 or 79.99
  • send priceMinor as that same decimal value, so 79.99 stays 79.99
  • clearly show dependency warnings if relevant
  • restrict module selection to modules whose type is addon
  • not present add-ons as user permissions

The Admin frontend must provide company lifecycle management through the Admin backend.

  • company list
  • company detail
  • company create
  • company edit
  • company approval panel
  • company subscription panel
  • company add-on management panel
  • company entitlement summary panel
  • company history panel
  • company legal name
  • display name
  • status
  • basic profile summary
  • primary address summary
  • current package summary if present
  • add-on count if relevant
  • GET /api/v1/admin/companies
  • POST /api/v1/admin/companies
  • GET /api/v1/admin/companies/{id}
  • PATCH /api/v1/admin/companies/{id}
  • POST /api/v1/admin/companies/{id}/approve
  • POST /api/v1/admin/companies/{id}/reject
  • POST /api/v1/admin/companies/{id}/activate
  • POST /api/v1/admin/companies/{id}/deactivate
  • GET /api/v1/admin/companies/{id}/subscription
  • POST /api/v1/admin/companies/{id}/package
  • POST /api/v1/admin/companies/{id}/addons
  • DELETE /api/v1/admin/companies/{id}/addons/{addonId}
  • GET /api/v1/admin/companies/{id}/entitlements
  • GET /api/v1/admin/companies/{id}/history
{
"legalName": "Kisum Entertainment Group Pte Ltd",
"displayName": "Kisum Entertainment Group",
"status": "active",
"createdSource": "admin",
"metadata": {
"region": "SG"
},
"profile": {
"website": "https://group.kisum.dev",
"email": "group@kisum.dev",
"phone": "+65 6999 8888",
"timezone": "Asia/Singapore",
"industry": "Entertainment",
"description": "Regional artist management and touring group"
},
"addresses": [
{
"type": "primary",
"line1": "120 Orchard Road",
"city": "Singapore",
"state": "Singapore",
"postalCode": "238888",
"country": "Singapore",
"isPrimary": true
}
],
"socialLinks": [
{
"platform": "instagram",
"label": "Official Instagram",
"url": "https://instagram.com/kisumgroup"
}
],
"documents": [
{
"type": "business_registration",
"name": "Business Registration Certificate",
"storageKey": "companies/company-id/business-registration.pdf",
"url": "https://files.kisum.dev/companies/company-id/business-registration.pdf",
"mimeType": "application/pdf",
"sizeBytes": 248392
}
]
}

Company UI must:

  • treat company creation as a Core-backed workflow orchestrated by Admin
  • not invent company ids locally
  • separate company profile editing from subscription assignment
  • show status transitions clearly
  • require confirmation for approve, reject, activate, and deactivate actions

The Admin frontend must provide full platform-user administration.

These screens manage platform staff users only.

They are not the same as tenant users inside companies.

  • platform-user list
  • platform-user detail
  • platform-user create
  • platform-user edit
  • platform-user invitation create
  • platform-user context view
  • platform-user session panel
  • GET /api/v1/admin/platform-users
  • POST /api/v1/admin/platform-users
  • GET /api/v1/admin/platform-users/{userId}
  • PATCH /api/v1/admin/platform-users/{userId}
  • DELETE /api/v1/admin/platform-users/{userId}
  • GET /api/v1/admin/platform-users/{userId}/context
  • POST /api/v1/admin/platform-users/{userId}/revoke-all
  • POST /api/v1/admin/platform-users/invitations
  • GET /api/v1/admin/platform-users
    • Admin backend -> Auth GET /internal/users?globalRole=true
  • POST /api/v1/admin/platform-users
    • Admin backend -> Auth POST /internal/users
  • GET /api/v1/admin/platform-users/{userId}
    • Admin backend -> Auth GET /internal/users/{id}
  • PATCH /api/v1/admin/platform-users/{userId}
    • Admin backend -> Auth PATCH /internal/users/{id}
  • DELETE /api/v1/admin/platform-users/{userId}
    • Admin backend -> Auth DELETE /internal/users/{id}
{
"email": "ops-admin@kisum.dev",
"fullName": "Ops Admin",
"password": "temporary-password",
"globalRole": "PLATFORM_ADMIN",
"approvalStatus": "APPROVED"
}

Platform-user UI must:

  • clearly separate platform staff from tenant users
  • show platform role
  • show approval status
  • support session revocation
  • support viewing connected sessions

The Admin frontend must also support listing all non-platform users across the system.

This is the global tenant-user directory, not filtered to one company.

  • user list
  • user detail
  • user search and filters
  • approval-status filtered views
  • GET /api/v1/admin/users
  • GET /api/v1/admin/platform-users/{userId}
    • may be reused for shared user detail if Admin normalizes the route design
  • GET /api/v1/admin/users
    • Admin backend -> Auth GET /internal/users?globalRole=false

User list UI should support at minimum:

  • approval status
  • pagination
  • search by email or name when backend support exists
  • sorting by creation or recent activity when backend support exists

13. Company-user and membership management screens

Section titled “13. Company-user and membership management screens”

The Admin frontend must provide user and membership governance inside companies.

  • company users list
  • company memberships list
  • membership edit modal or page
  • business-unit memberships list
  • business-unit membership editor
  • GET /api/v1/admin/companies/{companyId}/users
  • GET /api/v1/admin/companies/{companyId}/memberships
  • POST /api/v1/admin/companies/{companyId}/memberships
  • GET /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}/users
  • POST /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}/memberships
{
"userId": "9e280dc5-c1cf-4d62-bad9-0774e4a3b9e1",
"role": "ADMIN",
"isActive": true,
"moduleGrants": ["basic", "finance"],
"permissionGrants": [
"basic.events.read",
"finance.bills.read"
],
"delegation": {
"grantableModules": ["basic"],
"grantablePermissions": ["basic.events.read"],
"canManageUsers": false,
"canBuyAddons": false
}
}

Membership UI must:

  • distinguish role, module grants, permission grants, and delegation
  • show which modules are company-enabled commercially
  • disable grants that are not commercially valid
  • disable grants that exceed the actor’s own delegation powers
  • explain why a grant cannot be applied

The Admin frontend must expose connected-user and active-session monitoring.

Platform staff need to know:

  • how many users are connected
  • which users are connected
  • where sessions are coming from
  • which sessions need revocation
  • global sessions list
  • session stats dashboard card/panel
  • user session detail panel
  • company session list
  • GET /api/v1/admin/sessions
  • GET /api/v1/admin/session-stats
  • GET /api/v1/admin/platform-users/{userId}/sessions
  • GET /api/v1/admin/companies/{companyId}/sessions
  • POST /api/v1/admin/platform-users/{userId}/revoke-all
  • user id
  • email
  • full name when available
  • global role
  • IP address
  • user agent
  • device name
  • created at
  • last used at
  • expires at
  • revoked or active status

The Admin frontend should treat:

connected user = user with at least one active session
active session = not revoked and not expired

This is active authenticated presence, not realtime websocket presence.


The Admin frontend must provide governance screens for delegation.

Delegation screens answer:

What may a user grant or manage for someone else?

They are not the same as direct permission assignment screens.

  • delegation rule list
  • delegation rule detail
  • delegation rule create
  • delegation rule edit
  • role-based delegation matrix
  • GET /api/v1/admin/delegation-rules
  • POST /api/v1/admin/delegation-rules
  • PATCH /api/v1/admin/delegation-rules/{id}
{
"role": "ADMIN",
"grantableModules": ["basic", "finance"],
"grantablePermissions": [
"basic.events.read",
"basic.events.create",
"finance.bills.read"
],
"canManageUsers": true,
"canBuyAddons": false
}

Delegation UI must:

  • clearly separate personal access from grantable access
  • clearly explain why a role can or cannot grant something
  • avoid mixing permission-assignment UI with delegation policy UI in one unclear editor

16. Payment-provider configuration screens

Section titled “16. Payment-provider configuration screens”

The Admin frontend must provide operational payment-provider configuration.

  • payment provider list
  • Stripe configuration
  • Xendit configuration
  • region/deployment mapping
  • GET /api/v1/admin/payment-providers
  • POST /api/v1/admin/payment-providers/stripe
  • POST /api/v1/admin/payment-providers/xendit
{
"region": "SG",
"mode": "live",
"publishableKey": "pk_live_xxx",
"secretRef": "secrets/stripe/sg/live",
"webhookSecretRef": "secrets/stripe/sg/webhook",
"isDefault": true
}
{
"region": "ID",
"mode": "live",
"secretRef": "secrets/xendit/id/live",
"callbackTokenRef": "secrets/xendit/id/callback",
"isDefault": true
}

Payment-provider UI must:

  • never expose raw secrets after submission
  • support masked config display
  • support environment and region separation
  • require explicit confirmation on overwrite

17. Operational Admin surfaces that remain first-class

Section titled “17. Operational Admin surfaces that remain first-class”

The new architecture does not remove these Admin frontend responsibilities.

The Admin frontend must keep first-class UI for:

  • approvals
  • artists
  • venues
  • files
  • AI tools

Required endpoints:

  • GET /api/v1/admin/approvals
  • GET /api/v1/admin/approvals/{id}
  • POST /api/v1/admin/approvals/approve
  • POST /api/v1/admin/approvals/reject

Required endpoints:

  • GET /api/v1/admin/artists
  • GET /api/v1/admin/artists/{id}
  • POST /api/v1/admin/artists
  • PATCH /api/v1/admin/artists/{id}
  • DELETE /api/v1/admin/artists
  • GET /api/v1/admin/artists/genres
  • GET /api/v1/admin/artists/latest-counters
  • POST /api/v1/admin/artists/platforms
  • GET /api/v1/admin/artists/search
  • GET /api/v1/admin/artists/spotify

Required endpoints:

  • GET /api/v1/admin/venues
  • GET /api/v1/admin/venues/{id}
  • POST /api/v1/admin/venues
  • PATCH /api/v1/admin/venues/{id}
  • DELETE /api/v1/admin/venues
  • GET /api/v1/admin/venues/types
  • GET /api/v1/admin/venues/bandsintown
  • GET /api/v1/admin/venues/viberate
  • GET /api/v1/admin/venues/gemini
  • GET /api/v1/admin/venues/search-by-platform
  • GET /api/v1/admin/venues/sleeping
  • POST /api/v1/admin/venues/{id}/takeover-approvals
  • POST /api/v1/admin/venues/{id}/activate
  • POST /api/v1/admin/venues/{id}/revert-takeover
  • GET /api/v1/admin/venue-requests
  • GET /api/v1/admin/venue-requests/{id}
  • GET /api/v1/admin/venue-requests/{id}/proof-url
  • POST /api/v1/admin/venue-requests/{id}/approve
  • POST /api/v1/admin/venue-requests/{id}/reject
  • GET /api/v1/admin/artist-company-requests (2026-05-25 — agency provisioning queue, mirror of venue-requests with no proof-url variant)
  • GET /api/v1/admin/artist-company-requests/{id}
  • POST /api/v1/admin/artist-company-requests/{id}/approve
  • POST /api/v1/admin/artist-company-requests/{id}/reject

Required endpoint:

  • POST /api/v1/admin/files/upload

Required endpoint:

  • POST /api/v1/admin/ai/gemini

The Admin frontend should behave like a control plane.

Require confirmation for:

  • deactivate user
  • revoke sessions
  • deactivate company
  • reject company
  • remove add-on
  • overwrite provider config

Where possible, UI should explain:

  • this change affects commercial entitlements
  • this change affects user access
  • this change revokes live sessions
  • this change will affect what users can see

Important screens should identify where the action writes:

  • commercial write -> Core
  • access write -> Auth
  • operational write -> Admin-owned domain

This reduces operator confusion.


19. Loading, caching, and invalidation rules

Section titled “19. Loading, caching, and invalidation rules”

The Admin frontend must assume writes have downstream effects.

Examples:

  • package changes should refresh package list, package detail, and any company entitlement summary
  • module changes should refresh package and add-on editors
  • membership or delegation changes should refresh user context and membership panels
  • revoke-all should refresh session list and user session panels

The frontend should invalidate queries by domain:

  • packages
  • modules
  • add-ons
  • companies
  • users
  • memberships
  • sessions
  • delegation rules
  • approvals
  • artists
  • venues

The Admin frontend is complete only when platform staff can:

  • manage packages
  • manage modules
  • manage add-ons
  • create and manage companies
  • inspect subscription and entitlement outcomes
  • manage platform users
  • manage company memberships and business-unit memberships
  • inspect connected users and sessions
  • define delegation rules
  • manage payment-provider configuration
  • continue using approvals, artists, venues, files, and AI utilities

Frontend-Kisum-Admin is a React Router 7 app in SPA mode (react-router.config.ts has ssr: false). The build emits a single build/client/index.html plus static assets — there are no per-route HTML files. Hosting therefore needs an explicit rewrite rule so client-side routes resolve to index.html instead of returning a 404 from the static origin.

The production deployment at admin.kisum.io is CloudFront → S3 (not Amplify Hosting at the edge). For client-side routes to work, the CloudFront distribution must rewrite “missing object” responses from S3 into a 200 serving /index.html. There are two layers to get right:

  1. CloudFront custom error responses (required). Distribution → Error pages → create one entry each for HTTP 404 and 403:
    • HTTP error code: 404 (and a second entry for 403)
    • Customize error response: Yes
    • Response page path: /index.html
    • HTTP Response Code: 200 ← this is the part that is easy to miss; if left at the original error code, the browser receives 404 + HTML body and refuses to execute the bundle, so the in-browser router never boots
    • Error caching minimum TTL: 0 (so future fixes propagate without waiting on the edge cache) Cover both 404 and 403 because S3 private buckets fronted by OAC/OAI typically return 403 for a missing key rather than 404.
  2. CloudFront invalidation on every deploy. After uploading new assets to S3, invalidate /* (or at minimum /index.html and any changed routes). Without this the edge keeps serving the previous build.

Symptom of a misconfigured #1: curl -I https://admin.kisum.io/<new-route>/ returns HTTP/2 404 but with content-length / etag / last-modified headers identical to /index.html. That means the body is already being rewritten to index.html but the status code stayed 404. Flip the HTTP Response Code to 200 on the error-page rule and the route starts working immediately.

The same constraint applies to every future client-side route added to this app. Anyone adding a new top-level route should verify the route returns HTTP/2 200 end-to-end and trigger an invalidation before reporting the deploy as done.

If the app is ever moved to AWS Amplify Hosting for serving (not just CI/CD), the equivalent of #1 is a single rewrite rule under App settings → Rewrites and redirects: source </^[^.]+$|\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|woff2|ttf|map|json|webp)$)([^.]+$)/> → target /index.html → type 200 (Rewrite).


Frontend-Kisum-Admin is the platform control-plane UI.

It must:

  • authenticate platform staff through Auth
  • call only the Admin backend for control-plane work
  • expose commercial, access, and operational management surfaces
  • separate Core-owned truth from Auth-owned truth
  • remain the main platform-staff operating console for the system