Skip to main content

Customer bike

A specific bike owned by a specific customer. Surfaces on the customer profile, links to service tickets, persists across multiple visits.

Drafted from planning · v0.1

Why this entity exists separately from customers

A customer can own multiple bikes; each bike has its own service history. Tracking bikes as first-class lets us:

  • Show "this bike was here in 2022 for a chain replacement" on the next visit
  • Surface relevant service intervals ("brake bleed due in 1000 km")
  • Distinguish "Bob's gravel bike" from "Bob's mountain bike" when he drops one off

Table: customer_bikes

ColumnTypeNotes
idINTEGER PK
customer_idINTEGER FK → customers
nicknameTEXTOptional human label ("gravel bike")
brandTEXTSpecialized, Trek, Devinci, etc.
modelTEXTModel name
model_yearINTEGERFilter year 0001 sentinel from AIM
frame_sizeTEXT"M", "54cm", "L/XL"
serial_numberTEXTPII; the bike's frame serial
colorTEXT
wheel_sizeTEXT"29", "27.5", "700c", "650b"
purchase_dateDATEWhen the customer bought it (from us or elsewhere)
purchased_from_usINTEGER (0/1)Sourced from a Helm sale vs externally owned
notesTEXTFree text about the bike
created_at, updated_atTEXT

How bikes get into the system

Three paths:

  1. Sale from this shop — at the point of sale of a new bike (category cat_pk=448 in AIM, inventory_categories.is_bike in Helm), a customer_bikes row is automatically created and linked.
  2. Drop-off form — when a customer drops off a bike for service, the operator picks the customer, then either selects an existing bike or adds a new one inline.
  3. Manual add — on the customer profile, the operator can "+ Add bike" with serial/model/year fields.

Behaviors

Service history

GET /api/customer-bikes/{id}/tickets returns all service tickets for this bike, with their statuses and dates. Used in:

  • The customer profile's bike card hover state
  • The drop-off form (shows previous tickets when this bike is selected)
  • The ticket detail page (when the bike has history)

Delete

Blocked if the bike has any service_tickets not in picked_up or cancelled. Otherwise hard DELETE with audit log.

Edit

Editable fields in-situ on the customer profile: nickname, frame_size, color, notes. The serial number and brand/model are editable but flagged as audit-relevant ("are you sure? this is the identity of the bike").

Migrated from AIM

For Swicked: sales-derived bikes from AIM's scsasld (sales line items) where the line is in BIKES category (sccat.cat_pk = 448). The migration:

  • Joins scsasldscsasrl (serial registry) on sld_sernosrl_serno to get the frame serial
  • Joins to cust for the customer
  • Joins to pim (product image / product master) for brand + model
  • Creates customer_bikes rows with purchased_from_us = 1

Bikes purchased elsewhere are not in AIM data; they enter Helm via service drop-offs.

In-situ editing surface

On the customer profile, in the Bikes section, in edit mode:

  • Each bike card: drag handle for reordering, × for remove
  • Click any field to edit inline
    • Add bike opens a quick form (brand, model, year, size, serial)

On the service drop-off form:

  • Picking the customer reveals their bikes
  • Picking a bike shows its history; selecting "New bike" reveals the inline add form

See also