Building maintenance
and inspections
you actually own.
Jobs, costs, and templated condition inspections with ingoing/outgoing comparison — in one static binary and one SQLite file.
Built for managing agents, landlords with a portfolio, body corporates and facilities teams. It is designed to work fully offline, to need no central server, and to let a contractor run their own node as a first-class participant rather than a login on somebody else's system.
There is no binary, no release, no container image and no user interface. A previous cloud-coupled implementation is being replaced rather than patched. What exists right now is the design contract and the documentation around it. Everything described on this page is designed, not built — each feature says so, and each will be corrected individually as code lands. Read the architecture or the FAQ.
The problem
Two of them, and the second is why this product exists.
Maintenance software assumes you have signal
A contractor is in a basement. A manager is walking a block with no coverage. The office line is down. Conventional systems put a server in the middle of every write, so in each of those moments the work stops or gets written on paper and typed in later — badly, or never.
PropFix is designed so that every surface accepts writes while partitioned and converges afterwards. Nothing blocks on the network, and no central server is required at any point: peers are enrolled by hand and sync directly. If neither side is reachable, a shared folder — or a USB stick — is a valid transport.
Move-out damage is argued, not evidenced
The tenant says the counter was chipped when they moved in. The agent says it was not. Both are sincere, neither has evidence, and the deposit deduction gets decided by whoever is more insistent or can better afford to escalate.
PropFix's differentiator is ingoing/outgoing inspection comparison: the same template run twice, diffed item by item, with both sets of photos side by side. It does not decide who is right — and it explicitly distinguishes "deteriorated" from "not captured ingoing", so a missing baseline never gets laundered into a confident-looking claim.
And one inherited bug worth naming
The legacy system stored units as free text on the job (unitIdentifier) with no table — while its analytics grouped by that text. "Flat 3A", "3A" and "flat 3a" silently became three different units, fragmenting the per-unit cost reporting that was the product's main analytical claim. Units are now real rows with a normalised key and the label as typed.
And one inherited security flaw
The legacy system trusted the frontend to send organization_id filters. That is not isolation — it is a suggestion enforced by the attacker. Scoping is now derived server-side from the authenticated identity and never taken from a client-supplied parameter.
What it will do
Every card below is designed and specified, with no implementation yet. The tags are not decoration — nothing here works today, and each tag comes off individually when the code that earns it lands.
Maintenance jobs Designed
Raise a job against a unit, triage it, assign it, cost it, close it. Job numbers come from the building's own sequence, so they allocate offline with no coordination between nodes.
Units as real entities Designed
A normalised key plus the display label exactly as typed, created on first use, with the building's numbering scheme driving normalisation. Per-unit cost reporting stops fragmenting.
Templated inspections Designed
Reusable checklists by area and item, with per-item condition, comments, and photo requirements. Findings are append-only, so a correction adds an observation rather than overwriting one.
Ingoing/outgoing comparison Designed
The differentiator. Item-by-item deltas — unchanged, deteriorated, improved, not captured ingoing, not captured outgoing — with the evidence from both runs attached.
Append-only money & hours Designed
Costs and times are immutable, insert-only rows. A job's cost is SUM(amount_minor) at read time, never a stored counter, so two people costing the same job offline add instead of one silently overwriting the other. Corrections are negative entries. Money is int64 minor units — floats never touch it.
Peer-to-peer sync Designed
An HLC oplog with stateless, symmetric rounds and mutual Ed25519 authentication. Peers are enrolled by hand — no mDNS, no DHT, no rendezvous. Any node can relay any other node's operations.
Folder & USB transport Designed
Each node appends only its own ops-<node>.jsonl to a shared folder, so no file ever has two writers and there is nothing to conflict. A NAS, a synced drive or a stick carried between sites all work, with no simultaneous connectivity.
Cross-org work over WRAP Designed
A plumbing company runs its own PropFix node and receives work orders over the open WRAP trades/v0 profile. No platform between the landlord and the plumber, and nobody taking a cut. Optional — in-house work never touches it.
Tenants without accounts Designed
A tenant is a participant, not an account: attached to a unit or job, seeing only events marked public. No key, no install, no signup to report a leak and be told it is fixed.
How it works
The design. Not a description of running code — see the notice at the top of this page.
flowchart TD
subgraph node["one PropFix node — one binary, one SQLite file"]
ui["React frontend
embedded in the binary"]
api["api/ — routes, JSON, auth"]
dom["domain/ — entities & invariants"]
repo["repo/ — one file per aggregate"]
store[("store/ — SQLite
migrations · HLC · oplog")]
ui --> api --> repo --> store
api --> dom
repo --> dom
end
peer["another PropFix node
(a branch office, a contractor)"]
folder[["shared folder / NAS / USB
ops-<node>.jsonl"]]
wrapnet["WRAP trades/v0
cross-organisation work orders"]
store <--> |"HLC oplog · mutual Ed25519
stateless symmetric rounds"| peer
store <--> |"append-only, one writer per file"| folder
api <-.-> |"optional — external contractors only"| wrapnet
The building is the authority
Whoever manages a building is the single writer for its jobs, its job-number sequence, assignment, and inspection scheduling. Because the only contended decision — who does the work — has exactly one legitimate writer, there is no consensus protocol, no leader election and no distributed lock anywhere in the system.
Money and hours are append-only
If two people record spend on the same job while partitioned, union merge means the amounts add. A stored cost column would keep whichever write landed last and silently lose the other — with no error, and no way to notice until the numbers were wrong at month end.
Self-hosting is the only mode
There is no hosted PropFix, no free tier, no seat count, and no account with us — because there is nothing to sell you. It is MIT-licensed software you run on hardware you already have.
One binary, one file
A Go binary with the frontend embedded, plus a SQLite file and a directory of content-addressed attachments. No database server, no cache, no queue, no object store. Pure Go via modernc.org/sqlite, so an arm64 build for a Pi is a plain cross-compile.
It talks to nothing
A fresh install is designed to make no outbound network calls at all: no telemetry, no update check, no licence call, no font CDN, and no map-tile provider — MapLibre with Protomaps needs no API key. Every destination is one you entered.
Your data is a directory
The database, the node's identity key and the attachments live in one folder you back up however you already back things up. PropFix ships no backup service. Note that sync signatures authenticate peers but do not encrypt — run it over a LAN, your own VPN, or TLS you terminate.
# planned — there is no binary to build or run today git clone https://github.com/vul-os/propfix cd propfix npm install && npm run build # one node, local SQLite, loopback only, no cloud ./propfix --data-dir /var/lib/propfix # seeded in-memory dataset — no database, no configuration ./propfix --demo
The one command in this repository that does work today is npm run docs:sync, which copies docs/*.md into the site so the page you are reading can never drift from the repository's own documentation.
Part of VulOS
Vulos publishes one thing: the OS. The Vulos OS, all its apps (PropFix included) and the app store are free and open-source, dual MIT OR Apache-2.0 — you self-host them. You self-provision and self-pay your own box; Vulos does not host or provision boxes, and does not bill for anything.
- Vulos OS — the web-native desktop shell that hosts the apps
- diwan — docs, sheets, slides, PDF and whiteboards
- Vulos Files — file storage and P2P sharing, built into the OS
- Ephor — self-hostable reachability broker the box dials out to
- llmux — sovereign AI gateway
PIM is bring-your-own (Mail / Calendar / Contacts via lilmail); chat and video are third-party (Matrix/Element, Element Call / Jitsi) — not Vulos products.
PropFix's role: the property maintenance and inspections app. It is designed to run standalone and be hosted as an app by the Vulos OS — the same binary, with the OS wiring identity and scoped storage in front of it. Ephor, the control plane and DMTAP are optional seams; a hard runtime dependency on any of them is forbidden.
Explore VulOS →