docs user business logic - AlexandreZanata/Abastevo GitHub Wiki

User Business Logic

Contract document. Defines how the ANP Fuel Prices app behaves from the user's perspective. All implementation must follow this document and .cursor/rules/. In case of conflict, this document and agent core principles prevail.

Product vision

The user opens the app to discover official ANP fuel prices for their city (or any Brazilian municipality), compare products, and optionally see per-station prices β€” without an account, without a backend, and without real-time data (ANP publishes weekly surveys).

All processing happens on the device. The app is a reader and local index of public ANP spreadsheets.


Actors

Actor Description
End User Brazilian consumer or driver looking up fuel prices
System Background sync (WorkManager), local database, parsers
ANP (external) Publishes weekly XLSX files on gov.br β€” not controlled by the app

There is no authentication in v1. The End User is anonymous; preferences are stored locally only.


User goals

  1. See current-week average prices for fuels in my city.
  2. Search any municipality by name or browse by state.
  3. Know when data was last updated and whether I am offline.
  4. Optionally see cheapest stations near my selected city.
  5. Optionally see price history for my city over past weeks.
  6. Trust that data comes from official ANP sources.
  7. Track estimated tank fill cost per registered vehicle on home (UC-011).
  8. Get local alerts when fuel price drops vs the previous survey week (UC-014).
  9. Skip manual city selection on first launch by optionally sharing device location (UC-012).
  10. Navigate to a gas station in Maps or Waze from the station list (UC-013).
  11. Reach the cheapest station near me with one tap instead of comparing every row (UC-015).

Core user journey

flowchart LR
    A[Launch app] --> B{Active week set?}
    B -->|No| C[Onboarding + week picker]
    B -->|Yes| D{Data synced?}
    C --> W[Select survey week]
    W --> S[Sync selected week]
    S --> D
    D -->|No| C
    D -->|Yes| E[Home]
    E --> F[Select location]
    F --> G[View fuel prices]
    G -->|Tap fuel card| I[Station list for that fuel]
    G -->|View full price details| P[Fuel averages detail]
    P -->|Tap fuel row| I
    I --> J[Done / history / settings]
    P --> J

Journey steps (business language)

  1. Launch β€” App checks activeSurveyWeek preference and local database for imported SurveyWeek records (BR-018, BR-019).
  2. Onboarding (first run) β€” Explain data source (ANP), offline model, weekly cadence. User selects survey week (UC-009) before first sync.
  3. Week selection β€” User picks latest week or a historical week from the gov.br catalog; optional operational notes shown per week block.
  4. Sync β€” Targeted download/import for the selected week only (UC-001 scoped); progress visible.
  5. Home β€” Show selected city (or prompt to select), active week chip (tap to change week), prices per FuelProduct with vector icons, and tank fill cost cards (UC-011).
  6. Location selection β€” User picks state + municipality, searches nationally by name (IBGE catalog + FTS, UC-004), or uses device location once after onboarding (UC-012).
  7. Fuel detail β€” Tapping a fuel card on Home opens the station list for that fuel directly (UC-007) β€” one tap, no intermediate fuel selection. The min/avg/max averages view remains one tap away via View full price details (UC-005); from there, tapping a fuel row also opens its station list. On the station list, Cheapest near me (UC-015) recommends the cheapest station close to the user β€” within a configurable search radius (Settings) β€” and opens Maps on it.
  8. Vehicles β€” Register cars with tank size and fuel type; choose cheapest or specific station for cost estimates (UC-010).
  9. Settings β€” Language, sync preferences, storage management, data attribution, week picker shortcut, geocoding attribution.

Week picker journey (v2 β€” UC-009)

Step User action System response
1 Completes onboarding intro or taps Survey week chip / settings Opens week picker (full screen or bottom sheet)
2 Taps Use latest week Sets activeSurveyWeek to catalog newest; triggers sync (UC-001)
3 Selects historical week (e.g. 31/05–06/06/2026) Confirmation for download; sync scoped to that week
4 Sync completes Home/prices reflect selected week; chip shows range + β€œLatest” badge when applicable
5 Returns later with cached week Skips picker; chip allows one-tap week change globally

