Skip to content

About

Crowdsourced Flutter app (Android + Web) for finding condominium blocks in Addis Ababa's condo projects.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Addis Condo Finder

A crowdsourced app for finding condominium blocks inside the big condominium projects of Addis Ababa (e.g. Koye Feche Project 16, Block 56). Flutter on Android and Web for users; one Laravel app (its own repo: condominium_finder_server, kept as a sibling folder) is the entire backend — REST API + Filament admin panel — and runs on any shared hosting plan.

  • Guests can search, browse the map and navigate to any block — no login.
  • Signed-in users can add projects, add blocks, confirm/report block locations, and suggest corrections ("block 15 is here, not there"). A block becomes Verified after 3 independent confirmations (you can't confirm your own).
  • Moderation: new submissions and corrections are pending until an admin approves them in the admin panel — then they appear on the map. 3+ reports automatically pull a block's Verified badge for review.
  • Trust & ranking: approved contributions earn points (project 10, block 5, correction 3, confirmation vote 1). At 50 points a user becomes trusted and skips the review queue; a leaderboard lives in the profile.
  • No paid services: flutter_map + OSM/Stadia tiles (no map SDK billing), your existing shared hosting for the API and database, and external-app navigation via URL schemes (no Directions API).
Layer Choice
App Flutter (Material 3), Riverpod 3 — Android + Web
Map flutter_map 8 + OpenStreetMap tiles (Stadia Maps optional)
Backend Laravel 13 (condominium_finder_server repo): REST API + Filament 5 admin panel
Database SQLite locally (auto-created); MySQL on the server
Auth Email/password + free Telegram bot sign-in (all through the API)
Offline Hive cache of recently viewed projects/blocks + bundled demo data
Navigation url_launcher handoff to the Google Maps app / web
Location geolocator one-shot "my location" (no background tracking)

Design system

Swiss-modernism utility palette chosen for a navigation tool: navy #1E3A5F (brand), route blue #2563EB (interactive), green #059669 (reserved for the verified state), slate neutrals, full light + dark themes, WCAG-AA contrast. Typography is Figtree (headings/labels) and Noto Sans (body) with Noto Sans Ethiopic bundled so the Amharic UI renders natively on every device. All fonts ship in the binary — no runtime font fetching.

Quick start — everything runs locally, zero setup

No MySQL, no config files. On its first request the server creates a SQLite database, migrates it, and seeds the 10 real Addis areas plus a local-only admin (admin@local / admin123).

# Terminal 1 — API + admin panel   → http://localhost:8000/admin
cd ../condominium_finder_server && php artisan serve

# Terminal 2 — the app (env.json already points at localhost:8000/api)
flutter run --dart-define-from-file=env.json           # Android
flutter run -d chrome --dart-define-from-file=env.json # Web

Try the loop: register a user in the app → add a block (it shows "pending review") → approve it in the panel → it appears on the map.

No PHP installed at all? flutter run with no dart-defines still works as a pure demo with bundled sample data.

Deploying

1. Server — one upload, one file to edit

  1. In cPanel, create a MySQL database + user, and make sure your domain has HTTPS (SSL/TLS Status → Run AutoSSL — it's free; Telegram sign-in and safe token transport need it). Requires PHP 8.3+ (MultiPHP Manager).
  2. Upload the condominium_finder_server folder (including vendor/) into public_html/.
  3. Rename the included .env.production to .env and fill in the 6 marked values: your domain (with https://), the MySQL database/user/password from step 1, and your admin email + password.
  4. Optional — Sign in with Telegram (free): message @BotFather, send /newbot, pick a name and username, and paste the token it replies with into TELEGRAM_BOT_TOKEN= in the same .env. That's the entire setup — the bot username and webhook configure themselves, and the app shows the button automatically. Leave it empty to hide the button.
  5. Open https://your-domain.com/api/health — the database installs and seeds itself on this first load, your admin account included. You should see "status":"ok" (and "telegram":true if you did step 4). The panel is at https://your-domain.com/admin.

Re-uploading the server folder later is a safe deploy — all state lives in MySQL (schedule backups in cPanel: Backup → MySQL databases).

2. Release the Android app

Point env.json at the live server first:

{ "API_BASE_URL": "https://your-domain.com/api", "STADIA_API_KEY": "" }

(STADIA_API_KEY is optional — empty means plain OSM tiles.)

One-time release signing — required before sharing the APK or publishing to Play; without it builds are debug-signed and users can't install updates:

cd android
keytool -genkey -v -keystore upload-keystore.jks -keyalg RSA \
        -keysize 2048 -validity 10000 -alias upload
cp key.properties.example key.properties   # then fill in the paths/passwords

Keep upload-keystore.jks + passwords backed up somewhere safe (losing them means you can never update the app); both files are gitignored. Then build:

flutter build apk --release --dart-define-from-file=env.json          # direct APK
flutter build appbundle --release --dart-define-from-file=env.json    # Play Store

3. Web app (optional)

The web build is served from the /app/ path on your domain, so it must be built with that base href:

flutter build web --release --base-href=/app/ --dart-define-from-file=env.json

Upload the contents of build/web/ to public_html/public/app/ and set CONDO_WEB_APP_URL=https://your-domain.com/app in the server .env. The app is then live at https://your-domain.com/app/.

Go-live checklist

  • https://your-domain.com/api/health says ok (+ "telegram":true if configured), and /admin accepts your admin login.
  • Sign in with Telegram from a real phone: tap the button → bot chat opens → Start → you're signed in.
  • Send yourself a password-reset email from the live site — shared hosting mail sometimes lands in spam; if so, switch MAIL_* in .env to your host's SMTP account.
  • Full loop: register → add a block (pending) → approve in /admin → it appears on the map.

How it works

  • Geo without PostGIS: coordinates are DECIMAL(10,7) lat/lng columns. Condominium and project footprints are free-form polygons drawn corner-by-corner in the app (older projects fall back to a generated hexagon); "which area contains this tap" is a client-side ray-casting test, innermost shape first — no spatial extension needed at this scale. Tapping a condominium highlights it and shows the project footprints nested inside it at any zoom.
  • Search: GET /search?q= uses indexed LIKE matching across project names, area names and block numbers, grouped in the UI into Projects and Blocks. Debounced 300 ms in the client.
  • Crowdsourcing integrity: block_verifications /block_reports have UNIQUE(block_id, user_id) constraints (no double-voting); the API maintains verified_count and flips is_verified at 3+. Submitters can't confirm their own blocks, and 3+ reports pull the Verified badge until an admin reviews.
  • Moderation & trust: projects/blocks carry a pending/approved/rejected status; public endpoints only serve approved rows. Approvals award points; at 50 points contributors become trusted and publish instantly.
  • Auth: bearer tokens (stored SHA-256-hashed, 90-day expiry) issued by the API; passwords bcrypt-hashed. All write endpoints require Authorization: Bearer. Login, register, and the password-reset endpoints are rate limited (per IP / email), and reset codes die after 5 wrong attempts. The moderation panel (/admin) only admits accounts with role = admin.
  • Navigation: google.navigation: / geo: intents on Android; the universal Google Maps URL in a new tab on web. Zero API calls.
  • Offline: last-fetched projects/blocks are cached in Hive and served with an "offline" banner when the network fails.
  • Responsive: bottom sheets and stacked forms on phones; centered dialogs, a fixed-width search panel, and side-by-side map+form layouts from 720 px up. Verified on 360 px phones through desktop.
  • Language: English / Amharic (አማርኛ) toggle, persisted locally.

Project layout

lib/
  core/          config (dart-define), theme + design tokens, breakpoints,
                 EN/AM strings, constants
  models/        CondoProject, CondoBlock, SearchResult, UserProfile,
                 Leaderboard
  data/          api_client (bearer token), repository (+cache/demo), Hive
  services/      auth controller (email/Telegram), maps launcher,
                 location (GPS)
  providers.dart Riverpod 3 providers
  screens/       map, search panel, project/block sheets, add flows,
                 suggest-edit flow, auth, profile (+leaderboard)
assets/fonts/    Figtree, Noto Sans, Noto Sans Ethiopic (bundled)

The backend is its own repo, condominium_finder_server (sibling folder, see its README): routes/api.php (the REST API consumed by the app), app/Http/Controllers/Api/, app/Filament/ (admin panel), database/migrations/ (auto-installing schema), and .env.production (ready-to-upload server settings).

API reference

Method & path Auth Purpose
GET /projects – approved projects with block counts
GET /projects/{id}/blocks – approved blocks of a project
GET /blocks/{id} – one approved block
GET /search?q= – fuzzy search, approved projects + blocks
GET /leaderboard opt top contributors (+ your rank when signed in)
GET /privacy – privacy policy page (link it in Play Store)
POST /projects ✓ add project → pending unless trusted
POST /blocks ✓ add block → pending unless trusted
POST /blocks/{id}/verify ✓ confirm location (once, not your own)
POST /blocks/{id}/report ✓ report incorrect (3+ pulls Verified)
POST /blocks/{id}/suggest-edit ✓ propose corrected pin → review queue
POST /auth/register /login /logout – / ✓ email auth, returns bearer token (rate limited)
POST /auth/forgot /reset – 6-digit email reset code (attempt-capped)
GET /auth/me · PATCH /me ✓ session profile / display name
DELETE /me ✓ permanent account deletion
GET /me/contributions ✓ my projects + blocks, incl. pending status
POST /auth/telegram/start /poll – Telegram bot sign-in (one-time code + poll)

About

Crowdsourced Flutter app (Android + Web) for finding condominium blocks in Addis Ababa's condo projects.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages