One codebase four app

Flutter Classified Ads Engine Prompt

Flutter Classified Ads Engine

Copy the prompt below and use it with any AI

Prompt

You are a senior Flutter architect. Build a production-grade 
config-driven Classified Ads Engine mobile app in Flutter.

The entire app transforms into a different product by changing 
one constant in main.dart. Same codebase becomes a Marketplace, 
Job Board, Rental app, or Second-hand store.

TECH STACK:
- Flutter
- Firebase Auth (Google Sign-In only)
- Firestore
- Cloudinary (image uploads)
- flutter_bloc (state management)
- get_it (dependency injection)
- go_router (navigation)
- dartz (Either for error handling)
- Clean Architecture, feature-first folder structure

STRICT RULES:
- Firebase only in data/datasources layer. Never in BLoC or UI.
- Cloudinary behind an abstract interface
- Every feature has domain/ data/ presentation/ layers
- Use Either<Failure, T> for all repository returns
- No hardcoded strings — everything flows from AppConfig

THE CONFIG SYSTEM (most important part):

class AppConfig {
  final String appName;
  final String appTagline;
  final AppDomain domain;
  final bool enableChat;
  final bool enablePrice;
  final bool enableLocation;
  final bool enableCategories;
  final bool enableFavorites;
  final bool enableRoleSwitch;
  final bool enableImageUpload;
  final bool enableContactSeller;
  final String listingLabel;
  final String listingLabelPlural;
  final String sellerLabel;
  final String buyerLabel;
  final String priceLabel;
  final String locationLabel;
  final String currencySymbol;
  final String currencyCode;
  final CategoryPreset? categoryPreset;
}

Include 4 ready-to-use preset configs:
- marketplaceConfig (Marketplace, buy/sell anything)
- jobBoardConfig (Job board, employer/job seeker)
- rentalConfig (Rental listings, landlord/tenant)
- secondHandConfig (Second-hand goods, no role switch)

Switching between them = one line change in main.dart.

FOLDER STRUCTURE:
lib/
├── config/
│   ├── app_config.dart
│   └── category_presets.dart
├── core/
│   ├── di/injection_container.dart
│   ├── error/failures.dart + exceptions.dart
│   ├── usecases/usecase.dart
│   ├── network/network_info.dart
│   └── utils/constants.dart + app_utils.dart
├── features/
│   ├── auth/
│   ├── listings/
│   ├── categories/
│   ├── favorites/
│   ├── profile/
│   └── role/
├── shared/
│   ├── navigation/app_router.dart
│   ├── theme/app_theme.dart
│   └── widgets/
└── main.dart

BLOCS TO BUILD:
- AuthBloc (Google sign-in, auth state stream)
- ListingBloc (browse, search, filter, paginate, CRUD)
- FavoritesBloc (real-time Firestore stream)
- CategoryBloc (load categories, track selection)
- RoleBloc (buyer/seller toggle, persist to SharedPreferences)
- ProfileBloc (load and update user profile)

FIRESTORE SCHEMA:
users/{userId}
  - email, displayName, photoUrl, bio, phone, city, 
    listingCount, joinedAt

listings/{listingId}
  - title, description, price, images, categoryId, 
    userId, userDisplayName, userPhotoUrl, location, 
    status (active/sold/draft), metadata, createdAt

favorites/{userId}_{listingId}
  - userId, listingId, savedAt

categories/{categoryId}
  - name, icon (emoji), color (hex), listingCount

MVP FEATURES:
1. Google Sign-In with persistent auth state
2. Browse listings — masonry grid + list toggle + infinite scroll
3. Search and filter — category chips, price range, city, sort
4. Listing detail — image gallery with fullscreen viewer
5. Create listing — image picker, category selector, location
6. Edit and delete listing (owner only)
7. Favorites — real-time stream, heart button on every card
8. Role switching — buyer vs seller, persisted to SharedPreferences
9. Profile page — role-aware (sellers see their listings and a 
   Post button, buyers see an upsell to switch to seller mode)
10. Edit profile — name, bio, phone, city

GOROUTER ARCHITECTURE (critical — get this right):
GoRouter ShellRoute creates a new widget subtree that is 
completely disconnected from main.dart's MultiBlocProvider.

Global blocs in main.dart (available everywhere):
- AuthBloc, RoleBloc, FavoritesBloc

Shell blocs in MainScaffold (available to shell routes only):
- ListingBloc, CategoryBloc, ProfileBloc

Self-contained blocs (each pushed page provides its own):
- CreateListingPage: own ListingBloc + CategoryBloc
- EditListingPage: own ListingBloc + CategoryBloc  
- ListingDetailPage: own ListingBloc
- EditProfilePage: own ProfileBloc
- ProfilePage: own ProfileBloc + own ListingBloc

Any page reached via context.push() must provide its own 
BlocProviders. Any page reached via context.go() inside the 
shell can use the shell's blocs.

FIRESTORE QUERY RULE (critical for MVP):
Do not combine where() and orderBy() on different fields.
This requires composite indexes that don't exist yet.
Instead: query with single field only, sort client-side.
Example: .where('userId', isEqualTo: id) then sort in Dart.

CATEGORY PRESETS:
Marketplace: Electronics, Vehicles, Furniture, Clothing, 
             Sports, Books, Home & Garden, Other
Job Board: Technology, Design, Marketing, Finance, 
           Healthcare, Education, Sales, Remote
Rental: Apartment, House, Studio, Room, Commercial, Land
Second-hand: Electronics, Clothing, Toys, Books, 
             Sports, Furniture, Other

UI REQUIREMENTS:
- Material 3 design
- Custom theme with AppColors and AppTextStyles
- Shimmer loading skeletons
- Empty states with icons and action buttons
- Error states with retry
- Loading overlay for async operations
- Masonry grid (flutter_staggered_grid_view)
- Cached network images (cached_network_image)
- Photo gallery with fullscreen viewer (photo_view)

CLOUDINARY:
- Upload via unsigned upload preset
- Abstract behind CloudinaryDataSource interface
- Auto-optimize on delivery using transformation URLs
- Support multiple images per listing (max 5)

ALSO INCLUDE:
- firestore.rules with proper security rules
- firestore.indexes.json for composite indexes
- Complete README with domain transformation guide,
  feature flag reference, and architecture decisions

Post a Comment

Previous Post Next Post