Rules: BR-006, BR-018, BR-019 β€” default display follows activeSurveyWeek, not implicit β€œnewest in DB” when preference is set.

National search journey (v2 β€” UC-004)

Step User action System response
1 Types β‰₯ 2 characters in search (BR-007) FTS queries municipality_catalog (~5β€―570 IBGE municipalities)
2 Sees ranked results with state abbreviation BR-017 tiers: exact match β†’ prefix β†’ fuzzy; duplicate names disambiguated
3 Selects city with no ANP data this week UC-005 empty state (BR-010), not an error
4 Works offline Local FTS only (BR-004); no network required after catalog seed

Examples (Appendix A2): "san paolo" β†’ SΓ£o Paulo (SP); "Bom Jesus" β†’ multiple states listed.


Application states (user-visible)

The app exposes a single DataReadiness state derived from local storage:

State User sees Transitions to
EMPTY Onboarding: "No data yet. Connect to download ANP tables." SYNCING (first sync started)
SYNCING Progress indicator with stage (discover / download / import) READY, PARTIAL, or ERROR
PARTIAL Prices available but station detail missing or sync incomplete READY or SYNCING
READY Full home experience for latest SurveyWeek SYNCING (refresh), STALE (time-based)
STALE Cached data shown + banner "Data may be outdated" SYNCING, READY
ERROR Error screen with retry; cached data still shown if any (BR-004) SYNCING

Rule: The UI never blocks reading cached data when sync fails (BR-004, BR-011).


SyncJob state machine

Owned by the Domain Layer. UI only observes and displays.

stateDiagram-v2
    [*] --> IDLE
    IDLE --> DISCOVERING: trigger sync
    DISCOVERING --> DOWNLOADING: new files found
    DISCOVERING --> COMPLETED: nothing new
    DOWNLOADING --> PARSING: file saved
    PARSING --> IMPORTING: rows validated
    IMPORTING --> COMPLETED: success
    DISCOVERING --> FAILED: network/scrape error
    DOWNLOADING --> FAILED: download error
    PARSING --> FAILED: parse error
    IMPORTING --> FAILED: db error
    FAILED --> IDLE: acknowledged / retry
    COMPLETED --> IDLE: idle
Transition Trigger Allowed actor
IDLE β†’ DISCOVERING Manual refresh, periodic WorkManager, first launch User, System
DISCOVERING β†’ DOWNLOADING New PriceTable URL not in local catalog System
DOWNLOADING β†’ PARSING File checksum/size validated System
PARSING β†’ IMPORTING BR-001, BR-002 pass System
* β†’ FAILED Unrecoverable error after retries System
FAILED β†’ IDLE User taps Retry or auto-backoff elapsed User, System

Terminal states per run: COMPLETED, FAILED. A new sync starts a new run from IDLE.


User preferences (local)

Stored on device only. No cloud sync in v1.

Preference Type Default Business rule
preferredState BrazilianState? null BR-012
preferredMunicipality string? null BR-012
preferredFuelProduct FuelProduct? null Highlights on home
locale BCP 47 (en, pt-BR) system default i18n rule
syncStationDetail boolean true BR-008
autoDownloadLatestWeek boolean true BR-020
stationDetailRetentionWeeks int 12 BR-013
autoSyncOnWifi boolean true BR-014
showPriceHistory boolean true UC-006
activeSurveyWeek SurveyWeek? null BR-018, BR-019, UC-009
locationPromptCompleted boolean false UC-012 β€” show GPS prompt only once
vehicles list of Vehicle empty UC-010, stored in Room (not cloud)

Feature scope by version

