Turning Rows Into a File
A delivery is only useful if the thing that lands on the other end can be read by whatever the customer already runs, which in practice means a delimited text file that a decades-old import job will accept without complaint. That sounds trivial until you enumerate what is actually configurable: the delimiter, the character encoding, whether a header row is present, and how the file is named.
File naming got more attention than it looks like it deserves. The name encodes the profile and both boundaries of the exported window, so a file is self-describing once it has been copied out of the directory it was delivered to. Support questions about delivery are almost always some variant of which records were in which file, and a self-describing name answers most of them without anybody opening a database.
Where the File Lives
The platform's own object storage was treated as a first-class destination rather than a staging area. A customer who does not want to operate any receiving infrastructure selects it, and their files simply appear in the console with a download button. Objects are laid out under a stable prefix keyed by tenant and profile, which makes retention policies and access rules expressible as storage-level configuration instead of application code.
Serving those files back is the one place where a naive implementation is genuinely dangerous. An export can be tens of megabytes, and reading it into memory to send it means a handful of concurrent downloads can take out the process. The route opens a stream from storage and pipes it straight to the response, so memory use is constant regardless of file size. It also deliberately does not delete on download, unlike an older ad-hoc export route in the same codebase which did; deliveries are a record of what was sent, and a record you can only read once is not a record.
The Delivery Log Is the Product
Every run writes a log row: the window it covered, how many records it contained, where it went, whether it worked, and if not, why. This is not instrumentation, it is the feature. When a customer says they did not get their file, the log is the entire conversation, and its quality determines whether that conversation takes two minutes or two days.
The rule that emerged is that the log records outcomes in terms the customer can act on. A failure that says the connection was refused is actionable by their network team. A failure that says an internal exception type is actionable by nobody. That distinction shaped the error taxonomy that part three leans on heavily.