Not policies in a PDF. Constraints in the engine.
CareSewa holds medical records. That earns you the right to know exactly how they are separated, who can reach them, what is recorded when they change — and where the honest limits of our claims are. All of it is on this page, including the parts most vendors leave off.
Tenant isolation
enforced in every query
Two identities
tenant and patient, separate
Append-only audit
on every mutation
Consent as the gate
the patient decides
A rule you can skip is not a rule
Most healthcare security pages describe intentions. This one describes code paths. The difference matters more than the wording suggests.
A policy is a promise
It lives in a document, it is enforced by people remembering it, and it fails silently. Nothing about writing it down makes it true at three in the morning under load.
A constraint is a fact
It lives in the code path every request passes through. It cannot be forgotten, skipped under deadline pressure, or overridden by someone who means well.
So we wrote constraints
Everything below is a rule the engine enforces on every request, for every tenant, every time. We describe it in this much detail because vagueness is where trust goes to die.
If a control below could be turned off by a busy engineer on a Friday, we would not have listed it.
Every one of them sits in the request path itself — not in a checklist somebody is supposed to consult first.
Seven layers. Watch one get through — and five get stopped.
Every request to CareSewa passes through seven independent enforcement layers. Rather than list them, we let you fire real requests at the stack and see exactly where each one dies.
Send a request through it
GET /api/v1/data/patientA ward nurse, signed in, reading patients in an ERP her account owns and her grants cover.- 1EdgeHTTPS/HSTS, security headers, CORS allow-list, rate limiting
- 2IdentityJWT verified; tenant and patient tokens are separate identities
- 3Tenant scopeTenant pinned from the token; every query filtered by it
- 4EntitlementDoes this account actually own the ERP being addressed?
- 5PermissionRole and per-model grants, read fresh from the database
- 6ValidationPayload checked against your own ModelDefinition
- 7Audit & preservationAppend-only trail; medical records soft-deleted, never destroyed
These are the real layers, in the real order, returning the codes the API really returns — you can reproduce every one of them against a demo tenant. What this is not is a claim that CareSewa cannot be broken into. Defence in depth exists precisely because any single layer can fail; the design assumption is that one eventually will, and that the next six still have to hold. Anyone who tells you their system is unhackable is telling you how their next incident report will begin.
The point of seven layers is not that seven is a big number.
It is that they are independent. A bug in the entitlement check does not hand you another tenant’s data, because the tenant filter is a separate layer that never ran the buggy code. Compromise one and you have compromised one. Every layer below is written on the assumption that the layer above it has already failed — which is the only assumption that has ever aged well in this industry.
Tenant separation is structural, not conventional
The most common way multi-tenant systems leak is a query somebody forgot to scope. We removed the opportunity to forget.
Every ModelDefinition — the description of a model you built in Studio — and every DynamicRecord stored against it carries a tenantId. Every query filters by it. There is no implicit cross-tenant read anywhere in the system, and super-admin access across tenants exists only as an explicit, deliberate assertion — never as a default a request can drift into.
- Definitions and records both carry the tenant — the schema is isolated, not just the data
- Every query filters by tenant, so an unscoped read is not a risk you are trusting us to avoid
- Relations must point at records in the same tenant — you cannot build a link that leaks
- Super-admin cross-tenant access is explicit only, and it is audit-logged like everything else
What a record actually carries
DynamicRecord {
tenantId ← every read filters on this
portal ← and entitlement is checked against it
model ← validated against its ModelDefinition
data { … your fields … }
deletedAt ← soft delete. never a hard DELETE.
createdBy
updatedBy
}The first line is the whole argument. Isolation is not a middleware you can bypass by calling the database directly — it is a property of the record, so every path that reads one has to reckon with it.
Two identities that cannot be mistaken for each other
A hospital’s staff and a hospital’s patients are not two roles in one system. They are two separate identities, with separate tokens, that meet only where the patient allows it.
Tenant tokens
Issued to the people who run an organisation — owners, admins, doctors, technicians, front desk. They carry the tenant and the portal entitlements that account holds.
- Rejected outright on patient routes
- Carry portal entitlements, checked per request
- Reissued with new entitlements when you subscribe to an ERP
Patient tokens
Issued to a person, for an account that belongs to them and to no hospital. They authenticate a human being across every provider that human has chosen to connect to.
- Rejected outright on tenant routes
- Platform-level — not scoped to, or owned by, any provider
- Reach a provider’s data only through an explicit share
Short-lived access tokens
Access tokens are JWTs with a short TTL. A stolen one has a narrow window to be useful in, by design.
Refresh tokens, separately
Longer-lived refresh tokens exchange for new access tokens, so the credential that lives longest is the one used least.
Wrong-door requests fail
Presenting the wrong identity at the wrong route is not a permissions error to be argued about. It is rejected.
Owning an account is not the same as owning every portal
One account can own ten ERPs. It can also own two. The engine has to know the difference on every single record operation — so it checks, every single time.
Which portals an account is entitled to is carried in the JWT, and assertPortalEntitled gates every record operation against it. Ask for a record in a portal your account has not subscribed to and the answer is a 403 with PORTAL_NOT_ENTITLED — not a filtered list, not an empty array, not a partial answer that leaves you guessing what exists behind the wall.
- Entitlements live in the token, and the check runs on every record operation
- A clear 403 with a named code — refusals are legible, not silent
- Subscribing provisions the portal and issues fresh tokens carrying the new entitlement
- Disconnecting a portal removes the entitlement the same way it was granted
Request lifecycle
- 1
Token verified
signature, expiry, identity type
- 2
Tenant resolved
every query scoped from here on
- 3
Portal entitlement asserted
assertPortalEntitled
- 4
Staff permission read from DB
fresh, never cached from login
- 5
Payload validated
against the ModelDefinition
- 6
Mutation written + audited
before/after, actor, ip, timestamp
Six gates. Every request. There is no express lane for internal callers, because there are no internal callers — the product uses the same API you do.
Revocation that does not wait for a token to expire
The usual trade-off: bake permissions into the token and revocation lags, or read them per request and pay for it. We pay for it. When you revoke access, you mean now — not in fifteen minutes.
Grants are per portal and per model
A staff member does not get “access”. They get named portals, and inside those, named models, and on each of those, individual create / read / update / delete grants. A lab technician can read orders and update samples without ever being able to touch billing — not because they are trusted not to, but because the grant does not exist.
| Example grant | Create | Read | Update | Delete |
|---|---|---|---|---|
| lab · Order | ||||
| lab · Sample | ||||
| lab · Report | ||||
| hospital · Bill |
Illustrative. The models are the ones you defined — so are the grants.
Read fresh, every request
Permissions are loaded from the database on every request rather than trusted from the token that was minted at login. It costs a read. It buys you the only revocation guarantee that means anything: the next request they make is already denied.
Someone leaves at 4pm. Their access ends at 4pm — not whenever their token happened to be due for renewal.
The patient is the gate. Not a setting inside your system.
This is the part of the architecture we are most willing to argue about, because it is the part most healthcare software gets backwards.
In most systems, a patient record is something a hospital owns and a patient is granted a view of. In CareSewa it is the other way round. Patient accounts are platform-level and belong to the patient — not to any hospital, not to the clinic that first registered them, not to us. A provider sees nothing until the patient connects to them and explicitly shares.
Connect
The patient chooses a provider and connects to them — usually by their public code. Connection alone is a relationship, not an open door.
Share
Sharing is a separate, explicit act. Until it happens, the provider does not see the profile. Nothing is shared because a form was filled in at a front desk once.
Revoke
The patient revokes, and everything is hidden from that provider instantly. Not queued, not on next sync, not after a support ticket. Instantly.
What this costs providers, honestly: you cannot quietly accumulate a patient population you have no relationship with. That is not a bug we intend to fix. The upside is that every patient in your system is one who chose to be there — and their records arrive complete, from every provider they use, instead of arriving as a photograph of a report in a plastic bag.
Reject the ambiguous. Never drop it silently.
A no-code engine where anyone can define a model has one obvious failure mode: garbage in the database because nothing was checking. So something is always checking.
Every write is validated against the ModelDefinition it targets. Coercion — turning the string "42" into the number 42 for a number field — is deterministic: the same input always produces the same result. And where the input is genuinely ambiguous, the write is rejected rather than silently dropped.
That is a deliberate choice with a cost. A rejected write is an error somebody has to deal with. A silently dropped field is a lab value that vanished between the analyser and the report, discovered six months later by nobody. We will take the error every time.
Validated against its definition
Every record, every write. The definition is data, so the validation follows your model the instant you change it — there is no generated code to fall out of sync.
Deterministic coercion
Type conversion follows fixed rules across the 18 field types. The same input produces the same stored value, today and next year.
Ambiguity is an error
When the engine cannot be sure what you meant, it refuses and says so. It does not guess, and it does not quietly discard the field.
Relations stay in-tenant
A relation field can only reference records inside the same tenant. Isolation is not just enforced on read — it constrains what you are able to build in the first place.
Medical data is not ours to destroy
Delete means something different in a clinical system than it does in a to-do app. We treat it that way.
Records are soft-deleted, never dropped
Deleting a medical record marks it with a deletedAt and removes it from view. It is not hard-deleted by default. A mis-click at a busy front desk is recoverable, and the audit trail still resolves to a real record rather than a dangling id.
Where genuine erasure is required — and in some jurisdictions and some circumstances it is — that is a deliberate, privileged operation, not the thing that happens when someone clicks the wrong row.
Removing a field stops collection. It does not erase history.
This is where a no-code engine could do real damage, and it is where we were most careful. Take a field off a model in Studio and you stop collecting it and stop showing it — the values already recorded against existing records are preserved.
Your protocol changed in March. That does not mean February’s observations were never made. A system that let a dropdown edit rewrite clinical history would not be a system you should put patients into.
Every mutation, written down and never editable
Not a log level you can turn down. Not a feature on a higher plan. A property of writing to the system at all.
Every create, update and delete writes an audit entry. It is append-only: admins read it, nobody edits it, and that includes us. An audit trail that can be tidied up afterwards is not an audit trail — it is a diary.
Recorded on every mutation
actor | Which user or patient performed it — not “the system”. |
tenant | Which tenant the action belongs to. |
action | Create, update, delete — the operation attempted. |
resource | The model and the record it touched. |
before | The state of the record prior to the change. |
after | The state of the record following it. |
ip | The address the request originated from. |
userAgent | The client that made it. |
timestamp | When, to the millisecond. |
Append-only. There is no update path and no delete path on the audit collection. The trail is the one part of the system that the no-code engine deliberately cannot reshape.
The boring controls, which are the ones that catch things
None of these are interesting. All of them are the reason an incident stays small.
Rate limiting
Requests are rate limited at the edge of the API. A misbehaving integration or a brute-force attempt hits a ceiling before it hits your data.
Pagination is capped
Lists default to 20 records and are hard-capped at 100. There is no “give me everything” parameter, so a compromised credential cannot vacuum a database in one call.
Helmet & CORS
Standard security headers are applied on every response, and cross-origin access is restricted to the origins we serve rather than left open.
One response envelope
Every endpoint answers in the same shape with the same error codes. Uniformity is a security property: surprising responses are where parsing bugs and information leaks live.
One API, no side doors. The REST endpoints your integrations call are the same endpoints the hospital web app and the CareSewa One mobile app call. Same auth, same entitlement assertion, same tenant filter, same validation, same audit write. There is no privileged internal API with the checks turned off — which is precisely why an analyser bridge or an existing HIS can be wired in without anyone having to reason about whether it weakens the model.
Asia-first means no single country was ever assumed
A platform built for one market and later “expanded” carries that market’s assumptions in its bones. This one did not start there.
The stack — Node, Express, MongoDB — is deployable per region. Nothing in the architecture pins your data to one country, one database location, or one regulatory regime. Tenants are isolated from each other regardless of where they run, so a regional deployment is a deployment decision rather than a re-architecture.
Read this precisely. What we are describing is an architectural capability: the platform can be deployed per region. That is not the same as a certified guarantee about where your specific tenant’s data resides today, or a legal opinion about what your local law requires of it. Both of those are conversations to have with our team about your deployment — not claims to take from a marketing page.
No national assumption
No identifier scheme, currency, or regulatory workflow is hard-coded into the engine.
Deployable per region
The stack runs where you need it to run, without a fork or a special build.
Local rules are models
What a country requires you to record is a field you define — not a release we have to ship.
Isolation travels
Tenant separation holds identically wherever the deployment lives. It is a property of the data.
Found something? We want to hear it.
Researchers who report vulnerabilities are doing us — and every patient on the platform — a favour. We would rather learn it from you than from an incident.
Choose “security disclosure” on the contact form and it routes to the people who can act on it, not to a sales queue.
Send us the details
Reach us through the contact page and choose “security disclosure”. Include what you found, where, and the steps to reproduce it. A working proof of concept helps enormously; a vague “you have a vulnerability, pay me” does not.
We acknowledge it
A person reads it and replies. We will not leave a genuine report sitting in a queue while we decide whether it is convenient — but we also will not invent a response-time SLA on a marketing page that we have not staffed to meet.
We investigate and fix
We reproduce it, assess the blast radius across tenants, and ship a fix. If it touched customer data, the affected tenants hear from us — the audit trail is precisely what lets us say who was affected instead of guessing.
We credit you, if you want it
Researchers who report responsibly get acknowledged by name, or stay anonymous — your call. Please give us a reasonable window to fix before publishing, and please do not test against real tenants or real patient data.
What we do not claim
This section exists because we would want to read it. Everything above describes controls we built. Here is the boundary of what that entitles us to say — stated plainly, so you never have to work out where the marketing stops.
We do not claim any compliance certification
Not HIPAA. Not GDPR. Not ISO 27001. Not SOC 2. None of them appear as a badge on this page, because a certification is a specific audit, by a specific auditor, against a specific scope, with a specific report date — and we are not going to imply one by decorating a page with acronyms.
Architectural controls are not certification
Tenant isolation, audit logging and consent gates are the kind of controls those frameworks look for. Having them is necessary; it is not sufficient. The gap between “we built the control” and “an auditor verified the control, its evidence, and the organisation around it” is real, and it is the whole point of certification. We are on the first side of that gap.
Confirm certification status with us, not with this page
If your procurement process needs to know what is certified, in progress, planned or out of scope for your deployment, ask our team. You will get the current position in writing. What you will not get is a marketing page quietly aging into a false claim.
Data residency is a capability, not a guarantee here
The platform is deployable per region and assumes no single country — that is architecture, and it is true. Which region your specific tenant runs in, and what that means under your local law, is a deployment and contractual matter to settle with us directly.
We do not publish penetration test results we have not commissioned
No third-party report is being cited on this page, so please do not read one into it. If you require independent testing as a condition of working with us, raise it — that is a legitimate ask and a real conversation.
No security architecture is a promise of invulnerability
Every control described above narrows what can go wrong and makes what did go wrong legible after the fact. Neither of those is the same as “nothing can go wrong”, and any vendor who tells you otherwise is selling you the badge, not the system.
A vendor who tells you what they have not done is telling you the truth about what they have.
We could have filled this page with acronyms in grey boxes and most buyers would never have checked. We would rather you trusted the specific, verifiable things above — every one of which we will happily demonstrate in the product — than a badge that means nothing without the report behind it.
The questions procurement actually asks
Straight answers, including to the uncomfortable ones.
We make no certification claim on this page, and you should treat any page that does without naming an auditor and a report date with suspicion. What we describe here are architectural controls we built and can show you in the product. Whether a given certification or audit is in progress, planned, or not applicable to your deployment is a question for our team directly — ask, and you will get a straight answer rather than a badge.
Put the security model in front of your team
Bring the hardest questions you have. We would rather answer them now than have you discover the answer for yourself later.
Multi-country by design · tenant-isolated · every change audit-logged