Work out what it would take for Everwood to put appointments into the tools customers already use, Apple Calendar, Google Calendar, and eventually Apple and Google Wallet, sourced from the canonical booking state.
I framed this as a build question. It was a correctness question. We already send customers a calendar file, and holding it up against the standard it is meant to follow turned up several places where it falls short.
A calendar entry is a small public promise. It runs on a device I do not control, in an app I did not choose, in front of the customer rather than in front of me. That is the worst place for a bug to live, and it is why the boring parts of a standard matter.
The Build
Nothing shipped from this research. Nothing below has been fixed, and no wallet pass exists. What changed is what I know about something that was already running.
The question I started with was whether customers want appointments in their calendar and wallet badly enough to justify building it. The industry answer to appointment logistics has been to ask people to download an app per business, which nobody wants to do for a single haircut. Putting the appointment into the calendar and wallet apps people already have is obviously better, so the interesting question was cost.
Then I went looking in our own product and found we already do the calendar half. Every confirmation email carries an add-to-calendar button, and behind it sits a working calendar file. It is served through a signed link rather than a public address anyone could guess, which is exactly the privacy failure I had been planning to avoid. It reads the real booking, folds several services booked back to back into one event running from the first start to the last finish, attaches a thirty minute reminder, and writes its times in a universal timezone so they land correctly wherever the customer happens to be.
That is a good foundation. It gets right the two things I expected us to get wrong. So the research question changed from should we build this to what is wrong with what we built.
The Problem
Held against the standard, the file we generate has six gaps. None of them are visible to me. All of them are visible on a customer's phone.
The first is the one that would actually hurt. Nothing in the file says which version of the appointment it is. The standard carries a revision number for exactly this, and ours has none. The appointment keeps a stable identity every time we regenerate it, which is the harder half and we got it right, but identity with no revision gives the calendar app no reason to believe the new copy is the newer one. Move an appointment, hand the customer a fresh file, and a strict calendar has no reason to prefer it over the entry already sitting there.
The second is punctuation, and it is the one most likely to be happening already. The business name goes into the file exactly as typed. The standard treats a few characters as separators, the comma among them. A salon called Nails, Etc. produces a title the calendar reads as two values rather than one, and the field is malformed. Nobody here ever sees it, because everything parses cleanly right up until a business signs up with punctuation in its name.
The third is line length. The standard says a line should not run past a set length, and longer ones should be wrapped a particular way. Worth being precise, because I had this wrong at first: it says should, not must. An overlong line is not strictly a violation. It is still a risk with stricter calendar apps, and a business with a long name and a long list of services will sail past the limit.
The remaining three are smaller. There is no address in the file, so the customer gets a time with no place. The status is fixed at confirmed, so there is no way to tell a calendar that an appointment is off. And the description carries a fragment of an internal booking reference, which is the sort of thing customers do not want sitting in their calendar.
Assumption vs Reality
Calendar export is a solved, boring feature. You write some fields into a text file, the calendar app opens it, done. The interesting engineering was going to be in the wallet passes, with their certificates and push notifications.
The boring feature is where the defects were, precisely because it looks too simple to review. The wallet work has not started and therefore has no bugs. The calendar work shipped and has six. Every one is a small detail a reviewer skims past, and every one fails on a device nobody here is holding.
The Fix
What changed is the design, not the code. I now have a specific list rather than a vague sense that this could be tightened, and an order to work through it.
Punctuation comes first, because it is the only gap that can corrupt a file today for a business that already exists. Handling the reserved characters wherever customer-visible text enters the file is a small piece of work with a test around it.
The revision number comes second. It needs the appointment itself to start counting its own changes, which is a data decision rather than a formatting one. That is why it is second, not first.
Line wrapping comes third. It is fiddly, because the limit counts bytes rather than characters, so a business name with accents in it cannot be split by eye.
Then the address, a real cancellation that tells the calendar the appointment is off instead of leaving it sitting there, and taking the internal reference back out of the description.
For wallet, the decision is not to start. The research made the cost concrete. Apple wants a developer account, a signing certificate, and a live service that every device checks in with, where an update means nudging the phone to come back and fetch a new copy. Google works differently, closer to updating a record on their servers and letting them deliver it. The failure I keep coming back to is the reported one where an Apple pass installs perfectly against a broken service and then quietly never updates, showing a customer a time that is no longer true. That is worse than having no pass at all, and it is only worth risking once the calendar path is correct.
Getting the hard part right does not mean the easy parts got done. What we shipped nails the two things I would have called hard. Keeping an appointment's identity stable across regenerations is a decision people get wrong constantly, and the line-ending convention is the classic silent import failure. Both are correct. What is missing is the small stuff: escaping a comma, wrapping a line, counting a revision. I think that happens because the hard parts announce themselves. You go and research identity because you already know reschedules are tricky. Punctuation does not announce itself, because it works perfectly for every business whose name has none, which is most of them, right up until it does not. The wider version is that a file format is a contract with software you will never see. Ordinary code fails in front of you, in a log, in a test. A malformed calendar entry fails on a stranger's phone, silently, and the only signal is a customer who turns up on the wrong day.
For a salon owner, two of these are worth caring about today. If your business name has a comma or a semicolon in it, the calendar entry your customer downloads may render wrong. Not catastrophically, but it looks unprofessional, and it looks like your salon made the mistake rather than your software. If you reschedule an appointment, the customer's calendar may keep showing the old time alongside the new one. They arrive at the wrong hour, and they do not think the calendar file was malformed. They think you told them the wrong time. Neither of these has been reported by an actual customer. I found them by reading code against a spec, not by investigating a complaint, and I want to be clear about that distinction. They are defects waiting for the right business name or the right reschedule, not an incident.
Builder Notes
An audit of the calendar file we already send, held against the standard it follows, plus a cost assessment for wallet passes. Nothing here has been fixed.
Technical Note 1
Shipped and correct: the calendar file is served behind a signed link rather than a guessable public address, which avoids the schedule-leak problem public calendar links have. Line endings follow the convention strict calendar apps insist on. Times are written in a universal timezone. The appointment keeps the same identity every time the file is regenerated. Several services booked back to back collapse into one event running from the first start to the last finish, which is right for a customer booking three things in a row.
Technical Note 2
Gap, punctuation: the standard treats a handful of characters as structural inside any text field, and a line break has to be written a particular way. We pass the business name through untouched. First thing to fix, because it can already produce a malformed entry.
Technical Note 3
Gap, revision number: the standard carries a counter that goes up every time an appointment is modified, and ours is absent. It needs the appointment record to track its own revisions, so it is a data change rather than a formatting tweak.
Technical Note 4
Gap, line length: the standard says a line should not exceed a set length and longer ones should be wrapped. The research I started from described this as a hard requirement. It is not, and getting the strength of a rule right matters when you are deciding what to do first.
Technical Note 5
Gap, the smaller three: no address, no way to signal a cancellation, and a fragment of an internal booking reference sitting in the description. All straightforward once the first three are done.
Technical Note 6
Wallet, Apple: needs a developer account, a signing certificate, a packaged and signed pass, plus a service every device checks in with and a push to tell it to come back for a new copy. The finer details came from the research and I could not confirm them against Apple's own documentation, which would not load for me. Confirm before writing anything.
Technical Note 7
Wallet, Google: closer to keeping a record on Google's own servers. Define the template once, create one per booking, hand the customer a save link, and update by changing the record. That update path is confirmed from Google's reference.
Technical Note 8
Naming: call it Add to Calendar or Export, never Sync. A downloaded file and a subscription feed are both pull-based, and a subscribed calendar checks on its own schedule, not ours. Calling that sync sets an expectation the mechanism cannot meet.
Technical Note 9
Safe content boundary: a calendar file and a wallet pass live on the customer's device, outside anything we can protect. No provider notes, no payment details, no intake form answers, no keys of any kind. A booking reference on a pass is a pointer for a human to reconcile, not something that authorises anything.
Technical Note 10
Still open: whether the file we already send has ever actually produced a broken entry or a stale appointment for a real customer. I have not looked at incident data and I am not claiming any exists. Some of the Apple detail, and a few of the newer optional parts of the calendar standard, are also unconfirmed.
Before / After
- Calendar export is a solved feature we have not built yet
- The engineering risk lives in the wallet passes
- Stable identity and clean line endings are the hard parts to get right
- The calendar file is an implementation detail
- Calendar export is shipped, and it is six small details short of correct
- The engineering risk lives in the part that already looks finished
- The hard parts were done and the easy parts were skipped
- The calendar file is a public promise, kept by software I will never see
What I'd Do Differently
I would have read the codebase before reading the spec.
I spent the first stretch of this research comparing how other platforms handle calendar and wallet integration, building a picture of what Everwood should do. That was answering a question I did not have, because the thing was already built. Twenty minutes in the repo first would have reframed the whole exercise as an audit and saved most of the competitor comparison.
The general version: when researching whether to build something, check whether it already exists before deciding what it should look like.