Appearance
Adding a module
The platform is built to take new kinds of work without rewiring. Pick the kind you're adding.
A new feature inside institutions
For example a transport module that some institutions run and others don't:
- Permissions. Add the page and its permissions to the permission catalogue (
20260915000400_permission_catalog.sqlshows the shape), then runnpm run gen:permission-defs. - Feature. One
app.featuresrow, itsapp.feature_pagesrows, andapp.institution_type_featuresrows for the types that get it by default. - Tables. Add each table to
app.auth_table_manifest(scope column, page key, narrowing), thenselect * from app.generate_policies('<table>'). - UI. Routes behind
PermissionGate(staff) orFeatureGate(student pages), and a nav item with thepageKey.
Branch on features, never on the institution type's name.
A new institution type
One app.institution_types row with its vocabulary and settings, plus its app.institution_type_features. No application code changes.
A new kind of public site
For example a hostel with its own public site:
- Database. Add a branch to
app.site_labelsand the kind tosite_domains_kind_check. Give the entity asubdomaincolumn with the same format and reserved-label checks as the others, and check availability across every kind. - Frontend. Add an entry to
SITE_MODULESinsrc/public-site/siteModules.ts, with a renderer insrc/public-site/hostSites.tsx.
The edge router and resolve_site_host need no change: they already route by whatever app.site_labels returns.
A new platform entity with its own staff
Libraries and stores are the pattern: a scope type, a principal_grants scope, a manager role in app.roles, provisioning RPCs that mint the auth user, principal, aliases and grant together (see create_librarian_manager), and a portal route with its own layout.