Exports that fight back
Bakeano runs paid advertising for a dozen client accounts across Meta and Google. Every month, reporting meant downloading exports, opening them one at a time, reconciling numbers by hand, and rebuilding the same deck twelve times.
The exports do not cooperate:
Any one of those breaks a normal importer. All of them together is why this was still being done by hand.
A multi-tenant reporting platform
Ingestion that expects a fight
Files are parsed by column name rather than position, because positions differ per client. Header variants are normalised. Metadata and footer rows are detected and dropped. Locale-specific number formats are handled explicitly, not guessed.
Isolation at the database level
Every tenant-specific record carries a tenant identifier and every client-specific record carries a client identifier. Isolation is enforced by row-level security in Postgres, not by application code remembering to filter.
Anomaly detection
Six rules watch for spend spikes and collapses, cost-per-click jumps, reach collapse, conversion drops and accounts going silent, with guards against divide-by-zero on empty periods. A consolidated digest goes out grouped by severity. A whole account going dark bypasses the digest and alerts immediately, because that one can't wait until tomorrow.
Reporting that leaves the building
Per-client dashboards with period-over-period comparison, campaign breakdowns and multi-metric overlays. PDF export for client delivery. Passwordless magic-link authentication. Interface in Spanish and English.
AI that has to ask permission
The platform generates written insight summaries over the data. Those summaries do not reach a client. Not until a human reads them, edits them if needed, and approves them.
Approval state lives in the database. An unapproved insight is not degraded or watermarked, it is simply absent from the client view and from the PDF. Editing an already-approved insight automatically returns it to draft and pulls it from client view until it is approved again, so an edit can never quietly ship unreviewed.
This was the client's requirement, and it was the right one. An agency's reputation rides on what it hands a client. Generated text going out unreviewed under their name was not acceptable, and the system enforces that rather than relying on someone remembering.
What's running
The monthly ingestion of real client exports is live and in use. The daily metrics pipeline, including anomaly detection and digests, is built and tested but running against generated data pending API credentials from the platforms. Switching it to live data is a configuration change, not a build. I'd rather say that than let you assume otherwise.
Anywhere the source data arrives as inconsistent files
Any business reporting across accounts, locations or clients where the data comes as file exports rather than a clean API. Franchise reporting, multi-location retail, agency reporting, distributed sales operations.
Rebuilding the same report every month?
If the data arrives as files, it can arrive as a dashboard instead.