Skip to content
Every figure traces to a comparable, or the report does not render

The platform

The parts that decide whether this is safe to put several clients in

A valuation practice hands this software the addresses, owner names, survey numbers and title documents of every client it acts for. That makes the architecture a purchasing question rather than an engineering footnote, so it is written down here instead of being described on a call.

Six properties

Each of these is checkable, which is why it is written down

“We take security seriously” is not a claim anybody can test. “Scoping is applied where the query is built, and a build that forgets it fails” is.

Tenancy is enforced below the API

The firm sits on every row and is applied in the layer that builds the query, not in the handlers. That gives scoping exactly one place it can be forgotten, and a build that forgets it fails rather than shipping.

  • A read, list, search or download across firms answers as though the record does not exist
  • That answer is deliberate: a refusal confirms the row is there, and for a mandate name or an address the confirmation is the disclosure
  • The firm comes from a signed token — no endpoint accepts a firm identifier as an argument
  • A test fails the build if any data-access function can be called without a scope, and the handful of deliberate exceptions are listed individually with the reason each has no session to scope by

The engine is deterministic, and separate

The valuation arithmetic is a pure module with no model call in it, now or later. That separation is what makes the output reproducible and the drafting layer replaceable.

  • The same inputs produce the same figures on every run, to the rupee
  • A regression set replays a fixed job per document type with the provider replaced by a recording, and compares every figure exactly — a paisa of drift fails
  • Exact decimals throughout, rounded once at the boundary; no floating-point number touches money
  • Area conversion comes from one shared table that both the engine and the console read

Generation runs on a queue

The web process records the job and enqueues it; a separate worker runs the generation. A deploy does not interrupt a valuation, and a dropped connection does not produce a second one.

  • A submission repeated after a timeout returns the same job rather than generating a duplicate deliverable
  • Tasks are written to be safe to run twice, because at-least-once is what a queue actually gives you
  • A job that reached a terminal state is frozen — further status writes are refused at the data layer, where every writer passes through
  • Progress is readable while it runs rather than only when it finishes

Provenance and audit are structural

The chain from a rendered figure to the row it came from is stored, not reconstructed. So is the record of who read and exported what.

  • Deliverable sections carry the valuation lines and documents they drew on
  • Valuation lines carry their comparables and the source they were computed from
  • Every read and export writes an audit row with the actor, the address and the time
  • A figure or an assertion with no chain behind it blocks rather than rendering

Location and ownership are sensitive by default

Exact coordinates, owner names and survey numbers are treated as confidential data rather than as ordinary fields, because in this domain they are.

  • Redacted out of logs, so an operational log is not an ownership dataset
  • Absent from what a client-role response carries — not hidden in the interface, absent from the payload
  • Documents and photographs encrypted with per-firm keys
  • A written note of what is stored, where, for how long and which third parties see any of it, available for your own review

The threats specific to this input path

The dangerous inputs here are spreadsheets and scanned documents from third parties, and both have well-known ways of being weapons rather than data.

  • A tenant name beginning with an equals sign exports as inert text rather than as a formula in somebody’s spreadsheet
  • Documents in the scanning path are handled in isolation, so a malicious file does not escape the process reading it
  • Any address fetched from imported data is treated as untrusted rather than followed
  • Tenant names, addresses and narrations are client-controlled text, and are rendered as text everywhere in the console

The API

The console is one client of it, not a wrapper around a private one

Anything a person can do through the console, a system can do through the API — which is what makes an integration a configuration exercise rather than a project.

  • Request and response types are generated from the API’s own specification, so a change the console has not caught up with fails a build rather than surfacing as a runtime error in front of somebody.
  • Signed completion callbacks over the raw body with the timestamp inside the signed payload; a one-character change fails verification.
  • Failed deliveries retried with increasing backoff, then dead-lettered — a delivery is either confirmed or visibly not.
  • Exports as documents, as spreadsheets with the adjustment grid’s formulas intact, and as structured data.
  • Live job progress readable as it happens, so a caller does not poll blindly.
  • Quotas answer as a quota rather than as a server error, and the console shows that as a real state.

What it runs on

Boring where it can be

None of these choices is interesting, which is the point. The interesting decisions in this product are the refusals, and those are on the standard page.

EnginePython, layered so that route handlers hold no queries and the valuation module holds no model calls
DataPostgreSQL with geospatial indexing for comparables and properties, and exact decimal columns for every monetary figure
QueueRedis-backed jobs, run by a worker process separate from the web process
ConsoleReact and TypeScript, with server state cached and money handled as strings the browser never computes on
IdentitySigned tokens with multi-factor authentication on by default; the token is held in memory rather than in browser storage
DocumentsObject storage with per-firm encryption keys, and retention sweeps rather than indefinite accumulation

Multi-factor authentication is on by default and turning it off is a deliberate act with a name attached. These accounts sign documents a bank or a tribunal relies on.

Send this page to whoever does your security review

It is written for them rather than for a buyer, and the data-flow note behind it exists for the same reason. If something they need is not here, tell us what and we will write it down rather than answer it once on a call.

Get in touch

Talk to the people building it

No chatbot and no ticket queue. Tell us what your practice actually looks like — how many valuers, which asset classes, who reviews, which banks you are on the panel of — and someone who works on the software will reply.

info@legosphere.com

Please keep client names, owner names, survey numbers and exact addresses out of this box — it is an ordinary enquiry form, not a channel for a live mandate.