Urvi today

Urvi is Platform Commons' offline-first Android app for natural-farming field staff. It serves one programme: Andhra Pradesh's natural-farming programme run by RySS (APCNF, tenant ap.gov). Staff register farmers, record land, livestock, crops, models, harvests and plans, and supervisors endorse the data, all of it working offline for days.

Vital statisticscounted from source, Oct 2026
Features
40 live features in 8 groups
Screens
75 (21 activities, 54 fragments), 28 ViewModels
Local tables
71 live tables in 5 stores (55 in agri_db, schema v62)
Endpoints
111 live endpoints
Services
12 on the gateway host, plus S3 and Firebase
Set-aside code
234 unused items, about 6,500 lines
Size
91,553 Kotlin lines, 9 test methods

What Urvi is

Field staff register farmers (each farmer is an "IE"), record their land, livestock, crops, monthly crop progress, ATM and kitchen-garden models, harvests, annual plans and surveys. Supervisors review and endorse that data at VO, SHG and farmer level. The app works for days without a network and syncs when it can.

FactValue
PlatformAndroid only (minSdk 26, targetSdk 36), no iOS code
Version2.2.13 (versionCode 126)
AgeCode from about 2018 (Mindtree IGX era); git history from 2022, 1,013 commits
Size91,553 Kotlin LOC in :app and :data, 170 layouts, 21 activities, 54 fragments
LanguagesEnglish, Telugu (48 strings missing), Tamil (416 strings missing, 40%)
BackendAbout 12 services and about 40 report datasets, called directly
TeamAbout 5-6 core Android developers, all Kotlin
Local storage4 Room databases (agri_db at schema v62 with 57 migrations) plus the Bridge sync queue
Networking5 HTTP stacks, 3 JSON libraries
Background work23 WorkManager workers (15 live), 41 sync response handlers (33 live)
Tests9 @Test methods in 6 files; effectively no coverage of business rules, sync or migrations
Dead codeAbout 6,500-7,000 lines; see Set-aside code
Coupling149 files import the proprietary Bridge libraries

Who uses it

RoleHow the app recognises itWhat they mainly do
Cadre (CRP, lead, etc.)Default ap.gov userPicks one Village → Habitation → VO, manages its farmers, logs daily activities
Unit In-charge / FMT L1Role code contains unit-incharge or fmt_l1Gets all assigned VOs, endorses VO/SHG/farmer data, builds compact blocks, runs VO/SHG surveys
HAN (add-on)Role code contains role.ap.gov.hanRead-only view of farmer data
FCCC (add-on)Role code contains role.ap.gov.fcccExtra geographic VO filter on endorsements

No usage numbers (active users, farmers, devices) exist in the code. The farmer download pages at 250 rows by default, which suggests VOs of a few hundred farmers; ask the programme for real counts before sizing the backend.

A field worker's day

A cadre opens Urvi in a village with weak signal. The app skips login (the account is already on the phone) and opens the farmer list for their VO. They search for a farmer by mobile number, open the farmer hub and see that the profile is complete and land is authenticated, so most tiles are open. They enter this month's Crop Actual: the app has already copied last month's crop blocks, and they edit one crop, give an edit reason and add a photo. For a new ATM plot they walk the boundary with GPS motion capture, which drops a point every 5 m. Back home in the evening they record their day's activities in the Activity Tracker, which only lets them submit after 18:00. When the phone finds a network, a background job drains the queued changes. If the server rejects one (for example, the crop area now exceeds the land), a red badge appears on the sync-error icon the next morning.

Module map

ModuleWhat it doesKey tablesMore
Startup and loginLanguage pick, Bridge login, role and tenant detection, work-node pickprefs, worknode*App startup
Data downloadPages farmers, roles, land, portfolios, ATM and attachments onto the device; resumablesync_status, ie_flat_entityData download
Home, menu, settingsFarmer list or VO tabs, sync badge, force sync, backup, language switchprefs, sync_errorsHome
Device binding and remote actionsOne device per user (optional), remote logout or wipedevice_registration_prefsDevice registration
Farmer list and profile (IE)Search, filter, add and edit farmers, category and statusie_flat_entity, ie (+6 child tables), legacy ieFarmer profile
Farmer hubGate rules that decide which tiles a farmer can usereads manyFarmer hub
Land and leaseLand parcels, authentication, leased-in land, disablefarmerassets, legacy ie_assetLand assets
GeofencingWalk, tap or KML polygon capture for land, crop tile, ATMfarmerassets, PLI, farming_model + filesGeofencing
Livestock and inventoryAnimal counts; crop stock in quintalsfarmerassets, inventoryproduct, ie_inventoryLivestock
Crop Actual (portfolio) and harvestMonthly crop blocks per land, practices, PMDS, month-on-month copy, harvestportfolio*, harvest_logsCrop Actual
ATM and ATM harvestSmall year-round income plot modelfarming_modelATM model
365 DKGMonthly kitchen-garden yes/nofarming_model365 DKG
KAP / AAP 2025-26Annual action plan with ceilingsie_flat_entity.annualActionPlanData2526KAP 2025-26
Endorsements and commentsVO → SHG → farmer review, flags, abstractsendorsement_entity, endorsement_comment_entityEndorsement
Compact BlockGroups geofenced S2S tiles of several farmers, at least 5 acrescompact_block, compact_block_memberCompact Block
Surveys, certification, activity trackerBuilt on the internal assessment librarylibrary DBActivity Tracker
Analytics and notificationsMIS dashboard, comment and push notificationsprefs, notificationsAnalytics

