Swopix — Technical Documentation
Last updated: May 5, 2026
Table of Contents
- Project Overview
- Tech Stack
- Project Structure
- Architecture
- Dependencies
- Theme System
- Routing
- Screens & Components
- Shared Widgets
- Platform Considerations
- Known Issues Summary
- Environment & Configuration
1. Project Overview
Swopix is a Flutter-based college campus marketplace application. It enables verified students to buy, sell, and rent items within their local college community. The app enforces identity verification (student ID capture) and uses a trust score system to build community confidence.
Target Platforms: Android, iOS, Web (Chrome)
Package Name: com.swopix.app
Flutter SDK Requirement: ^3.6.0 (Dart SDK ^3.6.0)
2. Tech Stack
| Layer | Technology |
|---|---|
| UI Framework | Flutter 3.x (Material 3) |
| Language | Dart 3.x |
| Responsive Layout | sizer ^2.0.15 |
| Typography | Google Fonts (plus_jakarta_sans, inter, jetbrains_mono) |
| Navigation | Flutter Named Routes (MaterialApp.routes) |
| State Management | setState (local, no global state manager) |
| Backend | Firebase (Auth, Firestore, Storage) |
| Payments | Razorpay |
| Networking | dio ^5.4.0 (declared, not yet integrated) |
| Local Storage | shared_preferences ^2.2.2 |
| Image Loading | cached_network_image ^3.3.1 |
| SVG Rendering | flutter_svg ^2.0.9 |
| Camera | camera ^0.10.5+5 |
| Image Picker | image_picker ^1.0.4 |
| Permissions | permission_handler ^11.1.0 |
| Phone Input | intl_phone_number_input ^0.7.5 |
| OTP Input | pinput ^6.0.0 |
| Apple Sign In | sign_in_with_apple ^7.0.1 |
| Connectivity | connectivity_plus ^6.1.4 |
| Sharing | share_plus ^12.0.1 |
| Toasts | fluttertoast ^8.2.4 |
| Charts | fl_chart ^0.65.0 |
| Page Indicators | smooth_page_indicator ^1.2.1 |
| Swipeable List Items | flutter_slidable ^4.0.3 |
| Dropdown Search | dropdown_search ^6.0.2 |
| Build Target | Android (minSdk 21), iOS 12+, Web |
3. Project Structure
lib/
├── main.dart # App entry point, Firebase init, error handler, orientation lock
├── firebase_options.dart # Generated by FlutterFire CLI
├── app/
│ ├── routes.dart # All named route definitions and route map
│ └── theme.dart # Light & dark ThemeData, color constants, text styles
├── core/
│ ├── app_export.dart # Barrel export: connectivity, google_fonts, routes, widgets, theme
│ ├── currency_service.dart # Multi-currency formatting (default: INR)
│ ├── listings_notifier.dart # ChangeNotifier for global listings state (not yet wired)
│ └── theme_service.dart # Theme persistence via SharedPreferences
├── models/
│ └── user_model.dart # UserModel with Firestore serialization
├── services/
│ ├── auth_service.dart # Firebase Auth wrapper (email, Google, Apple, phone OTP)
│ ├── firestore_service.dart # All Firestore reads/writes
│ ├── storage_service.dart # Firebase Storage + Cloudinary uploads
│ ├── payment_service.dart # Razorpay checkout wrapper
│ ├── order_service.dart # Order + payment recording in Firestore
│ ├── ocr_service.dart # ML Kit OCR fallback for ID verification
│ ├── gemini_ocr_service.dart # Gemini Vision API OCR (primary ID extraction)
│ ├── gemini_id_verification_service.dart # Gemini authenticity check (unused — see RED-02)
│ ├── content_moderation_service.dart # Keyword-based listing moderation (not yet called)
│ ├── trust_score_service.dart # Trust score calculation (not yet called)
│ ├─ ─ college_service.dart # OpenStreetMap college lookup
│ └── env_loader.dart # Reads env.json for API keys
├── widgets/ # Shared reusable widgets
│ ├── custom_app_bar.dart # AppBar variants (standard, search, transparent, minimal)
│ ├── custom_error_widget.dart # Global error fallback widget
│ ├── custom_icon_widget.dart # Icon name → IconData mapper (large icon map)
│ ├── custom_image_widget.dart # Multi-source image widget (network, file, SVG, asset)
│ └── main_shell.dart # Main navigation shell with bottom bar + FAB
└── screens/
├── splash/
│ └── splash_screen.dart
├── onboarding/
│ └── onboarding_screen.dart
├── auth/
│ └── auth_screen.dart
├── college_selection/
│ ├── college_selection_screen.dart
│ └── widgets/
│ ├── college_dropdown_field.dart
│ ├── location_permission_card.dart
│ └── progress_indicator_widget.dart
├── id_verification/
│ ├── id_verification_screen.dart
│ └── widgets/
│ ├── camera_preview_overlay.dart
│ ├── id_capture_card.dart
│ ├── verification_instructions.dart
│ └── verification_step_indicator.dart
├── admin_panel/
│ └── admin_panel_screen.dart # Full admin dashboard (fully implemented)
├── home/
│ ├── home_screen.dart
│ └── widgets/
│ ├── empty_state_widget.dart
│ ├── filter_bottom_sheet_widget.dart
│ ├── filter_chip_widget.dart
│ ├── listing_card_widget.dart
│ └── search_bar_widget.dart
├── listing_details/
│ ├── listing_details_screen.dart
│ └── widgets/
│ ├── image_carousel_widget.dart
│ ├── purchase_bottom_sheet.dart
│ ├── rental_duration_bottom_sheet.dart
│ ├── rental_info_card_widget.dart
│ └── seller_info_card_widget.dart
├── create_listing/
│ ├── create_listing_screen.dart
│ └── widgets/
│ ├── category_selector_widget.dart
│ ├── condition_selector_widget.dart
│ ├── photo_gallery_widget.dart
│ └── pricing_section_widget.dart
├── chat/
│ ├── chat_screen.dart # Inbox / conversation list (mock data — GAP-02)
│ ├── individual_chat_screen.dart # Single conversation view (mock data — GAP-03)
│ └── widgets/
│ ├── chat_input_widget.dart
│ ├── listing_context_card_widget.dart
│ ├── message_bubble_widget.dart
│ ├── quick_action_chip_widget.dart
│ └── typing_indicator_widget.dart
├── rentals/
│ ├── rentals_screen.dart
│ └── widgets/
│ ├── empty_state_widget.dart
│ ├── rental_card_widget.dart
│ └── rental_history_card_widget.dart
├── profile/
│ ├── profile_screen.dart
│ └── widgets/
│ ├── menu_item_widget.dart
│ ├── profile_header_widget.dart
│ ├── stats_section_widget.dart
│ ├── trust_score_widget.dart
│ └── verification_status_widget.dart
├── settings/
│ └── settings_screen.dart
├── support/
│ └── support_screen.dart
└── legal/
├── privacy_policy_screen.dart
└── terms_conditions_screen.dart
assets/
├── images/
│ ├── img_app_logo.svg
│ ├── no-image.jpg # Fallback image for CustomImageWidget
│ └── sad_face.svg # Used in CustomErrorWidget
4. Architecture
Pattern
The app currently uses a simple stateful widget pattern with setState for all local state. There is no global state management layer. Each screen is self-contained with its own mock data.
Entry Point (main.dart)
- Calls
WidgetsFlutterBinding.ensureInitialized() - Installs a custom
ErrorWidget.builderthat showsCustomErrorWidgeton Flutter render errors (with a 5-second debounce to avoid repeated error widgets) - Locks device orientation to portrait via
SystemChrome.setPreferredOrientations - Runs
MyAppwhich wraps everything inSizerfor responsive sizing
MyApp
- Uses
MaterialAppwith named routes - Applies
AppTheme.lightTheme(dark theme defined butthemeModeis hard-coded toThemeMode.light) - Wraps child in
MediaQueryoverride to locktextScalerto1.0(prevents system font size from breaking layouts) - Sets
initialRoutetoAppRoutes.initialwhich maps toSplashScreen
Navigation
- All navigation uses
Navigator.pushNamed/Navigator.pushReplacementNamed/Navigator.pushNamedAndRemoveUntil - Route arguments are passed via
argumentsparameter but not yet consumed by destination screens (see BUG-16) - No deep linking or dynamic link handling is implemented
5. Dependencies
Core (Do Not Remove)
| Package | Version | Purpose |
|---|---|---|
flutter | SDK | Framework |
sizer | ^2.0.15 | Responsive sizing (w, h, sp units) |
flutter_svg | ^2.0.9 | SVG rendering for logo and error assets |
google_fonts | ^6.1.0 | PlusJakartaSans, Inter, JetBrainsMono |
shared_preferences | ^2.2.2 | Local key-value storage |
web | ^1.1.1 | Web platform interop |
Feature Dependencies
| Package | Version | Purpose |
|---|---|---|
cached_network_image | ^3.3.1 | Network image caching |
connectivity_plus | ^6.1.4 | Network connectivity detection |
dio | ^5.4.0 | HTTP client (not yet used) |
fluttertoast | ^8.2.4 | Toast notifications |
fl_chart | ^0.65.0 | Charts (not yet used in screens) |
smooth_page_indicator | ^1.2.1 | Onboarding page dots |
intl_phone_number_input | ^0.7.5 | International phone number input |
pinput | ^6.0.0 | OTP/PIN input field |
sign_in_with_apple | ^7.0.1 | Apple Sign In (iOS only) |
permission_handler | ^11.1.0 | Camera, location permissions |
dropdown_search | ^6.0.2 | Searchable dropdown (college selection) |
camera | ^0.10.5+5 | Camera access for ID capture |
image_picker | ^1.0.4 | Gallery/camera image selection |
share_plus | ^12.0.1 | Native share sheet |
flutter_slidable | ^4.0.3 | Swipeable list items (rental management) |
6. Theme System
Color Palette
The app defines two visual themes. Note: As of the current codebase state, only 7 light-theme colors are declared as static const. The dark theme and many screens reference ~25 additional color constants that are not yet declared (see BUG-01 in errors.md).
Declared Light Theme Colors:
| Constant | Hex | Usage |
|---|---|---|
primaryIndigo | #4F46E5 | Primary brand color |
secondaryEmerald | #10B981 | Secondary accent |
accentAmber | #F59E0B | Tertiary accent |
surfaceWhite | #FAFAFA | Scaffold background |
textDark | #111827 | Primary text |
textLight | #6B7280 | Secondary text |
softBorder | #E5E7EB | Border color |
Required But Undeclared Colors (must be added):
primarySkyBlue, primarySkyBlueDark, accentLimeGreen, accentLimeGreenDark, backgroundDark, surfaceDark, cardDark, borderDark, borderLight, neutralCharcoal, mediumGrey, lightGrey, pureWhite, shadowDark, errorRed, successGreen, warningOrange, trustGold, textHighEmphasisLight, textHighEmphasisDark, textMediumEmphasisLight, textMediumEmphasisDark, textDisabledLight, textDisabledDark
Typography
- Light theme:
PlusJakartaSans(Google Fonts) - Dark theme:
Inter(Google Fonts) - Data display (prices, codes):
JetBrainsMono(viaAppTheme.dataTextStyle()) - Text scaling is locked to
1.0globally viaMediaQueryoverride inMyApp
Responsive Sizing
All sizing uses sizer package units:
x.w— percentage of screen widthx.h— percentage of screen heightx.sp— scalable font size
7. Routing
All routes are defined in lib/routes/app_routes.dart.
| Route Constant | Path | Screen |
|---|---|---|
AppRoutes.initial | / | SplashScreen |
AppRoutes.splash | /splash-screen | SplashScreen |
AppRoutes.onboarding | /onboarding-screen | OnboardingScreen |
AppRoutes.authentication | /authentication-screen | AuthenticationScreen |
AppRoutes.collegeSelection | /college-selection-screen | CollegeSelectionScreen |
AppRoutes.idVerification | /id-verification-screen | IdVerificationScreen |
AppRoutes.homeMarketplace | /home-marketplace-screen | HomeMarketplaceScreen |
AppRoutes.listingDetails | /listing-details-screen | ListingDetailsScreen |
AppRoutes.createListing | /create-listing-screen | CreateListingScreen |
AppRoutes.chat | /chat-screen | ChatScreen |
AppRoutes.individualChat | /individual-chat-screen | IndividualChatScreen |
AppRoutes.rentalManagement | /rental-management-screen | RentalManagementScreen |
AppRoutes.profile | /profile-screen | ProfileScreen |
Navigation Flow
SplashScreen
├─ ─ (new user) → OnboardingScreen → AuthenticationScreen
├── (authenticated, unverified) → IdVerificationScreen
└── (authenticated, verified) → HomeMarketplaceScreen
8. Screens & Components
SplashScreen
- Purpose: App launch screen with animated logo, initialization status messages, and navigation routing
- Key Logic:
_initializeApp()simulates service initialization with staged delays._navigateToNextScreen()determines where to go based on auth/verification state (currently hard-coded to always go to onboarding) - Animations: Scale + fade animation on logo using
AnimationControllerwithSingleTickerProviderStateMixin - Error Handling: Shows retry dialog on initialization failure
OnboardingScreen
- Purpose: 3-slide feature introduction for new users
- Key Logic:
PageControllerwithSmoothPageIndicator. Slide content is data-driven from_slideslist. Last slide shows "Get Started" button instead of "Next Step" - Navigation: Skip button →
AuthenticationScreen. Last slide "Get Started" →AuthenticationScreen
AuthenticationScreen
- Purpose: Multi-method authentication (Phone OTP, Google, Apple, Email)
- Key Logic:
AuthMethodenum tracks selected method. Phone flow showsInternationalPhoneNumberInputthen transitions toPinputOTP entry. Apple Sign In is conditionally shown only on non-web iOS (!kIsWeb && defaultTargetPlatform == TargetPlatform.iOS) - OTP Timer:
Future.doWhilecountdown from 60 seconds. Resend button appears when timer reaches 0 - Navigation: All auth methods →
CollegeSelectionScreenon success
CollegeSelectionScreen
- Purpose: Step 2 of 4 in verification. User selects their college from GPS-detected nearby institutions
- Key Logic:
WidgetsBindingObserverdetects app resume to re-check location permission.Permission.locationrequest flow with permanent denial dialog. Mock college data filtered by detected town - Widgets:
CollegeDropdownField(usesdropdown_search),LocationPermissionCard,ProgressIndicatorWidget - Navigation: Continue →
IdVerificationScreen
IdVerificationScreen
- Purpose: Step 3 of 4. Captures front and back of student ID using device camera
- Key Logic:
availableCameras()initialization. Platform-specific camera settings (focus mode, flash).CameraPreviewOverlaypushed as a full-screen route for capture. Web uses front camera; native uses back camera - Widgets:
IdCaptureCard,VerificationInstructions,VerificationStepIndicator,CameraPreviewOverlay - Navigation: Submit →
HomeMarketplaceScreen(after success dialog)
HomeMarketplaceScreen
- Purpose: Main browsing hub. Grid of listings with search, filter, and category quick-links
- Key Logic: Debounced search (300ms
Timer).ScrollControllerlistener for infinite scroll trigger.FilterBottomSheetWidgetfor multi-criteria filtering. Long-press on listing card shows quick actions bottom sheet - Widgets:
SearchBarWidget,FilterChipWidget,ListingCardWidget,EmptyStateWidget,FilterBottomSheetWidget - Navigation: Listing tap →
ListingDetailsScreen(with listing as argument). FAB/bottom bar →CreateListingScreen
ListingDetailsScreen
- Purpose: Full listing view with images, description, seller info, and rental/purchase actions
- Key Logic:
ImageCarouselWidgetfor photo gallery. Collapsible description (5-line limit with "Read More").RentalDurationBottomSheetfor rental initiation.Share.share()for native sharing - Widgets:
ImageCarouselWidget,SellerInfoCardWidget,RentalInfoCardWidget,RentalDurationBottomSheet - Note: Currently ignores route arguments and always shows mock MacBook Pro data (BUG-16)
CreateListingScreen
- Purpose: Form to create a new marketplace listing with photos, details, and pricing
- Key Logic:
ImagePickerfor camera/gallery photo selection (max 8 photos). Form validation with per-field error state. Pricing type toggle (sell / rent / both) shows/hides relevant price fields. Draft auto-save hooks (not yet implemented) - Widgets:
PhotoGalleryWidget,CategorySelectorWidget,ConditionSelectorWidget,PricingSectionWidget - Navigation: Post success →
HomeMarketplaceScreen
ChatScreen (Inbox)
- Purpose: List of all active conversations
- Key Logic: Mock conversation list with unread count badges, online status indicators, and listing context tags. Pull-to-refresh. Filter tabs (All/Unread/Archived) are rendered but non-functional
- Navigation: Conversation tap →
IndividualChatScreen
IndividualChatScreen
- Purpose: Real-time messaging interface between buyer and seller
- Key Logic: Message list with
ListView.builder. Typing indicator simulation viaFuture.delayed.ChatInputWidgetwith image attachment support. Long-press on message shows copy/delete/report options. Quick action chips for common messages - Widgets:
ListingContextCardWidget,QuickActionChipWidget,MessageBubbleWidget,TypingIndicatorWidget,ChatInputWidget
RentalManagementScreen
- Purpose: Tracks active rentals and rental history with countdown timers
- Key Logic:
TabControllerfor Active/History tabs.Slidablelist items with Contact/Details/Report swipe actions. Overdue rentals visually distinguished. Rating dialog for completed rentals. Timer updates via recursiveFuture.delayed(see BUG-19) - Widgets:
RentalCardWidget,RentalHistoryCardWidget,EmptyStateWidget
ProfileScreen
- Purpose: User profile, verification status, trust score, stats, and account management
- Key Logic: Verification status drives conditional UI (pending/rejected shows
VerificationStatusWidget, approved showsTrustScoreWidget). Trust score breakdown bottom sheet. Logout with confirmation dialog - Widgets:
ProfileHeaderWidget,VerificationStatusWidget,TrustScoreWidget,StatsSectionWidget,MenuItemWidget
9. Shared Widgets
CustomAppBar
Implements PreferredSizeWidget. Four variants:
standard— title + optional actionssearch— embedded searchTextFieldtransparent— for image backgroundsminimal— back button only, no title
Additional variants: CustomAppBarWithTrustScore, CustomAppBarWithTimer
CustomBottomBar
Floating pill-shaped bottom navigation with 4 items (Browse, Messages, Rentals, Profile) and a central + FAB for creating listings. Note: Has compile errors (BUG-02, BUG-03).
CustomErrorWidget
Global error fallback. Displays sad_face.svg, error message, and a back/home button. Installed as ErrorWidget.builder in main.dart.
CustomIconWidget
Maps string icon names to IconData. Contains a comprehensive icon map covering the full Material Icons set. Used throughout the app to allow icon names to be passed as strings (e.g., from data models).
CustomImageWidget
Multi-source image widget supporting:
- Network URLs →
CachedNetworkImage - Local file paths →
Image.file(native) /Image.network(web) - SVG assets →
SvgPicture.asset - Asset paths →
Image.asset - Falls back to
assets/images/no-image.jpgon error
10. Platform Considerations
Web
Platform.isIOS/Platform.isAndroidmust not be used — usekIsWebanddefaultTargetPlatformfrompackage:flutter/foundation.dart- Apple Sign In button is hidden on web (
!kIsWeb && defaultTargetPlatform == TargetPlatform.iOS) - Camera uses front-facing lens on web
- File images use
Image.networkinstead ofImage.fileon web
Android
AndroidManifest.xmldeclaresINTERNET,CAMERA,READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE,ACCESS_FINE_LOCATION,ACCESS_COARSE_LOCATIONpermissions (verify current manifest)minSdkVersionshould be 21+ forcamerapackage compatibility
iOS
Info.plistrequiresNSCameraUsageDescription,NSLocationWhenInUseUsageDescription,NSPhotoLibraryUsageDescription- Apple Sign In requires
Sign In with Applecapability in Xcode
11. Known Issues Summary
See errors.md for the full tracker and phased fix plan. Critical open items:
| ID | Issue | Severity | Phase |
|---|---|---|---|
| GAP-14 | Listing not marked sold after purchase | 🔴 HIGH | B |
| GAP-18 | Trust score service never called after transactions | 🟠 MEDIUM | C |
| GAP-20 | Phone OTP auth has no UI | 🟠 MEDIUM | D |
12. Environment & Configuration
env.json
Located at project root. Contains environment-specific configuration (Gemini API key, Razorpay keys, Cloudinary credentials, etc.). This file should not be committed to version control. Add to .gitignore immediately and rotate any exposed keys.
Active keys used by the app:
geminiApiKey— used byGeminiOcrServiceandGeminiIdVerificationServicerazorpayKeyId/razorpayKeySecret— used byPaymentService(secret must move to Cloud Function)cloudinaryCloudName/cloudinaryApiKey/cloudinaryApiSecret— used byCloudinaryService
Dead keys (defined but never used — safe to remove):
supabaseUrl,supabaseAnonKey— app uses Firebase, not SupabaseopenaiApiKey,anthropicApiKey,perplexityApiKey— no AI provider other than Gemini is used
Firebase
The project uses Firebase for Auth, Firestore, and Storage. Configuration is in firebase_options.dart (generated by FlutterFire CLI) and GoogleService-Info.plist (iOS) / google-services.json (Android).
# Reconfigure Firebase (regenerates firebase_options.dart)
flutterfire configure --project=swopix-cbf7c
⚠️ Firebase Security Rules for Firestore and Storage must be configured before production launch to prevent unauthorized reads/writes.
Flutter SDK
The project requires Flutter SDK ^3.6.0. Ensure flutter is in your system PATH. Run flutter doctor to verify setup.
Running the App
# Install dependencies
flutter pub get
# Run on Android
flutter run -d android
# Run on iOS
flutter run -d ios
# Run on Chrome (web)
flutter run -d chrome
Build
# Android APK
flutter build apk --release
# iOS
flutter build ios --release
# Web
flutter build web --release