Skip to content

Security

Isolation, access, and a trail you can read.

You are about to put other people’s names, phone numbers, bank references and identity documents into somebody else’s software. This page describes what protects them, in the specific — and ends with the things we do not claim, because a security page that only lists strengths is not telling you anything.

Isolation

One organisation cannot see another.

Every landlord and every agency on QaceHomes shares a database with every other one. This is how they stay apart.

  • Every record belongs to an organisation

    Tenant-scoped tables carry a non-nullable, indexed organisation column. There is no row in the system that belongs to nobody, and the schema will not accept one.

  • Which organisation comes from the token, never the request

    The organisation you are acting as is read from your signed session token on every request. It is not a parameter, a header, or a field in the body — so it is not something a client can change, and code that tries to read it without an authenticated session throws rather than defaulting.

  • Scoped query helpers, on thirty-four record types

    A shared repository layer supplies organisation-scoped read and write helpers that inject the organisation predicate into the query, and thirty-four record types are built on it. Isolation is enforced in application code — see the note at the foot of this page for what that does and does not mean.

  • Cross-organisation access is tested, not assumed

    Sixty-four automated test cases across forty-three suites assert that a request carrying one organisation’s context cannot read or write another’s records — leases, invoices, tickets, statements, imports, signatures.

  • Public pages leak nothing sideways

    A portfolio’s branding is injected as custom properties scoped to the public surface, and the vendor and applicant responses are assembled from explicit whitelists. Internal costs, internal comments and the organisation’s own identity are not hidden by the interface — they are absent from the payload.

Access control

Your team sees its own part.

Nine roles over a registry of permission strings, narrowable to particular properties, enforced by a guard rather than by each developer remembering.

  • Nine roles

    Owner, Admin, Manager, Member, Leasing agent, Maintenance staff, Accountant, Viewer, and Tenant portal. A tenant using the mobile app is a role in the same system, not a separate back door.

  • Permissions are resource and action

    Over a hundred and seventy permission strings across twenty-seven resource types — invoice:create, lease:activate, audit:view. A role is a bundle of them, and an individual member can be granted or denied specific permissions on top of their role. A denial always wins over a grant.

  • Access narrows below the organisation

    A member can be scoped to particular portfolios or properties. Leasing agents and tenant-portal users must be. Owners and admins cannot be — a role that governs everything is not one you can quietly half-restrict.

  • A scoped member cannot be widened by an override

    Organisation-wide permission overrides are stripped at resolution time for a member who is scoped to specific properties, so a grant intended to unblock one task cannot become a route out of the scope.

  • Only an owner can create an owner

    The role that can do everything is the one role an administrator cannot hand out.

  • Seat limits are enforced by the server

    Three sub-users for an individual landlord, twenty for a business. The invitation is refused at the API with an explicit reason, not hidden behind a disabled button.

Accounts and sessions

A stolen token stops working.

Password handling, session lifetime, and what happens the moment something looks wrong.

  • Passwords are hashed with bcrypt at cost factor 12

    The plaintext is never stored, and password fields are on the redaction list applied before anything is written to the audit log.

  • Short-lived access tokens, rotating refresh tokens

    Access tokens are signed with HS256 and verified with the algorithm pinned, which closes the algorithm-confusion attack outright. Refresh tokens rotate on every single use.

  • A reused refresh token revokes the whole account

    If a refresh token is presented a second time, that is a copied token. Every session on the account is revoked and every issued access token invalidated — not the one request refused, the whole account signed out.

  • Sessions are revocable, individually and together

    Five concurrent sessions per account, oldest evicted. Changing a password or completing a reset revokes the others, so a compromised session does not outlive the response to it.

  • The refresh-token record holds no secret

    The database row for a refresh token contains an opaque identifier, an expiry, and a revocation flag. There is no token value stored in it to steal.

  • Failed logins lock the account; resets reveal nothing

    Five failed attempts, then fifteen minutes. A password-reset request returns the same response whether or not the address is registered, so the form cannot be used to enumerate who has an account. Reset links last an hour.

The audit trail

Who did what, to which record, and when.

A property dispute is settled by records. The audit log is written to be one.

Illustration of an audit entry in QaceHomes: a stream of recent actions, and one entry expanded to show the actor and their role, the record affected, the timestamp, each changed field with its value before and after, and a secret field replaced with a redaction marker.
  • Each entry holds the before and the after

    The actor, the action, the record type and its identifier, the values before, the values after, which fields changed, and the timestamp. The changed-field list is computed server-side rather than submitted.

  • Append-only in the schema and in the API

    The audit table has no update column and no delete column. The API exposes no endpoint that edits or removes an entry — only reads and an export. What that does not include is stated at the foot of this page.

  • Secrets are redacted before the row is written

    Passwords, password hashes, token hashes, API keys, access tokens, refresh tokens and anything named as a secret are replaced with a redaction marker on the way in, so the audit log cannot become the place a credential leaks from.

  • It is yours, and you can take it with you

    Audit and activity are screens in your own dashboard, filterable, with a CSV export of up to ten thousand rows. Every read is organisation-scoped like everything else.

  • Signatures carry their own evidence

    Separately from the audit log, every signature on a lease records the signer’s IP address and browser, when they opened the document, when they signed it, and a SHA-256 hash of the exact document they were shown.

