All formats

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
}
KeyMeaning
idbuiltin.export.<name> for built-ins (never stored), else a lowercase UUID
versioncontent version
nametext per language code, like template labels (0010)
formatpdf_list, pdf_catalogue, or csv: the file the export sheet starts with and a PDF's layout (section 2b)
columnsin order; see below
includesPhotosPDFs only: small photos in a list, a large photo and up to five small ones in a catalogue
includesDisposedinclude sold and given-away items
showsTotalsPDF lists only (pdf_list and csv drawn as a PDF): item count and value totals
sortname, value, dateAdded, or purchaseDate (within each collection)
basedOnthe template this one was copied from
includesJournal, includesLinks, includesFileNames, includesRemovedFieldswhat the export also includes (issue #82, section 2a); a missing key reads as true, so templates saved before include everything

Columns:

ValueShows
number, title, collection, status, count, away, location, purchaseDate, purchasePrice, pricePerUnit, source, estimatedValue, value, condition, tags, notes, idthe 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:allevery visible field of the item's collection
fields:identifyingthe 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):

IDFormatColumnsOptions
builtin.export.insurance (version 3)PDF listtitle, collection, identifying fields, count, away, purchase date, purchase price, price per unit, estimated value, placephotos, totals, sorted by value
builtin.export.catalogue (version 3)PDF cataloguetitle, collection, status, count, away, estimated value, purchase price, price per unit, purchase date, source, condition, place, tags, all fields, notesphotos, sorted by name
builtin.export.spreadsheet (version 4)CSVinventory number, title, collection, status, count, away, place, purchase date, purchase price, price per unit, source, estimated value, condition, tags, notes, all fields, IDsold items included, sorted by name

2. What an export contains

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.

SwitchColumn IDLabelWhat a piece shows
JournaljournalJournalevery 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)
Linkslinks:partOf, links:includes, links:linkedWithPart of, Includes, Linked withthe 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 namesfilesFilesthe 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 fieldsremoved:<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 formatStarts asAs a PDFAs Excel or CSV
pdf_listPDFthe list (section 5)one row per item with the template's columns
pdf_cataloguePDFthe catalogue, a page per itemone row per item with the same facts
csvCSVa list, as pdf_list with the template's optionsone 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

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.

5. PDF

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.