My County
Live on Google Play Android & web · v1.4.7Community platform · Published Android and web app · Django backend · AI news desk
My County is published on Google Play and runs as a web app from the same Flutter codebase. It gives Kenyan counties, constituencies and wards their own local feed — posts, events, a marketplace, a business directory, attractions and real-time chat, all scoped to where you actually live. It is the project I have worked on longest, it has real users, and it spans four distinct pieces of engineering.
The app
Flutter across twelve feature modules, at version 1.4.7, build 30, with Riverpod for state and go_router for navigation. The feed ranks on a blend of recency and engagement, pages with Firestore cursors rather than offsets, and keeps like and comment counts correct under concurrency using transactional counters behind an optimistic UI. Access is enforced with ownership and field-level Firestore rules, image-only Storage rules, and composite indexes backing every ward and constituency query. Chat carries presence, typing indicators and last-seen; posts and comments support @mention tagging with de-duplicated notifications.
The backend migration
I rebuilt the backend as Django REST Framework on PostgreSQL, verifying Firebase ID tokens as JWTs so the mobile client's authentication carried over unchanged, with S3 presigned URLs for media. It deploys to a DigitalOcean droplet through Docker and GitHub Actions on every push to main, behind Caddy for automatic TLS.
I mapped the Django models one-to-one onto the existing tables and adopted them with migrate --fake-initial, so 241 live posts carried across with no data migration at all. The cutover was a single base-URL change in the Flutter client, and reversible instantly by changing it back.
The AI news desk
A Django app that drafts local news through a five-stage pipeline: ingest, dedupe, write, critique, gate. A critic stage checks every claim in a draft against its source and sends unsupported ones back to the writer for a bounded revise loop. Nothing reaches the feed on its own — anything the critic marks sensitive always goes to a human review queue, and by default routine stories do too.
The cost controls are deliberate. A queue cap stops drafting entirely once the review queue is full, so there is no model spend on stories nobody has capacity to judge, and deferred clusters flow again once it drains. Headline-only and paywalled sources are skipped and marked seen so they are never paid for twice. Every stage reports its cost, and each cluster, space agent and persona is isolated so one failure cannot take down the batch.
Systems design
The platform is growing an identity graph — schools, cohorts, workplaces and shared spaces. One endpoint answers "how are we connected?" with a bounded six-degrees path search: direct links first, then a single intermediary, with school ties deliberately usable only as a direct link and never as a traversal hop, because alumni fan-out is enormous. Space-mate fan-out is capped per side and the intersection is done in memory, keeping the whole answer to roughly seven indexed queries. I specified it, and twenty other features, as written design docs before building them.
Specification
- Status
- Live on Google Play — 500+ installs, rated 5.0
- Role
- Sole developer
- Platforms
- Android and web from one Flutter codebase
- Mobile
- Flutter · Dart · Riverpod · go_router · flutter_map · geolocator
- Backend
- Django REST Framework · PostgreSQL · Redis · Firebase Admin SDK
- Infrastructure
- Docker · GitHub Actions · DigitalOcean · AWS S3 · Caddy
- AI
- Multi-stage drafting pipeline with a critic, human approval gate and queue-cap cost control
- Scale
- 12 feature modules · 9 backend apps · 21 written design specs
- Notable
- Live backend migration with one-line rollback, bounded graph search, transactional counters, field-level security rules