v1 β€” MVP (must implement)

  • First sync + manual refresh
  • Home with municipality averages (latest week)
  • Search city (FTS) + filter by state
  • Fuel product list with avg/min/max
  • Offline read + sync status banner
  • Settings: language, data attribution, clear cache
  • i18n: en + pt-BR

v1.1 β€” Enhanced

  • Station-level prices (included in sync by default; optional opt-out in Settings)
  • Price history chart per fuel (last N weeks)
  • Compare two SurveyWeeks side by side

v2 β€” Week picker, national search, polish (shipped v2.0.0)

  • Survey week selection before sync (UC-009) β€” gov.br catalog parity, historical weeks on demand
  • National municipality search β€” IBGE baseline catalog + FTS ranking (BR-016, BR-017)
  • Edge-to-edge safe areas β€” AnpScaffold on all screens (Phase 13)
  • Fuel product vector icons β€” per-fuel MDI icons with accessible labels (Phase 14)
  • Active week chip on app bars; week picker bottom sheet for returning users

v3 β€” Vehicles, geolocation, navigation, alerts (shipped v3.0.0)

  • Tank fill cost on home (UC-011) β€” per-vehicle estimate below survey week label
  • Vehicle profiles (UC-010) β€” up to 3 vehicles, one FuelProduct each
  • Optional device location (UC-012) β€” Nominatim reverse geocode after first sync
  • Station navigation (UC-013) β€” open Maps/Waze from station list
  • Local price drop notifications (UC-014) β€” after weekly sync, no backend

v3.2 β€” Nearest best-price station (unreleased)

  • Find nearest best-price station (UC-015) β€” one-tap recommendation from the station list using device location plus Nominatim forward geocoding of the cheapest candidates, inside a user-configured search radius (3/5/10/15 km, BR-028)

Out of scope (v1)

  • User accounts / login
  • Real-time prices
  • Backend API
  • Server-side push notifications

Use case index

Detailed specs live in docs/use-cases/. Do not implement undocumented use cases.

ID Name Actor Doc
UC-001 Sync price tables User, System uc-001-sync-price-tables.md
UC-002 Onboarding and first launch User uc-002-onboarding.md
UC-003 Select location (state + city) User uc-003-select-location.md
UC-004 Search municipality User uc-004-search-municipality.md
UC-005 View municipality fuel prices User uc-005-view-municipality-prices.md
UC-006 View price history User uc-006-view-price-history.md
UC-007 View station prices User uc-007-view-station-prices.md
UC-008 Manage settings and storage User uc-008-manage-settings.md
UC-009 Select survey week User uc-009-select-survey-week.md
UC-010 Manage vehicles User uc-010-manage-vehicles.md
UC-011 Estimate tank fill cost User uc-011-estimate-tank-fill-cost.md
UC-012 Resolve location from device User uc-012-resolve-location-from-device.md
UC-013 Navigate to station User uc-013-navigate-to-station.md
UC-014 Fuel price drop alerts User, System uc-014-fuel-price-drop-alerts.md
UC-015 Find nearest best-price station User uc-015-find-nearest-best-price-station.md

Business rules catalog (user-facing)

Rules referenced by use cases. Full list maintained in glossary.md.

