customer-servicesTypes, services and utils for interacting with Customers
CustomerDocumentService keeps a customer's documents: the bytes in S3 under customer-documents/<shortName>/, and one row per file or folder in b2b.customer_document. It is the shared DocumentIndex of document-services, the engine bank documents use, so the writes, the upload flow and the customer-document-search cache behave as BankDocumentService's do. Every file written or deleted is published as customer.document.created / customer.document.deleted on the internal event bus, with data { customerId, key }. They are not customer webhook events. Dashboard writes and s3-event-handler publish the same two.
CUSTOM files sit at the customer's root and the other types under pricing-schedules/, logos/ and terms/, so those three names are reserved at the CUSTOM root and reconcile leaves their subtrees out of it.getObject / getObjectStream, not from the index: Drive sync (file-sync) writes the bucket and the row follows from s3-event-handler, so a file can be readable before it is listed, and the terms fall back to the bucket-wide defaults/.reconcile indexes what S3 already holds and never changes an existing row. scripts/backfillCustomerDocuments.ts runs it for one customer or all of them; when and how is in customer-document-not-indexed.md.reconcileObject({ key }) is the one-key version s3-event-handler calls for each S3 object event. It ignores the event type and reads S3: a live object with no row gets its row and the folder rows above it, and a row whose object is gone is soft-deleted. S3 is never written. An object carrying uploaded-by metadata is a signed dashboard upload and is skipped, because a row written first would make completeUpload refuse the user's upload.