# Requirements Document

## Introduction

This feature adds visceral fat tracking to the Albi health tracker app. Users can record waist circumference measurements over time, store static profile data (height, gender), and receive risk assessments based on clinical thresholds (waist circumference alone, and waist-to-height ratio). A new entry screen, chart screen, and tips content provide a complete tracking experience consistent with existing health metrics in the app.

## Glossary

- **App**: The Albi health tracker Flutter application
- **User_Profile**: A database table storing static user data (height, gender) that does not change over time
- **Waist_Entry**: A single waist circumference measurement record, tracked over time like weight entries
- **Risk_Assessor**: The component that calculates visceral fat risk levels from waist measurements and profile data
- **Waist_Chart_Screen**: The screen displaying waist measurement and waist-to-height ratio charts over time
- **Track_Visceral_Fat_Screen**: The screen for entering new waist circumference measurements and collecting profile data
- **DatabaseService**: The singleton SQLite database service managing all persistence operations
- **ChartDataService**: The service providing data aggregation and statistics for chart visualisation

## Requirements

### Requirement 1: User Profile Storage

**User Story:** As a user, I want to store my height and gender once, so that the app can calculate waist-to-height ratio and apply gender-specific thresholds without re-entering this data.

#### Acceptance Criteria

1. THE DatabaseService SHALL store height as a numeric value paired with a unit (cm or inches) in a single-row User_Profile table
2. THE DatabaseService SHALL store gender (male or female) in the User_Profile table
3. WHEN the user saves height or gender and no User_Profile row exists, THE DatabaseService SHALL insert a new row in the User_Profile table
4. WHEN the user saves height or gender and a User_Profile row already exists, THE DatabaseService SHALL overwrite the previous value in the existing row
5. WHEN the app requests profile data, THE DatabaseService SHALL return the stored height (value and unit) and gender, or null for each field that has not been set
6. THE DatabaseService SHALL create the User_Profile table via a database migration from version 1 to version 2 without altering existing tables

### Requirement 2: Waist Circumference Entry Storage

**User Story:** As a user, I want to record waist circumference measurements over time, so that I can track changes in my visceral fat indicator.

#### Acceptance Criteria

1. THE DatabaseService SHALL store each Waist_Entry with a canonical value in centimetres, the original unit (cm, mm, or inches), a timestamp, and optional notes (maximum 500 characters)
2. THE Waist_Entry model SHALL extend the HealthData base class providing id, timestamp, and notes fields
3. WHEN the user enters a waist measurement in cm, THE Waist_Entry SHALL store the value directly as the canonical centimetre value without conversion
4. WHEN the user enters a waist measurement in mm, THE Waist_Entry SHALL convert the value to centimetres by dividing by 10 for canonical storage
5. WHEN the user enters a waist measurement in inches, THE Waist_Entry SHALL convert the value to centimetres by multiplying by 2.54 for canonical storage
6. IF the converted canonical value falls outside the range of 30.0 cm to 300.0 cm, THEN THE Waist_Entry SHALL reject the entry and indicate a validation error specifying the acceptable range
7. THE DatabaseService SHALL create the waist_entries table via the same version 1 to version 2 migration alongside the User_Profile table
8. THE DatabaseService SHALL create an index on the timestamp column of the waist_entries table

### Requirement 3: Waist Circumference Unit Conversion

**User Story:** As a user, I want to enter waist measurements in my preferred unit, so that I can use familiar measurement systems.

#### Acceptance Criteria

1. THE Waist_Entry SHALL accept numeric input in centimetres, millimetres, and inches and convert the value to centimetres for canonical storage using the factors: 1 mm = 0.1 cm, 1 inch = 2.54 cm
2. WHEN displaying a stored Waist_Entry, THE App SHALL convert the canonical centimetre value back to the original unit using the inverse factors (cm to mm: multiply by 10, cm to inches: divide by 2.54) and display the result to 1 decimal place
3. THE Waist_Entry SHALL satisfy the round-trip property: converting any valid input (30–300 cm equivalent) from the original unit to centimetres and back to the original unit produces a value within 0.01 of the original input
4. IF the Waist_Entry is provided with a unit other than cm, mm, or inches, THEN THE Waist_Entry SHALL reject the input and indicate an invalid unit error

### Requirement 4: Risk Assessment — Waist Circumference Threshold

**User Story:** As a user, I want to see whether my waist circumference indicates increased visceral fat risk, so that I can understand my health status.

#### Acceptance Criteria