ID Summary
BR-001 Valid SurveyWeek date range (≀ 7 days)
BR-002 Normalize ANP product labels to FuelProduct
BR-003 Price history records are immutable
BR-004 Offline read always serves cache + status indicator
BR-005 Search requires β‰₯ 1 imported SurveyWeek
BR-006 Default displayed week = most recent successfully imported
BR-007 City search requires β‰₯ 2 characters
BR-008 Station detail syncs by default; opt-out or on-demand when disabled
BR-009 ANP data attribution visible on every price screen
BR-010 Empty municipality yields empty state, not an error
BR-011 Sync failure must not delete existing local data
BR-012 Preferred location persists across sessions
BR-013 Station detail retention follows rolling window preference
BR-014 Background sync respects Wi‑Fi-only preference
BR-015 Only one active SyncJob at a time
BR-016 Municipality catalog completeness (IBGE baseline)
BR-017 Intelligent search ranking tiers
BR-018 Week selection required before sync when auto-download latest is disabled
BR-019 Active survey week overrides default-latest display
BR-020 Latest survey week auto-selected and synced unless user opts out
BR-021 Nominatim reverse geocode compliance (rate limit, cache, attribution)
BR-022 One FuelProduct per Vehicle
BR-023 Tank fill cost and alert price resolution (station β†’ average fallback)
BR-024 Multiple vehicle tank cost cards on home with stable layout
BR-025 Price drop alerts only when price decreases vs previous week
BR-026 Normalized station address for external map navigation
BR-027 Maximum three registered vehicles
BR-028 Nearest best-price station (price band + device distance)

Domain events (user-triggered)

Event Triggered by Payload
CitySelected UC-003, UC-004 municipality, state, surveyWeekId
FuelProductSelected UC-005, UC-007 fuelProduct, municipality, state
SyncRequested UC-001 source: MANUAL | SCHEDULED | FIRST_LAUNCH
StationDetailRequested UC-007 surveyWeekId, municipality, state
PreferencesUpdated UC-008 changed keys
CacheCleared UC-008 scope: ALL | STATION_DETAIL_ONLY
SurveyWeekSelected UC-009 surveyWeek, selectionMode: LATEST | SPECIFIC
VehicleRegistered UC-010 vehicleId, displayName, fuelProduct
VehicleUpdated UC-010 vehicleId, changed fields
VehicleRemoved UC-010 vehicleId
PriceDropAlertConfigured UC-014 vehicleId, enabled, alertPriceSource
DeviceLocationResolved UC-012 state, municipality
StationNavigationRequested UC-013, UC-015 cnpj, stationNavigationQuery

Error handling (user experience)

All errors use a structured error model in Application layer; UI maps to i18n strings.

Code User message (i18n key) Recovery
SYNC_NETWORK_ERROR error_sync_network Retry button
SYNC_PARSE_ERROR error_sync_parse Retry; log for support
SYNC_NO_NEW_DATA info_sync_up_to_date Informational, not failure
SEARCH_NO_RESULTS error_search_no_results Widen search / pick state
STATION_DETAIL_NOT_SYNCED error_station_detail_missing Offer download (UC-007)
STORAGE_FULL error_storage_full Link to settings (UC-008)

Data freshness rules

Condition UI behavior
Latest week imported < 8 days ago Show week range only (normal)
Latest week imported β‰₯ 8 days ago Show STALE banner + refresh CTA
No network + cache exists Show offline banner (BR-004)
No network + no cache Show onboarding/sync required

ANP typically publishes weekly; the 8-day threshold allows for publication delay.


Privacy and compliance

  • No account or cloud sync β€” preferences and vehicles stored on device only.
  • Optional device location (UC-012) β€” one-shot GPS for municipality resolution; coordinates not persisted.
  • Nominatim β€” reverse (UC-012) and forward (UC-015) geocode calls subject to OSM usage policy; results cached locally (BR-021). UC-015 sends candidate station addresses (public ANP data) and uses device coordinates only to pick the nearest station β€” coordinates are not stored.
  • Local notifications (UC-014) β€” generated on device after sync; no push backend.
  • CNPJ and station addresses are public ANP data β€” display as-is, no masking required.
  • No analytics SDK without explicit future ADR.
  • LGPD: location and notifications require transparent disclosure in privacy policy and runtime permission prompts.

Implementation checklist

Before coding a feature:

  • Use case document exists and is approved
  • Business rules referenced are listed in glossary
  • Domain events identified
  • State machine transitions validated (if applicable)
  • i18n keys listed for all user-visible strings
  • Unit tests written (GIVEN/WHEN/THEN) for domain rules
  • Empty, loading, error UI states defined