feat(export): CSV export for bookings and customers

GET /v1/export/bookings.csv (optional from/to bounds) and
/v1/export/customers.csv — UTF-8 with BOM for Excel, labels resolved
at export time, buffered responses so auth failures stay JSON.
Export buttons on the bookings and customers pages.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Tomas DvorakandDevin committed 2026-09-18 16:15:36 +02:00
1 parent d86cba61e3
commit 4674203502
12 files changed
+583 -5

No files matched your search

@@ -664,6 +664,46 @@ export interface paths {
patch?: never;
trace?: never;
};
"/v1/export/bookings.csv": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Export tenant bookings as CSV
* @description Full booking export for accounting and backup — UTF-8 with BOM so Czech diacritics open correctly in Excel. Optional `from`/`to` (YYYY-MM-DD) bounds the export window; `to` is inclusive.
*/
get: operations["exportBookingsCsv"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/v1/export/customers.csv": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Export tenant customers as CSV
* @description Full customer list export — UTF-8 with BOM for Excel.
*/
get: operations["exportCustomersCsv"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/v1/internal/jobs/reminders/dispatch": {
parameters: {
query?: never;
@@ -3359,6 +3399,63 @@ export interface operations {
};
};
};
exportBookingsCsv: {
parameters: {
query?: {
from?: string;
to?: string;
};
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description CSV file download */
200: {
headers: {
[name: string]: unknown;
};
content: {
"text/csv": string;
};
};
/** @description Tenant membership not found */
404: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
exportCustomersCsv: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description CSV file download */
200: {
headers: {
[name: string]: unknown;
};
content: {
"text/csv": string;
};
};
/** @description Tenant membership not found */
404: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
dispatchReminderJobs: {
parameters: {
query?: never;