GainUp

Security and architecture

The short version: your data is isolated below the business logic, permissions are explicit grants rather than job titles, nothing is truly deleted, and every operation is recorded.


Tenancy is enforced at the data layer

Multi-tenant systems usually isolate customers in application code — every query is supposed to include a filter for the right company. It works until one query forgets.

emko cloud doesn't rely on remembering. Tenant scoping is applied one layer below the business logic, inside the component that talks to the database. Every retrieve, list, count, update and delete is scoped before it runs. A feature cannot forget the filter, because a feature never writes the filter.

Defence in depth: even if business logic has a bug, the data layer prevents cross-company access. Every record type in the system — all of them, with no exemptions — sits inside this boundary.


Permissions are grants, not roles

There is no role table, and that's deliberate. A "Sales Manager" at one company holds a completely different set of powers than a "Sales Manager" at another. The label is the same; the permissions aren't. Naming the label and pretending it means something is how access control quietly stops matching the org chart.

Instead, each user carries explicit grants: a resource, an action, and the constraints that apply.

Constraints can scope a grant to a company, a team, a project, a specific record, a set of statuses, or a time window — nested so that company-wide access implies project access implies access to your own records.

Two consequences worth knowing:

  • Everything is a positive grant. There are no deny rules to reason about, so "what can this person actually do?" has one answer you can read.
  • Revocation takes effect on the next request. No waiting for a session to expire.

Nothing is hard-deleted

Deletes mark records as deleted rather than removing them. Deleted data stays recoverable, history stays intact, and reports over past periods keep working.

Cascades are explicit and controlled by the application rather than the database, specifically so that a cascade can never chase a reference across a company boundary.


Everything is on the record

Two independent trails run under every operation:

  • An audit log capturing every invocation — who, when, what went in, what came out.
  • A change stream emitting created, updated and deleted events with the actor, the company, the timestamp and the payload. Subscribe to it by record type to drive live updates, notifications or your own webhooks.

Identity you can read

Every record's identifier names its own type. A person's ID is visibly a person's ID; a project's is visibly a project's. Two consequences show up in daily use:

  • Paired records share an identity. Your company and its account record are the same identity seen from two angles — never mismatched, never out of sync.
  • A reference doesn't need a type column. A note attached to "this record" knows what it's attached to from the identifier alone.

Companies also carry a short, human-readable public ID — the one your people type on the sign-in form, rather than a UUID nobody can read over the phone.


Four ways in, and one check in front of all of them

Every operation is published on four surfaces at once. Not four integrations maintained in parallel — one catalogue of operations with four protocols in front of it. Add a record type and it appears on all four the same day.

The security point matters more than the convenience one. These are not four implementations that each have to remember the rules — they are four doors into the same catalogue, behind the same permission check and the same tenant scoping.

  • No surface is a back door. A request does not skip the check because it arrived over a different protocol. The assistant's MCP call and your curl request are authorized identically.
  • Your integrations are not second-class. They call exactly what the product calls — same operations, same validation, same audit entries.
  • No SDK to install and no client to keep in step. The operation catalogue is the interface.
  • Live updates and webhooks are the same event stream. Subscribe over WebSocket, or point the change events at your own endpoint.

Where it runs

emko cloud is one process. The public site and the signed-in application share a single server on a single origin. There is no separate frontend server, no bundler running in production, no orchestration layer.

  • SQLite by default. Postgres when you need it.
  • Cookie and token authentication with cross-site request forgery protection built in.
  • Required configuration is two values: a signing secret and your allowed origin.

Run it on your own hardware, in your own jurisdiction, with your data on your disk. Or let us run it.


How it works · The assistant · Pricing