Licence register
Banking and fintech businesses,
sold with the licence attached.
Buyers state a mandate once. Sellers list an entity. The catalogue ranks one against the other, so nobody reads every listing to find the three that fit.
Three sides, three different screens
The same catalogue looks different depending on who is holding it, and not as a matter of styling: each role reaches a different set of rows.
Seller
Sees Their own listings including drafts, plus every published listing.
Does Publishes an entity, reads what buyers are looking for, writes to one directly.
Buyer
Sees Published listings only, ordered by how well each fits their mandate.
Does States a mandate once, then lets the catalogue do the shortlisting.
Platform manager
Sees Everything. Drafts, removed listings, every participant, every message.
Does Suspends an account or takes a listing down, and both take effect in the database.
The rules live in the database
Not in a route guard, and not in a hidden button. Every read and every write goes through row level security in Postgres, so a request that skips this interface entirely gets the same answer.
That claim was tested rather than asserted. Attacking the first version of the policies found six holes, one of which let any account promote itself to platform manager, because RLS restricts rows and never columns. All six are written up with the request that proved each one.
Read the audit- Suspended accountsees zero rows, and cannot write one
- Suspended sellertheir live listings leave the catalogue with them
- Suspended managerloses the console; holding the role is not enough
- Any accountcannot rewrite its own role or status
- Any sellercannot award itself the validated badge
- Buyer mandatesvisible to sellers and managers, nobody else
Pick the side you are on
Three seeded accounts, no sign-up. Each one drops you straight into that role.
Every demo account uses the password demo1234. Create an account
There is a fourth account, suspended, on the role picker — worth a click if you want to see what a blocked participant gets.