Exports: export templates, PDF, Excel, and CSV
Status: draft until app version 1.0 ships. Reference implementation: KuriosaCore/Export (templates, rules, the Excel workbook writer XLSX.swift), KuriosaAppSupport/ExportFormatter.swift (text, CSV, and Excel cells), Kuriosa/Features/Export (PDF drawing, export sheet). Decision record: 0019. Everything at once, in open formats and in one password-protected ZIP file with every photo and document, is "Export everything": export-everything.md.
1. Export template JSON
Own templates are stored in the catalog table export_template (catalog-schema.md), one JSON document per row:
{
"basedOn" : "builtin.export.insurance",
"columns" : [ "title", "collection", "fields:identifying", "purchasePrice", "field:caliber" ],
"format" : "pdf_list",
"id" : "<lowercase uuid>",
"includesDisposed" : false,
"includesFileNames" : true,
"includesJournal" : true,
"includesLinks" : true,
"includesPhotos" : true,
"includesRemovedFields" : false,
"name" : { "en" : "For the broker" },
"showsTotals" : true,
"sort" : "value",
"version" : 1
}
| Key | Meaning |
|---|---|
id | builtin.export.<name> for built-ins (never stored), else a lowercase UUID |
version | content version |
name | text per language code, like template labels (0010) |
format | pdf_list, pdf_catalogue, or csv: the file the export sheet starts with and a PDF's layout (section 2b) |
columns | in order; see below |
includesPhotos | PDFs only: small photos in a list, a large photo and up to five small ones in a catalogue |
includesDisposed | include sold and given-away items |
showsTotals | PDF lists only (pdf_list and csv drawn as a PDF): item count and value totals |
sort | name, value, dateAdded, or purchaseDate (within each collection) |
basedOn | the template this one was copied from |
includesJournal, includesLinks, includesFileNames, includesRemovedFields | what the export also includes (issue #82, section 2a); a missing key reads as true, so templates saved before include everything |
Columns:
| Value | Shows |
|---|---|
number, title, collection, status, count, away, location, purchaseDate, purchasePrice, pricePerUnit, source, estimatedValue, value, condition, tags, notes, id | the item's common attribute; number is the inventory number as text (K-0007, issue #50); collection and location as paths ("Home › Safe"); value is the estimated value, else the purchase price; count, away, and pricePerUnit see below |
fields:all | every visible field of the item's collection |
fields:identifying | the fields marked identifying (brand, reference, serial number, …) |
field:<key> | one collection field |
Readers ignore unknown keys and refuse unknown column values.
The count (issue #82): count is what is owned of a piece by its journal (decision 0031), away what of it is lent out or at a service and not back yet, and pricePerUnit what one unit cost (the purchases with a price and a count), each with the collection's unit ("380 rounds", "20 rounds", "CHF 0.45 per round"). They are empty for pieces of collections that do not count, while no journal entry has a count, and away also when nothing is away. A count removed from a collection in "Edit fields" is still exported, like the other removed standard fields.
Built-in templates (each also includes the journal, links, file names, and removed fields):
| ID | Format | Columns | Options |
|---|---|---|---|
builtin.export.insurance (version 3) | PDF list | title, collection, identifying fields, count, away, purchase date, purchase price, price per unit, estimated value, place | photos, totals, sorted by value |
builtin.export.catalogue (version 3) | PDF catalogue | title, collection, status, count, away, estimated value, purchase price, price per unit, purchase date, source, condition, place, tags, all fields, notes | photos, sorted by name |
builtin.export.spreadsheet (version 4) | CSV | inventory number, title, collection, status, count, away, place, purchase date, purchase price, price per unit, source, estimated value, condition, tags, notes, all fields, ID | sold items included, sorted by name |
2. What an export contains
- Scope: the whole library, one collection with all its sub-collections, or one item.
- Included collections (issue #44): for the library or a collection with sub-collections, the export sheet lists the collections of the scope (depth first, indented), all ticked at first. A tap leaves a collection out together with everything below it, or brings them back; a sub-collection can then be ticked again on its own. A left-out collection gives none of the items that sit directly in it. The choice holds while the sheet is open and is never stored (not in the template, not on the device). A single item ignores it.
- Items: owned items only (no wishes). Sold and given-away items only if the template includes them; a single exported item is always included. Lost items are included with their status.
- Order: collections in the user's order (depth first); items sorted within each collection.
- Fields: the columns expand per collection; fields with the same key in several collections share one column (label of the first). A cell is empty for an item whose collection does not have the field. Hidden fields (removed in "Edit fields") appear only as removed fields (section 2a). Relation fields show the other item's title. Wishlist fields are not exported.
- Totals: item count and value totals count held items only, per currency, like the overview.
2a. What an export also includes
Issue #82, decision 0019 (amendment). The export sheet's panel "Also include" has four switches, all on at first. Choosing a template sets them to what it remembers (built-in templates: all on); a change in the sheet holds for the files made while it is open. An own template stores them (section 1) and its editor shows them under "Options". Each adds a column only when an exported piece has something for it.
| Switch | Column ID | Label | What a piece shows |
|---|---|---|---|
| Journal | journal | Journal | every journal entry (decision 0031), newest first, for an owned piece with more than its first purchase (item.events not empty); the first purchase is one of the entries. One entry reads "1 Sep 2026 · At service · 20 rounds · CHF 80 · Tudor service centre · due 15 Dec 2026 · note" (what is not set is left out) |
| Links | links:partOf, links:includes, links:linkedWith | Part of, Includes, Linked with | the other pieces of each kind of link, oldest link first, as "Leather strap (K-0012)" (a wish has no number), also pieces that are not in the export; deleted pieces are left out |
| File names | files | Files | the names of the piece's files that are not removed, in the piece's order ("Document" for a file without a name); never the files |
| Removed fields | removed:<key> | "Caliber (removed)" | the fields removed from the piece's collection in "Edit fields" (hidden), with their values, for the template's field columns: all of them for fields:all, the identifying ones for fields:identifying, the one for field:<key>. Each comes right after the shown fields of that column and has a column of its own, also when another collection shows the same field |
Sensitive fields that were removed are left out like the others and named as "Serial number (removed)" until "Include sensitive fields" (section 3).
2b. The file: PDF, Excel, or CSV
Issue #84 (owner's choice: option 1, "first what, then the format"). The export sheet lists the templates under "Content" and below them "Format": PDF ("To print or send"), Excel ("Opens in Excel, Numbers, and Google Sheets"), or CSV ("Plain text, for any program"). Every template works in every format; the file type is never stored.
Template format | Starts as | As a PDF | As Excel or CSV |
|---|---|---|---|
pdf_list | the list (section 5) | one row per item with the template's columns | |
pdf_catalogue | the catalogue, a page per item | one row per item with the same facts | |
csv | CSV | a list, as pdf_list with the template's options | one row per item |
Choosing a template sets the format to the one it starts with (and "Also include" to what it remembers); choosing another format afterwards holds for that export. Photos appear only in PDFs. PDFs come with Kuriosa Unlimited; Excel and CSV are free (a table of one's own data is always one's own). "Also include", "Included", and the sensitive fields (section 3) work the same in every format.
3. Sensitive fields
Fields marked sensitive are left out. They are included only for one export, when the user switches "Include sensitive fields" on, confirms the warning, and passes Face ID, Touch ID, or the passcode. The switch turns off again after the file is made. The choice is never stored in a template.
When sensitive fields with values are left out, the export sheet and the first PDF page name them ("Not included (sensitive): Serial number"). When they are included, page 1 names them in a framed note with the shield, and the footer of every page says "Contains sensitive data" with the shield, in ink and semibold (never only in a color, so it survives a grey-scale printer).
4. CSV
- UTF-8 with byte order mark, CRLF line endings, fields quoted as in RFC 4180 (when they contain the delimiter, a quote, or a line break; quotes doubled).
- Delimiter:
;where the locale's decimal separator is a comma, else,. - One header line with the column labels in the user's language, then one line per item.
- Numbers without grouping in the locale's decimal style (
6450.5or6450,5). - Amounts: two columns, the amount with the currency's minor digits (
6450.50) and the ISO currency code (CHF), header "Purchase price (currency)" for the second. The price per unit too. - Counts (
count,away): two columns, the number (380) and the unit's name for that number in the user's language (rounds), header "Count (unit)" for the second, so the numbers can be added up. - Journal, links, and file names (section 2a): one column each, one entry, piece, or name per line inside the cell; journal days as
YYYY-MM-DD. - Measurements: the number in the user's display unit; the unit is in the header ("Case diameter (mm)"). Numbers with a suffix: the suffix in the header ("Power reserve (h)").
- Dates:
YYYY-MM-DD. Ratings: the number of stars. Checkboxes: Yes/No in the user's language. Dropdowns and quantities: their display text. Multiple choice fields: one column, the choices in the order of the field's options joined by ", " ("Leather, Steel"; decision 0042). - Privacy mode never masks exported amounts.
4a. Excel
An Office Open XML workbook (.xlsx) that Kuriosa writes itself (XLSX in KuriosaCore, no other code, decision 0007), opened by Excel, Numbers, and Google Sheets.
- Package: a ZIP file (files deflated, every time stamp 1 January 1980) with
[Content_Types].xml,_rels/.rels,xl/workbook.xml,xl/_rels/workbook.xml.rels,xl/styles.xml,xl/sharedStrings.xml, andxl/worksheets/sheet1.xml. No document properties: the file names no author, device, or time. - One worksheet, named after the export's title (the collection or item, "All collections", "Selected collections"; at most 31 characters, without
[ ] : * ? / \, else "Kuriosa"). Row 1 holds the column labels in bold and stays on top while scrolling (a frozen pane); then one row per item, in the order of section 2. Column widths follow the longest value (10 to 60 characters). - Columns: as in the CSV file (section 4), except that an amount (purchase price, price per unit, estimated value, value, currency fields) is one column: the number with the ISO code of its currency in the cell's number format (
"CHF "#,##0.00, the currency's minor digits), so the spreadsheet shows "CHF 6,450.50" with its own separators and can add the amounts up. Counts stay two columns, the number and the unit. - Cells: numbers, measurements (in the user's display unit, rounded to three decimals; the unit in the header), ratings, and counts are numbers. Days are dates (serial numbers of the 1900 date system with built-in number format 14, the spreadsheet's own short date); a day before 1 March 1900 is text
YYYY-MM-DD. Everything else is text: statuses, conditions, checkboxes (Yes/No), choices, and links as in the CSV file; the journal, links, and file names one per line in a wrapping cell, journal days as in the app ("1 Sep 2026"). Text is a shared string, never a formula; characters XML cannot hold are left out, and text longer than 32,767 characters is cut. Every cell sits at the top of its row.
5. PDF
- Paper: A4, or US Letter in the US and Canada, with a 48 pt margin. White paper and the day theme's inks (ink, secondary ink, hairline); no brass, no floor, no halo, no shadows (design system "PrintPages"). Nothing depends on color.
- Names are New York: the title on page 1 (28 pt) and object names (11.5 pt in rows, 26 pt on catalogue pages). Everything else is SF with tabular digits.
- Every page has a footer: "<title> · Kuriosa" on the left, "Page 3 of 12" on the right (a first pass counts the pages), and "Contains sensitive data" with the shield in the middle when sensitive fields are included. The document title is the collection or item, "All collections", or "Selected collections" when collections of the library were left out; it is also the file's only metadata.
- Layout: the template's catalogue for
pdf_catalogue, else the list (also for acsvtemplate, issue #84). - List: a title block (template name, title, item count and "As of" date, totals, the sensitive note), then the column labels ("Object" and the date and amount columns), repeated at the top of every page. Per collection a heading with count and subtotal; per item a row that never splits across pages: the photo whole in a hairline frame, the maker and reference line, the name, the other facts in secondary ink ("380 rounds · 20 rounds away · CHF 0.45 per round"), and the purchase date and amounts right-aligned in their columns. A removed field says what it is ("Caliber (removed) 3861"); under the facts, in small type, a line each for the links ("Linked with: Leather strap (K-0012)") and the files, then "Journal:" with one entry per line (section 2a). The last page ends with a total per amount column.
- Catalogue: a first page with the title block when there is more than one item, then one page per item: the photo whole on white, up to five more photos, the maker and reference line, the name, the facts in two columns with hairlines (removed fields, links, and files among them), the notes, and the journal: a small uppercase "Journal" and one entry per row with a hairline, the day on the left, going on to the next page when the entries do not fit.
- Photos are scaled down (360 px in lists, 1,600 px in catalogues), flattened on white, and embedded as JPEG.
6. Files
Export files are written to the app's temporary folder Exports/ with complete file protection and named "<title> – <template> – <YYYY-MM-DD>.pdf|xlsx|csv". They are deleted when the export sheet closes and when the app starts. The sheet's "Share" button hands the file to the system share sheet.
A piece's own file (a receipt, certificate, or scan in its "Files" panel) is shared the same way without an export template (issue #80): "Share" in the file view writes the stored bytes as they are (already without metadata) to Exports/ under the file's own name with the extension of its content type (DocumentProcessor.sharedFilename), opens the system share sheet, which also offers "Print", and the copy is deleted when the file view closes and when the app starts. Viewing a file alone never writes it to disk.
7. Log export (Kuriosa Pro)
Issue #73, decision 0039. Reference implementation: Catalog.activityLog(about:from:until:) (KuriosaStore), KuriosaAppSupport/ActivityLog.swift (span, document, CSV), Kuriosa/App/AppModel+ActivityLog.swift (entries in the user's language), Kuriosa/Features/Export/PDFLogRenderer.swift, and Kuriosa/Features/Activity/LogExportSheet.swift.
- Where: the Activity page's "⋯" menu › "Export log …": the whole cabinet's Activity (from the Collections tab or Settings), a piece's, a collection's (with its sub-collections), or the wishlist's. Without Kuriosa Pro the item opens the purchase sheet with Pro first.
- Span: everything, the last 30 days (today and the 29 days before), this year, or from a day to a day (both included, in the device's time zone). A step belongs to the span by the time it happened.
- Entries: every step of the history in the span, oldest first by the time it happened, one per history batch as on the Activity page: what happened (the same sentence), the pieces with their inventory numbers, their collections (deleted ones by their last name, with their parents), every changed value of a change (old and new, no limit; additions and deletions list none, as on the screen), which iPhone made it ("This iPhone" or "Another iPhone", issue #52), and "Undone" for a step a later one undid. Undo steps are entries of their own ("Undo: …"); nothing is ever left out. The whole cabinet's log also lists the backups and restores with their folder, counts, size, file, and why one did not work. A scoped log lists no backups.
- Sensitive fields: their values read "hidden" (the word in the user's language), and the first PDF page names them ("Not included (sensitive): Serial number"). They are readable only for one file after "Include sensitive fields", the warning, and Face ID, Touch ID, or the passcode, as in section 3; then page 1 has the framed note and every footer "Contains sensitive data". Privacy mode never masks amounts in the file.
- CSV: as in section 4, with the columns Date (
YYYY-MM-DD), Time (HH:mm, 24 hours), What happened, Inventory number, Piece, Collection, Field, Before, After, iPhone, Note. One line per changed value, so a step with three changes has three lines with the same first columns; a step without changed values, and a backup, has one line with Field, Before, and After empty. Several pieces or collections are joined with ", ". - PDF: paper, inks, and footer as in section 5. A title block ("Activity log", the title in New York: "All collections" or the piece's, collection's, or wishlist's name, then the number of entries and the span as dates, or "Everything"), the sensitive note, then one heading per day with a hairline and one row per entry that never splits across pages: the time on the left; what happened in semibold; the pieces, collections, iPhone, and note in secondary ink; then each changed value as "Field old → new". The iPhone is named only when the log holds changes of more than one iPhone.
- Files: "Kuriosa log <YYYY-MM-DD>.pdf|csv" (the name in the user's language), in the temporary
Exports/folder with complete file protection, deleted when the sheet closes and when the app starts, like the other exports.