# JWT -> filter -> TenantContext -> @TenantId, real HTTP against the discriminator application

== the filter: who gets in
-- no Authorization header
   GET /invoices  ->  HTTP 401  {"error":"missing bearer token"}
-- garbage token
   GET /invoices  ->  HTTP 401  {"error":"invalid token"}
-- token signed with a different secret
   GET /invoices  ->  HTTP 401  {"error":"invalid token"}
-- expired token (exp = 10 minutes ago)
   GET /invoices  ->  HTTP 401  {"error":"invalid token"}
-- valid signature, no tenant_id claim
   GET /invoices  ->  HTTP 403  {"error":"token carries no valid tenant"}
-- valid signature, tenant_id = "x; drop schema public cascade"
   GET /invoices  ->  HTTP 403  {"error":"token carries no valid tenant"}
-- valid signature, tenant_id = "public" (reserved name)
   GET /invoices  ->  HTTP 403  {"error":"token carries no valid tenant"}

== two tenants, same URL, different data
-- acme creates INV-1
   POST /invoices  ->  HTTP 201  {"id":1,"number":"INV-1","amount":100.00,"tenant":"acme"}
-- acme creates INV-2
   POST /invoices  ->  HTTP 201  {"id":2,"number":"INV-2","amount":250.00,"tenant":"acme"}
-- globex creates INV-9
   POST /invoices  ->  HTTP 201  {"id":3,"number":"INV-9","amount":999.00,"tenant":"globex"}
-- acme lists
   GET /invoices  ->  HTTP 200  [{"id":1,"number":"INV-1","amount":100.00,"tenant":"acme"},{"id":2,"number":"INV-2","amount":250.00,"tenant":"acme"}]
-- globex lists
   GET /invoices  ->  HTTP 200  [{"id":3,"number":"INV-9","amount":999.00,"tenant":"globex"}]

== cross-tenant read by id
-- globex asks for acme's INV-2 by id (2)
   GET /invoices/2  ->  HTTP 404  
-- acme asks for the same id
   GET /invoices/2  ->  HTTP 200  {"id":2,"number":"INV-2","amount":250.00,"tenant":"acme"}

== a well-formed tenant nobody has onboarded
-- token for tenant "ghostco": GET /invoices
   GET /invoices  ->  HTTP 200  []
-- token for tenant "ghostco": POST /invoices
   POST /invoices  ->  HTTP 201  {"id":4,"number":"INV-G","amount":1.00,"tenant":"ghostco"}
