Document Version: 1.0
Last Updated: January 2026
Status: Active (2025 Standard)
Source: Code analysis and domain expert interview
The treatments collection stores all user interventions and system events related to diabetes management. This includes insulin doses, carbohydrate intake, temp basals, profile switches, CGM sensor events, and free-form notes.
Collection Name: treatments
Primary Timestamp Field: created_at (ISO 8601)
Display/Query Field: mills (computed from created_at)
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
_id |
ObjectId | Yes (auto) | MongoDB ObjectId | Primary key, auto-generated |
eventType |
String | Yes* | Defaults to <none> if missing |
Classification of the treatment type |
created_at |
String (ISO 8601) | Yes | Valid ISO timestamp | When the event was observed/occurred (NOT upload time) |
mills |
Number | Computed | new Date(created_at).getTime() |
Milliseconds since epoch, computed for queries |
enteredBy |
String | No | Free-form, max ~50 chars typical | Nickname of person/device that entered the record |
notes |
String | No | Free-form text | Additional notes or comments |
units |
String | No | mg/dL or mmol/L |
Unit system for glucose values in this record |
*Note: If eventType is missing, the websocket layer defaults it to <none> (see lib/server/websocket.js:357-358).
| Field | Type | Constraints | Description |
|---|---|---|---|
glucose |
Number | Optional | Blood glucose value at time of treatment |
glucoseType |
String | Sensor, Finger, or Manual |
Method used to obtain the glucose reading |
| Field | Type | Constraints | Description |
|---|---|---|---|
carbs |
Number | ≥ 0, in grams | Carbohydrates consumed |
protein |
Number | ≥ 0, in grams | Protein consumed |
fat |
Number | ≥ 0, in grams | Fat consumed |
foodType |
String | Optional | Description of food eaten |
absorptionTime |
Number | Optional, in minutes | Expected absorption time for carbs |
preBolus |
Number | Optional, in minutes | Time offset between insulin and meal |
| Field | Type | Constraints | Description |
|---|---|---|---|
insulin |
Number | ≥ 0, in units | Amount of insulin administered |
splitNow |
Number | 0-100, percentage | For Combo Bolus: immediate portion |
splitExt |
Number | 0-100, percentage | For Combo Bolus: extended portion |
| Field | Type | Constraints | Description |
|---|---|---|---|
duration |
Number | ≥ 0, in minutes | How long the temp basal or override lasts |
percent |
Number | Can be negative | Basal change as percentage (e.g., -50 for 50% reduction) |
absolute |
Number | ≥ 0, U/hr | Absolute basal rate override |
Note: percent and absolute are mutually exclusive for temp basals.
| Field | Type | Constraints | Description |
|---|---|---|---|
targetTop |
Number | In user's units | Upper bound of temporary target range |
targetBottom |
Number | In user's units | Lower bound of temporary target range |
correctionRange |
Array[2] | [min, max] |
Alternative format for target range |
reason |
String | Optional | Reason for temporary target (e.g., "Eating Soon", "Activity") |
insulinNeedsScaleFactor |
Number | Multiplier | Adjustment factor for insulin sensitivity |
| Field | Type | Constraints | Description |
|---|---|---|---|
profile |
String | Profile name | Name of the profile being switched to |
Note: The profile field is a string name reference, not a foreign key. If the named profile doesn't exist, behavior is undefined.
| Field | Type | Constraints | Description |
|---|---|---|---|
sensorCode |
String | Optional | Sensor identification code |
transmitterId |
String | Optional | CGM transmitter ID |
| Field | Type | Source | Description |
|---|---|---|---|
srvCreated |
String (ISO 8601) | Server | When the server first received this record |
srvModified |
String (ISO 8601) | Server | When the server last modified this record |
identifier |
String | AAPS | AAPS-specific unique identifier for sync |
uuid |
String | Various | Client-assigned unique identifier |
pumpId |
String | Loop/pumps | Pump-assigned identifier |
pumpType |
String | Loop/pumps | Type of pump that created this treatment |
pumpSerial |
String | Loop/pumps | Serial number of the pump |
Important: Different controller systems use different field names for duplicate detection:
- AAPS: Uses
identifierfield - Loop: Uses
_idor pump-related fields - xDrip: Uses
uuidfield
This inconsistency suggests that schema registration / inversion of control would be valuable - controllers should register their sync identity field conventions.
| eventType Value | Display Name | Key Fields Used |
|---|---|---|
<none> |
(none) | bg, insulin, carbs |
BG Check |
BG Check | bg |
Snack Bolus |
Snack Bolus | bg, insulin, carbs, protein, fat, prebolus |
Meal Bolus |
Meal Bolus | bg, insulin, carbs, protein, fat, prebolus |
Correction Bolus |
Correction Bolus | bg, insulin |
Carb Correction |
Carb Correction | bg, carbs, protein, fat |
Combo Bolus |
Combo Bolus | bg, insulin, carbs, duration, split |
Announcement |
Announcement | bg |
Note |
Note | bg, duration |
Question |
Question | bg |
Exercise |
Exercise | duration |
Site Change |
Pump Site Change | bg, insulin |
Sensor Start |
CGM Sensor Start | bg, sensor |
Sensor Change |
CGM Sensor Insert | bg, sensor |
Sensor Stop |
CGM Sensor Stop | bg |
Pump Battery Change |
Pump Battery Change | bg |
Insulin Change |
Insulin Cartridge Change | bg |
Temp Basal Start |
Temp Basal Start | bg, duration, percent, absolute |
Temp Basal End |
Temp Basal End | bg, duration |
Profile Switch |
Profile Switch | bg, duration, profile |
D.A.D. Alert |
D.A.D. Alert | bg |
| eventType Value | Description |
|---|---|
Temporary Target |
Sets a temporary target range with duration |
Temporary Target Cancel |
Cancels an active temporary target |
OpenAPS Offline |
Indicates loop is offline for specified duration |
Loop uses similar event types to the core set, plus controller-specific extensions.
Custom closed-loop systems (AAPS, Loop, Trio, oref0) may send additional event types. These are not enumerated here and may include:
- SMB (Super Micro Bolus) records
- Autosens data
- Override presets
- Algorithm-specific annotations
Note: The eventType field is essentially free-form - clients can send any string value. The UI treats unknown types gracefully but may not render them optimally.
| Field | Meaning | Set By |
|---|---|---|
created_at |
When the event was observed/happened | Client or Server |
srvCreated |
When the server first received this record | Server only |
Use Case: AAPS uses srvCreated for cache control during its update/reconcile sync loop. This allows distinguishing between "this insulin was given at 8am" (created_at) vs "we learned about it at 8:15am" (srvCreated).
If a treatment arrives without created_at, the server sets it to the current time:
// lib/server/websocket.js:360-361
if (!('created_at' in data.data)) {
data.data.created_at = new Date().toISOString();
}The enteredBy field is a free-form nickname with the following characteristics:
- Browser Auto-fill: The web UI prefills this field with the last value entered on that device
- Not Identity-Verified: This is an optimistic field - there's no authentication tied to it
- Use Cases: Helpful for families where multiple people (e.g., "Mom", "Dad", "Nurse") enter treatments
- Future Consideration: Real identity tracking may be needed for audit trails, but currently this is just a convenience field
Symptom: Some temp basal slices disappear in the Nightscout UI when uploaded from AAPS.
Status: Possible PR exists to address this. Needs investigation.
Workaround: None documented.
Symptom: Override events (like temporary targets) sometimes:
- Appear indefinite when they should have ended
- Cannot be ended or cancelled through the UI
- Don't render at all
Status: Active bug, cause unclear.
The code filters out Temp Basal from some event type dropdowns:
// lib/report_plugins/treatments.js:176-178
if (event.name.indexOf('Temp Basal') > -1) {
return;
}Then adds it back manually. This suggests special handling is needed for temp basals that may cause edge cases.
- Uses
identifierfield for sync deduplication - Relies heavily on
srvCreatedfor cache control - May send SMB-specific event types
- Uses pump-related fields (
pumpId,pumpType,pumpSerial) for identification - Sends override presets with emoji symbols
- Profile documents include
loopSettingsobject
- Uses
uuidfield for sync - May send BG checks and calibrations
- Fork of Loop with similar patterns
- May have additional event types
The following fields have been observed in treatment records but are less commonly used or controller-specific. This list is not exhaustive - custom controllers can add any fields they need.
| Field | Type | Description | Source |
|---|---|---|---|
utcOffset |
Number | UTC offset in minutes for the client timezone | Various clients |
durationInMillis |
Number | Alternative to duration in milliseconds |
Some pumps |
insulinInjections |
Array | Detailed injection records from some pumps | Pump-specific |
splitNow / splitExt |
Number | Combo bolus split percentages | Careportal |
targetBottom / targetTop |
Number | Alternative naming for target range bounds | Some clients |
timestamp |
String | Alternative to created_at in some contexts |
Legacy |
isAnnouncement |
Boolean | Flags announcement type | Some clients |
pumpId, pumpType, pumpSerial |
String | Pump identification for deduplication | Loop/pumps |
Note on glucoseType: Beyond Sensor, Finger, and Manual, some clients may send other values. The core system treats these as display strings without validation.
The defaults documented (eventType defaulting to <none>, created_at defaulting to current time) are applied in WebSocket ingestion (lib/server/websocket.js). The REST API v1 treatment endpoint (lib/server/treatments.js) may have different or no defaults - always verify behavior for your ingestion path.
| Constraint | Fields Affected | Enforcement |
|---|---|---|
| Non-negative | carbs, protein, fat, insulin, duration, absolute |
UI min="0" |
| Step increments | insulin (0.05), percent (10), duration (1) |
UI step attribute |
| Mutually exclusive | percent vs absolute |
UI hides one when other has value |
| Required | eventType (defaulted), created_at (defaulted) |
Server-side fallback |
Note: Server-side validation is minimal. Most constraints are UI-enforced only.
- Report plugins are schema documentation - The treatments report plugin (
lib/report_plugins/treatments.js) reveals which fields are actually used and displayed - Event types come from plugins - The
getAllEventTypes()function aggregates types from enabled plugins, making the canonical list dynamic - Sync identity is client-dependent - Each controller (AAPS, Loop, xDrip) uses different fields for duplicate detection, complicating server-side deduplication
- Should eventType be enumerated? Currently free-form, but validation could catch typos
- Should sync identity be standardized? A single
clientIdoruuidfield could simplify reconciliation - Are field constraints documented anywhere? The UI has min/max but there's no schema validation layer
- No formal schema file exists - had to extract from code
- Event types are scattered across multiple plugin files
- Some fields (like
identifier) are undocumented and discovered by reading AAPS source
| File | Purpose |
|---|---|
lib/server/treatments.js |
Server-side treatment CRUD operations |
lib/server/websocket.js |
Real-time treatment insertion |
lib/plugins/careportal.js |
Core event type definitions |
lib/plugins/openaps.js |
OpenAPS-specific event types |
lib/plugins/loop.js |
Loop-specific event types |
lib/report_plugins/treatments.js |
Treatment report (reveals field usage) |
lib/data/ddata.js |
Treatment data processing |
lib/client/careportal.js |
Client-side treatment entry UI |
lib/server/swagger.yaml |
API documentation (partial schema) |
| Date | Author | Changes |
|---|---|---|
| 2026-01-15 | Agent | Initial schema documentation from code analysis and domain expert interview |