1. WHEN gender is male and waist circumference is greater than 102 cm, THE Risk_Assessor SHALL classify the measurement as "increased risk"
2. WHEN gender is male and waist circumference is 102 cm or less, THE Risk_Assessor SHALL classify the measurement as "normal risk"
3. WHEN gender is female and waist circumference is greater than 88 cm, THE Risk_Assessor SHALL classify the measurement as "increased risk"
4. WHEN gender is female and waist circumference is 88 cm or less, THE Risk_Assessor SHALL classify the measurement as "normal risk"
5. IF gender is not set in the User_Profile, THEN THE Risk_Assessor SHALL return a status indicating that the waist circumference threshold assessment cannot be performed due to missing gender
6. WHEN the Risk_Assessor classifies a measurement, THE App SHALL display the risk classification label ("increased risk" or "normal risk") with a colour indicator distinguishing the two categories, consistent with the existing blood pressure category colour scheme
7. WHEN the Risk_Assessor returns a missing-gender status, THE App SHALL display a prompt directing the user to set their gender in order to receive a waist circumference risk assessment

### Requirement 5: Risk Assessment — Waist-to-Height Ratio

**User Story:** As a user, I want to see my waist-to-height ratio and whether it is within a healthy range, so that I can track a validated health indicator.

#### Acceptance Criteria

1. WHEN height is available in the User_Profile, THE Risk_Assessor SHALL convert the stored height to centimetres (multiplying by 2.54 if stored in inches) and calculate the waist-to-height ratio by dividing the waist circumference in cm by the height in cm, displaying the result rounded to 2 decimal places
2. WHEN the waist-to-height ratio is below 0.5, THE Risk_Assessor SHALL classify the result as healthy
3. WHEN the waist-to-height ratio is 0.5 or above, THE Risk_Assessor SHALL classify the result as increased risk
4. IF height is not set in the User_Profile, THEN THE Risk_Assessor SHALL skip the waist-to-height ratio calculation and display a prompt to set height
5. IF no Waist_Entry exists for the user, THEN THE Risk_Assessor SHALL skip the waist-to-height ratio calculation and display guidance to add a waist measurement
6. THE Risk_Assessor SHALL produce a ratio that equals waist_cm divided by height_cm for all waist values between 30 and 300 cm and height values between 50 and 275 cm (mathematical correctness property)

### Requirement 6: Track Visceral Fat Screen

**User Story:** As a user, I want a dedicated screen to enter my waist measurement, so that I can easily log visceral fat data.

#### Acceptance Criteria

1. THE Track_Visceral_Fat_Screen SHALL provide a numeric input field for waist circumference accepting up to one decimal place, with unit selection (cm, mm, or inches)
2. THE Track_Visceral_Fat_Screen SHALL display an instructional note above the waist input field stating that waist should be measured at navel level, not where pants sit
3. IF height is not set in the User_Profile, THEN THE Track_Visceral_Fat_Screen SHALL display a dismissible prompt to enter height with an explanation of why height improves risk assessment accuracy
4. IF gender is not set in the User_Profile, THEN THE Track_Visceral_Fat_Screen SHALL display a dismissible prompt to enter gender with an explanation of why gender is needed for threshold calculation
5. THE Track_Visceral_Fat_Screen SHALL include a tips section displaying the visceral fat reduction guidance defined in Requirement 10
6. WHEN the user submits a valid waist measurement, THE Track_Visceral_Fat_Screen SHALL save the Waist_Entry via the HealthDataBloc, display a success snackbar, and navigate back to the previous screen
7. IF the HealthDataBloc emits an error state after submission, THEN THE Track_Visceral_Fat_Screen SHALL display an error message and remain on the screen with the entered data preserved
8. THE Track_Visceral_Fat_Screen SHALL include a date and time picker defaulting to the current date and time
9. THE Track_Visceral_Fat_Screen SHALL include an optional notes text field with a maximum length of 500 characters
10. THE Track_Visceral_Fat_Screen SHALL disable the save button until the waist circumference field contains a valid value

### Requirement 7: Visceral Fat Chart Screen

**User Story:** As a user, I want to visualise my waist measurements and waist-to-height ratio over time, so that I can track directional progress.

#### Acceptance Criteria

1. THE Waist_Chart_Screen SHALL display waist circumference measurements as a line chart over the selected time period, with the vertical axis labelled in the user's preferred unit (cm, mm, or inches)
2. IF height is available in the User_Profile, THEN THE Waist_Chart_Screen SHALL display waist-to-height ratio as a second axis on the chart
3. THE Waist_Chart_Screen SHALL use the ChartDateSelector widget for period selection (one month, three months, all time, and custom range)
4. THE Waist_Chart_Screen SHALL display statistics: average waist measurement, total entry count, change from first to last entry, daily trend, minimum, maximum, and range, all shown in the user's preferred unit
5. WHEN the user taps the visceral fat tips button, THE Waist_Chart_Screen SHALL display the visceral fat tips content in a popup dialog
6. IF no waist entries exist for the selected period, THEN THE Waist_Chart_Screen SHALL display an empty state indicating no data is available and prompting the user to add waist measurements
7. IF height is not available in the User_Profile, THEN THE Waist_Chart_Screen SHALL hide the waist-to-height ratio axis and display only the waist circumference line
8. IF chart data fails to load, THEN THE Waist_Chart_Screen SHALL display an error state with a retry option

