

Yerush
Wills, probate and power of attorney in Israel, written online in plain Hebrew for a price fixed before you start
The problem
Writing a will in Israel means a lawyer's office, an open-ended fee and a document in language most people cannot read. The same is true of probate after a death, of a lasting power of attorney, and of a living will. These are the four moments where a family most needs the process to be calm and legible, and they are the four where it is least likely to be.
Most of these cases are simple. A smaller number genuinely need a lawyer. Nobody tells you which one you are before you have paid.
What I built
Yerush is four guided wizards over one codebase: wills, probate, lasting power of attorney and living wills. Hebrew is the default and English is served alongside it. Each one starts with a short suitability check that runs before payment, so someone whose case is complicated is told to see a lawyer instead of being sold a form.

The part that took the care
This is a product that holds people's family details, identity numbers and the contents of their estate. Almost all of the engineering effort went into the handling of that, and most of it takes the form of the application refusing to run rather than doing something clever.
- Case data is encrypted with AES-256-GCM before it is stored. In development, without a key, envelopes are plain. In production the app refuses to start writing case data at all without one, rather than quietly storing plaintext.
- Production refuses an in-memory store. A per-process map loses every case when the service scales to zero, and gives each instance a different view of the data. Development may use it; production will not boot on it.
- Uploads go to Cloud Storage, encrypted before the bytes leave the process, and production will not start without a bucket. The development fallback is a capped in-memory store, which would run a real service out of heap after a couple of dozen files.
- Every AI capability has its own kill switch, and the provider defaults to a mock that fabricates answers locally with no external call and no key. A separate flag makes the app refuse to fall back to that mock, so production can never silently serve invented legal text.
- Staff and admin are different secrets. The admin token is the only one allowed to run data retention. Setting it equal to the staff token disables admin entirely and logs an error, which is a deliberate guard against privilege escalation rather than a bug.
The setting with no safe default
Rate limits are keyed on the client IP, read out of x-forwarded-for. Google's front end appends to that header rather than prepending, so the trustworthy entry is counted from the right, at a position that depends on how many proxies sit in front of the app.
Get it too low and the key becomes attacker-controlled again: any caller can rotate the header and bypass every limit. Get it too high and every caller collapses into one shared infrastructure IP, so a single attacker exhausts the limit for everybody. Neither failure throws anything.
There is no value that is correct everywhere, so the app logs the chain length it actually observes, once per process, and the README says to check that line against real traffic after the first deploy to any new environment and set the number to match.
Building something in this territory? Start a conversation →
