Inspiration
In the Houston area, a home standby generator is essential equipment, not a luxury. The Gulf Coast lives with hurricanes, tropical storms, derechos, flash floods, brutal summer heat and the occasional deep freeze, and every one of them can take the grid down. When Hurricane Beryl hit in July 2024, more than 2 million customers lost power, many of them for over a week, in the middle of a heat wave. Only weeks earlier, a derecho had torn through the city and left neighborhoods dark for days. In February 2021, Winter Storm Uri left millions of Texans without heat at freezing temperatures. For a family with an elderly parent, a newborn, a medical device, a refrigerator full of medication or a house that floods once the sump pump stops, the generator is the only thing between an inconvenience and a real emergency. That's why thousands of Houston homeowners have installed standby generators. The problem we kept seeing is what happens next: people install the generator and forget about it. A standby unit can sit silent for months, while oil breaks down, batteries lose their charge, filters clog, fuel goes stale and the weekly exercise cycle quietly stops running. Nobody notices until the storm arrives, the lights go out and the generator doesn't start. Homeowners don't know the model, the service interval or the last time anyone touched it. The manual is lost, and the nameplate is a sun-faded sticker behind the unit. The service side can't keep up either. Every hurricane season, demand for generator maintenance spikes, and the few qualified service companies in the area are booked for weeks right when people need them most. Technicians spend their time chasing paperwork and identifying unknown units instead of fixing them, and many homeowners can't even find someone willing to come out. Demand for reliable maintenance in the area far outstrips the coverage the industry can provide. And this isn't only a Houston problem. Generac, which holds more than 70% of the U.S. home standby market, reports that about 6.75% of the addressable U.S. homes (owner-occupied, single-family detached) already have a standby generator. Based on U.S. Census housing counts, we estimate that works out to roughly 4 million home standby generators installed across the country, and every one of them needs regular oil changes, battery checks and exercise cycles to be ready when it's needed. The market is still growing fast: the U.S. home standby genset market is projected to grow from about $3.3 billion in 2025 to $7.2 billion by 2035 (≈7.9% CAGR), driven by more frequent extreme weather and an aging grid. Every new unit installed adds to an installed base that already needs more maintenance than today's paper logs, forgotten reminders and overbooked technicians can handle. We built GentrackAI to close that gap. We wanted any homeowner to be able to point a phone at their generator and instantly know what it is, what it needs and when it needs it, with reminders before storm season instead of after the outage. We also wanted to give local technicians a direct channel to the households that need them. Our goal is simple: when the next storm makes landfall, every generator should start on the first try.
What it does
GentrackAI turns a single photo of a generator's nameplate into a fully managed maintenance program. Standby generators sit idle for months and then have to work perfectly during an outage, at the moment you need them most. Most of them fail because someone missed an oil change, a battery went flat or nobody tracked the run hours. GentrackAI is built to prevent that.
Point, scan, done. Snap the nameplate and our vision pipeline (Gemini multimodal + JSON-schema structured output) extracts manufacturer, model, serial number, rated power, fuel type, transfer-switch rating and service interval, with a confidence score. It's tuned to read angled, glare-heavy, dimly lit and partially legible labels, and it never invents values: anything it can't read comes back as null.
Usage-aware maintenance, no sensors required. Our projection engine estimates run hours and fuel burn in real time from a single anchor point. When a technician logs a real reading, it corrects the estimate and re-anchors, so schedules follow how the unit is actually used instead of a generic calendar reminder.
A fleet-aware AI assistant. "GenTrack AI" chat answers questions about your generators using tool calling, not RAG: the model queries scoped, read-only tools (list_generators, get_generator, list_maintenance, list_open_tasks, fleet_analytics) and grounds every answer in live data. You can also send it a photo of a fault code or a nameplate.
Predictive fleet insights. A deterministic health score, 4-week run-hour trends and 30-day forecasts, plus up to three prioritized AI recommendations (info / warning / critical) that also take seasonality into account.
Teams and fleets. Multi-organization membership with roles, invitations, task assignment and automatic daily reminders (in-app + email) to whoever is responsible for each service. A built-in maintenance marketplace. Owners post a service request. Local technicians whose service area covers that U.S. state get notified, bid on the job and get scheduled, and they're rated once the work is done. Technicians run their whole business from a dedicated Technician Panel. Audit-ready reports. PDF maintenance reports covering 3 months up to 5 years, with cost paid and estimated savings from preventive care, ready for insurance, warranty or a property sale.
It works for homeowners protecting a single backup unit, facility managers responsible for dozens of units and service companies running their entire operation.
How we built it
GentrackAI is a React Native app (Expo) live on iOS, backed by a production-grade Laravel 12 API (PHP 8.2+). The API keeps all business logic and every AI call on the server: the app never talks to Gemini directly, so API keys, prompts and usage limits stay out of the client.
Mobile app — React Native + Expo
Expo SDK 56, React Native 0.85, React 19 and TypeScript, with roughly 280 typed source files (~17k lines) organized by feature (generators, maintenance, chat, insights, tasks, team, billing, technician, maintenance-requests…). Each feature has its own screens, hooks, components and types.
Expo Router file-based navigation drives 35+ screens across two separate experiences: the owner app (Home, Fleet, Tasks, Insights) and a dedicated Technician Panel with its own tab bar for requests, jobs and its profile. State and data: Redux Toolkit holds the auth session, SWR handles server state with focus-aware revalidation, and a single Axios client attaches the bearer token and turns Laravel validation errors into readable messages. Forms use Formik + Yup.
Camera-first scanning: a live expo-camera viewfinder with flash control and a gallery fallback. Before upload, an on-device image pipeline (expo-image-manipulator) downscales captures to a 1600px long edge, applies the EXIF orientation and re-encodes them as JPEG. That avoids HEIC, cuts 12–48 MP photos down to roughly 200–400 KB for fast uploads over cellular, and keeps the label sharp enough for OCR.
Security: the auth token is stored in the iOS Keychain through expo-secure-store. Platform-specific .web.ts implementations of auth, storage and billing let the same codebase also run on the web.
Polished native UX: React Native Paper theming with light and dark mode, Reanimated 4, custom SVG icons and gauges, a health-ring visualization, markdown rendering for AI replies (react-native-marked), and PDF report sharing through the native share sheet.
Ships with EAS Build in development, preview and production profiles with automatic build-number increments, plus universal and app links (applinks:api.gentrackai.com) for flows such as password reset.
Backend architecture
Laravel 12 with the streamlined application structure, Sanctum bearer-token auth, Eloquent API Resources, Form Request validation and single-action invokable controllers for every non-CRUD operation (ScanGeneratorController, AcceptOfferController, CompleteJobController…). Domain logic lives in focused services: GeneratorLabelExtractor, GeneratorUsage, FleetAnalytics, InsightGenerator, ChatAssistant, PlanGate, TechnicianGate, StoreEntitlements, MaintenanceReport.
~50 versioned migrations model a multi-tenant domain: organizations with many-to-many memberships and roles, generators (soft-deleted), readings, maintenance items, tasks, insights, chat history, notifications, provider profiles, service areas, marketplace requests, offers, reviews and subscriptions.
AI layer — Google Gemini via Prism PHP
Vision OCR with structured output: nameplate photos go to Gemini through a typed ObjectSchema, which guarantees a machine-parseable response. We run Gemini 3 with thinkingLevel: low because nameplate reading is an extraction task, not a reasoning task. That keeps vision calls well inside request timeouts.
Layered resilience: a custom GeminiRetry policy applies exponential backoff with jitter (≈0.5s → 1s, capped at 2s) only to fast transient failures (429/500/502/503). It deliberately does not retry timeouts, since retrying those would multiply wall-clock latency on a synchronous request. On top of that, if the vision model fails we fall back to a different model, and if the provider rejects the thinking hint we retry once with the provider defaults. Each layer maps to a clean HTTP status code (429 / 503 / 504 / 422) that the app can act on.
Agentic chat: Prism tool calling with up to 6 reasoning steps and a bounded 20-turn history replay. Every tool is scoped to the user's organization and role, so a technician only ever sees their own assignments.
Token-efficient insights: a SHA-1 digest of the fleet state decides whether recommendations need to be regenerated. Generation runs in a queued job guarded by WithoutOverlapping per organization. It's throttled by a configurable minimum interval and TTL, and we log prompt and completion tokens on every run. Reads never spend tokens.
Usage projection engine
Generators store committed values (run_hours, fuel_level) anchored at running_since. On each read we project the single open interval, and we commit it on stop or when a new reading arrives. History therefore never depends on more than one open interval, and the analytics digest stays stable while a unit is running.
Monetization — RevenueCat + Stripe, unified
RevenueCat (react-native-purchases) handles in-app subscriptions on iOS through StoreKit. Pro and the technician plan are sold as two separate RevenueCat offerings, both served by one shared purchase hook. The paywall shows the store's own localized price from getOfferings(), never a hard-coded label, and includes Restore purchases and the native subscription-management screen. Selling digital subscriptions through the stores keeps us compliant with App Store guideline 3.1.1. Laravel Cashier (Stripe) handles web checkout and the billing portal only.
Identity-safe purchasing: the RevenueCat identity follows the user's active organization for the whole session (sign-in, sign-out and organization switching). The app refuses to start a purchase until that identity is active, so no purchase can attach to an anonymous device ID that the webhook couldn't map back to a team. A missing SDK key fails loudly instead of silently falling back to Stripe.
Two paths keep entitlements correct: a post-purchase sync endpoint (/billing/iap/sync) that calls RevenueCat's REST API right away, so users are unlocked even before the webhook arrives, and an authenticated RevenueCat webhook for renewals, cancellations, billing issues and expirations.
Both paths go through one idempotent writer (StoreEntitlements): an updateOrCreate keyed by subscription type, with deduplication on last_event_id. Replayed events and repeated syncs always converge on the same state. The RevenueCat app-user ID is the organization (org_{id}), so a whole team's entitlement comes from one purchase regardless of channel.
PlanGate and TechnicianGate turn plan limits (generators, members, AI insights, daily chat quota) into a single decision point. A PLAN_ENFORCE master switch let us ship the billing plumbing to production before turning gating on.
Identity & compliance
Email/password, Google Sign-In (@react-native-google-signin, verified against both the web and iOS client IDs) and native Sign in with Apple, both with server-side identity-token verification. For Apple, we exchange the authorization code for a refresh token using an ES256-signed client-secret JWT generated from the .p8 key, and revoke it on account deletion as App Store guideline 5.1.1(v) requires.
Platform
Scheduled jobs (daily stale-insight backstop, 08:00 maintenance reminders), DomPDF reports, deep-link return flows from Stripe Checkout back into the app, and a GitHub Actions pipeline that ships atomic, symlinked releases to a VPS with migrations, cache optimization, a zero-downtime PHP-FPM reload and automatic release pruning. ~200 PHPUnit feature and unit tests cover auth, scanning, readings, insights, chat, organizations, the marketplace, the technician panel, billing and RevenueCat store subscriptions. Pint enforces code style.
Challenges we ran into
We faced several rejections from Apple Store reviewers who asked us to change certain things. The problem was that we would make the changes requested by one reviewer, only for the next reviewer to ask for something completely different to be changed.
Reading real-world nameplates. Generator labels are weathered, reflective, photographed at odd angles and often only half legible. Getting reliable fields required careful system prompting, a strict schema that allows null but never a fabricated value, and an acceptance rule that rescues clear labels the model was unsure how to classify.
LLM provider volatility. Gemini's flash tier often returns transient 503 "model overloaded" errors, and floating -latest aliases can move to a model generation that rejects parameters we already send (Gemini 3 rejects the older thinkingBudget: 0). We built the retry policy, the model fallback and the defaults retry so that a configuration value or a bad day on Google's side can't break scanning.
Latency vs. retries. Naive retries on timeouts would have stacked 30-second waits on a synchronous mobile request. We had to decide exactly which failures are worth retrying (fast 5xx) and which should fail immediately (cURL 28, 504/408).
Two billing worlds, one source of truth. Apple requires in-app purchase for digital subscriptions, while web users pay through Stripe. Reconciling RevenueCat entitlements and Cashier subscriptions at the organization level was hard: webhooks arrive out of order or after the app returns, events get redelivered, RevenueCat's REST API sends ISO-8601 dates while its webhooks send epoch milliseconds, and UTC values have to be converted so an expired subscription never reads as active. Estimating usage without IoT. Most generators have no telemetry. Designing a projection model that feels live, stays accurate once real readings arrive and doesn't make the AI digest churn every second took several iterations.
Marketplace race conditions. Two customers or technicians acting at the same moment, such as accepting an offer twice, required guarded state transitions inside database transactions that re-read the record before writing.
Getting through App Review. Apple rejected our first submission because the native app opened Stripe Checkout for the Pro subscription. We rebuilt the whole purchase flow around StoreKit through RevenueCat, kept Stripe only for the web, and turned off up-front Stripe card capture for technicians because that capture would violate guideline 3.1.1. A second round of review (guideline 2.1) asked for a full demo account, a screen recording on a physical device and a description of every external service. On top of that, we had to ship account deletion with Apple token revocation, Sign in with Apple alongside Google, and the 3.1.2 subscription disclosures on the paywall.
Tying a purchase to the right team. Subscriptions belong to an organization, not to the person paying, and a user can switch between organizations. Keeping the RevenueCat identity, the webhook mapping and the backend entitlements in sync across sign-out and organization switching, without ever creating an orphaned anonymous purchase, was one of the hardest parts of the project.
Uploading big photos over weak connections. Modern phone cameras produce photos of several megabytes, often in HEIC, that are rotated through EXIF metadata. Normalizing them on the device into small, upright JPEGs made uploads fast and gave Gemini consistent input.
Accomplishments that we're proud of
Having our application ready in time to participate in the competition gives us a great sense of satisfaction and pride.
Photo to maintenance plan in seconds, with structured, schema-validated output and an AI that says "I don't know" instead of hallucinating specs.
A self-healing AI pipeline: jittered backoff, model fallback and graceful degradation. Every failure mode maps to a clear, actionable response in the app.
Grounded agentic chat. The assistant answers from the user's real fleet through scoped tool calls, not from guesswork or a stale vector index.
Near-zero idle AI cost. Digest-based cache invalidation, queued generation, overlap locks and token accounting mean we only pay for intelligence when the fleet actually changes.
A production-ready, cross-platform subscription system: RevenueCat and Stripe converge on one idempotent entitlement model, so the same Pro unlock works whether a team pays on iPhone or on the web.
A two-sided marketplace that turns GentrackAI from a tracking tool into a place where generator owners and service technicians actually do business, with state-based matching, bidding, scheduling, completion and reviews.
One TypeScript codebase for iOS and the web. Both share the same feature modules, with platform-specific auth, secure storage and billing where Apple requires it.
We turned an App Store rejection into a stronger product. Billing went from a Stripe redirect to a native, multi-offering RevenueCat integration with restore, store-localized pricing and organization-level entitlements.
~200 automated backend tests, atomic zero-downtime deployments and full App Store compliance (Sign in with Apple, token revocation, account deletion, IAP).
What we learned
Structured output beats prompt engineering. A typed schema with explicit nullability did more for reliability than any amount of prompt tweaking.
Design for the model to fail. LLM APIs are distributed systems with real outages. Retry policies have to be deliberate, and knowing what not to retry matters as much as knowing what to retry.
Tool calling is the right shape for user data. Giving the model narrow, permission-scoped tools produced more accurate, more secure answers than stuffing context into the prompt.
Cache AI like any other expensive computation. Fingerprint the inputs, regenerate off the hot path and measure tokens. Deterministic analytics should never cost tokens.
Subscriptions are a state machine, not a checkbox. Idempotency, event deduplication, timezone normalization and a single writer are what make RevenueCat and Stripe trustworthy together.
Platform rules shape architecture. App Store guidelines 3.1.1, 3.1.2 and 5.1.1(v) shaped real decisions about billing channels, the paywall, onboarding and account deletion. Reading the guidelines before writing the code saves a release cycle.
Do the cheap work on the device. Resizing and normalizing images before upload improved latency, reliability and OCR quality all at once, at no server cost.
Identity is the hardest part of payments. Deciding who owns a subscription (the organization) mattered more than any purchase API call.
What's next for GentrackAI
IoT and telemetry integrations. Connect to generator controllers and existing monitoring platforms (Generac Mobile Link, Kohler OnCue and similar) to replace estimates with live run hours, fuel and battery data.
Push notifications (APNs) for due services, low fuel, new marketplace offers and job updates. Today, alerts are delivered in-app and by email.
Predictive failure detection. Use reading history and fault-code photos to catch battery degradation, abnormal fuel burn and recurring faults before they cause an outage.
Outage-aware alerts. Combine weather and utility-outage data so owners get a "run a pre-storm check now" alert before a storm arrives.
Marketplace expansion beyond U.S. state-level matching: ZIP-radius matching, in-app payments to technicians, parts ordering and service-level guarantees for commercial clients.
An enterprise and facility tier with multi-site dashboards, compliance logs (NFPA 110-style testing records) and API access for property-management systems.
Model upgrades. Benchmark stronger vision models on hard nameplates, and build a growing manufacturer spec catalog so every scan gets richer over time.
Built With
- big-query
- cloud-logging
- cloud-monitoring
- cloud-storage
- cloud-text-to-speech
- expo.io
- gcp
- gemini-api
- ios
- laravel
- react-native
- revenuecatsdk
- vertexai

Log in or sign up for Devpost to join the conversation.