V1 Baseline — Current State¶
V1 is the system Stefan uses today. It is not being rebuilt — V2 is built directly and inherits the full V1 history via migration. This page documents V1 as a reference for what V2 must preserve, replace, and improve.
Source artifacts¶
- Spreadsheet:
stringing_orders.xlsx(repo root) — 4 sheets:Client-Stringing-Orders,Self-Stringing-Orders,Stats,Lists. - Public site: stringing.wagen.io — single page "Listing all Orders" with per-row PDF receipts at
/receipt_<id>.pdf. Backed by a script that reads the XLSX directly; no separate database.
Sheets at a glance¶
Client-Stringing-Orders¶
The big one — 329 real orders, IDs 1..329, dates 2019-05-02 → 2026-04-25. Two-row header (group label + field), 35 columns:
| Group | Fields |
|---|---|
| ID | ID (sequential) |
| Dates | Ordered, Strung, Returned, Paid |
| Player | Last Name, First Name |
| Racquet | Model, Head Size, String Pattern |
| Main-String | Manufacturer, Model, Gauge, Tension, Price, BYO (Yes/No) |
| Cross-String | Manufacturer, Model, Gauge, Tension, Price, BYO |
| Price | Labor, Strings (formula skips price for BYO sides), Total |
| DT | empty in samples — Dynamic Tension reading |
| Comments | free text |
| Status | derived: Ordered, Strung, Payment open, Done |
| Stats | derived: Year, Month, Strung (any-of-status) |
47 distinct players, 65 distinct racket-model strings (free text — same model written multiple ways), ~43 distinct string mfr/model combos.
Self-Stringing-Orders¶
Stefan's own jobs — 416 rows, dates 2020-03 → 2026-04. 20 columns. Single date (Strung). Uses a per-racket ID (e.g. PA98_2023_45, B98_V8_NS_43) that VLOOKUPs into Lists for model + pattern. Adds Color per side, Method (e.g. "Standard"), Dynamic Tension After Stringing. No prices, no payment, no player.
Lists¶
Two lookup tables:
BYO: Yes / No.My Racquets: 30 of Stefan's own rackets —ID,Racket,String Pattern,Head Size,Year,Current(in rotation),# Stringjobs(COUNTIF).
Stats¶
Derived dashboard: counts and revenue, all-time and per-year (2019–2027), Self vs Client split, plus a 12-month cross-tab.
V1 domain model (synthesis)¶
Entities¶
- Player / Client — identified only by
(Last Name, First Name). No email, phone, address, or stable ID. Stefan himself is on a separate sheet. - Client Racket — free-text model + head size + string pattern, attached directly to an order. No persistence across orders.
- Own Racket — first-class entity in
Lists, with stable ID, year, in-rotation flag, history count. Linked fromSelf-Stringing-Ordersby ID. - Stringing Order / Job — central record. For clients, 4-stage lifecycle: Ordered → Strung → Returned → Paid. For self-jobs, single
Strungdate. - String Spec (per side: Main, Cross) — manufacturer, model, gauge, (color for self), tension, price, BYO flag.
- Receipt — PDF artefact per client order at
receipt_<id>.pdf.
Primary flows¶
- Client stringing job (happy path): Stefan logs order with player + racket + main/cross specs and tensions, sets
Ordereddate. Strings the racket, setsStrungdate and anyComments/ DT. Returns to player, setsReturneddate. Receives payment, setsPaiddate.Statuscolumns derive lifecycle position. Pricing auto-computes (BYO sides excluded). Receipt PDF served by the website. - Self stringing job: Stefan picks one of his own rackets (by ID), records main/cross strings + tensions + colors + method + post-stringing DT.
- Reporting:
Statssheet rolls up counts and revenue per year and per month, Self vs Client. - Public visibility:
stringing.wagen.ioexposes the full client-orders list and printable receipts to anyone with the URL.
Implicit business rules¶
- Each order has exactly one player, one racket, one main string spec, one cross string spec.
- "BYO = Yes" on a side excludes that side's price from the Strings subtotal.
- A job is "Done" only when both
ReturnedandPaidare set. - Stefan's own rackets have richer modelling than client rackets (because he tracks per-racket performance over time).
- Dates are required in causal order (Ordered ≤ Strung ≤ Returned ≤ Paid), not enforced by the spreadsheet.
Data findings¶
Computed from the XLSX on 2026-04-27:
- Main vs Cross identity (same mfr + model + gauge): Client 89.1%, Self 87.7%. Hybrid setups are the ~11% minority. → "Same as main" shortcut for cross is the right default.
- BYO (client orders): Main 48.3%, Cross 49.2%, both sides 48.3%, cross-only 0.9%, main-only 0%. → BYO is essentially all-or-nothing in practice.
- Tension delta (main − cross): mean +0.46 kg, median 0.00, range −1.0 to +2.0. 95% of orders are at delta 0 or +1 kg. → UI should default cross-tension = main-tension with a one-tap ±1 kg nudge.
Gaps and smells visible in V1¶
- Client identity has no stable key — duplicate or misspelled names will silently create new "players".
- Client rackets are free-text — no normalization; "Wilson Blade 98" vs "Wilson Blade 98 V7" vs "Wilson Blade 98 V8 (306g)" all coexist.
- String catalogue is free-text on both sides — same string typed inconsistently.
- No contact info → no way to notify a client that their racket is ready.
- The public site exposes client names with no auth — fine in a friend-circle context but not intentional.
- Receipts are static PDFs — invoicing/payment status invisible to the client.
- Spreadsheet and website are two stores fed by a script — risk of drift.
Migration commitment¶
V2 migrates the full XLSX history: all 329 client orders + all 416 self orders + Stefan's Lists.My Racquets rackets. See data model for the target shape and the V2 scope Must list (M15).