### Requirement 8: Navigation Integration

**User Story:** As a user, I want quick access to visceral fat tracking from the home screen and charts from the charts navigation screen, so that the feature is easy to discover and use.

#### Acceptance Criteria

1. THE App SHALL display a "Track Visceral Fat" quick action button in the 4th position of the home screen quick actions grid, replacing the previous "View Charts" button
2. WHEN the user taps the "Track Visceral Fat" quick action button, THE App SHALL navigate to the Track_Visceral_Fat_Screen
3. THE App SHALL display a navigation card titled "Waist Circumference" on the charts screen, positioned between the "Mood Patterns" card and the Quick Stats card, linking to the Waist_Chart_Screen
4. WHEN the user taps the "Waist Circumference" navigation card on the charts screen, THE App SHALL navigate to the Waist_Chart_Screen

### Requirement 9: Database Migration

**User Story:** As a user, I want the app to upgrade my database seamlessly, so that I retain all existing data when the visceral fat feature is added.

#### Acceptance Criteria

1. THE DatabaseService SHALL migrate from version 1 to version 2 by executing CREATE TABLE statements for the User_Profile table and the waist_entries table without modifying or deleting existing tables (weight_entries, blood_pressure_entries, mood_entries)
2. WHEN the migration runs, THE DatabaseService SHALL preserve all existing weight, blood pressure, and mood entries such that row counts and column values in each existing table remain identical before and after the migration
3. IF the migration fails, THEN THE DatabaseService SHALL roll back the transaction so the database remains at version 1 with all existing data intact, and throw an exception to the caller
4. WHEN a fresh install occurs at database version 2, THE DatabaseService SHALL create all tables (weight_entries, blood_pressure_entries, mood_entries, User_Profile, and waist_entries) via the onCreate callback

### Requirement 10: Visceral Fat Tips Content

**User Story:** As a user, I want evidence-based tips on reducing visceral fat, so that I can take actionable steps to improve my health.

#### Acceptance Criteria

1. THE App SHALL display a tip that visceral fat responds well to exercise and is lost preferentially during weight loss
2. THE App SHALL display a tip recommending three sessions of moderate-to-vigorous exercise per week for 12 to 16 weeks for measurable changes
3. THE App SHALL display a tip that cardio should be moderate-to-vigorous intensity, harder than an easy walk
4. THE App SHALL display a tip to include resistance training to maintain muscle mass
5. THE App SHALL display a tip that poor sleep raises cortisol, triggers hunger hormones, and decreases insulin sensitivity
6. THE App SHALL display a tip that subcutaneous fat is more stubborn and typically requires a sustained caloric deficit
7. THE App SHALL display a disclaimer note, visually distinct from the tips in criteria 1 through 6, stating that waist measurement is a guide and cannot distinguish between subcutaneous fat, muscle, and visceral fat
8. THE App SHALL display all seven tips and the disclaimer note in both the tips section on the Track_Visceral_Fat_Screen and the popup dialog accessible from the Waist_Chart_Screen
9. THE App SHALL display tips in a fixed order matching the sequence defined in criteria 1 through 7

### Requirement 11: Input Validation

**User Story:** As a user, I want the app to prevent me from saving invalid measurements, so that my data remains reliable.

#### Acceptance Criteria

1. WHEN the user enters a waist circumference less than 30 cm (or equivalent in mm/inches), THE Track_Visceral_Fat_Screen SHALL display a validation error indicating the acceptable range and prevent saving
2. WHEN the user enters a waist circumference greater than 300 cm (or equivalent in mm/inches), THE Track_Visceral_Fat_Screen SHALL display a validation error indicating the acceptable range and prevent saving
3. WHEN the user enters a height less than 50 cm (or equivalent in inches), THE Track_Visceral_Fat_Screen SHALL display a validation error indicating the acceptable range and prevent saving
4. WHEN the user enters a height greater than 275 cm (or equivalent in inches), THE Track_Visceral_Fat_Screen SHALL display a validation error indicating the acceptable range and prevent saving
5. WHEN the user selects a timestamp in the future, THE Track_Visceral_Fat_Screen SHALL display a validation error and prevent saving
6. WHEN the user leaves the waist circumference field empty or enters non-numeric input, THE Track_Visceral_Fat_Screen SHALL display a validation error and prevent saving
7. WHEN a validation error occurs, THE Track_Visceral_Fat_Screen SHALL preserve the entered form data so the user can correct the specific invalid field without re-entering other data
