Product documentation
TafTaf
Premium real estate, transacted in taps. TafTaf connects property owners and clients across Kenya — Airbnb stays, apartments, houses, plots and commercial space — with verified listings, M-Pesa-native payments, and tools for owners to manage tenants and rent from their pocket.
“Home is not a place. It’s a feeling.” — from the TafTaf onboarding carousel
What TafTaf is
TafTaf is a two-sided marketplace app. Clients browse verified listings, unlock full property details with a single M-Pesa payment, message owners directly, and book stays. Owners list properties across five categories, track views and saves, and run day-to-day rent operations for their buildings through a dedicated Tenant Manager — down to bulk-importing tenants from a spreadsheet and printing PDF receipts.
Product
Features
Everything below ships in the current build — pulled directly from the app’s feature set, not a roadmap.
Verified Listings
Airbnb stays, apartments, houses, plots/land and commercial space, each with a verified badge, rating, and live availability status.
Pay-Per-Unlock
Full property details — owner contact, exact location, amenities — stay behind a one-time KES 50 charge. Pay once, unlock forever.
M-Pesa Native
STK Push checkout straight against the Safaricom Daraja API, with status polling and graceful failure handling.
In-App Messaging
Direct chat between clients and owners once a conversation is started from a listing.
Voice Calling
Real-time voice calls powered by ZegoCloud — no phone minutes required on either side.
Tenant Manager
Owners create apartments, assign tenants to rooms, and track rent and due dates from a single screen.
Bulk Tenant Import
Onboard a whole building at once via an Excel template, parsed on-device.
PDF Receipts
Generate, print, and share rent receipts and statements directly from the phone.
Location-Aware Search
Filter by price range and property type, or tap “Near Me” for live geolocation results.
Dual Roles, One Codebase
The same app renders a Client shell (browse & book) or an Owner shell (list & manage), decided by the account’s role.
Product · Client role
Client Experience
From sign-up to booking: the flow a person renting or buying moves through. Screenshots below are captured from a real build running on an Android emulator, not mockups.
Product · Owner role
Owner Dashboard
Owners get a management console instead of a browse feed: listing performance at a glance, a fast path to add inventory, and a rent-collection tool most listing apps don’t bother building.
Why a Tenant Manager exists
Most listing marketplaces stop at the booking. TafTaf’s owner side keeps going after move-in: rooms get assigned to tenants with a rent amount and due date, a whole building can be imported from a spreadsheet in one pass, and receipts get generated as PDFs the owner can print or share — no separate landlord software required.
Engineering
Architecture
One Flutter codebase, Firebase as the backend of record, and three external services doing the jobs Firebase doesn’t: payments, voice, and maps.
- Flutter 3.44 / Dart 3.12
- flutter_riverpod — state
- go_router — navigation
- Material 3 — component base
- Poppins — typeface
- Firebase Auth — email/password + Google
- Cloud Firestore — users, properties, chats
- Firebase Storage — listing photos
- Safaricom Daraja — M-Pesa STK Push
- ZegoCloud — voice calling
- Google Maps + Geolocator — location
- pdf / printing / excel — documents
Account documents live in two Firestore collections: users/{uid} holds the profile, and usernames/{usernameLower} is a lookup index that enforces username uniqueness and resolves username → email at login.
Engineering
Code Reference
Three excerpts, taken directly from the codebase, that show how the core mechanics actually work.
Property price formatting
From lib/core/models/property_model.dart — collapses raw KES values into the K/M shorthand shown throughout the app.
enum PropertyType { airbnb, apartment, house, plot, commercial }
enum PriceType { daily, monthly, fixed }
String get priceFormatted {
if (price >= 1000000) {
return 'KES ${(price / 1000000).toStringAsFixed(1)}M';
} else if (price >= 1000) {
final k = price / 1000;
final s = k == k.truncateToDouble()
? k.toInt().toString()
: k.toStringAsFixed(1);
return 'KES ${s}K';
}
return 'KES ${price.toStringAsFixed(0)}';
}
Signup — username uniqueness
From lib/core/services/auth_service.dart — a username reservation doc is written alongside the Firebase Auth account so logins can resolve username → email.
Future<UserModel> signup(String username, String email,
String phone, UserRole role, String password) async {
final usernameLower = username.trim().toLowerCase();
final existing = await _usernames.doc(usernameLower).get();
if (existing.exists) throw Exception('Username or email already taken');
final cred = await _auth.createUserWithEmailAndPassword(
email: email.trim(), password: password);
final uid = cred.user!.uid;
final newUser = UserModel(id: uid, username: username.trim(),
email: email.trim(), phone: phone.trim(), role: role,
createdAt: DateTime.now());
await _users.doc(uid).set(newUser.toJson());
await _usernames.doc(usernameLower)
.set({'uid': uid, 'email': email.trim().toLowerCase()});
return newUser;
}
M-Pesa STK Push
From lib/core/services/mpesa_service.dart — the request that pops the payment prompt on the payer’s phone.
Future<StkPushResult> initiateStkPush({
required String phoneNumber,
required int amount,
required String accountReference,
required String transactionDescription,
}) async {
final token = await _getAccessToken(); // Daraja OAuth, cached
final password = base64Encode(utf8.encode(
'${ApiKeys.mpesaBusinessShortCode}${ApiKeys.mpesaPasskey}$ts'));
final res = await http.post(
Uri.parse('$_baseUrl/mpesa/stkpush/v1/processrequest'),
headers: {'Authorization': 'Bearer $token'},
body: jsonEncode({
'BusinessShortCode': ApiKeys.mpesaBusinessShortCode,
'TransactionType': 'CustomerPayBillOnline',
'Amount': amount,
'PartyA': phone, 'PhoneNumber': phone,
'AccountReference': accountReference,
}),
);
// ResponseCode '0' => success, checkout ID returned for polling
}
Engineering
Design System
Pulled directly from app_colors.dart and app_theme.dart. Neon lime on near-black, in the same register as the Apple Fitness palette, plus a matching light theme.
Brand accent
Semantic
Type scale — Poppins
Components
Buttons use a 30px pill radius; cards and inputs use 14–16px radii — consistent across both themes.
Engineering
Getting Started
Local setup for anyone picking up the codebase.
Clone & install dependencies
Standard Flutter workflow — SDK ^3.12.0.
git clone <repo> cd taftaf flutter pub get
Add Firebase config
Drop in the platform config files from your Firebase project (taftaf-app-b0167 for the reference build).
android/app/google-services.json ios/Runner/GoogleService-Info.plist
Add local API keys
Copy the example file and fill in Maps, M-Pesa Daraja, ZegoCloud and EmailJS keys. This file is gitignored on purpose.
cp lib/core/constants/api_keys.example.dart \ lib/core/constants/api_keys.dart
Run it
Pick a target device and launch in debug mode.
flutter devices flutter run -d <device-id>
zego_express_engine pins an old compileSdkVersion in its own Gradle file, which can conflict with newer Android Gradle Plugin versions. If a build fails on the Zego module, that plugin’s android/build.gradle in the pub cache is the first place to check.Contact
Developer
TafTaf is designed, built, and maintained end-to-end by a single fullstack engineer.
Sharks Muli
Building TafTaf end-to-end — the Flutter app, the Firebase backend, and the M-Pesa integration behind the pay-per-unlock model documented on this site. Software Engineering undergraduate at Kisii University, focused on API design, database architecture, and system integration. Also runs LM-Graphics, a technical & digital solutions studio.
Skills
Toolbox
Experience
Projects & roles
TafTaf
- Designed and built the entire product documented on this site — Flutter client, Firebase backend, M-Pesa payments, ZegoCloud calling.
- Owns the data model, the owner/client dual-role architecture, and the Tenant Manager rent-collection tools.
Medical Management System
- Designed and developed a backend-driven system to manage patient records and appointment scheduling.
- Implemented structured data storage and retrieval logic for secure record handling.
- Designed REST-style endpoints to support frontend integration.
Haki-Record Digital OB System
- Co-developed a digital Occurrence Book system to improve record accessibility and data security.
- Contributed backend logic for secure data handling and structured workflows.
LM-Graphics
- Leads client-based digital solution projects, from system design through implementation.
- Leads graphic design projects and delivery.
Local Service Hub
- Coordinates daily service requests and matches clients with appropriate local providers.
- Maintains accurate records of transactions, service delivery, and client feedback.
Education
Résumé
Meshack Muli Kikuvi — Full CV
One-page résumé: professional summary, full project & work history, skills and education. PDF, ready to download or open in a new tab.