Ids are made on the device, not the server

The server never hands out an id. Every todo is named by the device that created it, in the moment it is created — which is the only way offline capture can work honestly.

Here is a small decision with consequences out of all proportion to its size: when a todo is created, who gives it its identity?

The traditional answer is the database. You send the new thing to the server, the server inserts a row, the row gets the next number in the sequence, and the server tells you what it was. Clean, simple, and it has worked for decades.

memoratu does not do that. Every record is named by the device that created it, at the moment it is created, before the server has heard of it. The identifier is a UUID generated locally, and the server never assigns one.

Because you are going to be on a plane

The reason is not elegance. It is that you will write something down while you are offline, and the system has to behave sensibly when you do.

If the server assigns identity, then a todo created with no signal is not really a todo yet. It is a draft of one, waiting to be given a name. It cannot be properly referenced, it cannot be reliably linked to from anything else, and the app has to carry a second, temporary notion of identity for exactly as long as the connection is down — and then reconcile the two when it comes back.

That reconciliation is where the bugs live. Not because it is hard in principle, but because every feature downstream has to know that an id might change. A todo you dragged into a list, completed, and then edited, while offline, may have been doing all of that under a name that is about to be replaced.

If identity is created on the device, none of that exists. The todo you typed on the plane has the same identifier it will have forever. It is complete the moment it is written. Reaching the server later is a transfer, not a naming ceremony.

Why it must be a UUID, specifically

A sequence number would be a disaster here, and it is worth being precise about why.

Imagine two devices, both offline, both belonging to you. Your phone creates a todo and your laptop creates a different one. If each device is handing out the next number in its own sequence, both of them will produce the same id. Not might — will, almost immediately, because both sequences start in the same place and move at the same rate.

When the two eventually sync, the system is handed two different todos claiming to be the same record. Every possible resolution is wrong. Overwrite one and you have silently destroyed something a user wrote down. Keep both and you have broken the rule that an id names exactly one thing, which every other part of the system relies on. Refuse both and you have lost the data anyway.

A UUID is specifically designed so that independently-generated values do not collide. That property is the entire requirement. Two devices that have never communicated must never produce the same name for different things, and no coordination is available to help them, because the whole point is that they are not talking.

So this is not a preference about id formats. Client-generated UUIDs are mandatory, and the reason is a correctness one.

The quieter benefits

Once identity is local, some other things become easy almost by accident.

A record can be referred to before it has been stored anywhere. A client can build a whole structure — a project, the lists inside it, the todos inside those — and send it as one piece, with all the internal references already correct, because every part already knows its own name.

Retrying a failed request also stops being frightening. If the connection dies after the server received your todo but before you heard the reply, you can simply send it again. It carries the same id, so the server knows it is the same record rather than a second one. With server-assigned identity, the same retry is how you end up with two copies of the same task and no way to tell which is which.

What this does not solve

It is worth saying plainly what this buys and what it does not.

Client-generated ids solve identity. They say, unambiguously, which record you are talking about. They do not solve conflict — two devices editing the same todo while apart still produce two versions of it, and deciding what to do about that is a separate and genuinely harder problem.

What local identity does is make that harder problem tractable. You can only argue about which version of a todo is right if you can agree that both versions are of the same todo. Identity has to be settled first.

Sync itself is not switched on yet; it is written and not deployed. But the decision underneath it was made long before, in the shape of the data — because that is the kind of decision you cannot retrofit. By the time you have a sync problem, your ids are already whatever they are.

Where memoratu actually is: in development. The account system, projects, lists and todos are live on our server and the command line works, but nothing is in an app store, there is no way to sign up from a browser, and sync between devices is not switched on yet. The full picture is here.