How it is put together today

  • Two Gradle modules. :app (org.platformcommons.urvi) holds screens, its own Room DB and repositories; :data (org.mindtree.app.agricultor.data) holds the main DB, a 3,395-line god repository and the sync code. The boundary is blurred.
  • Six on-device stores. agri_db (Room v62, 64 tables), legacy ie_register.db (Room v20, a denormalised copy kept in step by "bridge" mappers), error_log_db, sync_ledger_db, the Bridge library's SYNC_QUEUE_DB, and the assessment library's DB. None is encrypted.
  • Two-level write queue. A screen saves a row and adds a sync_ledger entry with dependencies. A 15-minute WorkManager job turns ready entries into Bridge Operations in SYNC_QUEUE_DB, which an Android SyncAdapter in a separate process drains. About 40 response handlers write server ids back.
  • Reads go to report datasets. About 40 named datasets on two report engines, with parameters and SQL-like criteria= strings built on the phone.
  • Five HTTP stacks, three JSON libraries. Bridge CoreAPI on Apache HttpClient, three Retrofit clients, plus account-lib's own Retrofit; Gson, Moshi and Jackson.
  • Four in-house Bridge libraries (core-api, offline-core, offline-android, account-lib) carry login, HTTP and the queue. Login stores the password in AccountManager and uses a session token as X-SESSIONID.
  • Server-driven switches. Feature flags, season, paging and retry settings come from the CLASS.PORTFOLIO_APP_CONFIG ref data, read by string code across a 1,970-line AppUtils.
  • Firebase on the side. Crashlytics, Remote Config, FCM topics, and Firestore/Storage used as a sync debug log and image fallback.

Top findings

#FindingWhy it mattersRead more
1Release keystore and its passwords, Nexus credentials and the app key are committed or shipped in the APKAnyone with repo or APK access can sign or impersonate/security/
2Full sync operations, including session headers and farmer PII, go to Firestore on errors and the whole queue goes to sync-service every 6 hoursPersonal data (Aadhaar, phone) leaves the device unredacted/security/
3Aadhaar and phone numbers sit unencrypted in Room; the password is stored in plaintext in AccountManager; support exports zip the whole DBDevice loss or a shared log exposes farmers/security/
4Down-sync can overwrite unsynced work: ATM download inserts the unfiltered list, the VO filter wipes the whole farmer table, REPLACE inserts reset device-only flagsSilent loss of field data/sync/
5No conflict detection, effectively unlimited retries, handler exceptions silently drop operations, and two processes can drain the queue at onceData can vanish or be applied twice with no trace/sync/
6The app calls about 12 services and 40 datasets directly; one data setup costs roughly 300 calls for 1,500 farmers and Home fires about 15 calls on every openSlow, fragile on 2G/3G, and every backend rename needs an app release/api/
7Two databases hold the same farmers, land and crops in different shapes, with no foreign keys and few indexes; each new season is a copy-pasted screen, entity and handlerDrift between copies, slow queries, a release per season/database/
8About 6,500-7,000 lines are dead, 8% of lines are duplicated, and there are only 9 @Test methodsRules are hard to find and nothing protects a refactor/tech-debt/, /stale/

How to read this site

SectionPagesUse it to
TodayOverview, Features, Roles and access, Key flowsLearn what the app does now, screen by screen, rule by rule
DataDatabase, APIs and services, Sync and background, Sibling librariesFind which table, endpoint or worker holds or moves a piece of data
DebtTech debt, Security, Set-aside codeSee what is broken, risky or dead
TomorrowImprovements, Compose vs Flutter, App Service (BFF), RoadmapPlan the rewrite

Every factual page describes live code only. Unused classes, tables, endpoints and workers are listed once, on /stale/, and nowhere else. File paths are repo-relative. Secret values found in the code are never shown, only where they are.