Copec Personas — Flux Module
Projects | | Links:

Tech lead on Flux (copec_modulo_flux), a standalone Flutter module consumed by App Copec Personas — onboarding, device pairing, real-time energy state, daily accumulated energy and historical charts across day, week, month and year views.
Flux is a Flutter module that lives inside App Copec Personas — the host consumer app — for customers of Copec’s home-energy product. From inside the main app, users enter Flux to onboard a location, pair devices by scanning a barcode, see real-time and daily energy, browse historical charts, and respond to device alerts. I worked as tech lead on the module, which ships as a versioned Flutter package, copec_modulo_flux.
Context and problem
Copec is a fuel and convenience-store brand expanding into home energy, and Flux is the in-app experience for that product. Building it as a separate Flutter module — with its own changelog, version and release rhythm — kept the energy product moving at its own pace, independent of everything else happening in the base app.
How it works
App Copec Personas is the host; Flux is one of the Flutter modules it depends on. The two pieces communicate over a small, intentional surface: the host hands the user (and a barcode, if one was scanned) into Flux, and from there Flux talks to Copec’s backend on its own.
%%{init: {'theme': 'base'}}%%
flowchart LR
user((User))
host["App Copec Personas host app"]
flux["copec_modulo_flux module"]
backend[("Copec backend")]
user -->|enters Flux section| host
host -->|hands off routing context and barcode| flux
host -->|account and session API| backend
flux -->|locations, devices and energy API| backend
Inside Flux, the user comes in through a single entry point that branches by location state:
%%{init: {'theme': 'base'}}%%
flowchart LR
entry((Enter Flux))
strategy{Has locations?}
onboarding["Onboarding and device pairing"]
subhome["Subhome: real-time and daily totals"]
history["Historical charts"]
alerts["Device alerts"]
entry --> strategy
strategy -->|no| onboarding
strategy -->|yes| subhome
subhome --> history
subhome --> alerts
Flux owns its onboarding, the real-time and daily-totals subhome, energy-flow animations, device alerts and the historical analytics. The barcode handoff from the host resolves through a single decision point — onboarding for new users, alias-change for users with an existing location — so the two paths stay clear as more entry sources appear.
The historical charts are the heaviest surface: day as a continuous line, week, month and year as grouped bars, all with tooltips, date selectors and an expanded view. Day views are windowed to the active production hours, since most of the data is concentrated there. The expanded view keeps tooltips inside the visible area so the user doesn’t lose information when they zoom in.

Challenges
Being a guest in someone else’s app. Flux had to feel native to App Copec Personas while staying genuinely independent at the code level — sharing through the Copec mobile family’s design and utility libraries, and keeping the host/module surface as narrow as possible.
Charts that have to behave. Tooltip selection and locking, distinguishing tap from drag, centring tooltips on a group of bars rather than wherever the tap landed, and keeping tooltips inside the visible area in the expanded view — each is small on its own, together they’re the difference between a chart that feels considered and one that feels rough.
Routing through a barcode entry point. New users had to land at the start of onboarding with the code held; returning users with locations had to land in alias-change. Treating that as a single decision point made the entry logic extensible instead of patched every time a new source appeared.
Keeping quality measurable. As the surface grew, we layered in stricter linter and code-metrics rules — for unsafe dynamic calls, leaked subscriptions, missing return types, deep widget nesting. The goal was consistent signal on what was getting tangled, not a score.
Key decisions and trade-offs
| Decision | Trade-off |
|---|---|
| Ship Flux as a standalone Flutter module consumed by the host app | Independent release cadence and a clean ownership boundary, at the cost of a versioned dependency to manage |
| Use shared design and utility libraries instead of local equivalents | Visual and behavioural consistency across the Copec apps, at the cost of some flexibility inside the module |
| A single decision point for barcode entry from the host | Clear, testable entry-point logic that scales as more sources appear, at the cost of a small upfront indirection |
| Tighten linter and code-metrics rules incrementally | Consistent signals on complexity as the module grew, at the cost of occasional rewrites to clear new rules |
What I learned
Owning a Flutter module inside another team’s host app is its own discipline. The technical challenges are familiar; the integration story is where the module either succeeds or fails. Versioning the module like a library, with a real changelog tied back to the tickets that produced each entry, turned out to be the simplest way to keep a fast-moving module legible to everyone else — including future me.
Tech stack
- Flutter module (
copec_modulo_flux), versioned independently of App Copec Personas. fl_chart(viamuevo_utils_library) for the historical charts.muevo_modulo_design_kitfor shared design primitives.- Amplitude for product analytics.
dart_code_metricspresets and stricter lints for code-health enforcement.- Independent
CHANGELOG.mdtied to Jira tickets and Semantic Versioning.
Closing reflection
Flux is a project about restraint: small enough to live inside someone else’s app, focused enough to evolve quickly, consistent enough that users never feel they’ve left App Copec Personas. The technology is mainstream; the craft is in the boundaries.