Atelier is the property-management app I built for private landlords in Italy. Its core is the file of each lease, and inside the file there is the signature. This article explains how I designed it, what it really records and, above all, what it does not promise.
The problem
A rental contract between private individuals often travels as a PDF over WhatsApp, with a scanned signature and no trace of who signed what, when and with which text. If a dispute arises, reconstructing “what the contract said at the time of signing” becomes hard.
I wanted a simple way to fix three things: the text, who signed and when.
What the signature records
The signature in Atelier is a simple electronic signature. When a party signs, I store:
- the first and last name typed by the signer;
- date and time, shown in the Europe/Rome time zone;
- IP address;
- device (the browser’s user agent).
The lease becomes active only when both parties have signed, in any order.
The SHA-256 fingerprint
On activation I generate the signed contract PDF and compute a SHA-256 fingerprint over the contract text and the data of the two signatures. In simplified form:
import { createHash } from 'node:crypto'
function fingerprint({ leaseId, text, owner, tenant }) {
const sig = (s) => ({
fullName: s.fullName,
signedAt: s.signedAt,
ip: s.ip ?? null,
userAgent: s.userAgent ?? null,
})
return createHash('sha256')
.update(JSON.stringify({ leaseId, text, owner: sig(owner), tenant: sig(tenant) }))
.digest('hex')
}
Two details matter more than the algorithm:
- The key order is fixed. I build the object field by field before serializing it: if the order changed, the same content would produce a different fingerprint.
- The same data always gives the same fingerprint. I wrote tests checking that the fingerprint is deterministic and that it changes if even just the text or a signature field changes.
The fingerprint appears in the PDF, together with a sentence stating what was computed and what it is for: verifying that the content has not been altered after signing.
An important clarification: the fingerprint is not a cryptographic signature. Anyone who has the document can recompute it. It serves to check that the PDF matches the text and signatures the system keeps, not to prove who produced it.
The PDF stays as it was at signing
The PDF is generated once, when the lease becomes active, and is never regenerated. If the rent later changes (for example a statutory ISTAT adjustment), the signed document does not change: the fingerprint must describe the contract as it was, not as it became.
Two almost simultaneous signatures
A bug I could easily never have seen: if landlord and tenant sign at the same instant, a naive read-modify-write can make one signature erase the other. That is why signing happens inside a transaction on the freshest document, and an existing signature is never overwritten: a second attempt gets a 409 error and the original, with its timestamp and IP, stays intact.
What the signature is not
This is the part I care about most. A simple electronic signature, under Article 20 of the Italian Digital Administration Code, has evidentiary value that is freely assessed by a court: it is not equivalent to a qualified digital signature. I state this in the PDF itself, and Atelier also says what it is not on its “About” page.
That is why Atelier does not present itself as a qualified-signature provider and, for files managed by an agency, signing happens outside the app. It is a legal choice before a technical one, and my reading of it is my own: it is not legal advice, and a concrete case needs a professional.
What I learned
- A fingerprint is only useful if you know exactly what you put into it and you declare it.
- Concurrency tests (two signatures at once) are worth more than happy-path tests.
- Stating a product’s limits builds trust, it does not damage it.
