Giftly · 2025 – present
Giving a one-shot product a memory
Primary author of the calendar, contacts, and gift recommendation systems that turned a one-shot purchase flow into a product with a reason to return.
PublicThe situation
The product had a ceiling. Every gift began with a buyer who already knew what they wanted and who it was for; nothing in the system knew anything about the recipient — so nothing gave a buyer a reason to come back before the next occasion they remembered on their own.
The constraints
- The people being remembered are mostly not users. A recipient with a birthday, interests and a city usually has no account and never will, so the model had to hold people rather than logins.
- A reminder is a promise. "Why did this not send" has to be answerable, which constrains how the pipeline is allowed to work.
- A recommendation has to be explainable to someone who disagrees with it.
The call
Materialise reminder instances instead of computing what is due on the fly. A recurring event with a "3 days before" rule generates real rows on a rolling window, topped up as they are consumed. Recomputation would have been cheaper to write and much harder to answer questions about — with rows, "why did this not send" is a lookup rather than a re-derivation.
Attach requested information to the recipient, not to the request. When someone asks a contact for their birthday, the answer lands on that person's profile — a shadow profile if they have no account — so the next person to ask sees it already filled in. Per-request capture was the obvious model and the wrong one: it would have made the same person re-enter their details for every friend who asked.
Rank recommendations in fixed bands rather than by a blended score. Summing weighted signals let a strong semantic match outrank an explicit tag-and-location match, and the location weight outranked nationwide tag matches outright. Bands make the ordering deterministic and leave similarity as a tiebreak inside a band, which also means the ranking can be explained to someone who disagrees with it.
What happened
The product gained a memory. Calendar events, contacts with interests and locations, and recommendations built on them turned a one-shot purchase flow into something with a reason to return.
An occasion spreads between people instead of sitting inside one account: accepting an invitation is what creates a subscription, and no account is needed to accept one.
They keep calling me back. Four years into the engagement this is the largest workstream yet — which is the clearest verdict on the work I can offer.
What I'd do differently
I wrote the design docs for the calendar and contacts systems well after the code, and the schema shows it. Reminders shipped in October 2025, lost a unique constraint in November, and gained their instance table in December — three passes at one model, with the document that explains it written after all three. On a shared codebase the written spec is not documentation, it is the coordination mechanism, and I kept treating it as something to catch up on rather than the thing that goes first.