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
Version: 2.0
Last Updated: 2026-03-28
Status: Draft
1. Introduction
1.1 Purpose
Battery Cell Tracker is a client-side web application for managing rechargeable battery cell inventories. Users track cell metadata, record capacity measurements over time, detect degraded cells, compare cells for pairing, and synchronize data across devices via GitHub.
1.2 Target Users
Battery hobbyists and DIY builders who:
Collect and test rechargeable cells (18650, 21700, AA, etc.)
Build battery packs for e-bikes, powerwalls, flashlights
Need to match cells by capacity for series/parallel configurations
Use capacity testers (e.g., LiitoKala Lii-700, XTAR VC4SL, Opus BT-C3100)
1.3 Key Principles
Zero backend - all data stored locally (localStorage) and optionally synced to a user-owned GitHub repository
Privacy first - no telemetry, no analytics, no third-party data storage
Online required - internet connection required for GitHub sync; app does not support offline mode to prevent data consistency issues
Multi-device - reliable concurrent usage across phone and desktop via three-way merge
Multi-language - Hungarian and English UI
2. Functional Requirements
2.1 Cell Inventory Management
FR-01: Create Cell
User provides a unique alphanumeric ID (e.g., "01", "A1", "BK-042")
Required fields: ID, brand, nominal capacity, form factor, chemistry, status
Required fields: measured capacity (mAh), discharge current (mA)
Optional fields: date (defaults to today), charge current (mA), internal resistance (mohm), test device, notes, weight (g), charge temperature, discharge temperature, ambient temperature, charge time, discharge time
Temperature stored in Celsius internally; displayed in user's preferred unit (Celsius or Fahrenheit)
Time input in H:MM format, stored as integer minutes
Warning shown if discharge current differs from previous measurement
Auto-scrap detection runs after adding (see FR-15)
FR-09: Delete Measurement
Confirmation dialog required
"measurement_deleted" event logged
FR-10: View Measurements
Table sorted by date (newest first)
Columns: date, capacity, retention %, discharge current, charge current, internal resistance, test device, notes, charge/discharge temperature, charge/discharge time
Retention % color-coded: green (>=80%), amber (60-79%), red (<60%)
2.3 Cell Templates
FR-11: Create Template
Required fields: name, brand, nominal capacity, form factor, chemistry
Internet connection required; offline mode disabled to prevent data consistency issues
NFR-12: Data consistency
Three-way merge prevents data loss on concurrent edits
NFR-13: Sync retry
Up to 5 retries with exponential backoff
NFR-14: Graceful degradation
App works without GitHub config
NFR-15: Data backup
Export/import for manual backup
3.4 Usability
Requirement
Description
NFR-16: Responsive design
Mobile-first, works on 320px+ screens
NFR-17: Dark mode
System-detected or manual toggle
NFR-18: Internationalization
Hungarian (default) and English
NFR-19: Accessibility
Semantic HTML, form labels, keyboard navigation
NFR-20: PWA
Installable on mobile home screen
3.5 Deployment
Requirement
Description
NFR-21: Static export
No server required (output: "export")
NFR-22: Hosting
GitHub Pages (free)
NFR-23: CI/CD
Auto-deploy on push to main branch
NFR-24: Build
Must pass npm run build and npm run lint
3.6 Compatibility
Requirement
Description
NFR-25: Browsers
Chrome 90+, Firefox 90+, Safari 15+, Edge 90+
NFR-26: Devices
Desktop, tablet, phone
NFR-27: OS
Windows, macOS, Linux, iOS, Android
4. User Flows
4.1 First-Time Setup
flowchart TD
A[Open App] --> B{GitHub configured?}
B -->|No| C[Show Onboarding Wizard]
C --> D[Step 1: Welcome]
D --> E[Step 2: Repository Details]
E --> F[Step 3: Enter PAT]
F --> G[Step 4: Set PIN]
G --> H[Step 5: Complete]
H --> I[Initial Sync from GitHub]
I --> J[Dashboard]
B -->|Yes| K{Session locked?}
K -->|Yes| L[PIN Dialog]
L --> M{PIN correct?}
M -->|Yes| J
M -->|No| N[Show error + lockout delay]
N --> L
K -->|No| J
Loading
4.2 Add Cell with Template
flowchart TD
A[Navigate to /add] --> B[Select Template]
B --> C[Fields auto-filled from template]
C --> D[Enter unique Cell ID]
D --> E[Adjust fields if needed]
E --> F[Click Add Cell]
F --> G{Validation OK?}
G -->|No| H[Show field errors]
H --> E
G -->|Yes| I[Cell created in store]
I --> J[Navigate to /cells?id=newId]
J --> K[Debounced sync to GitHub]
Loading
4.3 Record Measurement
flowchart TD
A[Open Cell Detail] --> B[Expand Measurement Form]
B --> C[Enter capacity + discharge current]
C --> D[Optionally fill: resistance, temperature, time, weight]
D --> E[Click Save]
E --> F{Validation OK?}
F -->|No| G[Show errors]
G --> C
F -->|Yes| H[Measurement added to cell]
H --> I{Auto-scrap triggered?}
I -->|Yes| J[Status -> Selejt, event logged]
I -->|No| K[Event logged]
J --> L[UI refreshes: table, chart, profile]
K --> L
L --> M[Debounced sync to GitHub]
Loading
4.4 Multi-Device Sync
flowchart TD
A[User edits on Device A] --> B[Push to GitHub]
B --> C[User opens app on Device B]
C --> D[App startup: pull from GitHub]
D --> E[Three-way merge: base vs remote vs local]
E --> F{Conflicts?}
F -->|Field conflicts| G[Local wins for conflicting fields]
F -->|No conflicts| H[Remote changes accepted]
G --> I[Merged result saved locally]
H --> I
I --> J[Push merged result to GitHub]
J --> K{Push success?}
K -->|409 Conflict| L[Fetch remote again]
L --> E
K -->|Success| M[Update base snapshot + SHA]
Loading
4.5 Compare Cells
flowchart TD
A[View Cell Detail] --> B[Click Compare button]
B --> C[Modal: Select cells to compare]
C --> D[Filter by group/format/chemistry]
D --> E[Select 1-4 additional cells]
E --> F[Show comparison table]
F --> G[Choose comparison basis]
G --> H{Same discharge current?}
H -->|Yes| I[Direct comparison]
H -->|No| J[Show warning icon]
I --> K[Best values highlighted]
J --> K
K --> L[Best pair suggestions shown]
Loading
5. Data Model Summary
5.1 Core Entities
erDiagram
Cell ||--o{ Measurement : contains
Cell ||--o{ CellEvent : logs
CellTemplate ||--o{ Cell : "used to create"
Cell {
string internalId PK "UUID"
string id UK "User-defined"
string templateId FK "Optional"
string brand
string model
FormFactor formFactor
Chemistry chemistry
string cathodeType
string contactType
number nominalCapacity "mAh"
number continuousDischargeCurrent "mA"
number peakDischargeCurrent "mA"
number weight "grams"
number storageVoltage "V"
string batchNumber
CellStatus status
string currentDevice
string group
string notes
string platform
string seller
string purchaseDate
string purchaseUrl
number pricePerUnit
datetime createdAt
datetime updatedAt
}
Measurement {
string id PK "UUID"
string date
number measuredCapacity "mAh, required"
number dischargeCurrent "mA, required"
number chargeCurrent "mA"
number internalResistance "mohm"
string testDevice
string notes
number weight "grams"
number chargeTemperature "Celsius"
number dischargeTemperature "Celsius"
number ambientTemperature "Celsius"
number chargeTime "minutes"
number dischargeTime "minutes"
}
CellTemplate {
string internalId PK "UUID"
string id UK "UUID"
string name
string brand
string model
FormFactor formFactor
Chemistry chemistry
number nominalCapacity "mAh"
number weight "grams"
boolean archived
datetime createdAt
datetime updatedAt
}
CellEvent {
string id PK "UUID"
string date
CellEventType type
string description
}
Loading
5.2 Settings Structure
erDiagram
SharedSettings {
number scrapThresholdPercent "20-90, default 60"
string defaultTestDevice
number defaultDischargeCurrent "mA"
number defaultChargeCurrent "mA"
string_array devices
string_array testDevices
}
ClientSettings {
string clientId "6-digit hex"
Theme theme "light/dark/system"
Language language "hu/en"
TemperatureUnit temperatureUnit "celsius/fahrenheit"
}