You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A self-hosted web app for watch enthusiasts and watchmakers to track personal collection, flips, parts inventory, and equipment — all in one place.
5
6
6
7
Built with Flask + SQLite, runs entirely in Docker with no external dependencies.
@@ -17,20 +18,18 @@ Built with Flask + SQLite, runs entirely in Docker with no external dependencies
17
18
18
19
| Light Mode | Dark Mode |
19
20
|:----------:|:---------:|
20
-
|||
21
-
|||
22
-
|||
23
-
|||
24
-
|||
25
-
|||
26
-
|||
27
-
|||
28
-
|||
21
+
|||
22
+
|||
23
+
|||
24
+
|||
25
+
|||
26
+
|||
27
+
|||
28
+
|||
29
+
|||
29
30
30
31
---
31
32
32
-
33
-
34
33
## Features
35
34
36
35
| Section | Description |
@@ -42,13 +41,36 @@ Built with Flask + SQLite, runs entirely in Docker with no external dependencies
42
41
|**Equipment**| Tools and instruments with total value |
43
42
|**Settings**| Language, currency, date format, hourly rate, categories, and full ZIP backup/restore |
44
43
44
+
---
45
+
46
+
### Financial Tracking & ROI
47
+
48
+
Every flip is a complete financial record. Mainplate calculates total cost from the purchase price, every log entry expense, and labor hours billed at your configured hourly rate. Profit and **ROI %** are computed automatically once the flip is marked as sold — giving you a real picture of whether a job was worth your time.
49
+
50
+
The **Dashboard** aggregates everything: total capital deployed, realised profit, average ROI across all sold flips, and open inventory value. The **Collection** section tracks the same for personal watches — purchase price + service costs vs. eventual sale price, with a **gain/loss** figure per watch.
51
+
52
+
---
53
+
54
+
### Flip Status Workflow
55
+
56
+
Each flip moves through a four-stage lifecycle: **Acquired → In Progress → For Sale → Sold**. Stages are colour-coded throughout the UI. Only "Sold" flips contribute to the profit and ROI calculations, so your pipeline and closed deals are always kept separate.
57
+
58
+
---
59
+
45
60
### Photo Gallery
46
-
Every flip and every collection watch supports **multiple photos**. Images are processed on upload (resized to max 2400 px on the long side, saved as JPEG at 85% quality) using Pillow. Photos are displayed as thumbnails in the list views and in a full gallery on the detail page, with drag-to-reorder support.
47
61
48
-
### Flip Log
49
-
Each flip has a detailed log with **date + description + optional cost + category**. Log entries contribute to the net profit calculation and can optionally add parts to inventory automatically.
62
+
Every flip and every collection watch supports **multiple photos**. Images are processed on upload (resized to max 2400 px on the long side, saved as JPEG at 85% quality) using Pillow. Accepted formats: JPEG, PNG, WebP, GIF, HEIC/HEIF. Transparent images are flattened before conversion. Photos are displayed as thumbnails in the list views and in a full lightbox gallery on the detail page, with **drag-to-reorder** support.
63
+
64
+
---
65
+
66
+
### Flip Log with Automatic Inventory Sync
67
+
68
+
Each flip has a detailed log with **date + description + optional cost + category**. Log entries contribute to the net profit calculation. Ticking the **"Add to inventory"** checkbox on a log entry automatically creates or updates the corresponding part in the Inventory section — quantity is incremented and cost is added. Deleting or editing the log entry keeps the inventory record in sync.
69
+
70
+
---
50
71
51
72
### Timegrapher
73
+
52
74
Each flip has a **timegrapher readings log** to record the movement's timing across the six standard positions (DU, DD, 3U, 6U, 9U, 12U), plus overall amplitude and beat error. Multiple readings are stored per flip — useful to compare before/after a service — with the latest reading shown as a summary at the top.
53
75
54
76
The **delta** (max − min spread across all positions) is computed automatically and colour-coded: green below 10 s/d, yellow 10–20 s/d, red above 20 s/d.
@@ -66,29 +88,59 @@ Each cell also carries **per-field diagnostic warnings** that highlight anomalie
| 6U / 12U | diff > 15 s/d | warning — check lever or hairspring |
68
90
91
+
---
92
+
69
93
### Collection Log
70
-
Each watch in the collection has a service diary (revisions, part replacements, etc.) with optional cost and category per entry.
94
+
95
+
Each watch in the collection has a service diary (revisions, part replacements, etc.) with optional cost and category per entry. All service costs roll up into the total cost basis for gain/loss tracking.
96
+
97
+
---
71
98
72
99
### Wishlist
100
+
73
101
The collection page includes a dedicated **Wishlist** tab for watches you want to acquire. Wishlist entries support the same fields as owned watches and can be promoted to the active collection at any time.
74
102
103
+
---
104
+
75
105
### Sold Watches
106
+
76
107
Watches in the collection can be marked as sold with a sale date and sale price. Sold items move to a dedicated tab with a **gain/loss** calculation (sale price minus purchase + service costs).
77
108
109
+
---
110
+
78
111
### Categories
79
-
Log entry categories are managed from Settings with a **name + color** per category. The same category list is shared across flip logs, collection logs, and inventory, ensuring consistency throughout the app.
112
+
113
+
Log entry categories are managed from Settings with a **name + color** per category. A built-in color picker with live hex preview makes it easy to assign distinct colours. The same category list is shared across flip logs, collection logs, and inventory, ensuring consistency throughout the app.
114
+
115
+
---
80
116
81
117
### Watch Lookup
82
-
When adding a new flip or collection watch, a **Chrono24 search** field appears at the top of the form. Type a brand, model, or reference number and select a result to auto-fill brand, model, reference, year, and market price. If a photo is available, it is downloaded and attached automatically. The feature degrades gracefully if Chrono24 is unreachable.
83
118
84
-
### Inline Editing
85
-
Flips and collection watches can be edited directly **inline in the list table** without navigating to a separate page, keeping the workflow fast.
119
+
When adding a new flip or collection watch, a **Chrono24 search** field appears at the top of the form. Type a brand, model, or reference number and select a result to auto-fill brand, model, reference, year, and market price. If a photo is available, it is downloaded and attached automatically. Search is debounced (500 ms) and results are cached per session. The feature degrades gracefully if Chrono24 is unreachable.
120
+
121
+
---
122
+
123
+
### Inline Editing & Sorting
124
+
125
+
Flips and collection watches can be edited directly **inline in the list table** without navigating to a separate page, keeping the workflow fast. All tables support **clickable column headers** for sorting — ascending/descending toggle with smart type detection: numeric, date (all three common formats), and text. Destructive actions use an **inline Yes/No confirmation popover** that auto-dismisses after 5 seconds, avoiding disruptive modal dialogs.
126
+
127
+
---
128
+
129
+
### Dark Mode
130
+
131
+
A built-in **light/dark theme toggle** is available from every page. Your preference is saved to localStorage and applied immediately on load — no flash of unstyled content.
132
+
133
+
---
86
134
87
135
### Export / Import
88
-
Full backup and restore from Settings or Dashboard. The export is a **ZIP archive** containing `data.json` (all tables) plus the `images/` directory. Import accepts both the new ZIP format and the legacy plain-JSON format.
136
+
137
+
Full backup and restore from Settings or Dashboard. The export is a **ZIP archive** containing `data.json` (all tables) plus the `images/` directory. Import accepts both the new ZIP format and the legacy plain-JSON format. ZIP files are detected automatically by magic bytes — no extension guessing.
138
+
139
+
---
89
140
90
141
### Internationalisation
91
-
UI language is switchable from Settings. Translations live in `lang/en.json` and are also available in Italian, German, French, and Spanish (`lang/it.json`, `de.json`, `fr.json`, `es.json`).
142
+
143
+
UI language is switchable from Settings. Translations live in `lang/en.json` and are also available in Italian, German, French, and Spanish (`lang/it.json`, `de.json`, `fr.json`, `es.json`). Number formatting adapts to locale (e.g. Italian `1.234,56` vs. standard `1234.56`).
0 commit comments