Documents

Identity documents are the sensitive part.

A rental application carries a government ID, a payslip and a bank statement. Where those go matters more than most of this page.

  • Storage keys are namespaced by organisation

    Every stored object sits under a prefix derived from the owning organisation, so one tenant cannot write an object into another’s space even if a key were guessed.

  • Sensitive categories default to private

    Documents in sensitive categories are private unless someone deliberately makes them otherwise, rather than public unless someone remembers to lock them.

  • Private files are served through expiring signed links

    One hour for a download, five minutes for an upload, and the link is only issued after an organisation-scoped ownership check on the document itself.

  • Applicant uploads are quarantined until they belong to something

    A document attached before an application is submitted is held unbound and expires after thirty minutes. PDF, JPEG and PNG only, ten megabytes each, ten per application.

The public surface

The parts anyone on the internet can reach.

Portfolio pages, enquiry and application forms, vendor links, signing links. Each of them is a door, and each is treated like one.

  • Rate limits, tightest where it matters

    Three hundred requests a minute by default, and much less where abuse is worth something: five registrations an hour per address, five login attempts per fifteen minutes per email address, three password resets an hour, three demo requests a minute.

  • Unexpected fields are rejected, not ignored

    Request validation runs globally and refuses any property it was not expecting, rather than quietly dropping it and processing the rest.

  • Magic links are treated as credentials

    Vendor and signing links store only a hash of the token, never the token. Dedicated middleware strips them out of request logs. And the vendor link carries a per-token throttle that revokes it after thirty failed attempts — which closes the rotating-address bypass that per-address throttling alone leaves open.

  • Signing links are issued one at a time

    In a multi-party signature cohort only one live link exists at any moment. The second recipient’s link does not exist until the first has signed, so there is no dormant credential sitting in an inbox for a week.

  • Browser and transport hardening

    Security headers on the API, and clickjacking, MIME-sniffing and referrer-policy headers on every page of the app. Session cookies are HttpOnly, SameSite=Lax, and Secure in production. Cross-origin requests come from an allow-list, and request bodies are capped at two megabytes.

  • Portfolio analytics never store a visitor’s address

    Page views on your public site are counted against a daily-salted hash of address and browser. The database does not hold a visitor’s IP address at all.

NDPA & POPIA

Two jurisdictions, named.

Our privacy notice is the binding document. This is what it commits us to.

  • Both regimes and both regulators are named

    The notice is written against Nigeria’s NDPA 2023 and South Africa’s POPIA, and names the Nigeria Data Protection Commission and the South African Information Regulator as the bodies a person can complain to.

  • Controller and processor are separated

    Your workspace is the controller — the responsible party. QaceHomes is the processor, the operator. What we may do with your tenants’ personal information is bounded by what you instruct us to do with it.

  • Data-subject requests answered within thirty days

    The rights, the route to exercising them, and the response window are stated in the notice rather than left to be negotiated.

  • Sub-processors are disclosed, AI providers by name

    The notice lists the categories of sub-processor we rely on and names the AI providers specifically, rather than folding them into "third-party service providers" and hoping nobody asks.

  • Nothing is sold, and nothing follows you around

    No sale of personal information, no cross-context behavioural advertising, no third-party analytics cookies, and no marketing or retargeting cookies anywhere on this site or on your portfolio pages.

What we do not claim.

QaceHomes PMS is in pilot. Everything above is in the product today; everything here is not, and you should know which is which before you decide.

  • We hold no certification. No SOC 2, no ISO 27001, no completed third-party penetration test, no bug-bounty programme. If a vendor at this stage tells you otherwise, ask to see the report.
  • Isolation is enforced in application code. Every tenant-scoped query carries the organisation predicate and sixty-four tests assert it — but the database does not additionally enforce it with row-level security. There is one layer here, not two.
  • We do not encrypt individual fields inside the database. Whatever encryption applies to the storage volume is our hosting provider’s, and we are not going to describe it as though it were ours.
  • There is no multi-factor authentication, and no SSO, SAML, or SCIM. The six-digit code at sign-up verifies an email address; it is not a second factor and we will not call it one.
  • Append-only describes the audit table’s schema and the API surface. There is no database-level write protection and no hash chain over the entries.
  • Documents you deliberately publish are served from a permanent public URL. Only private documents go through signed, expiring links.

The binding document is the privacy notice, which sets out what we do with personal information, who processes it on our behalf, and how a data subject exercises their rights under NDPA and POPIA.

Ask us the question this page didn’t answer.

If one of the gaps above is a blocker for your organisation, say so — knowing which ones actually stop people is how we decide what to build next.