Skip to main content

max / goingson

5.7 KB · 107 lines History Blame Raw
1 # Data Export
2
3 GoingsOn stores everything in a SQLite database on your machine. You can take that data out at any time, in formats that other tools can read or that you can inspect yourself.
4
5 ## Export formats
6
7 | Format | Scope | File | What it's for |
8 |---|---|---|---|
9 | JSON (full) | Projects, tasks, events, emails, contacts | `.json` | Inspection, migration, scripted processing |
10 | Backup | Same as JSON (full) | `.json.gz` | Round-trip restore into a fresh install |
11 | CSV (tasks) | Tasks only | `.csv` | Spreadsheets |
12 | ICS (calendar) | Events only | `.ics` | Apple Calendar, Google Calendar, Outlook |
13 | Raw SQLite | Everything | `goingson.db` | Direct copy of the database file |
14
15 JSON and Backup share one schema; Backup is the same JSON gzipped. CSV and ICS are lossy conversions for interop with other tools.
16
17 The raw SQLite file lives in the Tauri app-data directory. You can copy it like any other file; this is the most complete export possible.
18
19 ## JSON schema
20
21 A JSON export is a single object with these top-level fields:
22
23 ```json
24 {
25 "version": "1.1",
26 "exportedAt": "2026-06-02T14:30:00Z",
27 "projects": [ ... ],
28 "tasks": [ ... ],
29 "events": [ ... ],
30 "emails": [ ... ],
31 "contacts": [ ... ]
32 }
33 ```
34
35 - `version` is the export-schema version, not the app version. Restore accepts any `1.x` file.
36 - `exportedAt` is UTC, ISO 8601.
37 - The five arrays are independent. An export with zero contacts but many tasks is well-formed.
38
39 Field names use `camelCase`. Timestamps are UTC ISO 8601 (`2026-06-02T14:30:00Z`). IDs are UUIDs (`550e8400-e29b-41d4-a716-446655440000`).
40
41 ### Entity shapes
42
43 The full field list for each entity is the serde-serialized form of the Rust types in `crates/core/src/`. Below is the minimum every entity carries; consult the source for the complete list.
44
45 **Project** (`crates/core/src/models/project.rs`)
46 ```json
47 {
48 "id": "...",
49 "name": "Q3 Launch",
50 "description": "",
51 "projectType": "work",
52 "status": "active",
53 "createdAt": "2026-04-01T10:00:00Z"
54 }
55 ```
56
57 **Task** (`crates/core/src/models/task.rs`) — the densest entity. Required: `id`, `description`, `status`, `priority`, `tags`, `urgency`, `createdAt`. Optional fields cover scheduling (`due`, `scheduledStart`, `scheduledDuration`), recurrence (`recurrence`, `recurrenceRule`, `recurrenceParentId`), workflow (`snoozedUntil`, `waitingForResponse`), linkage (`projectId`, `milestoneId`, `contactId`, `sourceEmailId`), nested data (`annotations`, `subtasks`), and time tracking (`estimatedMinutes`, `actualMinutes`).
58
59 **Event** (`crates/core/src/models/event.rs`) — calendar event with start/end times, optional project/contact links, recurrence rule.
60
61 **Email** (`crates/core/src/models/email.rs`) — message metadata, addresses, body (text and html), attachments are stored by reference (path, mime, size) — attachment **contents** are not embedded in the JSON to keep file sizes sane. To export attachment payloads, copy the `attachments/` directory next to the SQLite file.
62
63 **Contact** (`crates/core/src/contact.rs`) — name, multi-field emails/phones/socials, tags, notes.
64
65 ### Denormalized display fields
66
67 A few fields are duplicated for display convenience and are not authoritative:
68
69 - `Task.projectName`, `Task.contactName` — copies of the linked project/contact name at export time. On restore, GoingsOn re-derives these from the linked IDs; if a linked project was deleted before export, the display name still appears but the link won't resolve.
70
71 If you're processing exports programmatically, treat IDs as the source of truth and ignore the `*Name` fields.
72
73 ## Restore
74
75 Restoring a `.json.gz` backup goes through one of two modes:
76
77 - **Replace all** — clears the existing database, then loads the backup. Use this when restoring onto a fresh install.
78 - **Merge** — adds the backup's entities to whatever is already there. Useful for combining devices, but will create duplicates if the same entities exist on both sides (entities are matched by ID; a duplicate task on two devices created independently has two different IDs).
79
80 Plain `.json` exports are not restorable through the UI. They are intended for inspection and migration to other tools. If you want a round-trip backup, use the `.json.gz` format.
81
82 The restore version check accepts any export with `version` starting `1.`. Future major versions (`2.x`) will require an explicit conversion path.
83
84 ## Verifying an export
85
86 Open the `.json` file in a text editor. You should see:
87
88 1. The five top-level arrays match the counts shown in Settings → Data → Export summary.
89 2. Every `id` field is a UUID.
90 3. Every timestamp ends with `Z` (UTC).
91 4. Search for an entity you remember (a task title, a contact name) — it should appear verbatim.
92
93 For a `.json.gz` backup, decompress first: `gunzip -k backup.json.gz` produces `backup.json` which you can inspect the same way.
94
95 ## What's not exported
96
97 - **OAuth tokens and email passwords.** Re-authenticate after restoring. This is intentional — credentials should not travel in a portable file.
98 - **TOTP secrets.** Same reason.
99 - **Cloud sync state.** A restored database starts as if sync had never been configured; re-enable it in Settings → Cloud sync.
100 - **Plugin runtime state.** Plugins are loaded fresh from the plugin directory on next launch.
101 - **Window state.** Sidebar widths, last view, etc.
102 - **Theme files.** Bundled themes ship with the app; custom themes live as separate `.toml` files in the app config directory and can be copied alongside the database if needed.
103
104 ## Source of truth
105
106 The export schema is defined in `src-tauri/src/export/backup.rs::FullExport`. Entity field lists are the serde forms of the structs in `crates/core/src/`. Any drift between this document and the code is a bug in this document — open an issue or PR.
107