[{"data":1,"prerenderedAt":8574},["ShallowReactive",2],{"navigation":3,"articles":33},[4],{"title":5,"path":6,"stem":7,"children":8,"page":32},"Articles","/articles","articles",[9,13,17,21,25,28],{"title":10,"path":11,"stem":12},"Firebase Crashlytics for Flutter: Setup, Mindset, and Real-World Usage","/articles/firebase-crashlytics","articles/firebase-crashlytics",{"title":14,"path":15,"stem":16},"Flutter Architectural Overview: Framework, Engine, and Embedder Explained","/articles/flutter-architectural-overview","articles/flutter-architectural-overview",{"title":18,"path":19,"stem":20},"Flutter Core Trees Explained: Widget, Element, and RenderObject","/articles/flutter-core-trees","articles/flutter-core-trees",{"title":22,"path":23,"stem":24},"Flutter Environment Setup: Dev vs Prod the Right Way","/articles/flutter-environment-setup","articles/flutter-environment-setup",{"title":22,"path":26,"stem":27},"/articles/flutter-environment-setup-old","articles/flutter-environment-setup-old",{"title":29,"path":30,"stem":31},"why print() in Flutter is giving broke college student energy 💀","/articles/flutter-production-grade-logging","articles/flutter-production-grade-logging",false,[34,3447],{"id":35,"title":10,"author":36,"body":37,"date":3434,"description":3435,"extension":3436,"image":3437,"meta":3438,"minRead":36,"navigation":476,"path":11,"seo":3439,"series":3440,"status":3441,"stem":12,"tags":3442,"__hash__":3446},"articles/articles/firebase-crashlytics.md",null,{"type":38,"value":39,"toc":3393},"minimark",[40,57,64,73,81,84,89,92,111,118,125,127,131,134,145,148,162,169,172,174,178,184,187,200,203,217,220,231,233,237,240,261,264,270,273,275,279,284,291,305,308,310,314,317,320,334,337,340,342,346,349,352,363,366,368,372,375,378,389,392,394,398,401,415,421,423,427,430,546,548,552,555,768,770,774,777,926,928,932,935,1079,1081,1085,1088,1634,1636,1640,1643,1647,1756,1760,1858,1863,1926,1928,1932,1935,1955,1958,1960,1964,1970,1973,1987,1994,1997,2001,2151,2153,2157,2160,2284,2286,2290,2293,2421,2423,2427,2430,2464,2466,2470,2473,2704,2706,2710,2716,2719,2730,2733,2736,2740,3049,3055,3057,3061,3064,3081,3087,3089,3093,3096,3107,3118,3121,3123,3127,3130,3156,3159,3161,3165,3174,3177,3191,3197,3200,3202,3206,3210,3292,3296,3381,3383,3389],[41,42,43,51],"hero",{},[44,45,47],"h1",{"id":46},"",[48,49],"binding",{"value":50},"$doc.title",[52,53,54],"p",{},[48,55],{"value":56},"$doc.description",[52,58,59,60,63],{},"Your Flutter app works perfectly on your phone.",[61,62],"br",{},"\nThen users install it… and suddenly it crashes 😬",[52,65,66,67,69,70,72],{},"No screenshots.",[61,68],{},"\nNo logs.",[61,71],{},"\nJust bad reviews.",[52,74,75,76,80],{},"That's where ",[77,78,79],"strong",{},"Firebase Crashlytics"," saves you.",[82,83],"hr",{},[85,86,88],"h2",{"id":87},"overview","🧠 Overview",[52,90,91],{},"Firebase Crashlytics is a crash reporting tool that tells you:",[93,94,95,99,102,105,108],"ul",{},[96,97,98],"li",{},"When your app crashes",[96,100,101],{},"Why it crashed",[96,103,104],{},"Which screen the user was on",[96,106,107],{},"How many users are affected",[96,109,110],{},"Whether the issue is new or recurring",[52,112,113,114,117],{},"Instead of guessing, you ",[77,115,116],{},"see real production problems"," in real time.",[52,119,120,121,124],{},"This guide explains Crashlytics the way ",[77,122,123],{},"real Flutter teams use it",", not just how to \"enable a package\".",[82,126],{},[85,128,130],{"id":129},"why-crashlytics-matters-especially-for-beginners","🚦 Why Crashlytics Matters (Especially for Beginners)",[52,132,133],{},"When you're new to Flutter, crashes feel obvious:",[93,135,136,139,142],{},[96,137,138],{},"Red error screens",[96,140,141],{},"Debug logs everywhere",[96,143,144],{},"Instant feedback",[52,146,147],{},"But in production:",[93,149,150,153,156,159],{},[96,151,152],{},"Errors are silent",[96,154,155],{},"Users don't report bugs",[96,157,158],{},"Issues happen on devices you don't own",[96,160,161],{},"Timing and environment matter",[52,163,164,165,168],{},"Crashlytics becomes your ",[77,166,167],{},"eyes inside production",".",[52,170,171],{},"If you plan to publish apps seriously — this is not optional.",[82,173],{},[85,175,177],{"id":176},"dev-vs-prod-the-most-important-concept","🌍 Dev vs Prod: The Most Important Concept",[52,179,180,181,168],{},"Professional Flutter apps ",[77,182,183],{},"never use one Firebase project",[52,185,186],{},"They use:",[93,188,189,195],{},[96,190,191,192],{},"One Firebase project for ",[77,193,194],{},"development",[96,196,191,197],{},[77,198,199],{},"production",[52,201,202],{},"Why?",[93,204,205,208,211,214],{},[96,206,207],{},"Test crashes should never pollute real user data",[96,209,210],{},"Production crashes need clean, reliable signals",[96,212,213],{},"Experiments must stay isolated",[96,215,216],{},"Mistakes must be contained",[52,218,219],{},"Crashlytics works best when it clearly knows:",[93,221,222,225,228],{},[96,223,224],{},"Which environment it's running in",[96,226,227],{},"Which build caused the crash",[96,229,230],{},"Whether users are real or test users",[82,232],{},[85,234,236],{"id":235},"how-crashlytics-fits-into-your-app","🧩 How Crashlytics Fits Into Your App",[52,238,239],{},"Conceptually, Crashlytics works like this:",[241,242,243,246,249,252,255,258],"ol",{},[96,244,245],{},"App starts",[96,247,248],{},"Firebase initializes",[96,250,251],{},"Crashlytics attaches error listeners",[96,253,254],{},"Environment context is set",[96,256,257],{},"App runs normally",[96,259,260],{},"If something breaks → Crashlytics reports it",[52,262,263],{},"The key idea:",[265,266,267],"blockquote",{},[52,268,269],{},"Crashlytics runs quietly in the background until something goes wrong.",[52,271,272],{},"You don't \"use\" it daily — it protects you silently.",[82,274],{},[85,276,278],{"id":277},"firebase-setup-guidelines-beginner-friendly","🛠 Firebase Setup Guidelines (Beginner-Friendly)",[280,281,283],"h3",{"id":282},"step-1-create-two-firebase-projects","Step 1: Create Two Firebase Projects",[52,285,286,287,290],{},"You need ",[77,288,289],{},"two projects",", not one.",[93,292,293,299],{},[96,294,295,296,298],{},"Development project",[61,297],{},"\nUsed for testing crashes, logs, experiments",[96,300,301,302,304],{},"Production project",[61,303],{},"\nUsed for real users and real monitoring",[52,306,307],{},"This separation is the foundation of safe apps.",[82,309],{},[280,311,313],{"id":312},"step-2-register-your-android-apps","Step 2: Register Your Android Apps",[52,315,316],{},"Each Firebase project needs its own Android app entry.",[52,318,319],{},"That means:",[93,321,322,328],{},[96,323,324,325],{},"Dev app uses a ",[77,326,327],{},"dev package name",[96,329,330,331],{},"Prod app uses the ",[77,332,333],{},"real package name",[52,335,336],{},"Each app downloads its own Firebase configuration file.",[52,338,339],{},"Never mix these files.",[82,341],{},[280,343,345],{"id":344},"step-3-enable-crashlytics-in-firebase-console","Step 3: Enable Crashlytics in Firebase Console",[52,347,348],{},"Crashlytics is not active by default.",[52,350,351],{},"For each Firebase project:",[93,353,354,357,360],{},[96,355,356],{},"Open the Crashlytics section",[96,358,359],{},"Enable it",[96,361,362],{},"Complete the onboarding steps",[52,364,365],{},"Do this for both dev and prod projects.",[82,367],{},[280,369,371],{"id":370},"step-4-store-firebase-values-in-environment-configs","Step 4: Store Firebase Values in Environment Configs",[52,373,374],{},"Professional Flutter apps never hardcode Firebase values.",[52,376,377],{},"Instead:",[93,379,380,383,386],{},[96,381,382],{},"Development values live in dev configuration",[96,384,385],{},"Production values live in prod configuration",[96,387,388],{},"App selects the correct setup at launch",[52,390,391],{},"This keeps environments clean, predictable, and safe.",[82,393],{},[280,395,397],{"id":396},"step-5-verify-setup-before-shipping","Step 5: Verify Setup Before Shipping",[52,399,400],{},"Before publishing:",[93,402,403,406,409,412],{},[96,404,405],{},"Trigger a test crash in development",[96,407,408],{},"Confirm it appears in Firebase Console",[96,410,411],{},"Check environment labels",[96,413,414],{},"Confirm user context appears correctly",[52,416,417,418,168],{},"If you don't test Crashlytics, you ",[77,419,420],{},"don't actually have monitoring",[82,422],{},[85,424,426],{"id":425},"environment-configuration-structure","📋 Environment Configuration Structure",[52,428,429],{},"Here's how you structure environment-specific settings:",[431,432,436],"pre",{"className":433,"code":434,"language":435,"meta":46,"style":46},"language-dart shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","// lib/config/environment.dart\nenum Environment {\n  development,\n  production,\n}\n\nclass EnvironmentConfig {\n  static Environment _environment = Environment.development;\n\n  static Environment get environment => _environment;\n\n  static void setEnvironment(Environment env) {\n    _environment = env;\n  }\n\n  static bool get isDevelopment => _environment == Environment.development;\n  static bool get isProduction => _environment == Environment.production;\n}\n","dart",[437,438,439,447,453,459,465,471,478,484,490,495,501,506,512,518,524,529,535,541],"code",{"__ignoreMap":46},[440,441,444],"span",{"class":442,"line":443},"line",1,[440,445,446],{},"// lib/config/environment.dart\n",[440,448,450],{"class":442,"line":449},2,[440,451,452],{},"enum Environment {\n",[440,454,456],{"class":442,"line":455},3,[440,457,458],{},"  development,\n",[440,460,462],{"class":442,"line":461},4,[440,463,464],{},"  production,\n",[440,466,468],{"class":442,"line":467},5,[440,469,470],{},"}\n",[440,472,474],{"class":442,"line":473},6,[440,475,477],{"emptyLinePlaceholder":476},true,"\n",[440,479,481],{"class":442,"line":480},7,[440,482,483],{},"class EnvironmentConfig {\n",[440,485,487],{"class":442,"line":486},8,[440,488,489],{},"  static Environment _environment = Environment.development;\n",[440,491,493],{"class":442,"line":492},9,[440,494,477],{"emptyLinePlaceholder":476},[440,496,498],{"class":442,"line":497},10,[440,499,500],{},"  static Environment get environment => _environment;\n",[440,502,504],{"class":442,"line":503},11,[440,505,477],{"emptyLinePlaceholder":476},[440,507,509],{"class":442,"line":508},12,[440,510,511],{},"  static void setEnvironment(Environment env) {\n",[440,513,515],{"class":442,"line":514},13,[440,516,517],{},"    _environment = env;\n",[440,519,521],{"class":442,"line":520},14,[440,522,523],{},"  }\n",[440,525,527],{"class":442,"line":526},15,[440,528,477],{"emptyLinePlaceholder":476},[440,530,532],{"class":442,"line":531},16,[440,533,534],{},"  static bool get isDevelopment => _environment == Environment.development;\n",[440,536,538],{"class":442,"line":537},17,[440,539,540],{},"  static bool get isProduction => _environment == Environment.production;\n",[440,542,544],{"class":442,"line":543},18,[440,545,470],{},[82,547],{},[85,549,551],{"id":550},"app-configuration-model","🔧 App Configuration Model",[52,553,554],{},"Create a configuration model that holds all environment-specific values:",[431,556,558],{"className":433,"code":557,"language":435,"meta":46,"style":46},"// lib/config/app_config.dart\nclass AppConfig {\n  final Environment environment;\n  final String apiBaseUrl;\n\n  // Firebase configuration\n  final String firebaseApiKey;\n  final String firebaseAppId;\n  final String firebaseMessagingSenderId;\n  final String firebaseProjectId;\n\n  // Feature flags\n  final Map\u003CString, bool> featureFlags;\n\n  // Debug settings\n  final bool debugMode;\n  final int logLevel; // 0=DEBUG, 1=INFO, 2=WARNING, 3=ERROR\n\n  final String appName;\n  final String applicationId;\n\n  const AppConfig({\n    required this.environment,\n    required this.apiBaseUrl,\n    required this.firebaseApiKey,\n    required this.firebaseAppId,\n    required this.firebaseMessagingSenderId,\n    required this.firebaseProjectId,\n    required this.featureFlags,\n    required this.debugMode,\n    required this.logLevel,\n    required this.appName,\n    required this.applicationId,\n  });\n\n  bool isFeatureEnabled(String featureName) {\n    return featureFlags[featureName] ?? false;\n  }\n}\n",[437,559,560,565,570,575,580,584,589,594,599,604,609,613,618,623,627,632,637,642,646,652,658,663,669,675,681,687,693,699,705,711,717,723,729,735,741,746,752,758,763],{"__ignoreMap":46},[440,561,562],{"class":442,"line":443},[440,563,564],{},"// lib/config/app_config.dart\n",[440,566,567],{"class":442,"line":449},[440,568,569],{},"class AppConfig {\n",[440,571,572],{"class":442,"line":455},[440,573,574],{},"  final Environment environment;\n",[440,576,577],{"class":442,"line":461},[440,578,579],{},"  final String apiBaseUrl;\n",[440,581,582],{"class":442,"line":467},[440,583,477],{"emptyLinePlaceholder":476},[440,585,586],{"class":442,"line":473},[440,587,588],{},"  // Firebase configuration\n",[440,590,591],{"class":442,"line":480},[440,592,593],{},"  final String firebaseApiKey;\n",[440,595,596],{"class":442,"line":486},[440,597,598],{},"  final String firebaseAppId;\n",[440,600,601],{"class":442,"line":492},[440,602,603],{},"  final String firebaseMessagingSenderId;\n",[440,605,606],{"class":442,"line":497},[440,607,608],{},"  final String firebaseProjectId;\n",[440,610,611],{"class":442,"line":503},[440,612,477],{"emptyLinePlaceholder":476},[440,614,615],{"class":442,"line":508},[440,616,617],{},"  // Feature flags\n",[440,619,620],{"class":442,"line":514},[440,621,622],{},"  final Map\u003CString, bool> featureFlags;\n",[440,624,625],{"class":442,"line":520},[440,626,477],{"emptyLinePlaceholder":476},[440,628,629],{"class":442,"line":526},[440,630,631],{},"  // Debug settings\n",[440,633,634],{"class":442,"line":531},[440,635,636],{},"  final bool debugMode;\n",[440,638,639],{"class":442,"line":537},[440,640,641],{},"  final int logLevel; // 0=DEBUG, 1=INFO, 2=WARNING, 3=ERROR\n",[440,643,644],{"class":442,"line":543},[440,645,477],{"emptyLinePlaceholder":476},[440,647,649],{"class":442,"line":648},19,[440,650,651],{},"  final String appName;\n",[440,653,655],{"class":442,"line":654},20,[440,656,657],{},"  final String applicationId;\n",[440,659,661],{"class":442,"line":660},21,[440,662,477],{"emptyLinePlaceholder":476},[440,664,666],{"class":442,"line":665},22,[440,667,668],{},"  const AppConfig({\n",[440,670,672],{"class":442,"line":671},23,[440,673,674],{},"    required this.environment,\n",[440,676,678],{"class":442,"line":677},24,[440,679,680],{},"    required this.apiBaseUrl,\n",[440,682,684],{"class":442,"line":683},25,[440,685,686],{},"    required this.firebaseApiKey,\n",[440,688,690],{"class":442,"line":689},26,[440,691,692],{},"    required this.firebaseAppId,\n",[440,694,696],{"class":442,"line":695},27,[440,697,698],{},"    required this.firebaseMessagingSenderId,\n",[440,700,702],{"class":442,"line":701},28,[440,703,704],{},"    required this.firebaseProjectId,\n",[440,706,708],{"class":442,"line":707},29,[440,709,710],{},"    required this.featureFlags,\n",[440,712,714],{"class":442,"line":713},30,[440,715,716],{},"    required this.debugMode,\n",[440,718,720],{"class":442,"line":719},31,[440,721,722],{},"    required this.logLevel,\n",[440,724,726],{"class":442,"line":725},32,[440,727,728],{},"    required this.appName,\n",[440,730,732],{"class":442,"line":731},33,[440,733,734],{},"    required this.applicationId,\n",[440,736,738],{"class":442,"line":737},34,[440,739,740],{},"  });\n",[440,742,744],{"class":442,"line":743},35,[440,745,477],{"emptyLinePlaceholder":476},[440,747,749],{"class":442,"line":748},36,[440,750,751],{},"  bool isFeatureEnabled(String featureName) {\n",[440,753,755],{"class":442,"line":754},37,[440,756,757],{},"    return featureFlags[featureName] ?? false;\n",[440,759,761],{"class":442,"line":760},38,[440,762,523],{},[440,764,766],{"class":442,"line":765},39,[440,767,470],{},[82,769],{},[85,771,773],{"id":772},"development-configuration","🛠 Development Configuration",[52,775,776],{},"Your development config should have all debugging features enabled:",[431,778,780],{"className":433,"code":779,"language":435,"meta":46,"style":46},"// lib/config/env/dev_config.dart\nclass DevConfig {\n  static AppConfig get config => const AppConfig(\n    environment: Environment.development,\n\n    // Development API endpoint\n    apiBaseUrl: 'https://dev-api.yourapp.com',\n\n    // Firebase Development Project\n    firebaseApiKey: 'YOUR_DEV_FIREBASE_API_KEY',\n    firebaseAppId: 'YOUR_DEV_FIREBASE_APP_ID',\n    firebaseMessagingSenderId: 'YOUR_DEV_MESSAGING_SENDER_ID',\n    firebaseProjectId: 'your-app-dev',\n\n    // All features enabled for testing\n    featureFlags: {\n      'enable_dark_mode': true,\n      'enable_notifications': true,\n      'enable_analytics': true,\n      'enable_crashlytics': true,\n      'enable_beta_features': true,\n    },\n\n    debugMode: true,\n    logLevel: 0, // DEBUG - verbose logging\n\n    appName: 'Social App Dev',\n    applicationId: 'com.yourapp.social.dev',\n  );\n}\n",[437,781,782,787,792,797,802,806,811,816,820,825,830,835,840,845,849,854,859,864,869,874,879,884,889,893,898,903,907,912,917,922],{"__ignoreMap":46},[440,783,784],{"class":442,"line":443},[440,785,786],{},"// lib/config/env/dev_config.dart\n",[440,788,789],{"class":442,"line":449},[440,790,791],{},"class DevConfig {\n",[440,793,794],{"class":442,"line":455},[440,795,796],{},"  static AppConfig get config => const AppConfig(\n",[440,798,799],{"class":442,"line":461},[440,800,801],{},"    environment: Environment.development,\n",[440,803,804],{"class":442,"line":467},[440,805,477],{"emptyLinePlaceholder":476},[440,807,808],{"class":442,"line":473},[440,809,810],{},"    // Development API endpoint\n",[440,812,813],{"class":442,"line":480},[440,814,815],{},"    apiBaseUrl: 'https://dev-api.yourapp.com',\n",[440,817,818],{"class":442,"line":486},[440,819,477],{"emptyLinePlaceholder":476},[440,821,822],{"class":442,"line":492},[440,823,824],{},"    // Firebase Development Project\n",[440,826,827],{"class":442,"line":497},[440,828,829],{},"    firebaseApiKey: 'YOUR_DEV_FIREBASE_API_KEY',\n",[440,831,832],{"class":442,"line":503},[440,833,834],{},"    firebaseAppId: 'YOUR_DEV_FIREBASE_APP_ID',\n",[440,836,837],{"class":442,"line":508},[440,838,839],{},"    firebaseMessagingSenderId: 'YOUR_DEV_MESSAGING_SENDER_ID',\n",[440,841,842],{"class":442,"line":514},[440,843,844],{},"    firebaseProjectId: 'your-app-dev',\n",[440,846,847],{"class":442,"line":520},[440,848,477],{"emptyLinePlaceholder":476},[440,850,851],{"class":442,"line":526},[440,852,853],{},"    // All features enabled for testing\n",[440,855,856],{"class":442,"line":531},[440,857,858],{},"    featureFlags: {\n",[440,860,861],{"class":442,"line":537},[440,862,863],{},"      'enable_dark_mode': true,\n",[440,865,866],{"class":442,"line":543},[440,867,868],{},"      'enable_notifications': true,\n",[440,870,871],{"class":442,"line":648},[440,872,873],{},"      'enable_analytics': true,\n",[440,875,876],{"class":442,"line":654},[440,877,878],{},"      'enable_crashlytics': true,\n",[440,880,881],{"class":442,"line":660},[440,882,883],{},"      'enable_beta_features': true,\n",[440,885,886],{"class":442,"line":665},[440,887,888],{},"    },\n",[440,890,891],{"class":442,"line":671},[440,892,477],{"emptyLinePlaceholder":476},[440,894,895],{"class":442,"line":677},[440,896,897],{},"    debugMode: true,\n",[440,899,900],{"class":442,"line":683},[440,901,902],{},"    logLevel: 0, // DEBUG - verbose logging\n",[440,904,905],{"class":442,"line":689},[440,906,477],{"emptyLinePlaceholder":476},[440,908,909],{"class":442,"line":695},[440,910,911],{},"    appName: 'Social App Dev',\n",[440,913,914],{"class":442,"line":701},[440,915,916],{},"    applicationId: 'com.yourapp.social.dev',\n",[440,918,919],{"class":442,"line":707},[440,920,921],{},"  );\n",[440,923,924],{"class":442,"line":713},[440,925,470],{},[82,927],{},[85,929,931],{"id":930},"production-configuration","🚀 Production Configuration",[52,933,934],{},"Production config should be locked down and production-ready:",[431,936,938],{"className":433,"code":937,"language":435,"meta":46,"style":46},"// lib/config/env/prod_config.dart\nclass ProdConfig {\n  static AppConfig get config => const AppConfig(\n    environment: Environment.production,\n\n    // Production API endpoint\n    apiBaseUrl: 'https://api.yourapp.com',\n\n    // Firebase Production Project (different from dev!)\n    firebaseApiKey: 'YOUR_PROD_FIREBASE_API_KEY',\n    firebaseAppId: 'YOUR_PROD_FIREBASE_APP_ID',\n    firebaseMessagingSenderId: 'YOUR_PROD_MESSAGING_SENDER_ID',\n    firebaseProjectId: 'your-app-prod',\n\n    // Controlled feature rollout\n    featureFlags: {\n      'enable_dark_mode': true,\n      'enable_notifications': true,\n      'enable_analytics': true,\n      'enable_crashlytics': true,\n      'enable_beta_features': false, // Beta features disabled\n    },\n\n    debugMode: false,\n    logLevel: 1, // INFO - production logging only\n\n    appName: 'Social App',\n    applicationId: 'com.yourapp.social',\n  );\n}\n",[437,939,940,945,950,954,959,963,968,973,977,982,987,992,997,1002,1006,1011,1015,1019,1023,1027,1031,1039,1043,1047,1052,1057,1061,1066,1071,1075],{"__ignoreMap":46},[440,941,942],{"class":442,"line":443},[440,943,944],{},"// lib/config/env/prod_config.dart\n",[440,946,947],{"class":442,"line":449},[440,948,949],{},"class ProdConfig {\n",[440,951,952],{"class":442,"line":455},[440,953,796],{},[440,955,956],{"class":442,"line":461},[440,957,958],{},"    environment: Environment.production,\n",[440,960,961],{"class":442,"line":467},[440,962,477],{"emptyLinePlaceholder":476},[440,964,965],{"class":442,"line":473},[440,966,967],{},"    // Production API endpoint\n",[440,969,970],{"class":442,"line":480},[440,971,972],{},"    apiBaseUrl: 'https://api.yourapp.com',\n",[440,974,975],{"class":442,"line":486},[440,976,477],{"emptyLinePlaceholder":476},[440,978,979],{"class":442,"line":492},[440,980,981],{},"    // Firebase Production Project (different from dev!)\n",[440,983,984],{"class":442,"line":497},[440,985,986],{},"    firebaseApiKey: 'YOUR_PROD_FIREBASE_API_KEY',\n",[440,988,989],{"class":442,"line":503},[440,990,991],{},"    firebaseAppId: 'YOUR_PROD_FIREBASE_APP_ID',\n",[440,993,994],{"class":442,"line":508},[440,995,996],{},"    firebaseMessagingSenderId: 'YOUR_PROD_MESSAGING_SENDER_ID',\n",[440,998,999],{"class":442,"line":514},[440,1000,1001],{},"    firebaseProjectId: 'your-app-prod',\n",[440,1003,1004],{"class":442,"line":520},[440,1005,477],{"emptyLinePlaceholder":476},[440,1007,1008],{"class":442,"line":526},[440,1009,1010],{},"    // Controlled feature rollout\n",[440,1012,1013],{"class":442,"line":531},[440,1014,858],{},[440,1016,1017],{"class":442,"line":537},[440,1018,863],{},[440,1020,1021],{"class":442,"line":543},[440,1022,868],{},[440,1024,1025],{"class":442,"line":648},[440,1026,873],{},[440,1028,1029],{"class":442,"line":654},[440,1030,878],{},[440,1032,1033,1036],{"class":442,"line":660},[440,1034,1035],{},"      'enable_beta_features': false,",[440,1037,1038],{}," // Beta features disabled\n",[440,1040,1041],{"class":442,"line":665},[440,1042,888],{},[440,1044,1045],{"class":442,"line":671},[440,1046,477],{"emptyLinePlaceholder":476},[440,1048,1049],{"class":442,"line":677},[440,1050,1051],{},"    debugMode: false,\n",[440,1053,1054],{"class":442,"line":683},[440,1055,1056],{},"    logLevel: 1, // INFO - production logging only\n",[440,1058,1059],{"class":442,"line":689},[440,1060,477],{"emptyLinePlaceholder":476},[440,1062,1063],{"class":442,"line":695},[440,1064,1065],{},"    appName: 'Social App',\n",[440,1067,1068],{"class":442,"line":701},[440,1069,1070],{},"    applicationId: 'com.yourapp.social',\n",[440,1072,1073],{"class":442,"line":707},[440,1074,921],{},[440,1076,1077],{"class":442,"line":713},[440,1078,470],{},[82,1080],{},[85,1082,1084],{"id":1083},"firebase-service-implementation","🔥 Firebase Service Implementation",[52,1086,1087],{},"Create a dedicated service to manage Firebase and Crashlytics:",[431,1089,1091],{"className":433,"code":1090,"language":435,"meta":46,"style":46},"// lib/core/services/firebase_service.dart\nimport 'package:firebase_core/firebase_core.dart';\nimport 'package:firebase_crashlytics/firebase_crashlytics.dart';\nimport 'package:flutter/foundation.dart';\n\nclass FirebaseService {\n  static FirebaseService? _instance;\n  static FirebaseService get instance => _instance ??= FirebaseService._();\n\n  FirebaseService._();\n\n  bool _isInitialized = false;\n\n  /// Initialize Firebase and Crashlytics\n  Future\u003Cvoid> initialize(AppConfig config) async {\n    if (_isInitialized) return;\n\n    // Initialize Firebase with manual configuration\n    await Firebase.initializeApp(\n      options: FirebaseOptions(\n        apiKey: config.firebaseApiKey,\n        appId: config.firebaseAppId,\n        messagingSenderId: config.firebaseMessagingSenderId,\n        projectId: config.firebaseProjectId,\n      ),\n    );\n\n    // Initialize Crashlytics\n    await _initializeCrashlytics(config);\n\n    _isInitialized = true;\n  }\n\n  Future\u003Cvoid> _initializeCrashlytics(AppConfig config) async {\n    final crashlytics = FirebaseCrashlytics.instance;\n\n    // Check if Crashlytics is enabled via feature flag\n    if (!config.isFeatureEnabled('enable_crashlytics')) {\n      await crashlytics.setCrashlyticsCollectionEnabled(false);\n      return;\n    }\n\n    // Enable Crashlytics\n    await crashlytics.setCrashlyticsCollectionEnabled(true);\n\n    // Set environment context\n    await crashlytics.setCustomKey('environment', config.environment.name);\n    await crashlytics.setCustomKey('app_name', config.appName);\n    await crashlytics.setCustomKey('debug_mode', config.debugMode);\n\n    // Capture all Flutter errors\n    FlutterError.onError = (errorDetails) {\n      FirebaseCrashlytics.instance.recordFlutterFatalError(errorDetails);\n    };\n\n    // Capture all async errors\n    PlatformDispatcher.instance.onError = (error, stack) {\n      FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);\n      return true;\n    };\n  }\n\n  /// Set user identifier\n  Future\u003Cvoid> setUserIdentifier(String userId) async {\n    if (!_isInitialized) return;\n    await FirebaseCrashlytics.instance.setUserIdentifier(userId);\n  }\n\n  /// Clear user identifier (logout)\n  Future\u003Cvoid> clearUserIdentifier() async {\n    if (!_isInitialized) return;\n    await FirebaseCrashlytics.instance.setUserIdentifier('');\n  }\n\n  /// Set custom key-value for context\n  Future\u003Cvoid> setCustomKey(String key, dynamic value) async {\n    if (!_isInitialized) return;\n    await FirebaseCrashlytics.instance.setCustomKey(key, value);\n  }\n\n  /// Log breadcrumb message\n  Future\u003Cvoid> log(String message) async {\n    if (!_isInitialized) return;\n    await FirebaseCrashlytics.instance.log(message);\n  }\n\n  /// Record non-fatal exception\n  Future\u003Cvoid> recordException(\n    dynamic exception,\n    StackTrace? stackTrace, {\n    String? reason,\n    bool fatal = false,\n  }) async {\n    if (!_isInitialized) return;\n    await FirebaseCrashlytics.instance.recordError(\n      exception,\n      stackTrace,\n      reason: reason,\n      fatal: fatal,\n    );\n  }\n}\n",[437,1092,1093,1098,1103,1108,1113,1117,1122,1127,1132,1136,1141,1145,1150,1154,1159,1164,1169,1173,1178,1183,1188,1193,1198,1203,1208,1213,1218,1222,1227,1232,1236,1241,1245,1249,1254,1259,1263,1268,1273,1278,1284,1290,1295,1301,1307,1312,1318,1324,1330,1336,1341,1347,1353,1359,1365,1370,1376,1382,1388,1394,1399,1404,1409,1415,1421,1427,1433,1438,1443,1449,1455,1460,1466,1471,1476,1482,1488,1493,1499,1504,1509,1515,1521,1526,1532,1537,1542,1548,1554,1560,1566,1572,1578,1584,1589,1595,1601,1607,1613,1619,1624,1629],{"__ignoreMap":46},[440,1094,1095],{"class":442,"line":443},[440,1096,1097],{},"// lib/core/services/firebase_service.dart\n",[440,1099,1100],{"class":442,"line":449},[440,1101,1102],{},"import 'package:firebase_core/firebase_core.dart';\n",[440,1104,1105],{"class":442,"line":455},[440,1106,1107],{},"import 'package:firebase_crashlytics/firebase_crashlytics.dart';\n",[440,1109,1110],{"class":442,"line":461},[440,1111,1112],{},"import 'package:flutter/foundation.dart';\n",[440,1114,1115],{"class":442,"line":467},[440,1116,477],{"emptyLinePlaceholder":476},[440,1118,1119],{"class":442,"line":473},[440,1120,1121],{},"class FirebaseService {\n",[440,1123,1124],{"class":442,"line":480},[440,1125,1126],{},"  static FirebaseService? _instance;\n",[440,1128,1129],{"class":442,"line":486},[440,1130,1131],{},"  static FirebaseService get instance => _instance ??= FirebaseService._();\n",[440,1133,1134],{"class":442,"line":492},[440,1135,477],{"emptyLinePlaceholder":476},[440,1137,1138],{"class":442,"line":497},[440,1139,1140],{},"  FirebaseService._();\n",[440,1142,1143],{"class":442,"line":503},[440,1144,477],{"emptyLinePlaceholder":476},[440,1146,1147],{"class":442,"line":508},[440,1148,1149],{},"  bool _isInitialized = false;\n",[440,1151,1152],{"class":442,"line":514},[440,1153,477],{"emptyLinePlaceholder":476},[440,1155,1156],{"class":442,"line":520},[440,1157,1158],{},"  /// Initialize Firebase and Crashlytics\n",[440,1160,1161],{"class":442,"line":526},[440,1162,1163],{},"  Future\u003Cvoid> initialize(AppConfig config) async {\n",[440,1165,1166],{"class":442,"line":531},[440,1167,1168],{},"    if (_isInitialized) return;\n",[440,1170,1171],{"class":442,"line":537},[440,1172,477],{"emptyLinePlaceholder":476},[440,1174,1175],{"class":442,"line":543},[440,1176,1177],{},"    // Initialize Firebase with manual configuration\n",[440,1179,1180],{"class":442,"line":648},[440,1181,1182],{},"    await Firebase.initializeApp(\n",[440,1184,1185],{"class":442,"line":654},[440,1186,1187],{},"      options: FirebaseOptions(\n",[440,1189,1190],{"class":442,"line":660},[440,1191,1192],{},"        apiKey: config.firebaseApiKey,\n",[440,1194,1195],{"class":442,"line":665},[440,1196,1197],{},"        appId: config.firebaseAppId,\n",[440,1199,1200],{"class":442,"line":671},[440,1201,1202],{},"        messagingSenderId: config.firebaseMessagingSenderId,\n",[440,1204,1205],{"class":442,"line":677},[440,1206,1207],{},"        projectId: config.firebaseProjectId,\n",[440,1209,1210],{"class":442,"line":683},[440,1211,1212],{},"      ),\n",[440,1214,1215],{"class":442,"line":689},[440,1216,1217],{},"    );\n",[440,1219,1220],{"class":442,"line":695},[440,1221,477],{"emptyLinePlaceholder":476},[440,1223,1224],{"class":442,"line":701},[440,1225,1226],{},"    // Initialize Crashlytics\n",[440,1228,1229],{"class":442,"line":707},[440,1230,1231],{},"    await _initializeCrashlytics(config);\n",[440,1233,1234],{"class":442,"line":713},[440,1235,477],{"emptyLinePlaceholder":476},[440,1237,1238],{"class":442,"line":719},[440,1239,1240],{},"    _isInitialized = true;\n",[440,1242,1243],{"class":442,"line":725},[440,1244,523],{},[440,1246,1247],{"class":442,"line":731},[440,1248,477],{"emptyLinePlaceholder":476},[440,1250,1251],{"class":442,"line":737},[440,1252,1253],{},"  Future\u003Cvoid> _initializeCrashlytics(AppConfig config) async {\n",[440,1255,1256],{"class":442,"line":743},[440,1257,1258],{},"    final crashlytics = FirebaseCrashlytics.instance;\n",[440,1260,1261],{"class":442,"line":748},[440,1262,477],{"emptyLinePlaceholder":476},[440,1264,1265],{"class":442,"line":754},[440,1266,1267],{},"    // Check if Crashlytics is enabled via feature flag\n",[440,1269,1270],{"class":442,"line":760},[440,1271,1272],{},"    if (!config.isFeatureEnabled('enable_crashlytics')) {\n",[440,1274,1275],{"class":442,"line":765},[440,1276,1277],{},"      await crashlytics.setCrashlyticsCollectionEnabled(false);\n",[440,1279,1281],{"class":442,"line":1280},40,[440,1282,1283],{},"      return;\n",[440,1285,1287],{"class":442,"line":1286},41,[440,1288,1289],{},"    }\n",[440,1291,1293],{"class":442,"line":1292},42,[440,1294,477],{"emptyLinePlaceholder":476},[440,1296,1298],{"class":442,"line":1297},43,[440,1299,1300],{},"    // Enable Crashlytics\n",[440,1302,1304],{"class":442,"line":1303},44,[440,1305,1306],{},"    await crashlytics.setCrashlyticsCollectionEnabled(true);\n",[440,1308,1310],{"class":442,"line":1309},45,[440,1311,477],{"emptyLinePlaceholder":476},[440,1313,1315],{"class":442,"line":1314},46,[440,1316,1317],{},"    // Set environment context\n",[440,1319,1321],{"class":442,"line":1320},47,[440,1322,1323],{},"    await crashlytics.setCustomKey('environment', config.environment.name);\n",[440,1325,1327],{"class":442,"line":1326},48,[440,1328,1329],{},"    await crashlytics.setCustomKey('app_name', config.appName);\n",[440,1331,1333],{"class":442,"line":1332},49,[440,1334,1335],{},"    await crashlytics.setCustomKey('debug_mode', config.debugMode);\n",[440,1337,1339],{"class":442,"line":1338},50,[440,1340,477],{"emptyLinePlaceholder":476},[440,1342,1344],{"class":442,"line":1343},51,[440,1345,1346],{},"    // Capture all Flutter errors\n",[440,1348,1350],{"class":442,"line":1349},52,[440,1351,1352],{},"    FlutterError.onError = (errorDetails) {\n",[440,1354,1356],{"class":442,"line":1355},53,[440,1357,1358],{},"      FirebaseCrashlytics.instance.recordFlutterFatalError(errorDetails);\n",[440,1360,1362],{"class":442,"line":1361},54,[440,1363,1364],{},"    };\n",[440,1366,1368],{"class":442,"line":1367},55,[440,1369,477],{"emptyLinePlaceholder":476},[440,1371,1373],{"class":442,"line":1372},56,[440,1374,1375],{},"    // Capture all async errors\n",[440,1377,1379],{"class":442,"line":1378},57,[440,1380,1381],{},"    PlatformDispatcher.instance.onError = (error, stack) {\n",[440,1383,1385],{"class":442,"line":1384},58,[440,1386,1387],{},"      FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);\n",[440,1389,1391],{"class":442,"line":1390},59,[440,1392,1393],{},"      return true;\n",[440,1395,1397],{"class":442,"line":1396},60,[440,1398,1364],{},[440,1400,1402],{"class":442,"line":1401},61,[440,1403,523],{},[440,1405,1407],{"class":442,"line":1406},62,[440,1408,477],{"emptyLinePlaceholder":476},[440,1410,1412],{"class":442,"line":1411},63,[440,1413,1414],{},"  /// Set user identifier\n",[440,1416,1418],{"class":442,"line":1417},64,[440,1419,1420],{},"  Future\u003Cvoid> setUserIdentifier(String userId) async {\n",[440,1422,1424],{"class":442,"line":1423},65,[440,1425,1426],{},"    if (!_isInitialized) return;\n",[440,1428,1430],{"class":442,"line":1429},66,[440,1431,1432],{},"    await FirebaseCrashlytics.instance.setUserIdentifier(userId);\n",[440,1434,1436],{"class":442,"line":1435},67,[440,1437,523],{},[440,1439,1441],{"class":442,"line":1440},68,[440,1442,477],{"emptyLinePlaceholder":476},[440,1444,1446],{"class":442,"line":1445},69,[440,1447,1448],{},"  /// Clear user identifier (logout)\n",[440,1450,1452],{"class":442,"line":1451},70,[440,1453,1454],{},"  Future\u003Cvoid> clearUserIdentifier() async {\n",[440,1456,1458],{"class":442,"line":1457},71,[440,1459,1426],{},[440,1461,1463],{"class":442,"line":1462},72,[440,1464,1465],{},"    await FirebaseCrashlytics.instance.setUserIdentifier('');\n",[440,1467,1469],{"class":442,"line":1468},73,[440,1470,523],{},[440,1472,1474],{"class":442,"line":1473},74,[440,1475,477],{"emptyLinePlaceholder":476},[440,1477,1479],{"class":442,"line":1478},75,[440,1480,1481],{},"  /// Set custom key-value for context\n",[440,1483,1485],{"class":442,"line":1484},76,[440,1486,1487],{},"  Future\u003Cvoid> setCustomKey(String key, dynamic value) async {\n",[440,1489,1491],{"class":442,"line":1490},77,[440,1492,1426],{},[440,1494,1496],{"class":442,"line":1495},78,[440,1497,1498],{},"    await FirebaseCrashlytics.instance.setCustomKey(key, value);\n",[440,1500,1502],{"class":442,"line":1501},79,[440,1503,523],{},[440,1505,1507],{"class":442,"line":1506},80,[440,1508,477],{"emptyLinePlaceholder":476},[440,1510,1512],{"class":442,"line":1511},81,[440,1513,1514],{},"  /// Log breadcrumb message\n",[440,1516,1518],{"class":442,"line":1517},82,[440,1519,1520],{},"  Future\u003Cvoid> log(String message) async {\n",[440,1522,1524],{"class":442,"line":1523},83,[440,1525,1426],{},[440,1527,1529],{"class":442,"line":1528},84,[440,1530,1531],{},"    await FirebaseCrashlytics.instance.log(message);\n",[440,1533,1535],{"class":442,"line":1534},85,[440,1536,523],{},[440,1538,1540],{"class":442,"line":1539},86,[440,1541,477],{"emptyLinePlaceholder":476},[440,1543,1545],{"class":442,"line":1544},87,[440,1546,1547],{},"  /// Record non-fatal exception\n",[440,1549,1551],{"class":442,"line":1550},88,[440,1552,1553],{},"  Future\u003Cvoid> recordException(\n",[440,1555,1557],{"class":442,"line":1556},89,[440,1558,1559],{},"    dynamic exception,\n",[440,1561,1563],{"class":442,"line":1562},90,[440,1564,1565],{},"    StackTrace? stackTrace, {\n",[440,1567,1569],{"class":442,"line":1568},91,[440,1570,1571],{},"    String? reason,\n",[440,1573,1575],{"class":442,"line":1574},92,[440,1576,1577],{},"    bool fatal = false,\n",[440,1579,1581],{"class":442,"line":1580},93,[440,1582,1583],{},"  }) async {\n",[440,1585,1587],{"class":442,"line":1586},94,[440,1588,1426],{},[440,1590,1592],{"class":442,"line":1591},95,[440,1593,1594],{},"    await FirebaseCrashlytics.instance.recordError(\n",[440,1596,1598],{"class":442,"line":1597},96,[440,1599,1600],{},"      exception,\n",[440,1602,1604],{"class":442,"line":1603},97,[440,1605,1606],{},"      stackTrace,\n",[440,1608,1610],{"class":442,"line":1609},98,[440,1611,1612],{},"      reason: reason,\n",[440,1614,1616],{"class":442,"line":1615},99,[440,1617,1618],{},"      fatal: fatal,\n",[440,1620,1622],{"class":442,"line":1621},100,[440,1623,1217],{},[440,1625,1627],{"class":442,"line":1626},101,[440,1628,523],{},[440,1630,1632],{"class":442,"line":1631},102,[440,1633,470],{},[82,1635],{},[85,1637,1639],{"id":1638},"entry-points-dev-and-prod","🚪 Entry Points: Dev and Prod",[52,1641,1642],{},"Create separate entry points for each environment:",[280,1644,1646],{"id":1645},"development-entry-point","Development Entry Point",[431,1648,1650],{"className":433,"code":1649,"language":435,"meta":46,"style":46},"// lib/main_dev.dart\nimport 'package:flutter/material.dart';\nimport 'app.dart';\nimport 'config/env/dev_config.dart';\nimport 'config/environment.dart';\nimport 'core/services/firebase_service.dart';\n\nvoid main() async {\n  WidgetsFlutterBinding.ensureInitialized();\n\n  // Set environment\n  EnvironmentConfig.setEnvironment(Environment.development);\n\n  // Load dev config\n  final config = DevConfig.config;\n\n  // Initialize Firebase and Crashlytics\n  await FirebaseService.instance.initialize(config);\n\n  // Run app\n  runApp(MyApp(config: config));\n}\n",[437,1651,1652,1657,1662,1667,1672,1677,1682,1686,1691,1696,1700,1705,1710,1714,1719,1724,1728,1733,1738,1742,1747,1752],{"__ignoreMap":46},[440,1653,1654],{"class":442,"line":443},[440,1655,1656],{},"// lib/main_dev.dart\n",[440,1658,1659],{"class":442,"line":449},[440,1660,1661],{},"import 'package:flutter/material.dart';\n",[440,1663,1664],{"class":442,"line":455},[440,1665,1666],{},"import 'app.dart';\n",[440,1668,1669],{"class":442,"line":461},[440,1670,1671],{},"import 'config/env/dev_config.dart';\n",[440,1673,1674],{"class":442,"line":467},[440,1675,1676],{},"import 'config/environment.dart';\n",[440,1678,1679],{"class":442,"line":473},[440,1680,1681],{},"import 'core/services/firebase_service.dart';\n",[440,1683,1684],{"class":442,"line":480},[440,1685,477],{"emptyLinePlaceholder":476},[440,1687,1688],{"class":442,"line":486},[440,1689,1690],{},"void main() async {\n",[440,1692,1693],{"class":442,"line":492},[440,1694,1695],{},"  WidgetsFlutterBinding.ensureInitialized();\n",[440,1697,1698],{"class":442,"line":497},[440,1699,477],{"emptyLinePlaceholder":476},[440,1701,1702],{"class":442,"line":503},[440,1703,1704],{},"  // Set environment\n",[440,1706,1707],{"class":442,"line":508},[440,1708,1709],{},"  EnvironmentConfig.setEnvironment(Environment.development);\n",[440,1711,1712],{"class":442,"line":514},[440,1713,477],{"emptyLinePlaceholder":476},[440,1715,1716],{"class":442,"line":520},[440,1717,1718],{},"  // Load dev config\n",[440,1720,1721],{"class":442,"line":526},[440,1722,1723],{},"  final config = DevConfig.config;\n",[440,1725,1726],{"class":442,"line":531},[440,1727,477],{"emptyLinePlaceholder":476},[440,1729,1730],{"class":442,"line":537},[440,1731,1732],{},"  // Initialize Firebase and Crashlytics\n",[440,1734,1735],{"class":442,"line":543},[440,1736,1737],{},"  await FirebaseService.instance.initialize(config);\n",[440,1739,1740],{"class":442,"line":648},[440,1741,477],{"emptyLinePlaceholder":476},[440,1743,1744],{"class":442,"line":654},[440,1745,1746],{},"  // Run app\n",[440,1748,1749],{"class":442,"line":660},[440,1750,1751],{},"  runApp(MyApp(config: config));\n",[440,1753,1754],{"class":442,"line":665},[440,1755,470],{},[280,1757,1759],{"id":1758},"production-entry-point","Production Entry Point",[431,1761,1763],{"className":433,"code":1762,"language":435,"meta":46,"style":46},"// lib/main_prod.dart\nimport 'package:flutter/material.dart';\nimport 'app.dart';\nimport 'config/env/prod_config.dart';\nimport 'config/environment.dart';\nimport 'core/services/firebase_service.dart';\n\nvoid main() async {\n  WidgetsFlutterBinding.ensureInitialized();\n\n  // Set environment\n  EnvironmentConfig.setEnvironment(Environment.production);\n\n  // Load production config\n  final config = ProdConfig.config;\n\n  // Initialize Firebase and Crashlytics\n  await FirebaseService.instance.initialize(config);\n\n  // Run app\n  runApp(MyApp(config: config));\n}\n",[437,1764,1765,1770,1774,1778,1783,1787,1791,1795,1799,1803,1807,1811,1816,1820,1825,1830,1834,1838,1842,1846,1850,1854],{"__ignoreMap":46},[440,1766,1767],{"class":442,"line":443},[440,1768,1769],{},"// lib/main_prod.dart\n",[440,1771,1772],{"class":442,"line":449},[440,1773,1661],{},[440,1775,1776],{"class":442,"line":455},[440,1777,1666],{},[440,1779,1780],{"class":442,"line":461},[440,1781,1782],{},"import 'config/env/prod_config.dart';\n",[440,1784,1785],{"class":442,"line":467},[440,1786,1676],{},[440,1788,1789],{"class":442,"line":473},[440,1790,1681],{},[440,1792,1793],{"class":442,"line":480},[440,1794,477],{"emptyLinePlaceholder":476},[440,1796,1797],{"class":442,"line":486},[440,1798,1690],{},[440,1800,1801],{"class":442,"line":492},[440,1802,1695],{},[440,1804,1805],{"class":442,"line":497},[440,1806,477],{"emptyLinePlaceholder":476},[440,1808,1809],{"class":442,"line":503},[440,1810,1704],{},[440,1812,1813],{"class":442,"line":508},[440,1814,1815],{},"  EnvironmentConfig.setEnvironment(Environment.production);\n",[440,1817,1818],{"class":442,"line":514},[440,1819,477],{"emptyLinePlaceholder":476},[440,1821,1822],{"class":442,"line":520},[440,1823,1824],{},"  // Load production config\n",[440,1826,1827],{"class":442,"line":526},[440,1828,1829],{},"  final config = ProdConfig.config;\n",[440,1831,1832],{"class":442,"line":531},[440,1833,477],{"emptyLinePlaceholder":476},[440,1835,1836],{"class":442,"line":537},[440,1837,1732],{},[440,1839,1840],{"class":442,"line":543},[440,1841,1737],{},[440,1843,1844],{"class":442,"line":648},[440,1845,477],{"emptyLinePlaceholder":476},[440,1847,1848],{"class":442,"line":654},[440,1849,1746],{},[440,1851,1852],{"class":442,"line":660},[440,1853,1751],{},[440,1855,1856],{"class":442,"line":665},[440,1857,470],{},[52,1859,1860],{},[77,1861,1862],{},"Run commands:",[431,1864,1868],{"className":1865,"code":1866,"language":1867,"meta":46,"style":46},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# Development\nflutter run -t lib/main_dev.dart\n\n# Production\nflutter run -t lib/main_prod.dart\nflutter build apk -t lib/main_prod.dart\n","bash",[437,1869,1870,1876,1892,1896,1901,1912],{"__ignoreMap":46},[440,1871,1872],{"class":442,"line":443},[440,1873,1875],{"class":1874},"sHwdD","# Development\n",[440,1877,1878,1882,1886,1889],{"class":442,"line":449},[440,1879,1881],{"class":1880},"sBMFI","flutter",[440,1883,1885],{"class":1884},"sfazB"," run",[440,1887,1888],{"class":1884}," -t",[440,1890,1891],{"class":1884}," lib/main_dev.dart\n",[440,1893,1894],{"class":442,"line":455},[440,1895,477],{"emptyLinePlaceholder":476},[440,1897,1898],{"class":442,"line":461},[440,1899,1900],{"class":1874},"# Production\n",[440,1902,1903,1905,1907,1909],{"class":442,"line":467},[440,1904,1881],{"class":1880},[440,1906,1885],{"class":1884},[440,1908,1888],{"class":1884},[440,1910,1911],{"class":1884}," lib/main_prod.dart\n",[440,1913,1914,1916,1919,1922,1924],{"class":442,"line":473},[440,1915,1881],{"class":1880},[440,1917,1918],{"class":1884}," build",[440,1920,1921],{"class":1884}," apk",[440,1923,1888],{"class":1884},[440,1925,1911],{"class":1884},[82,1927],{},[85,1929,1931],{"id":1930},"what-crashlytics-tracks-automatically","📊 What Crashlytics Tracks Automatically",[52,1933,1934],{},"Without writing extra logic, Crashlytics records:",[93,1936,1937,1940,1943,1946,1949,1952],{},[96,1938,1939],{},"App crashes",[96,1941,1942],{},"Non-fatal errors",[96,1944,1945],{},"App version and build number",[96,1947,1948],{},"Device model and OS",[96,1950,1951],{},"Screen state",[96,1953,1954],{},"Session data",[52,1956,1957],{},"This information turns random crashes into clear patterns.",[82,1959],{},[85,1961,1963],{"id":1962},"user-context-without-privacy-issues","👤 User Context (Without Privacy Issues)",[52,1965,1966,1967,168],{},"Crashlytics supports ",[77,1968,1969],{},"anonymous user identification",[52,1971,1972],{},"This helps answer:",[93,1974,1975,1978,1981,1984],{},[96,1976,1977],{},"Is this affecting logged-in users?",[96,1979,1980],{},"Only premium users?",[96,1982,1983],{},"Only new users?",[96,1985,1986],{},"Only users in an experiment?",[52,1988,1989,1990,1993],{},"You track ",[77,1991,1992],{},"context",", not personal data.",[52,1995,1996],{},"Good monitoring respects privacy.",[280,1998,2000],{"id":1999},"setting-user-context","Setting User Context",[431,2002,2004],{"className":433,"code":2003,"language":435,"meta":46,"style":46},"// lib/core/utils/crashlytics_helper.dart\nclass CrashlyticsHelper {\n  /// Set user context after login\n  static Future\u003Cvoid> setUser(\n    String userId, {\n    String? email,\n    String? username,\n  }) async {\n    await FirebaseService.instance.setUserIdentifier(userId);\n\n    if (email != null) {\n      await FirebaseService.instance.setCustomKey('user_email', email);\n    }\n    if (username != null) {\n      await FirebaseService.instance.setCustomKey('username', username);\n    }\n  }\n\n  /// Clear user context on logout\n  static Future\u003Cvoid> clearUser() async {\n    await FirebaseService.instance.clearUserIdentifier();\n    await FirebaseService.instance.setCustomKey('user_email', '');\n    await FirebaseService.instance.setCustomKey('username', '');\n  }\n\n  /// Set current screen name\n  static Future\u003Cvoid> setCurrentScreen(String screenName) async {\n    await FirebaseService.instance.setCustomKey('current_screen', screenName);\n    await FirebaseService.instance.log('Screen: $screenName');\n  }\n}\n",[437,2005,2006,2011,2016,2021,2026,2031,2036,2041,2045,2050,2054,2059,2064,2068,2073,2078,2082,2086,2090,2095,2100,2105,2110,2115,2119,2123,2128,2133,2138,2143,2147],{"__ignoreMap":46},[440,2007,2008],{"class":442,"line":443},[440,2009,2010],{},"// lib/core/utils/crashlytics_helper.dart\n",[440,2012,2013],{"class":442,"line":449},[440,2014,2015],{},"class CrashlyticsHelper {\n",[440,2017,2018],{"class":442,"line":455},[440,2019,2020],{},"  /// Set user context after login\n",[440,2022,2023],{"class":442,"line":461},[440,2024,2025],{},"  static Future\u003Cvoid> setUser(\n",[440,2027,2028],{"class":442,"line":467},[440,2029,2030],{},"    String userId, {\n",[440,2032,2033],{"class":442,"line":473},[440,2034,2035],{},"    String? email,\n",[440,2037,2038],{"class":442,"line":480},[440,2039,2040],{},"    String? username,\n",[440,2042,2043],{"class":442,"line":486},[440,2044,1583],{},[440,2046,2047],{"class":442,"line":492},[440,2048,2049],{},"    await FirebaseService.instance.setUserIdentifier(userId);\n",[440,2051,2052],{"class":442,"line":497},[440,2053,477],{"emptyLinePlaceholder":476},[440,2055,2056],{"class":442,"line":503},[440,2057,2058],{},"    if (email != null) {\n",[440,2060,2061],{"class":442,"line":508},[440,2062,2063],{},"      await FirebaseService.instance.setCustomKey('user_email', email);\n",[440,2065,2066],{"class":442,"line":514},[440,2067,1289],{},[440,2069,2070],{"class":442,"line":520},[440,2071,2072],{},"    if (username != null) {\n",[440,2074,2075],{"class":442,"line":526},[440,2076,2077],{},"      await FirebaseService.instance.setCustomKey('username', username);\n",[440,2079,2080],{"class":442,"line":531},[440,2081,1289],{},[440,2083,2084],{"class":442,"line":537},[440,2085,523],{},[440,2087,2088],{"class":442,"line":543},[440,2089,477],{"emptyLinePlaceholder":476},[440,2091,2092],{"class":442,"line":648},[440,2093,2094],{},"  /// Clear user context on logout\n",[440,2096,2097],{"class":442,"line":654},[440,2098,2099],{},"  static Future\u003Cvoid> clearUser() async {\n",[440,2101,2102],{"class":442,"line":660},[440,2103,2104],{},"    await FirebaseService.instance.clearUserIdentifier();\n",[440,2106,2107],{"class":442,"line":665},[440,2108,2109],{},"    await FirebaseService.instance.setCustomKey('user_email', '');\n",[440,2111,2112],{"class":442,"line":671},[440,2113,2114],{},"    await FirebaseService.instance.setCustomKey('username', '');\n",[440,2116,2117],{"class":442,"line":677},[440,2118,523],{},[440,2120,2121],{"class":442,"line":683},[440,2122,477],{"emptyLinePlaceholder":476},[440,2124,2125],{"class":442,"line":689},[440,2126,2127],{},"  /// Set current screen name\n",[440,2129,2130],{"class":442,"line":695},[440,2131,2132],{},"  static Future\u003Cvoid> setCurrentScreen(String screenName) async {\n",[440,2134,2135],{"class":442,"line":701},[440,2136,2137],{},"    await FirebaseService.instance.setCustomKey('current_screen', screenName);\n",[440,2139,2140],{"class":442,"line":707},[440,2141,2142],{},"    await FirebaseService.instance.log('Screen: $screenName');\n",[440,2144,2145],{"class":442,"line":713},[440,2146,523],{},[440,2148,2149],{"class":442,"line":719},[440,2150,470],{},[82,2152],{},[85,2154,2156],{"id":2155},"recording-handled-exceptions","🔍 Recording Handled Exceptions",[52,2158,2159],{},"Not all errors crash your app. Some are caught and handled. But you still want to know about them:",[431,2161,2163],{"className":433,"code":2162,"language":435,"meta":46,"style":46},"// Record a handled exception\nstatic Future\u003Cvoid> recordHandledException(\n  dynamic exception,\n  StackTrace? stackTrace, {\n  String? context,\n}) async {\n  await FirebaseService.instance.recordException(\n    exception,\n    stackTrace,\n    reason: context,\n    fatal: false, // Non-fatal\n  );\n}\n\n// Usage example\ntry {\n  final data = await apiService.fetchData();\n} catch (e, stackTrace) {\n  await CrashlyticsHelper.recordHandledException(\n    e,\n    stackTrace,\n    context: 'Failed to fetch user data',\n  );\n  // Show error to user\n}\n",[437,2164,2165,2170,2175,2180,2185,2190,2195,2200,2205,2210,2215,2220,2224,2228,2232,2237,2242,2247,2252,2257,2262,2266,2271,2275,2280],{"__ignoreMap":46},[440,2166,2167],{"class":442,"line":443},[440,2168,2169],{},"// Record a handled exception\n",[440,2171,2172],{"class":442,"line":449},[440,2173,2174],{},"static Future\u003Cvoid> recordHandledException(\n",[440,2176,2177],{"class":442,"line":455},[440,2178,2179],{},"  dynamic exception,\n",[440,2181,2182],{"class":442,"line":461},[440,2183,2184],{},"  StackTrace? stackTrace, {\n",[440,2186,2187],{"class":442,"line":467},[440,2188,2189],{},"  String? context,\n",[440,2191,2192],{"class":442,"line":473},[440,2193,2194],{},"}) async {\n",[440,2196,2197],{"class":442,"line":480},[440,2198,2199],{},"  await FirebaseService.instance.recordException(\n",[440,2201,2202],{"class":442,"line":486},[440,2203,2204],{},"    exception,\n",[440,2206,2207],{"class":442,"line":492},[440,2208,2209],{},"    stackTrace,\n",[440,2211,2212],{"class":442,"line":497},[440,2213,2214],{},"    reason: context,\n",[440,2216,2217],{"class":442,"line":503},[440,2218,2219],{},"    fatal: false, // Non-fatal\n",[440,2221,2222],{"class":442,"line":508},[440,2223,921],{},[440,2225,2226],{"class":442,"line":514},[440,2227,470],{},[440,2229,2230],{"class":442,"line":520},[440,2231,477],{"emptyLinePlaceholder":476},[440,2233,2234],{"class":442,"line":526},[440,2235,2236],{},"// Usage example\n",[440,2238,2239],{"class":442,"line":531},[440,2240,2241],{},"try {\n",[440,2243,2244],{"class":442,"line":537},[440,2245,2246],{},"  final data = await apiService.fetchData();\n",[440,2248,2249],{"class":442,"line":543},[440,2250,2251],{},"} catch (e, stackTrace) {\n",[440,2253,2254],{"class":442,"line":648},[440,2255,2256],{},"  await CrashlyticsHelper.recordHandledException(\n",[440,2258,2259],{"class":442,"line":654},[440,2260,2261],{},"    e,\n",[440,2263,2264],{"class":442,"line":660},[440,2265,2209],{},[440,2267,2268],{"class":442,"line":665},[440,2269,2270],{},"    context: 'Failed to fetch user data',\n",[440,2272,2273],{"class":442,"line":671},[440,2274,921],{},[440,2276,2277],{"class":442,"line":677},[440,2278,2279],{},"  // Show error to user\n",[440,2281,2282],{"class":442,"line":683},[440,2283,470],{},[82,2285],{},[85,2287,2289],{"id":2288},"recording-network-errors","🌐 Recording Network Errors",[52,2291,2292],{},"Network failures are common. Track them to identify patterns:",[431,2294,2296],{"className":433,"code":2295,"language":435,"meta":46,"style":46},"static Future\u003Cvoid> recordNetworkError(\n  String url,\n  int? statusCode,\n  String errorMessage, {\n  String? method,\n}) async {\n  await FirebaseService.instance.setCustomKey('last_network_error_url', url);\n  await FirebaseService.instance.setCustomKey('last_network_error_code', statusCode ?? -1);\n\n  final error = Exception('NetworkError: $method $url - $statusCode');\n\n  await FirebaseService.instance.recordException(\n    error,\n    StackTrace.current,\n    reason: 'Network Error',\n    fatal: false,\n  );\n}\n\n// Usage\nawait CrashlyticsHelper.recordNetworkError(\n  'https://api.example.com/users',\n  500,\n  'Internal Server Error',\n  method: 'GET',\n);\n",[437,2297,2298,2303,2308,2313,2318,2323,2327,2332,2337,2341,2346,2350,2354,2359,2364,2369,2374,2378,2382,2386,2391,2396,2401,2406,2411,2416],{"__ignoreMap":46},[440,2299,2300],{"class":442,"line":443},[440,2301,2302],{},"static Future\u003Cvoid> recordNetworkError(\n",[440,2304,2305],{"class":442,"line":449},[440,2306,2307],{},"  String url,\n",[440,2309,2310],{"class":442,"line":455},[440,2311,2312],{},"  int? statusCode,\n",[440,2314,2315],{"class":442,"line":461},[440,2316,2317],{},"  String errorMessage, {\n",[440,2319,2320],{"class":442,"line":467},[440,2321,2322],{},"  String? method,\n",[440,2324,2325],{"class":442,"line":473},[440,2326,2194],{},[440,2328,2329],{"class":442,"line":480},[440,2330,2331],{},"  await FirebaseService.instance.setCustomKey('last_network_error_url', url);\n",[440,2333,2334],{"class":442,"line":486},[440,2335,2336],{},"  await FirebaseService.instance.setCustomKey('last_network_error_code', statusCode ?? -1);\n",[440,2338,2339],{"class":442,"line":492},[440,2340,477],{"emptyLinePlaceholder":476},[440,2342,2343],{"class":442,"line":497},[440,2344,2345],{},"  final error = Exception('NetworkError: $method $url - $statusCode');\n",[440,2347,2348],{"class":442,"line":503},[440,2349,477],{"emptyLinePlaceholder":476},[440,2351,2352],{"class":442,"line":508},[440,2353,2199],{},[440,2355,2356],{"class":442,"line":514},[440,2357,2358],{},"    error,\n",[440,2360,2361],{"class":442,"line":520},[440,2362,2363],{},"    StackTrace.current,\n",[440,2365,2366],{"class":442,"line":526},[440,2367,2368],{},"    reason: 'Network Error',\n",[440,2370,2371],{"class":442,"line":531},[440,2372,2373],{},"    fatal: false,\n",[440,2375,2376],{"class":442,"line":537},[440,2377,921],{},[440,2379,2380],{"class":442,"line":543},[440,2381,470],{},[440,2383,2384],{"class":442,"line":648},[440,2385,477],{"emptyLinePlaceholder":476},[440,2387,2388],{"class":442,"line":654},[440,2389,2390],{},"// Usage\n",[440,2392,2393],{"class":442,"line":660},[440,2394,2395],{},"await CrashlyticsHelper.recordNetworkError(\n",[440,2397,2398],{"class":442,"line":665},[440,2399,2400],{},"  'https://api.example.com/users',\n",[440,2402,2403],{"class":442,"line":671},[440,2404,2405],{},"  500,\n",[440,2407,2408],{"class":442,"line":677},[440,2409,2410],{},"  'Internal Server Error',\n",[440,2412,2413],{"class":442,"line":683},[440,2414,2415],{},"  method: 'GET',\n",[440,2417,2418],{"class":442,"line":689},[440,2419,2420],{},");\n",[82,2422],{},[85,2424,2426],{"id":2425},"breadcrumbs-understanding-user-journey","🍞 Breadcrumbs: Understanding User Journey",[52,2428,2429],{},"Breadcrumbs are logged events that show what the user did before a crash:",[431,2431,2433],{"className":433,"code":2432,"language":435,"meta":46,"style":46},"// Logging breadcrumbs\nawait FirebaseService.instance.log('User opened settings');\nawait FirebaseService.instance.log('User changed theme to dark');\nawait FirebaseService.instance.log('User saved preferences');\n\n// When a crash happens, you'll see all these logs leading up to it\n",[437,2434,2435,2440,2445,2450,2455,2459],{"__ignoreMap":46},[440,2436,2437],{"class":442,"line":443},[440,2438,2439],{},"// Logging breadcrumbs\n",[440,2441,2442],{"class":442,"line":449},[440,2443,2444],{},"await FirebaseService.instance.log('User opened settings');\n",[440,2446,2447],{"class":442,"line":455},[440,2448,2449],{},"await FirebaseService.instance.log('User changed theme to dark');\n",[440,2451,2452],{"class":442,"line":461},[440,2453,2454],{},"await FirebaseService.instance.log('User saved preferences');\n",[440,2456,2457],{"class":442,"line":467},[440,2458,477],{"emptyLinePlaceholder":476},[440,2460,2461],{"class":442,"line":473},[440,2462,2463],{},"// When a crash happens, you'll see all these logs leading up to it\n",[82,2465],{},[85,2467,2469],{"id":2468},"integrated-logging-with-crashlytics","📝 Integrated Logging with Crashlytics",[52,2471,2472],{},"Create an app-wide logger that automatically sends important logs to Crashlytics:",[431,2474,2476],{"className":433,"code":2475,"language":435,"meta":46,"style":46},"// lib/core/utils/app_logger.dart\nclass AppLogger {\n  static int _logLevel = 0;\n\n  static void init({required int logLevel}) {\n    _logLevel = logLevel;\n  }\n\n  /// Info-level log\n  static void info(String message) {\n    if (_logLevel \u003C= 1) {\n      print('INFO: $message');\n      FirebaseService.instance.log('INFO: $message');\n    }\n  }\n\n  /// Warning-level log\n  static void warning(String message) {\n    if (_logLevel \u003C= 2) {\n      print('WARNING: $message');\n      FirebaseService.instance.log('WARNING: $message');\n    }\n  }\n\n  /// Error-level log\n  static void error(\n    String message, {\n    Object? error,\n    StackTrace? stackTrace,\n  }) {\n    if (_logLevel \u003C= 3) {\n      print('ERROR: $message');\n      if (error != null) {\n        FirebaseService.instance.recordException(\n          error,\n          stackTrace,\n          reason: message,\n          fatal: false,\n        );\n      }\n    }\n  }\n}\n\n// Usage\nAppLogger.info('User logged in successfully');\nAppLogger.warning('API response took longer than expected');\nAppLogger.error('Failed to load profile', error: e, stackTrace: stackTrace);\n",[437,2477,2478,2483,2488,2493,2497,2502,2507,2511,2515,2520,2525,2530,2535,2540,2544,2548,2552,2557,2562,2567,2572,2577,2581,2585,2589,2594,2599,2604,2609,2614,2619,2624,2629,2634,2639,2644,2649,2654,2659,2664,2669,2673,2677,2681,2685,2689,2694,2699],{"__ignoreMap":46},[440,2479,2480],{"class":442,"line":443},[440,2481,2482],{},"// lib/core/utils/app_logger.dart\n",[440,2484,2485],{"class":442,"line":449},[440,2486,2487],{},"class AppLogger {\n",[440,2489,2490],{"class":442,"line":455},[440,2491,2492],{},"  static int _logLevel = 0;\n",[440,2494,2495],{"class":442,"line":461},[440,2496,477],{"emptyLinePlaceholder":476},[440,2498,2499],{"class":442,"line":467},[440,2500,2501],{},"  static void init({required int logLevel}) {\n",[440,2503,2504],{"class":442,"line":473},[440,2505,2506],{},"    _logLevel = logLevel;\n",[440,2508,2509],{"class":442,"line":480},[440,2510,523],{},[440,2512,2513],{"class":442,"line":486},[440,2514,477],{"emptyLinePlaceholder":476},[440,2516,2517],{"class":442,"line":492},[440,2518,2519],{},"  /// Info-level log\n",[440,2521,2522],{"class":442,"line":497},[440,2523,2524],{},"  static void info(String message) {\n",[440,2526,2527],{"class":442,"line":503},[440,2528,2529],{},"    if (_logLevel \u003C= 1) {\n",[440,2531,2532],{"class":442,"line":508},[440,2533,2534],{},"      print('INFO: $message');\n",[440,2536,2537],{"class":442,"line":514},[440,2538,2539],{},"      FirebaseService.instance.log('INFO: $message');\n",[440,2541,2542],{"class":442,"line":520},[440,2543,1289],{},[440,2545,2546],{"class":442,"line":526},[440,2547,523],{},[440,2549,2550],{"class":442,"line":531},[440,2551,477],{"emptyLinePlaceholder":476},[440,2553,2554],{"class":442,"line":537},[440,2555,2556],{},"  /// Warning-level log\n",[440,2558,2559],{"class":442,"line":543},[440,2560,2561],{},"  static void warning(String message) {\n",[440,2563,2564],{"class":442,"line":648},[440,2565,2566],{},"    if (_logLevel \u003C= 2) {\n",[440,2568,2569],{"class":442,"line":654},[440,2570,2571],{},"      print('WARNING: $message');\n",[440,2573,2574],{"class":442,"line":660},[440,2575,2576],{},"      FirebaseService.instance.log('WARNING: $message');\n",[440,2578,2579],{"class":442,"line":665},[440,2580,1289],{},[440,2582,2583],{"class":442,"line":671},[440,2584,523],{},[440,2586,2587],{"class":442,"line":677},[440,2588,477],{"emptyLinePlaceholder":476},[440,2590,2591],{"class":442,"line":683},[440,2592,2593],{},"  /// Error-level log\n",[440,2595,2596],{"class":442,"line":689},[440,2597,2598],{},"  static void error(\n",[440,2600,2601],{"class":442,"line":695},[440,2602,2603],{},"    String message, {\n",[440,2605,2606],{"class":442,"line":701},[440,2607,2608],{},"    Object? error,\n",[440,2610,2611],{"class":442,"line":707},[440,2612,2613],{},"    StackTrace? stackTrace,\n",[440,2615,2616],{"class":442,"line":713},[440,2617,2618],{},"  }) {\n",[440,2620,2621],{"class":442,"line":719},[440,2622,2623],{},"    if (_logLevel \u003C= 3) {\n",[440,2625,2626],{"class":442,"line":725},[440,2627,2628],{},"      print('ERROR: $message');\n",[440,2630,2631],{"class":442,"line":731},[440,2632,2633],{},"      if (error != null) {\n",[440,2635,2636],{"class":442,"line":737},[440,2637,2638],{},"        FirebaseService.instance.recordException(\n",[440,2640,2641],{"class":442,"line":743},[440,2642,2643],{},"          error,\n",[440,2645,2646],{"class":442,"line":748},[440,2647,2648],{},"          stackTrace,\n",[440,2650,2651],{"class":442,"line":754},[440,2652,2653],{},"          reason: message,\n",[440,2655,2656],{"class":442,"line":760},[440,2657,2658],{},"          fatal: false,\n",[440,2660,2661],{"class":442,"line":765},[440,2662,2663],{},"        );\n",[440,2665,2666],{"class":442,"line":1280},[440,2667,2668],{},"      }\n",[440,2670,2671],{"class":442,"line":1286},[440,2672,1289],{},[440,2674,2675],{"class":442,"line":1292},[440,2676,523],{},[440,2678,2679],{"class":442,"line":1297},[440,2680,470],{},[440,2682,2683],{"class":442,"line":1303},[440,2684,477],{"emptyLinePlaceholder":476},[440,2686,2687],{"class":442,"line":1309},[440,2688,2390],{},[440,2690,2691],{"class":442,"line":1314},[440,2692,2693],{},"AppLogger.info('User logged in successfully');\n",[440,2695,2696],{"class":442,"line":1320},[440,2697,2698],{},"AppLogger.warning('API response took longer than expected');\n",[440,2700,2701],{"class":442,"line":1326},[440,2702,2703],{},"AppLogger.error('Failed to load profile', error: e, stackTrace: stackTrace);\n",[82,2705],{},[85,2707,2709],{"id":2708},"testing-crashlytics-yes-on-purpose","🧪 Testing Crashlytics (Yes, On Purpose)",[52,2711,2712,2713,168],{},"Good teams test crashes ",[77,2714,2715],{},"before users do",[52,2717,2718],{},"In development:",[93,2720,2721,2724,2727],{},[96,2722,2723],{},"You simulate crashes",[96,2725,2726],{},"You log test errors",[96,2728,2729],{},"You verify reports appear correctly",[52,2731,2732],{},"This builds confidence before production releases.",[52,2734,2735],{},"Crashing your own app in dev is a feature — not a failure.",[280,2737,2739],{"id":2738},"crashlytics-test-screen-dev-only","Crashlytics Test Screen (Dev Only)",[431,2741,2743],{"className":433,"code":2742,"language":435,"meta":46,"style":46},"// lib/features/debug/crashlytics_test_screen.dart\nclass CrashlyticsTestScreen extends StatelessWidget {\n  const CrashlyticsTestScreen({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text('Crashlytics Test'),\n      ),\n      body: ListView(\n        padding: const EdgeInsets.all(16),\n        children: [\n          // Test non-fatal exception\n          ElevatedButton(\n            onPressed: () async {\n              try {\n                throw Exception('Test non-fatal exception');\n              } catch (e, stackTrace) {\n                await FirebaseService.instance.recordException(\n                  e,\n                  stackTrace,\n                  reason: 'Testing non-fatal exception',\n                  fatal: false,\n                );\n              }\n            },\n            child: const Text('Send Test Exception'),\n          ),\n\n          // Test custom keys\n          ElevatedButton(\n            onPressed: () async {\n              await FirebaseService.instance.setCustomKey('test_key', 'test_value');\n              await FirebaseService.instance.setCustomKey('test_number', 42);\n            },\n            child: const Text('Set Custom Keys'),\n          ),\n\n          // Test breadcrumbs\n          ElevatedButton(\n            onPressed: () async {\n              await FirebaseService.instance.log('User navigated to test screen');\n              await FirebaseService.instance.log('User clicked test button');\n              await FirebaseService.instance.log('Breadcrumb trail created');\n            },\n            child: const Text('Log Breadcrumbs'),\n          ),\n\n          // Test user context\n          ElevatedButton(\n            onPressed: () async {\n              await CrashlyticsHelper.setUser(\n                'test_user_123',\n                email: 'test@example.com',\n                username: 'testuser',\n              );\n            },\n            child: const Text('Set User Identifier'),\n          ),\n        ],\n      ),\n    );\n  }\n}\n",[437,2744,2745,2750,2755,2760,2764,2769,2774,2779,2784,2789,2793,2798,2803,2808,2813,2818,2823,2828,2833,2838,2843,2848,2853,2858,2863,2868,2873,2878,2883,2888,2892,2897,2901,2905,2910,2915,2919,2924,2928,2932,2937,2941,2945,2950,2955,2960,2964,2969,2973,2977,2982,2986,2990,2995,3000,3005,3010,3015,3019,3024,3028,3033,3037,3041,3045],{"__ignoreMap":46},[440,2746,2747],{"class":442,"line":443},[440,2748,2749],{},"// lib/features/debug/crashlytics_test_screen.dart\n",[440,2751,2752],{"class":442,"line":449},[440,2753,2754],{},"class CrashlyticsTestScreen extends StatelessWidget {\n",[440,2756,2757],{"class":442,"line":455},[440,2758,2759],{},"  const CrashlyticsTestScreen({super.key});\n",[440,2761,2762],{"class":442,"line":461},[440,2763,477],{"emptyLinePlaceholder":476},[440,2765,2766],{"class":442,"line":467},[440,2767,2768],{},"  @override\n",[440,2770,2771],{"class":442,"line":473},[440,2772,2773],{},"  Widget build(BuildContext context) {\n",[440,2775,2776],{"class":442,"line":480},[440,2777,2778],{},"    return Scaffold(\n",[440,2780,2781],{"class":442,"line":486},[440,2782,2783],{},"      appBar: AppBar(\n",[440,2785,2786],{"class":442,"line":492},[440,2787,2788],{},"        title: const Text('Crashlytics Test'),\n",[440,2790,2791],{"class":442,"line":497},[440,2792,1212],{},[440,2794,2795],{"class":442,"line":503},[440,2796,2797],{},"      body: ListView(\n",[440,2799,2800],{"class":442,"line":508},[440,2801,2802],{},"        padding: const EdgeInsets.all(16),\n",[440,2804,2805],{"class":442,"line":514},[440,2806,2807],{},"        children: [\n",[440,2809,2810],{"class":442,"line":520},[440,2811,2812],{},"          // Test non-fatal exception\n",[440,2814,2815],{"class":442,"line":526},[440,2816,2817],{},"          ElevatedButton(\n",[440,2819,2820],{"class":442,"line":531},[440,2821,2822],{},"            onPressed: () async {\n",[440,2824,2825],{"class":442,"line":537},[440,2826,2827],{},"              try {\n",[440,2829,2830],{"class":442,"line":543},[440,2831,2832],{},"                throw Exception('Test non-fatal exception');\n",[440,2834,2835],{"class":442,"line":648},[440,2836,2837],{},"              } catch (e, stackTrace) {\n",[440,2839,2840],{"class":442,"line":654},[440,2841,2842],{},"                await FirebaseService.instance.recordException(\n",[440,2844,2845],{"class":442,"line":660},[440,2846,2847],{},"                  e,\n",[440,2849,2850],{"class":442,"line":665},[440,2851,2852],{},"                  stackTrace,\n",[440,2854,2855],{"class":442,"line":671},[440,2856,2857],{},"                  reason: 'Testing non-fatal exception',\n",[440,2859,2860],{"class":442,"line":677},[440,2861,2862],{},"                  fatal: false,\n",[440,2864,2865],{"class":442,"line":683},[440,2866,2867],{},"                );\n",[440,2869,2870],{"class":442,"line":689},[440,2871,2872],{},"              }\n",[440,2874,2875],{"class":442,"line":695},[440,2876,2877],{},"            },\n",[440,2879,2880],{"class":442,"line":701},[440,2881,2882],{},"            child: const Text('Send Test Exception'),\n",[440,2884,2885],{"class":442,"line":707},[440,2886,2887],{},"          ),\n",[440,2889,2890],{"class":442,"line":713},[440,2891,477],{"emptyLinePlaceholder":476},[440,2893,2894],{"class":442,"line":719},[440,2895,2896],{},"          // Test custom keys\n",[440,2898,2899],{"class":442,"line":725},[440,2900,2817],{},[440,2902,2903],{"class":442,"line":731},[440,2904,2822],{},[440,2906,2907],{"class":442,"line":737},[440,2908,2909],{},"              await FirebaseService.instance.setCustomKey('test_key', 'test_value');\n",[440,2911,2912],{"class":442,"line":743},[440,2913,2914],{},"              await FirebaseService.instance.setCustomKey('test_number', 42);\n",[440,2916,2917],{"class":442,"line":748},[440,2918,2877],{},[440,2920,2921],{"class":442,"line":754},[440,2922,2923],{},"            child: const Text('Set Custom Keys'),\n",[440,2925,2926],{"class":442,"line":760},[440,2927,2887],{},[440,2929,2930],{"class":442,"line":765},[440,2931,477],{"emptyLinePlaceholder":476},[440,2933,2934],{"class":442,"line":1280},[440,2935,2936],{},"          // Test breadcrumbs\n",[440,2938,2939],{"class":442,"line":1286},[440,2940,2817],{},[440,2942,2943],{"class":442,"line":1292},[440,2944,2822],{},[440,2946,2947],{"class":442,"line":1297},[440,2948,2949],{},"              await FirebaseService.instance.log('User navigated to test screen');\n",[440,2951,2952],{"class":442,"line":1303},[440,2953,2954],{},"              await FirebaseService.instance.log('User clicked test button');\n",[440,2956,2957],{"class":442,"line":1309},[440,2958,2959],{},"              await FirebaseService.instance.log('Breadcrumb trail created');\n",[440,2961,2962],{"class":442,"line":1314},[440,2963,2877],{},[440,2965,2966],{"class":442,"line":1320},[440,2967,2968],{},"            child: const Text('Log Breadcrumbs'),\n",[440,2970,2971],{"class":442,"line":1326},[440,2972,2887],{},[440,2974,2975],{"class":442,"line":1332},[440,2976,477],{"emptyLinePlaceholder":476},[440,2978,2979],{"class":442,"line":1338},[440,2980,2981],{},"          // Test user context\n",[440,2983,2984],{"class":442,"line":1343},[440,2985,2817],{},[440,2987,2988],{"class":442,"line":1349},[440,2989,2822],{},[440,2991,2992],{"class":442,"line":1355},[440,2993,2994],{},"              await CrashlyticsHelper.setUser(\n",[440,2996,2997],{"class":442,"line":1361},[440,2998,2999],{},"                'test_user_123',\n",[440,3001,3002],{"class":442,"line":1367},[440,3003,3004],{},"                email: 'test@example.com',\n",[440,3006,3007],{"class":442,"line":1372},[440,3008,3009],{},"                username: 'testuser',\n",[440,3011,3012],{"class":442,"line":1378},[440,3013,3014],{},"              );\n",[440,3016,3017],{"class":442,"line":1384},[440,3018,2877],{},[440,3020,3021],{"class":442,"line":1390},[440,3022,3023],{},"            child: const Text('Set User Identifier'),\n",[440,3025,3026],{"class":442,"line":1396},[440,3027,2887],{},[440,3029,3030],{"class":442,"line":1401},[440,3031,3032],{},"        ],\n",[440,3034,3035],{"class":442,"line":1406},[440,3036,1212],{},[440,3038,3039],{"class":442,"line":1411},[440,3040,1217],{},[440,3042,3043],{"class":442,"line":1417},[440,3044,523],{},[440,3046,3047],{"class":442,"line":1423},[440,3048,470],{},[52,3050,3051,3054],{},[77,3052,3053],{},"Important:"," Remove or hide this screen before production release!",[82,3056],{},[85,3058,3060],{"id":3059},"common-beginner-mistakes","🧠 Common Beginner Mistakes",[52,3062,3063],{},"Avoid these early:",[93,3065,3066,3069,3072,3075,3078],{},[96,3067,3068],{},"Using one Firebase project for everything",[96,3070,3071],{},"Ignoring non-fatal errors",[96,3073,3074],{},"Shipping without testing crash reporting",[96,3076,3077],{},"Logging sensitive data",[96,3079,3080],{},"Treating crashes as rare events",[52,3082,3083,3084],{},"Crashes are normal.\n",[77,3085,3086],{},"Untracked crashes are dangerous.",[82,3088],{},[85,3090,3092],{"id":3091},"crashlytics-logging-stability","🧭 Crashlytics + Logging = Stability",[52,3094,3095],{},"Crashlytics becomes powerful when combined with:",[93,3097,3098,3101,3104],{},[96,3099,3100],{},"Structured logging",[96,3102,3103],{},"Meaningful events",[96,3105,3106],{},"Intentional breadcrumbs",[52,3108,3109,3110,3114,3115,168],{},"Logs explain ",[3111,3112,3113],"em",{},"what happened before"," a crash.\nCrashlytics explains ",[3111,3116,3117],{},"why it matters",[52,3119,3120],{},"Together, they make debugging calm instead of stressful.",[82,3122],{},[85,3124,3126],{"id":3125},"production-mindset-checklist","🚀 Production Mindset Checklist",[52,3128,3129],{},"Before shipping your Flutter app, ask yourself:",[93,3131,3132,3135,3138,3141,3144,3147,3150,3153],{},[96,3133,3134],{},"✅ Can I see crashes without user reports?",[96,3136,3137],{},"✅ Can I separate dev and prod issues?",[96,3139,3140],{},"✅ Can I identify affected users or features?",[96,3142,3143],{},"✅ Can I trust crash data after release?",[96,3145,3146],{},"✅ Have I tested Crashlytics in dev?",[96,3148,3149],{},"✅ Are sensitive data excluded from logs?",[96,3151,3152],{},"✅ Is the environment context clear?",[96,3154,3155],{},"✅ Do I have breadcrumbs for user journeys?",[52,3157,3158],{},"If yes — you're building like a professional.",[82,3160],{},[85,3162,3164],{"id":3163},"final-thoughts","🎯 Final Thoughts",[52,3166,3167,3168,3170,3171,168],{},"Firebase Crashlytics is not about fear.",[61,3169],{},"\nIt's about ",[77,3172,3173],{},"confidence",[52,3175,3176],{},"Confidence to:",[93,3178,3179,3182,3185,3188],{},[96,3180,3181],{},"Release faster",[96,3183,3184],{},"Fix issues earlier",[96,3186,3187],{},"Protect real users",[96,3189,3190],{},"Sleep after deployment 😌",[52,3192,3193,3194,168],{},"Every serious Flutter app uses crash reporting.\nThe best ones set it up ",[77,3195,3196],{},"early",[52,3198,3199],{},"You're not overengineering.\nYou're building the right foundation. 💙",[82,3201],{},[85,3203,3205],{"id":3204},"quick-reference","📚 Quick Reference",[280,3207,3209],{"id":3208},"key-commands","Key Commands",[431,3211,3213],{"className":1865,"code":3212,"language":1867,"meta":46,"style":46},"# Run in development\nflutter run -t lib/main_dev.dart\n\n# Run in production\nflutter run -t lib/main_prod.dart\n\n# Build production APK\nflutter build apk -t lib/main_prod.dart\n\n# Build production App Bundle\nflutter build appbundle -t lib/main_prod.dart\n",[437,3214,3215,3220,3230,3234,3239,3249,3253,3258,3270,3274,3279],{"__ignoreMap":46},[440,3216,3217],{"class":442,"line":443},[440,3218,3219],{"class":1874},"# Run in development\n",[440,3221,3222,3224,3226,3228],{"class":442,"line":449},[440,3223,1881],{"class":1880},[440,3225,1885],{"class":1884},[440,3227,1888],{"class":1884},[440,3229,1891],{"class":1884},[440,3231,3232],{"class":442,"line":455},[440,3233,477],{"emptyLinePlaceholder":476},[440,3235,3236],{"class":442,"line":461},[440,3237,3238],{"class":1874},"# Run in production\n",[440,3240,3241,3243,3245,3247],{"class":442,"line":467},[440,3242,1881],{"class":1880},[440,3244,1885],{"class":1884},[440,3246,1888],{"class":1884},[440,3248,1911],{"class":1884},[440,3250,3251],{"class":442,"line":473},[440,3252,477],{"emptyLinePlaceholder":476},[440,3254,3255],{"class":442,"line":480},[440,3256,3257],{"class":1874},"# Build production APK\n",[440,3259,3260,3262,3264,3266,3268],{"class":442,"line":486},[440,3261,1881],{"class":1880},[440,3263,1918],{"class":1884},[440,3265,1921],{"class":1884},[440,3267,1888],{"class":1884},[440,3269,1911],{"class":1884},[440,3271,3272],{"class":442,"line":492},[440,3273,477],{"emptyLinePlaceholder":476},[440,3275,3276],{"class":442,"line":497},[440,3277,3278],{"class":1874},"# Build production App Bundle\n",[440,3280,3281,3283,3285,3288,3290],{"class":442,"line":503},[440,3282,1881],{"class":1880},[440,3284,1918],{"class":1884},[440,3286,3287],{"class":1884}," appbundle",[440,3289,1888],{"class":1884},[440,3291,1911],{"class":1884},[280,3293,3295],{"id":3294},"essential-crashlytics-operations","Essential Crashlytics Operations",[431,3297,3299],{"className":433,"code":3298,"language":435,"meta":46,"style":46},"// Set user context\nawait CrashlyticsHelper.setUser('user_123');\n\n// Set current screen\nawait CrashlyticsHelper.setCurrentScreen('home_screen');\n\n// Log breadcrumb\nawait FirebaseService.instance.log('User tapped submit button');\n\n// Record handled error\nawait CrashlyticsHelper.recordHandledException(e, stackTrace);\n\n// Record network error\nawait CrashlyticsHelper.recordNetworkError(url, statusCode, message);\n\n// Clear user on logout\nawait CrashlyticsHelper.clearUser();\n",[437,3300,3301,3306,3311,3315,3320,3325,3329,3334,3339,3343,3348,3353,3357,3362,3367,3371,3376],{"__ignoreMap":46},[440,3302,3303],{"class":442,"line":443},[440,3304,3305],{},"// Set user context\n",[440,3307,3308],{"class":442,"line":449},[440,3309,3310],{},"await CrashlyticsHelper.setUser('user_123');\n",[440,3312,3313],{"class":442,"line":455},[440,3314,477],{"emptyLinePlaceholder":476},[440,3316,3317],{"class":442,"line":461},[440,3318,3319],{},"// Set current screen\n",[440,3321,3322],{"class":442,"line":467},[440,3323,3324],{},"await CrashlyticsHelper.setCurrentScreen('home_screen');\n",[440,3326,3327],{"class":442,"line":473},[440,3328,477],{"emptyLinePlaceholder":476},[440,3330,3331],{"class":442,"line":480},[440,3332,3333],{},"// Log breadcrumb\n",[440,3335,3336],{"class":442,"line":486},[440,3337,3338],{},"await FirebaseService.instance.log('User tapped submit button');\n",[440,3340,3341],{"class":442,"line":492},[440,3342,477],{"emptyLinePlaceholder":476},[440,3344,3345],{"class":442,"line":497},[440,3346,3347],{},"// Record handled error\n",[440,3349,3350],{"class":442,"line":503},[440,3351,3352],{},"await CrashlyticsHelper.recordHandledException(e, stackTrace);\n",[440,3354,3355],{"class":442,"line":508},[440,3356,477],{"emptyLinePlaceholder":476},[440,3358,3359],{"class":442,"line":514},[440,3360,3361],{},"// Record network error\n",[440,3363,3364],{"class":442,"line":520},[440,3365,3366],{},"await CrashlyticsHelper.recordNetworkError(url, statusCode, message);\n",[440,3368,3369],{"class":442,"line":526},[440,3370,477],{"emptyLinePlaceholder":476},[440,3372,3373],{"class":442,"line":531},[440,3374,3375],{},"// Clear user on logout\n",[440,3377,3378],{"class":442,"line":537},[440,3379,3380],{},"await CrashlyticsHelper.clearUser();\n",[82,3382],{},[52,3384,3385,3388],{},[77,3386,3387],{},"Happy coding, and may your production crashes be few and easily debugged!"," 🚀",[3390,3391,3392],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}",{"title":46,"searchDepth":449,"depth":449,"links":3394},[3395,3396,3397,3398,3399,3406,3407,3408,3409,3410,3411,3415,3416,3419,3420,3421,3422,3423,3426,3427,3428,3429,3430],{"id":87,"depth":449,"text":88},{"id":129,"depth":449,"text":130},{"id":176,"depth":449,"text":177},{"id":235,"depth":449,"text":236},{"id":277,"depth":449,"text":278,"children":3400},[3401,3402,3403,3404,3405],{"id":282,"depth":455,"text":283},{"id":312,"depth":455,"text":313},{"id":344,"depth":455,"text":345},{"id":370,"depth":455,"text":371},{"id":396,"depth":455,"text":397},{"id":425,"depth":449,"text":426},{"id":550,"depth":449,"text":551},{"id":772,"depth":449,"text":773},{"id":930,"depth":449,"text":931},{"id":1083,"depth":449,"text":1084},{"id":1638,"depth":449,"text":1639,"children":3412},[3413,3414],{"id":1645,"depth":455,"text":1646},{"id":1758,"depth":455,"text":1759},{"id":1930,"depth":449,"text":1931},{"id":1962,"depth":449,"text":1963,"children":3417},[3418],{"id":1999,"depth":455,"text":2000},{"id":2155,"depth":449,"text":2156},{"id":2288,"depth":449,"text":2289},{"id":2425,"depth":449,"text":2426},{"id":2468,"depth":449,"text":2469},{"id":2708,"depth":449,"text":2709,"children":3424},[3425],{"id":2738,"depth":455,"text":2739},{"id":3059,"depth":449,"text":3060},{"id":3091,"depth":449,"text":3092},{"id":3125,"depth":449,"text":3126},{"id":3163,"depth":449,"text":3164},{"id":3204,"depth":449,"text":3205,"children":3431},[3432,3433],{"id":3208,"depth":455,"text":3209},{"id":3294,"depth":455,"text":3295},"2026-01-31","A complete beginner-friendly guide to Firebase Crashlytics in Flutter — what it is, how to set it up properly, and how professionals use it in real apps.","md","/img/flutter-firebase-crashlytics.png",{},{"title":10,"description":3435},"Flutter In Production","published",[1881,3443,3444,199,3445],"firebase","crashlytics","debugging","XWVjGBOgYqEL7GC315Ez5S8p-33RaYktwy5IjhV4xpQ",{"id":3448,"title":22,"author":36,"body":3449,"date":8564,"description":8565,"extension":3436,"image":8566,"meta":8567,"minRead":36,"navigation":476,"path":23,"seo":8568,"series":3440,"status":3441,"stem":24,"tags":8569,"__hash__":8573},"articles/articles/flutter-environment-setup.md",{"type":38,"value":3450,"toc":8499},[3451,3461,3467,3476,3482,3485,3487,3491,3494,3500,3517,3522,3539,3548,3551,3553,3557,3561,3576,3580,3595,3601,3603,3607,3610,3618,3626,3629,3631,3635,3638,3764,3769,3783,3785,3789,3792,4033,4041,4043,4047,4061,4065,4079,4083,4090,4415,4419,4425,4570,4584,4586,4590,4601,4858,4863,4883,4885,4889,4899,4905,5248,5253,5270,5272,5276,5279,5287,5530,5537,5814,5819,5842,5844,5848,5851,6046,6051,6065,6072,6074,6078,6082,6092,6112,6116,6121,6143,6148,6197,6201,6206,6227,6232,6294,6303,6307,6364,6377,6379,6383,6393,6497,6502,6519,6523,6526,6532,6535,6537,6541,6551,6555,6561,6567,6571,6576,6582,6586,6589,6595,6598,6615,6620,6622,6626,6629,7048,7053,7095,7098,7100,7104,7107,7182,7187,7204,7207,7209,7213,7217,7251,7255,7270,7280,7282,7285,7300,7303,7332,7337,7339,7342,7366,7369,7392,7397,7399,7402,7417,7420,7440,7445,7447,7451,7458,7464,7757,7760,7762,7769,7772,7918,7921,7923,7930,7937,8035,8038,8064,8067,8069,8076,8081,8093,8098,8120,8125,8136,8139,8141,8148,8151,8212,8215,8217,8221,8224,8350,8353,8355,8359,8365,8374,8377,8403,8406,8409,8426,8432,8435,8437,8441,8446,8473,8486,8489,8491,8496],[41,3452,3453,3457],{},[44,3454,3455],{"id":46},[48,3456],{"value":50},[52,3458,3459],{},[48,3460],{"value":56},[52,3462,3463,3464,3466],{},"So your Flutter app is lowkey perfect on your device, right?",[61,3465],{},"\nThen you deploy to prod and... 💀 everything's on fire.",[52,3468,3469,3470,3472,3473,3475],{},"Wrong API endpoint gets hit.",[61,3471],{},"\nTest data shows up for actual users.",[61,3474],{},"\nDebug logs are out here exposing passwords.",[52,3477,3478,3479,168],{},"That's when it hits you: ",[77,3480,3481],{},"you need proper environment setup, bestie",[52,3483,3484],{},"Let's fix this mess — with real code from an actual production app that doesn't crash and burn.",[82,3486],{},[85,3488,3490],{"id":3489},"wait-what-even-is-an-environment","🧠 Wait, What Even Is an \"Environment\"?",[52,3492,3493],{},"Think of environments like your app having different vibes:",[52,3495,3496,3499],{},[77,3497,3498],{},"Development (Dev)"," 🛠️",[93,3501,3502,3505,3508,3511,3514],{},[96,3503,3504],{},"Your personal testing sandbox",[96,3506,3507],{},"Breaking stuff is literally the point",[96,3509,3510],{},"Logs? Absolutely everywhere",[96,3512,3513],{},"Test Firebase project",[96,3515,3516],{},"Fake payment systems (no cap, you're not charging yourself)",[52,3518,3519,3388],{},[77,3520,3521],{},"Production (Prod)",[93,3523,3524,3527,3530,3533,3536],{},[96,3525,3526],{},"Where actual humans use your app",[96,3528,3529],{},"Breaking stuff = career-limiting move",[96,3531,3532],{},"Only essential logs",[96,3534,3535],{},"Real Firebase project",[96,3537,3538],{},"Real payment systems (yes, real money)",[52,3540,3541,3542,3544,3545,3547],{},"Same codebase.",[61,3543],{},"\nDifferent configs.",[61,3546],{},"\nNever the two shall meet.",[52,3549,3550],{},"That's literally it, fam.",[82,3552],{},[85,3554,3556],{"id":3555},"why-should-you-even-care-though","🤔 Why Should You Even Care Though?",[280,3558,3560],{"id":3559},"without-environment-setup-chaos-mode","Without Environment Setup (chaos mode):",[52,3562,3563,3564,3566,3567,3569,3570,3572,3573,3575],{},"❌ Test data pollutes your real database",[61,3565],{},"\n❌ Debug logs straight-up leak user passwords",[61,3568],{},"\n❌ Beta features accidentally go live",[61,3571],{},"\n❌ One oopsie = every user is affected",[61,3574],{},"\n❌ You're deploying fixes at 2 AM (not it)",[280,3577,3579],{"id":3578},"with-environment-setup-peaceful-mode","With Environment Setup (peaceful mode):",[52,3581,3582,3583,3585,3586,3588,3589,3591,3592,3594],{},"✅ Dev and prod are completely isolated",[61,3584],{},"\n✅ Logs know what's up with each environment",[61,3587],{},"\n✅ Test features without yolo-ing to prod",[61,3590],{},"\n✅ Mistakes stay in dev where they belong",[61,3593],{},"\n✅ Actually sleep after releases 😌",[52,3596,3597,3598,168],{},"This ain't \"senior dev flex\" territory — it's ",[77,3599,3600],{},"bare minimum for production apps",[82,3602],{},[85,3604,3606],{"id":3605},"️-the-architecture-actually-not-complicated","🏗️ The Architecture (Actually Not Complicated)",[52,3608,3609],{},"Here's how apps that don't suck structure environments:",[431,3611,3616],{"className":3612,"code":3614,"language":3615},[3613],"language-text","lib/\n├── main_dev.dart          ← Dev entry point\n├── main_prod.dart         ← Prod entry point\n├── app.dart               ← The actual app widget\n├── config/\n│   ├── environment.dart   ← Environment enum\n│   ├── app_config.dart    ← Config model\n│   ├── env_loader.dart    ← Loads .env files\n│   └── env/\n│       ├── dev_config.dart  ← Dev values\n│       └── prod_config.dart ← Prod values\n","text",[437,3617,3614],{"__ignoreMap":46},[52,3619,3620,3623,3625],{},[77,3621,3622],{},"The vibe:",[61,3624],{},"\nDifferent entry points → load different configs → same app, different behavior.",[52,3627,3628],{},"No magic tricks. No rocket science. Just clean separation of concerns.",[82,3630],{},[85,3632,3634],{"id":3633},"step-1-define-your-environment-enum","📦 Step 1: Define Your Environment Enum",[52,3636,3637],{},"First up, create a super simple enum for your environments:",[431,3639,3641],{"className":433,"code":3640,"language":435,"meta":46,"style":46},"/// Enum representing the different environments the app can run in\nenum Environment {\n  /// Development environment - for development and testing\n  development,\n\n  /// Production environment - for live users\n  production,\n}\n\n/// Global variable to hold the current environment\nclass EnvironmentConfig {\n  static Environment _environment = Environment.development;\n\n  /// Get the current environment\n  static Environment get environment => _environment;\n\n  /// Set the current environment\n  /// Should only be called at app startup\n  static void setEnvironment(Environment env) {\n    _environment = env;\n  }\n\n  /// Check if the app is running in development mode\n  static bool get isDevelopment => _environment == Environment.development;\n\n  /// Check if the app is running in production mode\n  static bool get isProduction => _environment == Environment.production;\n}\n",[437,3642,3643,3648,3652,3657,3661,3665,3670,3674,3678,3682,3687,3691,3695,3699,3704,3708,3712,3717,3722,3726,3730,3734,3738,3743,3747,3751,3756,3760],{"__ignoreMap":46},[440,3644,3645],{"class":442,"line":443},[440,3646,3647],{},"/// Enum representing the different environments the app can run in\n",[440,3649,3650],{"class":442,"line":449},[440,3651,452],{},[440,3653,3654],{"class":442,"line":455},[440,3655,3656],{},"  /// Development environment - for development and testing\n",[440,3658,3659],{"class":442,"line":461},[440,3660,458],{},[440,3662,3663],{"class":442,"line":467},[440,3664,477],{"emptyLinePlaceholder":476},[440,3666,3667],{"class":442,"line":473},[440,3668,3669],{},"  /// Production environment - for live users\n",[440,3671,3672],{"class":442,"line":480},[440,3673,464],{},[440,3675,3676],{"class":442,"line":486},[440,3677,470],{},[440,3679,3680],{"class":442,"line":492},[440,3681,477],{"emptyLinePlaceholder":476},[440,3683,3684],{"class":442,"line":497},[440,3685,3686],{},"/// Global variable to hold the current environment\n",[440,3688,3689],{"class":442,"line":503},[440,3690,483],{},[440,3692,3693],{"class":442,"line":508},[440,3694,489],{},[440,3696,3697],{"class":442,"line":514},[440,3698,477],{"emptyLinePlaceholder":476},[440,3700,3701],{"class":442,"line":520},[440,3702,3703],{},"  /// Get the current environment\n",[440,3705,3706],{"class":442,"line":526},[440,3707,500],{},[440,3709,3710],{"class":442,"line":531},[440,3711,477],{"emptyLinePlaceholder":476},[440,3713,3714],{"class":442,"line":537},[440,3715,3716],{},"  /// Set the current environment\n",[440,3718,3719],{"class":442,"line":543},[440,3720,3721],{},"  /// Should only be called at app startup\n",[440,3723,3724],{"class":442,"line":648},[440,3725,511],{},[440,3727,3728],{"class":442,"line":654},[440,3729,517],{},[440,3731,3732],{"class":442,"line":660},[440,3733,523],{},[440,3735,3736],{"class":442,"line":665},[440,3737,477],{"emptyLinePlaceholder":476},[440,3739,3740],{"class":442,"line":671},[440,3741,3742],{},"  /// Check if the app is running in development mode\n",[440,3744,3745],{"class":442,"line":677},[440,3746,534],{},[440,3748,3749],{"class":442,"line":683},[440,3750,477],{"emptyLinePlaceholder":476},[440,3752,3753],{"class":442,"line":689},[440,3754,3755],{},"  /// Check if the app is running in production mode\n",[440,3757,3758],{"class":442,"line":695},[440,3759,540],{},[440,3761,3762],{"class":442,"line":701},[440,3763,470],{},[52,3765,3766],{},[77,3767,3768],{},"Why this slaps:",[93,3770,3771,3774,3777,3780],{},[96,3772,3773],{},"Dead simple static class, no overcomplicated state management",[96,3775,3776],{},"Set it once when your app starts",[96,3778,3779],{},"Check it anywhere you want",[96,3781,3782],{},"Zero performance hit (literally none)",[82,3784],{},[85,3786,3788],{"id":3787},"step-2-create-your-config-model","🎯 Step 2: Create Your Config Model",[52,3790,3791],{},"Now let's define what \"configuration\" even means for your app:",[431,3793,3795],{"className":433,"code":3794,"language":435,"meta":46,"style":46},"import 'environment.dart';\n\n/// Configuration model that holds all environment-specific settings\nclass AppConfig {\n  /// The environment this configuration is for\n  final Environment environment;\n\n  /// API base URL for backend services\n  final String apiBaseUrl;\n\n  /// Firebase configuration\n  final String firebaseApiKey;\n  final String firebaseAppId;\n  final String firebaseMessagingSenderId;\n  final String firebaseProjectId;\n\n  /// Feature flags\n  final Map\u003CString, bool> featureFlags;\n\n  /// Debug mode flag\n  final bool debugMode;\n\n  /// Log level - controls what gets logged\n  /// DEBUG = 0, INFO = 1, WARNING = 2, ERROR = 3, FATAL = 4\n  final int logLevel;\n\n  /// App encryption key for secure storage\n  final String appEncryptionKey;\n\n  /// App name (can differ between environments)\n  final String appName;\n\n  /// Application ID (bundle identifier)\n  final String applicationId;\n\n  const AppConfig({\n    required this.environment,\n    required this.apiBaseUrl,\n    required this.firebaseApiKey,\n    required this.firebaseAppId,\n    required this.firebaseMessagingSenderId,\n    required this.firebaseProjectId,\n    required this.featureFlags,\n    required this.debugMode,\n    required this.logLevel,\n    required this.appEncryptionKey,\n    required this.appName,\n    required this.applicationId,\n  });\n\n  /// Check if a feature is enabled\n  bool isFeatureEnabled(String featureName) {\n    return featureFlags[featureName] ?? false;\n  }\n}\n",[437,3796,3797,3802,3806,3811,3815,3820,3824,3828,3833,3837,3841,3846,3850,3854,3858,3862,3866,3871,3875,3879,3884,3888,3892,3897,3902,3907,3911,3916,3921,3925,3930,3934,3938,3943,3947,3951,3955,3959,3963,3967,3971,3975,3979,3983,3987,3991,3996,4000,4004,4008,4012,4017,4021,4025,4029],{"__ignoreMap":46},[440,3798,3799],{"class":442,"line":443},[440,3800,3801],{},"import 'environment.dart';\n",[440,3803,3804],{"class":442,"line":449},[440,3805,477],{"emptyLinePlaceholder":476},[440,3807,3808],{"class":442,"line":455},[440,3809,3810],{},"/// Configuration model that holds all environment-specific settings\n",[440,3812,3813],{"class":442,"line":461},[440,3814,569],{},[440,3816,3817],{"class":442,"line":467},[440,3818,3819],{},"  /// The environment this configuration is for\n",[440,3821,3822],{"class":442,"line":473},[440,3823,574],{},[440,3825,3826],{"class":442,"line":480},[440,3827,477],{"emptyLinePlaceholder":476},[440,3829,3830],{"class":442,"line":486},[440,3831,3832],{},"  /// API base URL for backend services\n",[440,3834,3835],{"class":442,"line":492},[440,3836,579],{},[440,3838,3839],{"class":442,"line":497},[440,3840,477],{"emptyLinePlaceholder":476},[440,3842,3843],{"class":442,"line":503},[440,3844,3845],{},"  /// Firebase configuration\n",[440,3847,3848],{"class":442,"line":508},[440,3849,593],{},[440,3851,3852],{"class":442,"line":514},[440,3853,598],{},[440,3855,3856],{"class":442,"line":520},[440,3857,603],{},[440,3859,3860],{"class":442,"line":526},[440,3861,608],{},[440,3863,3864],{"class":442,"line":531},[440,3865,477],{"emptyLinePlaceholder":476},[440,3867,3868],{"class":442,"line":537},[440,3869,3870],{},"  /// Feature flags\n",[440,3872,3873],{"class":442,"line":543},[440,3874,622],{},[440,3876,3877],{"class":442,"line":648},[440,3878,477],{"emptyLinePlaceholder":476},[440,3880,3881],{"class":442,"line":654},[440,3882,3883],{},"  /// Debug mode flag\n",[440,3885,3886],{"class":442,"line":660},[440,3887,636],{},[440,3889,3890],{"class":442,"line":665},[440,3891,477],{"emptyLinePlaceholder":476},[440,3893,3894],{"class":442,"line":671},[440,3895,3896],{},"  /// Log level - controls what gets logged\n",[440,3898,3899],{"class":442,"line":677},[440,3900,3901],{},"  /// DEBUG = 0, INFO = 1, WARNING = 2, ERROR = 3, FATAL = 4\n",[440,3903,3904],{"class":442,"line":683},[440,3905,3906],{},"  final int logLevel;\n",[440,3908,3909],{"class":442,"line":689},[440,3910,477],{"emptyLinePlaceholder":476},[440,3912,3913],{"class":442,"line":695},[440,3914,3915],{},"  /// App encryption key for secure storage\n",[440,3917,3918],{"class":442,"line":701},[440,3919,3920],{},"  final String appEncryptionKey;\n",[440,3922,3923],{"class":442,"line":707},[440,3924,477],{"emptyLinePlaceholder":476},[440,3926,3927],{"class":442,"line":713},[440,3928,3929],{},"  /// App name (can differ between environments)\n",[440,3931,3932],{"class":442,"line":719},[440,3933,651],{},[440,3935,3936],{"class":442,"line":725},[440,3937,477],{"emptyLinePlaceholder":476},[440,3939,3940],{"class":442,"line":731},[440,3941,3942],{},"  /// Application ID (bundle identifier)\n",[440,3944,3945],{"class":442,"line":737},[440,3946,657],{},[440,3948,3949],{"class":442,"line":743},[440,3950,477],{"emptyLinePlaceholder":476},[440,3952,3953],{"class":442,"line":748},[440,3954,668],{},[440,3956,3957],{"class":442,"line":754},[440,3958,674],{},[440,3960,3961],{"class":442,"line":760},[440,3962,680],{},[440,3964,3965],{"class":442,"line":765},[440,3966,686],{},[440,3968,3969],{"class":442,"line":1280},[440,3970,692],{},[440,3972,3973],{"class":442,"line":1286},[440,3974,698],{},[440,3976,3977],{"class":442,"line":1292},[440,3978,704],{},[440,3980,3981],{"class":442,"line":1297},[440,3982,710],{},[440,3984,3985],{"class":442,"line":1303},[440,3986,716],{},[440,3988,3989],{"class":442,"line":1309},[440,3990,722],{},[440,3992,3993],{"class":442,"line":1314},[440,3994,3995],{},"    required this.appEncryptionKey,\n",[440,3997,3998],{"class":442,"line":1320},[440,3999,728],{},[440,4001,4002],{"class":442,"line":1326},[440,4003,734],{},[440,4005,4006],{"class":442,"line":1332},[440,4007,740],{},[440,4009,4010],{"class":442,"line":1338},[440,4011,477],{"emptyLinePlaceholder":476},[440,4013,4014],{"class":442,"line":1343},[440,4015,4016],{},"  /// Check if a feature is enabled\n",[440,4018,4019],{"class":442,"line":1349},[440,4020,751],{},[440,4022,4023],{"class":442,"line":1355},[440,4024,757],{},[440,4026,4027],{"class":442,"line":1361},[440,4028,523],{},[440,4030,4031],{"class":442,"line":1367},[440,4032,470],{},[52,4034,4035,4038,4040],{},[77,4036,4037],{},"This is literally your single source of truth.",[61,4039],{},"\nEverything that changes between environments lives right here, bestie.",[82,4042],{},[85,4044,4046],{"id":4045},"️-step-3-the-env-file-approach-modern-clean","🛠️ Step 3: The .env File Approach (Modern & Clean)",[52,4048,4049,4050,4053,4054,4060],{},"Before we dive into config values, let's talk about how to actually ",[3111,4051,4052],{},"load"," them. This project uses a ",[77,4055,4056,4059],{},[437,4057,4058],{},".env"," file approach"," which is honestly chef's kiss 👌",[280,4062,4064],{"id":4063},"why-env-files-are-goated","Why .env files are goated:",[93,4066,4067,4070,4073,4076],{},[96,4068,4069],{},"Run from IDE without complicated build scripts",[96,4071,4072],{},"Keep secrets out of your codebase",[96,4074,4075],{},"Switch environments easily",[96,4077,4078],{},"Works with both IDE runs AND build scripts",[280,4080,4082],{"id":4081},"create-the-envloader","Create the EnvLoader",[52,4084,4085,4086,4089],{},"First, create ",[437,4087,4088],{},"lib/config/env_loader.dart",":",[431,4091,4093],{"className":433,"code":4092,"language":435,"meta":46,"style":46},"import 'dart:io';\nimport 'package:flutter/foundation.dart';\n\n/// Loads environment variables from .env files\nclass EnvLoader {\n  static Map\u003CString, String>? _envCache;\n\n  /// Load environment variables from a .env file\n  static Future\u003CMap\u003CString, String>> load(String envFile) async {\n    if (_envCache != null) return _envCache!;\n\n    final env = \u003CString, String>{};\n\n    try {\n      final file = File(envFile);\n\n      if (!await file.exists()) {\n        debugPrint('⚠️  Environment file not found: $envFile');\n        return env;\n      }\n\n      final lines = await file.readAsLines();\n\n      for (var line in lines) {\n        line = line.trim();\n        if (line.isEmpty || line.startsWith('#')) continue;\n\n        final separatorIndex = line.indexOf('=');\n        if (separatorIndex == -1) continue;\n\n        final key = line.substring(0, separatorIndex).trim();\n        var value = line.substring(separatorIndex + 1).trim();\n\n        // Remove quotes\n        if (value.startsWith('\"') && value.endsWith('\"')) {\n          value = value.substring(1, value.length - 1);\n        }\n\n        env[key] = value;\n      }\n\n      _envCache = env;\n    } catch (e) {\n      debugPrint('❌ Error loading environment file: $e');\n    }\n\n    return env;\n  }\n\n  /// Get an environment variable\n  /// Priority: --dart-define > .env file > default\n  static String getVar(\n    String key,\n    Map\u003CString, String> envMap, {\n    String defaultValue = '',\n  }) {\n    // Check --dart-define first (from build scripts)\n    final compileTimeValue = String.fromEnvironment(key, defaultValue: '');\n    if (compileTimeValue.isNotEmpty) return compileTimeValue;\n\n    // Then check .env file (for IDE runs)\n    if (envMap.containsKey(key) && envMap[key]!.isNotEmpty) {\n      return envMap[key]!;\n    }\n\n    // Finally use default\n    return defaultValue;\n  }\n}\n",[437,4094,4095,4100,4104,4108,4113,4118,4123,4127,4132,4137,4142,4146,4151,4155,4160,4165,4169,4174,4179,4184,4188,4192,4197,4201,4206,4211,4216,4220,4225,4230,4234,4239,4244,4248,4253,4258,4263,4268,4272,4277,4281,4285,4290,4295,4300,4304,4308,4313,4317,4321,4326,4331,4336,4341,4346,4351,4355,4360,4365,4370,4374,4379,4384,4389,4393,4397,4402,4407,4411],{"__ignoreMap":46},[440,4096,4097],{"class":442,"line":443},[440,4098,4099],{},"import 'dart:io';\n",[440,4101,4102],{"class":442,"line":449},[440,4103,1112],{},[440,4105,4106],{"class":442,"line":455},[440,4107,477],{"emptyLinePlaceholder":476},[440,4109,4110],{"class":442,"line":461},[440,4111,4112],{},"/// Loads environment variables from .env files\n",[440,4114,4115],{"class":442,"line":467},[440,4116,4117],{},"class EnvLoader {\n",[440,4119,4120],{"class":442,"line":473},[440,4121,4122],{},"  static Map\u003CString, String>? _envCache;\n",[440,4124,4125],{"class":442,"line":480},[440,4126,477],{"emptyLinePlaceholder":476},[440,4128,4129],{"class":442,"line":486},[440,4130,4131],{},"  /// Load environment variables from a .env file\n",[440,4133,4134],{"class":442,"line":492},[440,4135,4136],{},"  static Future\u003CMap\u003CString, String>> load(String envFile) async {\n",[440,4138,4139],{"class":442,"line":497},[440,4140,4141],{},"    if (_envCache != null) return _envCache!;\n",[440,4143,4144],{"class":442,"line":503},[440,4145,477],{"emptyLinePlaceholder":476},[440,4147,4148],{"class":442,"line":508},[440,4149,4150],{},"    final env = \u003CString, String>{};\n",[440,4152,4153],{"class":442,"line":514},[440,4154,477],{"emptyLinePlaceholder":476},[440,4156,4157],{"class":442,"line":520},[440,4158,4159],{},"    try {\n",[440,4161,4162],{"class":442,"line":526},[440,4163,4164],{},"      final file = File(envFile);\n",[440,4166,4167],{"class":442,"line":531},[440,4168,477],{"emptyLinePlaceholder":476},[440,4170,4171],{"class":442,"line":537},[440,4172,4173],{},"      if (!await file.exists()) {\n",[440,4175,4176],{"class":442,"line":543},[440,4177,4178],{},"        debugPrint('⚠️  Environment file not found: $envFile');\n",[440,4180,4181],{"class":442,"line":648},[440,4182,4183],{},"        return env;\n",[440,4185,4186],{"class":442,"line":654},[440,4187,2668],{},[440,4189,4190],{"class":442,"line":660},[440,4191,477],{"emptyLinePlaceholder":476},[440,4193,4194],{"class":442,"line":665},[440,4195,4196],{},"      final lines = await file.readAsLines();\n",[440,4198,4199],{"class":442,"line":671},[440,4200,477],{"emptyLinePlaceholder":476},[440,4202,4203],{"class":442,"line":677},[440,4204,4205],{},"      for (var line in lines) {\n",[440,4207,4208],{"class":442,"line":683},[440,4209,4210],{},"        line = line.trim();\n",[440,4212,4213],{"class":442,"line":689},[440,4214,4215],{},"        if (line.isEmpty || line.startsWith('#')) continue;\n",[440,4217,4218],{"class":442,"line":695},[440,4219,477],{"emptyLinePlaceholder":476},[440,4221,4222],{"class":442,"line":701},[440,4223,4224],{},"        final separatorIndex = line.indexOf('=');\n",[440,4226,4227],{"class":442,"line":707},[440,4228,4229],{},"        if (separatorIndex == -1) continue;\n",[440,4231,4232],{"class":442,"line":713},[440,4233,477],{"emptyLinePlaceholder":476},[440,4235,4236],{"class":442,"line":719},[440,4237,4238],{},"        final key = line.substring(0, separatorIndex).trim();\n",[440,4240,4241],{"class":442,"line":725},[440,4242,4243],{},"        var value = line.substring(separatorIndex + 1).trim();\n",[440,4245,4246],{"class":442,"line":731},[440,4247,477],{"emptyLinePlaceholder":476},[440,4249,4250],{"class":442,"line":737},[440,4251,4252],{},"        // Remove quotes\n",[440,4254,4255],{"class":442,"line":743},[440,4256,4257],{},"        if (value.startsWith('\"') && value.endsWith('\"')) {\n",[440,4259,4260],{"class":442,"line":748},[440,4261,4262],{},"          value = value.substring(1, value.length - 1);\n",[440,4264,4265],{"class":442,"line":754},[440,4266,4267],{},"        }\n",[440,4269,4270],{"class":442,"line":760},[440,4271,477],{"emptyLinePlaceholder":476},[440,4273,4274],{"class":442,"line":765},[440,4275,4276],{},"        env[key] = value;\n",[440,4278,4279],{"class":442,"line":1280},[440,4280,2668],{},[440,4282,4283],{"class":442,"line":1286},[440,4284,477],{"emptyLinePlaceholder":476},[440,4286,4287],{"class":442,"line":1292},[440,4288,4289],{},"      _envCache = env;\n",[440,4291,4292],{"class":442,"line":1297},[440,4293,4294],{},"    } catch (e) {\n",[440,4296,4297],{"class":442,"line":1303},[440,4298,4299],{},"      debugPrint('❌ Error loading environment file: $e');\n",[440,4301,4302],{"class":442,"line":1309},[440,4303,1289],{},[440,4305,4306],{"class":442,"line":1314},[440,4307,477],{"emptyLinePlaceholder":476},[440,4309,4310],{"class":442,"line":1320},[440,4311,4312],{},"    return env;\n",[440,4314,4315],{"class":442,"line":1326},[440,4316,523],{},[440,4318,4319],{"class":442,"line":1332},[440,4320,477],{"emptyLinePlaceholder":476},[440,4322,4323],{"class":442,"line":1338},[440,4324,4325],{},"  /// Get an environment variable\n",[440,4327,4328],{"class":442,"line":1343},[440,4329,4330],{},"  /// Priority: --dart-define > .env file > default\n",[440,4332,4333],{"class":442,"line":1349},[440,4334,4335],{},"  static String getVar(\n",[440,4337,4338],{"class":442,"line":1355},[440,4339,4340],{},"    String key,\n",[440,4342,4343],{"class":442,"line":1361},[440,4344,4345],{},"    Map\u003CString, String> envMap, {\n",[440,4347,4348],{"class":442,"line":1367},[440,4349,4350],{},"    String defaultValue = '',\n",[440,4352,4353],{"class":442,"line":1372},[440,4354,2618],{},[440,4356,4357],{"class":442,"line":1378},[440,4358,4359],{},"    // Check --dart-define first (from build scripts)\n",[440,4361,4362],{"class":442,"line":1384},[440,4363,4364],{},"    final compileTimeValue = String.fromEnvironment(key, defaultValue: '');\n",[440,4366,4367],{"class":442,"line":1390},[440,4368,4369],{},"    if (compileTimeValue.isNotEmpty) return compileTimeValue;\n",[440,4371,4372],{"class":442,"line":1396},[440,4373,477],{"emptyLinePlaceholder":476},[440,4375,4376],{"class":442,"line":1401},[440,4377,4378],{},"    // Then check .env file (for IDE runs)\n",[440,4380,4381],{"class":442,"line":1406},[440,4382,4383],{},"    if (envMap.containsKey(key) && envMap[key]!.isNotEmpty) {\n",[440,4385,4386],{"class":442,"line":1411},[440,4387,4388],{},"      return envMap[key]!;\n",[440,4390,4391],{"class":442,"line":1417},[440,4392,1289],{},[440,4394,4395],{"class":442,"line":1423},[440,4396,477],{"emptyLinePlaceholder":476},[440,4398,4399],{"class":442,"line":1429},[440,4400,4401],{},"    // Finally use default\n",[440,4403,4404],{"class":442,"line":1435},[440,4405,4406],{},"    return defaultValue;\n",[440,4408,4409],{"class":442,"line":1440},[440,4410,523],{},[440,4412,4413],{"class":442,"line":1445},[440,4414,470],{},[280,4416,4418],{"id":4417},"create-envdev-file","Create .env.dev File",[52,4420,4421,4422,4089],{},"In your project root, create ",[437,4423,4424],{},".env.dev",[431,4426,4430],{"className":4427,"code":4428,"language":4429,"meta":46,"style":46},"language-dotenv shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# Development Environment Variables\n# Used when running from IDE or with make dev-run\n\nENCRYPTION_KEY=dev_test_key_32_chars_long_12\n\n# ============================================\n# App Configuration\n# ============================================\nAPP_NAME=Social App Dev\nAPPLICATION_ID=com.example.flutter_bloc.dev\n\n# ============================================\n# API Configuration\n# ============================================\nAPI_BASE_URL=https://dummyjson.com\n\n# ============================================\n# Firebase Configuration (Development Project)\n# ============================================\nFIREBASE_API_KEY=your_dev_firebase_api_key\nFIREBASE_APP_ID=your_dev_firebase_app_id\nFIREBASE_MESSAGING_SENDER_ID=your_dev_sender_id\nFIREBASE_PROJECT_ID=your-app-dev\n\n# ============================================\n# Optional: Third-Party Services\n# ============================================\n# GOOGLE_MAPS_API_KEY=\n# STRIPE_PUBLISHABLE_KEY=\n# SENTRY_DSN=\n","dotenv",[437,4431,4432,4437,4442,4446,4451,4455,4460,4465,4469,4474,4479,4483,4487,4492,4496,4501,4505,4509,4514,4518,4523,4528,4533,4538,4542,4546,4551,4555,4560,4565],{"__ignoreMap":46},[440,4433,4434],{"class":442,"line":443},[440,4435,4436],{},"# Development Environment Variables\n",[440,4438,4439],{"class":442,"line":449},[440,4440,4441],{},"# Used when running from IDE or with make dev-run\n",[440,4443,4444],{"class":442,"line":455},[440,4445,477],{"emptyLinePlaceholder":476},[440,4447,4448],{"class":442,"line":461},[440,4449,4450],{},"ENCRYPTION_KEY=dev_test_key_32_chars_long_12\n",[440,4452,4453],{"class":442,"line":467},[440,4454,477],{"emptyLinePlaceholder":476},[440,4456,4457],{"class":442,"line":473},[440,4458,4459],{},"# ============================================\n",[440,4461,4462],{"class":442,"line":480},[440,4463,4464],{},"# App Configuration\n",[440,4466,4467],{"class":442,"line":486},[440,4468,4459],{},[440,4470,4471],{"class":442,"line":492},[440,4472,4473],{},"APP_NAME=Social App Dev\n",[440,4475,4476],{"class":442,"line":497},[440,4477,4478],{},"APPLICATION_ID=com.example.flutter_bloc.dev\n",[440,4480,4481],{"class":442,"line":503},[440,4482,477],{"emptyLinePlaceholder":476},[440,4484,4485],{"class":442,"line":508},[440,4486,4459],{},[440,4488,4489],{"class":442,"line":514},[440,4490,4491],{},"# API Configuration\n",[440,4493,4494],{"class":442,"line":520},[440,4495,4459],{},[440,4497,4498],{"class":442,"line":526},[440,4499,4500],{},"API_BASE_URL=https://dummyjson.com\n",[440,4502,4503],{"class":442,"line":531},[440,4504,477],{"emptyLinePlaceholder":476},[440,4506,4507],{"class":442,"line":537},[440,4508,4459],{},[440,4510,4511],{"class":442,"line":543},[440,4512,4513],{},"# Firebase Configuration (Development Project)\n",[440,4515,4516],{"class":442,"line":648},[440,4517,4459],{},[440,4519,4520],{"class":442,"line":654},[440,4521,4522],{},"FIREBASE_API_KEY=your_dev_firebase_api_key\n",[440,4524,4525],{"class":442,"line":660},[440,4526,4527],{},"FIREBASE_APP_ID=your_dev_firebase_app_id\n",[440,4529,4530],{"class":442,"line":665},[440,4531,4532],{},"FIREBASE_MESSAGING_SENDER_ID=your_dev_sender_id\n",[440,4534,4535],{"class":442,"line":671},[440,4536,4537],{},"FIREBASE_PROJECT_ID=your-app-dev\n",[440,4539,4540],{"class":442,"line":677},[440,4541,477],{"emptyLinePlaceholder":476},[440,4543,4544],{"class":442,"line":683},[440,4545,4459],{},[440,4547,4548],{"class":442,"line":689},[440,4549,4550],{},"# Optional: Third-Party Services\n",[440,4552,4553],{"class":442,"line":695},[440,4554,4459],{},[440,4556,4557],{"class":442,"line":701},[440,4558,4559],{},"# GOOGLE_MAPS_API_KEY=\n",[440,4561,4562],{"class":442,"line":707},[440,4563,4564],{},"# STRIPE_PUBLISHABLE_KEY=\n",[440,4566,4567],{"class":442,"line":713},[440,4568,4569],{},"# SENTRY_DSN=\n",[52,4571,4572,4575,4576,4579,4580,4583],{},[77,4573,4574],{},"Pro tip:"," Add ",[437,4577,4578],{},".env.prod"," to ",[437,4581,4582],{},".gitignore"," so you never accidentally commit production secrets!",[82,4585],{},[85,4587,4589],{"id":4588},"step-4-create-dev-configuration","🔧 Step 4: Create Dev Configuration",[52,4591,4592,4593,4596,4597,4600],{},"Now create ",[437,4594,4595],{},"lib/config/env/dev_config.dart"," that ",[3111,4598,4599],{},"uses"," the .env file:",[431,4602,4604],{"className":433,"code":4603,"language":435,"meta":46,"style":46},"import '../app_config.dart';\nimport '../env_loader.dart';\nimport '../environment.dart';\n\n/// Development environment configuration\nclass DevConfig {\n  static Future\u003CAppConfig> loadConfig() async {\n    // Load environment variables from .env.dev\n    final env = await EnvLoader.load('.env.dev');\n\n    return AppConfig(\n      environment: Environment.development,\n\n      // Load from .env.dev or --dart-define\n      apiBaseUrl: EnvLoader.getVar('API_BASE_URL', env),\n\n      // Firebase Dev Project\n      firebaseApiKey: EnvLoader.getVar('FIREBASE_API_KEY', env),\n      firebaseAppId: EnvLoader.getVar('FIREBASE_APP_ID', env),\n      firebaseMessagingSenderId: EnvLoader.getVar('FIREBASE_MESSAGING_SENDER_ID', env),\n      firebaseProjectId: EnvLoader.getVar('FIREBASE_PROJECT_ID', env),\n\n      // Feature Flags - Everything enabled for testing\n      featureFlags: const {\n        'enable_dark_mode': true,\n        'enable_notifications': true,\n        'enable_analytics': true,\n        'enable_crashlytics': true,\n        'enable_social_login': true,\n        'enable_payments': false, // Keep payments off in dev\n        'enable_chat': true,\n        'enable_video_calls': true,\n        'enable_beta_features': true, // Test those beta features!\n      },\n\n      // Debug settings\n      debugMode: true,\n\n      // Log level: 0 = DEBUG (all the logs, bestie)\n      logLevel: 0,\n\n      // Encryption key\n      appEncryptionKey: EnvLoader.getVar('ENCRYPTION_KEY', env),\n\n      // App name with dev indicator\n      appName: EnvLoader.getVar('APP_NAME', env),\n\n      // Application ID with dev suffix\n      applicationId: EnvLoader.getVar('APPLICATION_ID', env),\n    );\n  }\n}\n",[437,4605,4606,4611,4616,4621,4625,4630,4634,4639,4644,4649,4653,4658,4663,4667,4672,4677,4681,4686,4691,4696,4701,4706,4710,4715,4720,4725,4730,4735,4740,4745,4753,4758,4763,4771,4776,4780,4785,4790,4794,4799,4804,4808,4813,4818,4822,4827,4832,4836,4841,4846,4850,4854],{"__ignoreMap":46},[440,4607,4608],{"class":442,"line":443},[440,4609,4610],{},"import '../app_config.dart';\n",[440,4612,4613],{"class":442,"line":449},[440,4614,4615],{},"import '../env_loader.dart';\n",[440,4617,4618],{"class":442,"line":455},[440,4619,4620],{},"import '../environment.dart';\n",[440,4622,4623],{"class":442,"line":461},[440,4624,477],{"emptyLinePlaceholder":476},[440,4626,4627],{"class":442,"line":467},[440,4628,4629],{},"/// Development environment configuration\n",[440,4631,4632],{"class":442,"line":473},[440,4633,791],{},[440,4635,4636],{"class":442,"line":480},[440,4637,4638],{},"  static Future\u003CAppConfig> loadConfig() async {\n",[440,4640,4641],{"class":442,"line":486},[440,4642,4643],{},"    // Load environment variables from .env.dev\n",[440,4645,4646],{"class":442,"line":492},[440,4647,4648],{},"    final env = await EnvLoader.load('.env.dev');\n",[440,4650,4651],{"class":442,"line":497},[440,4652,477],{"emptyLinePlaceholder":476},[440,4654,4655],{"class":442,"line":503},[440,4656,4657],{},"    return AppConfig(\n",[440,4659,4660],{"class":442,"line":508},[440,4661,4662],{},"      environment: Environment.development,\n",[440,4664,4665],{"class":442,"line":514},[440,4666,477],{"emptyLinePlaceholder":476},[440,4668,4669],{"class":442,"line":520},[440,4670,4671],{},"      // Load from .env.dev or --dart-define\n",[440,4673,4674],{"class":442,"line":526},[440,4675,4676],{},"      apiBaseUrl: EnvLoader.getVar('API_BASE_URL', env),\n",[440,4678,4679],{"class":442,"line":531},[440,4680,477],{"emptyLinePlaceholder":476},[440,4682,4683],{"class":442,"line":537},[440,4684,4685],{},"      // Firebase Dev Project\n",[440,4687,4688],{"class":442,"line":543},[440,4689,4690],{},"      firebaseApiKey: EnvLoader.getVar('FIREBASE_API_KEY', env),\n",[440,4692,4693],{"class":442,"line":648},[440,4694,4695],{},"      firebaseAppId: EnvLoader.getVar('FIREBASE_APP_ID', env),\n",[440,4697,4698],{"class":442,"line":654},[440,4699,4700],{},"      firebaseMessagingSenderId: EnvLoader.getVar('FIREBASE_MESSAGING_SENDER_ID', env),\n",[440,4702,4703],{"class":442,"line":660},[440,4704,4705],{},"      firebaseProjectId: EnvLoader.getVar('FIREBASE_PROJECT_ID', env),\n",[440,4707,4708],{"class":442,"line":665},[440,4709,477],{"emptyLinePlaceholder":476},[440,4711,4712],{"class":442,"line":671},[440,4713,4714],{},"      // Feature Flags - Everything enabled for testing\n",[440,4716,4717],{"class":442,"line":677},[440,4718,4719],{},"      featureFlags: const {\n",[440,4721,4722],{"class":442,"line":683},[440,4723,4724],{},"        'enable_dark_mode': true,\n",[440,4726,4727],{"class":442,"line":689},[440,4728,4729],{},"        'enable_notifications': true,\n",[440,4731,4732],{"class":442,"line":695},[440,4733,4734],{},"        'enable_analytics': true,\n",[440,4736,4737],{"class":442,"line":701},[440,4738,4739],{},"        'enable_crashlytics': true,\n",[440,4741,4742],{"class":442,"line":707},[440,4743,4744],{},"        'enable_social_login': true,\n",[440,4746,4747,4750],{"class":442,"line":713},[440,4748,4749],{},"        'enable_payments': false,",[440,4751,4752],{}," // Keep payments off in dev\n",[440,4754,4755],{"class":442,"line":719},[440,4756,4757],{},"        'enable_chat': true,\n",[440,4759,4760],{"class":442,"line":725},[440,4761,4762],{},"        'enable_video_calls': true,\n",[440,4764,4765,4768],{"class":442,"line":731},[440,4766,4767],{},"        'enable_beta_features': true,",[440,4769,4770],{}," // Test those beta features!\n",[440,4772,4773],{"class":442,"line":737},[440,4774,4775],{},"      },\n",[440,4777,4778],{"class":442,"line":743},[440,4779,477],{"emptyLinePlaceholder":476},[440,4781,4782],{"class":442,"line":748},[440,4783,4784],{},"      // Debug settings\n",[440,4786,4787],{"class":442,"line":754},[440,4788,4789],{},"      debugMode: true,\n",[440,4791,4792],{"class":442,"line":760},[440,4793,477],{"emptyLinePlaceholder":476},[440,4795,4796],{"class":442,"line":765},[440,4797,4798],{},"      // Log level: 0 = DEBUG (all the logs, bestie)\n",[440,4800,4801],{"class":442,"line":1280},[440,4802,4803],{},"      logLevel: 0,\n",[440,4805,4806],{"class":442,"line":1286},[440,4807,477],{"emptyLinePlaceholder":476},[440,4809,4810],{"class":442,"line":1292},[440,4811,4812],{},"      // Encryption key\n",[440,4814,4815],{"class":442,"line":1297},[440,4816,4817],{},"      appEncryptionKey: EnvLoader.getVar('ENCRYPTION_KEY', env),\n",[440,4819,4820],{"class":442,"line":1303},[440,4821,477],{"emptyLinePlaceholder":476},[440,4823,4824],{"class":442,"line":1309},[440,4825,4826],{},"      // App name with dev indicator\n",[440,4828,4829],{"class":442,"line":1314},[440,4830,4831],{},"      appName: EnvLoader.getVar('APP_NAME', env),\n",[440,4833,4834],{"class":442,"line":1320},[440,4835,477],{"emptyLinePlaceholder":476},[440,4837,4838],{"class":442,"line":1326},[440,4839,4840],{},"      // Application ID with dev suffix\n",[440,4842,4843],{"class":442,"line":1332},[440,4844,4845],{},"      applicationId: EnvLoader.getVar('APPLICATION_ID', env),\n",[440,4847,4848],{"class":442,"line":1338},[440,4849,1217],{},[440,4851,4852],{"class":442,"line":1343},[440,4853,523],{},[440,4855,4856],{"class":442,"line":1349},[440,4857,470],{},[52,4859,4860],{},[77,4861,4862],{},"Notice the vibe:",[93,4864,4865,4868,4871,4874,4880],{},[96,4866,4867],{},"Separate Firebase project for dev (crucial!)",[96,4869,4870],{},"All features enabled so you can test everything",[96,4872,4873],{},"DEBUG-level logging (verbose af, exactly what you need)",[96,4875,4876,4879],{},[437,4877,4878],{},".dev"," suffix on app ID (so you know which app you're looking at)",[96,4881,4882],{},"\"Dev\" in the app name (can't miss it)",[82,4884],{},[85,4886,4888],{"id":4887},"step-5-create-prod-configuration-security-first","🚀 Step 5: Create Prod Configuration (Security First!)",[52,4890,4891,4892,4894,4895,4898],{},"Prod is different, fam. We DON'T use a ",[437,4893,4578],{}," file checked into git. Instead, we use ",[437,4896,4897],{},"--dart-define"," flags for maximum security.",[52,4900,4901,4902,4089],{},"Create ",[437,4903,4904],{},"lib/config/env/prod_config.dart",[431,4906,4908],{"className":433,"code":4907,"language":435,"meta":46,"style":46},"import '../app_config.dart';\nimport '../environment.dart';\n\n/// Production environment configuration\n/// \n/// SECURITY: All values come from --dart-define flags\n/// NO hardcoded secrets - will throw errors if missing\nclass ProdConfig {\n  static AppConfig get config {\n    // Get values from --dart-define (or crash trying)\n    final apiBaseUrl = const String.fromEnvironment('API_BASE_URL', defaultValue: '');\n    final firebaseApiKey = const String.fromEnvironment('FIREBASE_API_KEY', defaultValue: '');\n    final firebaseAppId = const String.fromEnvironment('FIREBASE_APP_ID', defaultValue: '');\n    final firebaseMessagingSenderId = const String.fromEnvironment('FIREBASE_MESSAGING_SENDER_ID', defaultValue: '');\n    final firebaseProjectId = const String.fromEnvironment('FIREBASE_PROJECT_ID', defaultValue: '');\n    final encryptionKey = const String.fromEnvironment('ENCRYPTION_KEY', defaultValue: '');\n\n    // Validate that we actually got the values (no cap, this is important)\n    assert(\n      apiBaseUrl.isNotEmpty,\n      '❌ PRODUCTION BUILD ERROR: API_BASE_URL required via --dart-define',\n    );\n    assert(\n      firebaseApiKey.isNotEmpty,\n      '❌ PRODUCTION BUILD ERROR: FIREBASE_API_KEY required via --dart-define',\n    );\n    assert(\n      encryptionKey.length >= 32,\n      '❌ PRODUCTION BUILD ERROR: ENCRYPTION_KEY must be 32+ characters',\n    );\n\n    return AppConfig(\n      environment: Environment.production,\n\n      // Production API endpoint\n      apiBaseUrl: apiBaseUrl,\n\n      // Firebase Production Project (completely separate!)\n      firebaseApiKey: firebaseApiKey,\n      firebaseAppId: firebaseAppId,\n      firebaseMessagingSenderId: firebaseMessagingSenderId,\n      firebaseProjectId: firebaseProjectId,\n\n      // Feature Flags - Controlled rollout\n      featureFlags: const {\n        'enable_dark_mode': true,\n        'enable_notifications': true,\n        'enable_analytics': true,\n        'enable_crashlytics': true,\n        'enable_social_login': true,\n        'enable_payments': true,\n        'enable_chat': true,\n        'enable_video_calls': false, // Not released yet\n        'enable_beta_features': false, // Disabled in prod\n      },\n\n      // Debug settings\n      debugMode: false,\n\n      // Log level: 1 = INFO (no debug noise)\n      logLevel: 1,\n\n      // Encryption key\n      appEncryptionKey: encryptionKey,\n\n      // Clean app name\n      appName: 'Social App',\n\n      // Production bundle ID\n      applicationId: 'com.example.app',\n    );\n  }\n}\n",[437,4909,4910,4914,4918,4922,4927,4932,4937,4942,4946,4951,4956,4961,4966,4971,4976,4981,4986,4990,4995,5000,5005,5010,5014,5018,5023,5028,5032,5036,5041,5046,5050,5054,5058,5063,5067,5072,5077,5081,5086,5091,5096,5101,5106,5110,5115,5119,5123,5127,5131,5135,5139,5144,5148,5156,5164,5168,5172,5176,5181,5185,5190,5195,5199,5203,5208,5212,5217,5222,5226,5231,5236,5240,5244],{"__ignoreMap":46},[440,4911,4912],{"class":442,"line":443},[440,4913,4610],{},[440,4915,4916],{"class":442,"line":449},[440,4917,4620],{},[440,4919,4920],{"class":442,"line":455},[440,4921,477],{"emptyLinePlaceholder":476},[440,4923,4924],{"class":442,"line":461},[440,4925,4926],{},"/// Production environment configuration\n",[440,4928,4929],{"class":442,"line":467},[440,4930,4931],{},"/// \n",[440,4933,4934],{"class":442,"line":473},[440,4935,4936],{},"/// SECURITY: All values come from --dart-define flags\n",[440,4938,4939],{"class":442,"line":480},[440,4940,4941],{},"/// NO hardcoded secrets - will throw errors if missing\n",[440,4943,4944],{"class":442,"line":486},[440,4945,949],{},[440,4947,4948],{"class":442,"line":492},[440,4949,4950],{},"  static AppConfig get config {\n",[440,4952,4953],{"class":442,"line":497},[440,4954,4955],{},"    // Get values from --dart-define (or crash trying)\n",[440,4957,4958],{"class":442,"line":503},[440,4959,4960],{},"    final apiBaseUrl = const String.fromEnvironment('API_BASE_URL', defaultValue: '');\n",[440,4962,4963],{"class":442,"line":508},[440,4964,4965],{},"    final firebaseApiKey = const String.fromEnvironment('FIREBASE_API_KEY', defaultValue: '');\n",[440,4967,4968],{"class":442,"line":514},[440,4969,4970],{},"    final firebaseAppId = const String.fromEnvironment('FIREBASE_APP_ID', defaultValue: '');\n",[440,4972,4973],{"class":442,"line":520},[440,4974,4975],{},"    final firebaseMessagingSenderId = const String.fromEnvironment('FIREBASE_MESSAGING_SENDER_ID', defaultValue: '');\n",[440,4977,4978],{"class":442,"line":526},[440,4979,4980],{},"    final firebaseProjectId = const String.fromEnvironment('FIREBASE_PROJECT_ID', defaultValue: '');\n",[440,4982,4983],{"class":442,"line":531},[440,4984,4985],{},"    final encryptionKey = const String.fromEnvironment('ENCRYPTION_KEY', defaultValue: '');\n",[440,4987,4988],{"class":442,"line":537},[440,4989,477],{"emptyLinePlaceholder":476},[440,4991,4992],{"class":442,"line":543},[440,4993,4994],{},"    // Validate that we actually got the values (no cap, this is important)\n",[440,4996,4997],{"class":442,"line":648},[440,4998,4999],{},"    assert(\n",[440,5001,5002],{"class":442,"line":654},[440,5003,5004],{},"      apiBaseUrl.isNotEmpty,\n",[440,5006,5007],{"class":442,"line":660},[440,5008,5009],{},"      '❌ PRODUCTION BUILD ERROR: API_BASE_URL required via --dart-define',\n",[440,5011,5012],{"class":442,"line":665},[440,5013,1217],{},[440,5015,5016],{"class":442,"line":671},[440,5017,4999],{},[440,5019,5020],{"class":442,"line":677},[440,5021,5022],{},"      firebaseApiKey.isNotEmpty,\n",[440,5024,5025],{"class":442,"line":683},[440,5026,5027],{},"      '❌ PRODUCTION BUILD ERROR: FIREBASE_API_KEY required via --dart-define',\n",[440,5029,5030],{"class":442,"line":689},[440,5031,1217],{},[440,5033,5034],{"class":442,"line":695},[440,5035,4999],{},[440,5037,5038],{"class":442,"line":701},[440,5039,5040],{},"      encryptionKey.length >= 32,\n",[440,5042,5043],{"class":442,"line":707},[440,5044,5045],{},"      '❌ PRODUCTION BUILD ERROR: ENCRYPTION_KEY must be 32+ characters',\n",[440,5047,5048],{"class":442,"line":713},[440,5049,1217],{},[440,5051,5052],{"class":442,"line":719},[440,5053,477],{"emptyLinePlaceholder":476},[440,5055,5056],{"class":442,"line":725},[440,5057,4657],{},[440,5059,5060],{"class":442,"line":731},[440,5061,5062],{},"      environment: Environment.production,\n",[440,5064,5065],{"class":442,"line":737},[440,5066,477],{"emptyLinePlaceholder":476},[440,5068,5069],{"class":442,"line":743},[440,5070,5071],{},"      // Production API endpoint\n",[440,5073,5074],{"class":442,"line":748},[440,5075,5076],{},"      apiBaseUrl: apiBaseUrl,\n",[440,5078,5079],{"class":442,"line":754},[440,5080,477],{"emptyLinePlaceholder":476},[440,5082,5083],{"class":442,"line":760},[440,5084,5085],{},"      // Firebase Production Project (completely separate!)\n",[440,5087,5088],{"class":442,"line":765},[440,5089,5090],{},"      firebaseApiKey: firebaseApiKey,\n",[440,5092,5093],{"class":442,"line":1280},[440,5094,5095],{},"      firebaseAppId: firebaseAppId,\n",[440,5097,5098],{"class":442,"line":1286},[440,5099,5100],{},"      firebaseMessagingSenderId: firebaseMessagingSenderId,\n",[440,5102,5103],{"class":442,"line":1292},[440,5104,5105],{},"      firebaseProjectId: firebaseProjectId,\n",[440,5107,5108],{"class":442,"line":1297},[440,5109,477],{"emptyLinePlaceholder":476},[440,5111,5112],{"class":442,"line":1303},[440,5113,5114],{},"      // Feature Flags - Controlled rollout\n",[440,5116,5117],{"class":442,"line":1309},[440,5118,4719],{},[440,5120,5121],{"class":442,"line":1314},[440,5122,4724],{},[440,5124,5125],{"class":442,"line":1320},[440,5126,4729],{},[440,5128,5129],{"class":442,"line":1326},[440,5130,4734],{},[440,5132,5133],{"class":442,"line":1332},[440,5134,4739],{},[440,5136,5137],{"class":442,"line":1338},[440,5138,4744],{},[440,5140,5141],{"class":442,"line":1343},[440,5142,5143],{},"        'enable_payments': true,\n",[440,5145,5146],{"class":442,"line":1349},[440,5147,4757],{},[440,5149,5150,5153],{"class":442,"line":1355},[440,5151,5152],{},"        'enable_video_calls': false,",[440,5154,5155],{}," // Not released yet\n",[440,5157,5158,5161],{"class":442,"line":1361},[440,5159,5160],{},"        'enable_beta_features': false,",[440,5162,5163],{}," // Disabled in prod\n",[440,5165,5166],{"class":442,"line":1367},[440,5167,4775],{},[440,5169,5170],{"class":442,"line":1372},[440,5171,477],{"emptyLinePlaceholder":476},[440,5173,5174],{"class":442,"line":1378},[440,5175,4784],{},[440,5177,5178],{"class":442,"line":1384},[440,5179,5180],{},"      debugMode: false,\n",[440,5182,5183],{"class":442,"line":1390},[440,5184,477],{"emptyLinePlaceholder":476},[440,5186,5187],{"class":442,"line":1396},[440,5188,5189],{},"      // Log level: 1 = INFO (no debug noise)\n",[440,5191,5192],{"class":442,"line":1401},[440,5193,5194],{},"      logLevel: 1,\n",[440,5196,5197],{"class":442,"line":1406},[440,5198,477],{"emptyLinePlaceholder":476},[440,5200,5201],{"class":442,"line":1411},[440,5202,4812],{},[440,5204,5205],{"class":442,"line":1417},[440,5206,5207],{},"      appEncryptionKey: encryptionKey,\n",[440,5209,5210],{"class":442,"line":1423},[440,5211,477],{"emptyLinePlaceholder":476},[440,5213,5214],{"class":442,"line":1429},[440,5215,5216],{},"      // Clean app name\n",[440,5218,5219],{"class":442,"line":1435},[440,5220,5221],{},"      appName: 'Social App',\n",[440,5223,5224],{"class":442,"line":1440},[440,5225,477],{"emptyLinePlaceholder":476},[440,5227,5228],{"class":442,"line":1445},[440,5229,5230],{},"      // Production bundle ID\n",[440,5232,5233],{"class":442,"line":1451},[440,5234,5235],{},"      applicationId: 'com.example.app',\n",[440,5237,5238],{"class":442,"line":1457},[440,5239,1217],{},[440,5241,5242],{"class":442,"line":1462},[440,5243,523],{},[440,5245,5246],{"class":442,"line":1468},[440,5247,470],{},[52,5249,5250],{},[77,5251,5252],{},"Critical differences that matter:",[93,5254,5255,5258,5261,5264,5267],{},[96,5256,5257],{},"Different Firebase project (test crashes ≠ prod crashes)",[96,5259,5260],{},"Some features disabled (controlled rollout ftw)",[96,5262,5263],{},"INFO-level logging only (no spam)",[96,5265,5266],{},"Clean app name and ID",[96,5268,5269],{},"Requires secrets via --dart-define (can't build without them)",[82,5271],{},[85,5273,5275],{"id":5274},"step-6-create-entry-points-where-the-magic-happens","🚪 Step 6: Create Entry Points (Where the Magic Happens)",[52,5277,5278],{},"Now for the actually fun part — creating different entry points for each environment.",[280,5280,5282,5283,5286],{"id":5281},"development-entry-point-libmain_devdart","Development Entry Point (",[437,5284,5285],{},"lib/main_dev.dart",")",[431,5288,5290],{"className":433,"code":5289,"language":435,"meta":46,"style":46},"import 'package:flutter/material.dart';\n\nimport 'app.dart';\nimport 'config/env/dev_config.dart';\nimport 'config/environment.dart';\nimport 'core/di/injection_container.dart';\nimport 'core/services/firebase_service.dart';\nimport 'core/utils/app_logger.dart';\n\n/// Development entry point\n///\n/// Run from IDE: flutter run -t lib/main_dev.dart\n/// Run from terminal: make dev-run\nvoid main() async {\n  // Initialize Flutter\n  WidgetsFlutterBinding.ensureInitialized();\n\n  // Set environment to development\n  EnvironmentConfig.setEnvironment(Environment.development);\n\n  // Load dev config (from .env.dev)\n  final config = await DevConfig.loadConfig();\n\n  // Initialize logger (verbose mode activated)\n  AppLogger.init(\n    logLevel: config.logLevel,\n    enableConsoleOutput: true,\n    environment: config.environment,\n  );\n\n  // Log that we're starting up\n  AppLogger.info('🚀 Starting app in DEVELOPMENT mode');\n  AppLogger.debug('API URL: ${config.apiBaseUrl}');\n\n  // Initialize Firebase\n  try {\n    await FirebaseService.instance.initialize(config);\n    AppLogger.info('✅ Firebase initialized');\n  } catch (e, stackTrace) {\n    AppLogger.error(\n      'Firebase init failed',\n      error: e,\n      stackTrace: stackTrace,\n    );\n  }\n\n  // Setup dependency injection\n  await initDependencies(config);\n\n  // Run the app\n  runApp(MyApp(config: config));\n}\n",[437,5291,5292,5296,5300,5304,5308,5312,5317,5321,5326,5330,5335,5340,5345,5350,5354,5359,5363,5367,5372,5376,5380,5385,5390,5394,5399,5404,5409,5414,5419,5423,5427,5432,5437,5442,5446,5451,5456,5461,5466,5471,5476,5481,5486,5491,5495,5499,5503,5508,5513,5517,5522,5526],{"__ignoreMap":46},[440,5293,5294],{"class":442,"line":443},[440,5295,1661],{},[440,5297,5298],{"class":442,"line":449},[440,5299,477],{"emptyLinePlaceholder":476},[440,5301,5302],{"class":442,"line":455},[440,5303,1666],{},[440,5305,5306],{"class":442,"line":461},[440,5307,1671],{},[440,5309,5310],{"class":442,"line":467},[440,5311,1676],{},[440,5313,5314],{"class":442,"line":473},[440,5315,5316],{},"import 'core/di/injection_container.dart';\n",[440,5318,5319],{"class":442,"line":480},[440,5320,1681],{},[440,5322,5323],{"class":442,"line":486},[440,5324,5325],{},"import 'core/utils/app_logger.dart';\n",[440,5327,5328],{"class":442,"line":492},[440,5329,477],{"emptyLinePlaceholder":476},[440,5331,5332],{"class":442,"line":497},[440,5333,5334],{},"/// Development entry point\n",[440,5336,5337],{"class":442,"line":503},[440,5338,5339],{},"///\n",[440,5341,5342],{"class":442,"line":508},[440,5343,5344],{},"/// Run from IDE: flutter run -t lib/main_dev.dart\n",[440,5346,5347],{"class":442,"line":514},[440,5348,5349],{},"/// Run from terminal: make dev-run\n",[440,5351,5352],{"class":442,"line":520},[440,5353,1690],{},[440,5355,5356],{"class":442,"line":526},[440,5357,5358],{},"  // Initialize Flutter\n",[440,5360,5361],{"class":442,"line":531},[440,5362,1695],{},[440,5364,5365],{"class":442,"line":537},[440,5366,477],{"emptyLinePlaceholder":476},[440,5368,5369],{"class":442,"line":543},[440,5370,5371],{},"  // Set environment to development\n",[440,5373,5374],{"class":442,"line":648},[440,5375,1709],{},[440,5377,5378],{"class":442,"line":654},[440,5379,477],{"emptyLinePlaceholder":476},[440,5381,5382],{"class":442,"line":660},[440,5383,5384],{},"  // Load dev config (from .env.dev)\n",[440,5386,5387],{"class":442,"line":665},[440,5388,5389],{},"  final config = await DevConfig.loadConfig();\n",[440,5391,5392],{"class":442,"line":671},[440,5393,477],{"emptyLinePlaceholder":476},[440,5395,5396],{"class":442,"line":677},[440,5397,5398],{},"  // Initialize logger (verbose mode activated)\n",[440,5400,5401],{"class":442,"line":683},[440,5402,5403],{},"  AppLogger.init(\n",[440,5405,5406],{"class":442,"line":689},[440,5407,5408],{},"    logLevel: config.logLevel,\n",[440,5410,5411],{"class":442,"line":695},[440,5412,5413],{},"    enableConsoleOutput: true,\n",[440,5415,5416],{"class":442,"line":701},[440,5417,5418],{},"    environment: config.environment,\n",[440,5420,5421],{"class":442,"line":707},[440,5422,921],{},[440,5424,5425],{"class":442,"line":713},[440,5426,477],{"emptyLinePlaceholder":476},[440,5428,5429],{"class":442,"line":719},[440,5430,5431],{},"  // Log that we're starting up\n",[440,5433,5434],{"class":442,"line":725},[440,5435,5436],{},"  AppLogger.info('🚀 Starting app in DEVELOPMENT mode');\n",[440,5438,5439],{"class":442,"line":731},[440,5440,5441],{},"  AppLogger.debug('API URL: ${config.apiBaseUrl}');\n",[440,5443,5444],{"class":442,"line":737},[440,5445,477],{"emptyLinePlaceholder":476},[440,5447,5448],{"class":442,"line":743},[440,5449,5450],{},"  // Initialize Firebase\n",[440,5452,5453],{"class":442,"line":748},[440,5454,5455],{},"  try {\n",[440,5457,5458],{"class":442,"line":754},[440,5459,5460],{},"    await FirebaseService.instance.initialize(config);\n",[440,5462,5463],{"class":442,"line":760},[440,5464,5465],{},"    AppLogger.info('✅ Firebase initialized');\n",[440,5467,5468],{"class":442,"line":765},[440,5469,5470],{},"  } catch (e, stackTrace) {\n",[440,5472,5473],{"class":442,"line":1280},[440,5474,5475],{},"    AppLogger.error(\n",[440,5477,5478],{"class":442,"line":1286},[440,5479,5480],{},"      'Firebase init failed',\n",[440,5482,5483],{"class":442,"line":1292},[440,5484,5485],{},"      error: e,\n",[440,5487,5488],{"class":442,"line":1297},[440,5489,5490],{},"      stackTrace: stackTrace,\n",[440,5492,5493],{"class":442,"line":1303},[440,5494,1217],{},[440,5496,5497],{"class":442,"line":1309},[440,5498,523],{},[440,5500,5501],{"class":442,"line":1314},[440,5502,477],{"emptyLinePlaceholder":476},[440,5504,5505],{"class":442,"line":1320},[440,5506,5507],{},"  // Setup dependency injection\n",[440,5509,5510],{"class":442,"line":1326},[440,5511,5512],{},"  await initDependencies(config);\n",[440,5514,5515],{"class":442,"line":1332},[440,5516,477],{"emptyLinePlaceholder":476},[440,5518,5519],{"class":442,"line":1338},[440,5520,5521],{},"  // Run the app\n",[440,5523,5524],{"class":442,"line":1343},[440,5525,1751],{},[440,5527,5528],{"class":442,"line":1349},[440,5529,470],{},[280,5531,5533,5534,5286],{"id":5532},"production-entry-point-libmain_proddart","Production Entry Point (",[437,5535,5536],{},"lib/main_prod.dart",[431,5538,5540],{"className":433,"code":5539,"language":435,"meta":46,"style":46},"import 'dart:async';\nimport 'package:flutter/material.dart';\n\nimport 'app.dart';\nimport 'config/env/prod_config.dart';\nimport 'config/environment.dart';\nimport 'core/di/injection_container.dart';\nimport 'core/services/firebase_service.dart';\nimport 'core/utils/app_logger.dart';\n\n/// Production entry point\n///\n/// Build: flutter build apk -t lib/main_prod.dart --flavor prod\nvoid main() async {\n  // Initialize Flutter\n  WidgetsFlutterBinding.ensureInitialized();\n\n  // Set environment to production\n  EnvironmentConfig.setEnvironment(Environment.production);\n\n  // Load prod config (from --dart-define)\n  final config = ProdConfig.config;\n\n  // Initialize logger (quiet mode)\n  AppLogger.init(\n    logLevel: config.logLevel,\n    enableConsoleOutput: false, // No console spam in prod\n    environment: config.environment,\n  );\n\n  AppLogger.info('🚀 Starting app in PRODUCTION mode');\n\n  // Initialize Firebase\n  try {\n    await FirebaseService.instance.initialize(config);\n    AppLogger.info('✅ Firebase initialized');\n  } catch (e, stackTrace) {\n    AppLogger.error(\n      'Firebase init failed',\n      error: e,\n      stackTrace: stackTrace,\n    );\n  }\n\n  // Setup dependency injection\n  await initDependencies(config);\n\n  // Run with error handling (crucial for prod!)\n  runZonedGuarded(\n    () {\n      runApp(MyApp(config: config));\n    },\n    (error, stackTrace) {\n      AppLogger.fatal('Uncaught error', error: error, stackTrace: stackTrace);\n      FirebaseService.instance.recordException(\n        error,\n        stackTrace,\n        reason: 'Uncaught error',\n        fatal: true,\n      );\n    },\n  );\n}\n",[437,5541,5542,5547,5551,5555,5559,5563,5567,5571,5575,5579,5583,5588,5592,5597,5601,5605,5609,5613,5618,5622,5626,5631,5635,5639,5644,5648,5652,5657,5661,5665,5669,5674,5678,5682,5686,5690,5694,5698,5702,5706,5710,5714,5718,5722,5726,5730,5734,5738,5743,5748,5753,5758,5762,5767,5772,5777,5782,5787,5792,5797,5802,5806,5810],{"__ignoreMap":46},[440,5543,5544],{"class":442,"line":443},[440,5545,5546],{},"import 'dart:async';\n",[440,5548,5549],{"class":442,"line":449},[440,5550,1661],{},[440,5552,5553],{"class":442,"line":455},[440,5554,477],{"emptyLinePlaceholder":476},[440,5556,5557],{"class":442,"line":461},[440,5558,1666],{},[440,5560,5561],{"class":442,"line":467},[440,5562,1782],{},[440,5564,5565],{"class":442,"line":473},[440,5566,1676],{},[440,5568,5569],{"class":442,"line":480},[440,5570,5316],{},[440,5572,5573],{"class":442,"line":486},[440,5574,1681],{},[440,5576,5577],{"class":442,"line":492},[440,5578,5325],{},[440,5580,5581],{"class":442,"line":497},[440,5582,477],{"emptyLinePlaceholder":476},[440,5584,5585],{"class":442,"line":503},[440,5586,5587],{},"/// Production entry point\n",[440,5589,5590],{"class":442,"line":508},[440,5591,5339],{},[440,5593,5594],{"class":442,"line":514},[440,5595,5596],{},"/// Build: flutter build apk -t lib/main_prod.dart --flavor prod\n",[440,5598,5599],{"class":442,"line":520},[440,5600,1690],{},[440,5602,5603],{"class":442,"line":526},[440,5604,5358],{},[440,5606,5607],{"class":442,"line":531},[440,5608,1695],{},[440,5610,5611],{"class":442,"line":537},[440,5612,477],{"emptyLinePlaceholder":476},[440,5614,5615],{"class":442,"line":543},[440,5616,5617],{},"  // Set environment to production\n",[440,5619,5620],{"class":442,"line":648},[440,5621,1815],{},[440,5623,5624],{"class":442,"line":654},[440,5625,477],{"emptyLinePlaceholder":476},[440,5627,5628],{"class":442,"line":660},[440,5629,5630],{},"  // Load prod config (from --dart-define)\n",[440,5632,5633],{"class":442,"line":665},[440,5634,1829],{},[440,5636,5637],{"class":442,"line":671},[440,5638,477],{"emptyLinePlaceholder":476},[440,5640,5641],{"class":442,"line":677},[440,5642,5643],{},"  // Initialize logger (quiet mode)\n",[440,5645,5646],{"class":442,"line":683},[440,5647,5403],{},[440,5649,5650],{"class":442,"line":689},[440,5651,5408],{},[440,5653,5654],{"class":442,"line":695},[440,5655,5656],{},"    enableConsoleOutput: false, // No console spam in prod\n",[440,5658,5659],{"class":442,"line":701},[440,5660,5418],{},[440,5662,5663],{"class":442,"line":707},[440,5664,921],{},[440,5666,5667],{"class":442,"line":713},[440,5668,477],{"emptyLinePlaceholder":476},[440,5670,5671],{"class":442,"line":719},[440,5672,5673],{},"  AppLogger.info('🚀 Starting app in PRODUCTION mode');\n",[440,5675,5676],{"class":442,"line":725},[440,5677,477],{"emptyLinePlaceholder":476},[440,5679,5680],{"class":442,"line":731},[440,5681,5450],{},[440,5683,5684],{"class":442,"line":737},[440,5685,5455],{},[440,5687,5688],{"class":442,"line":743},[440,5689,5460],{},[440,5691,5692],{"class":442,"line":748},[440,5693,5465],{},[440,5695,5696],{"class":442,"line":754},[440,5697,5470],{},[440,5699,5700],{"class":442,"line":760},[440,5701,5475],{},[440,5703,5704],{"class":442,"line":765},[440,5705,5480],{},[440,5707,5708],{"class":442,"line":1280},[440,5709,5485],{},[440,5711,5712],{"class":442,"line":1286},[440,5713,5490],{},[440,5715,5716],{"class":442,"line":1292},[440,5717,1217],{},[440,5719,5720],{"class":442,"line":1297},[440,5721,523],{},[440,5723,5724],{"class":442,"line":1303},[440,5725,477],{"emptyLinePlaceholder":476},[440,5727,5728],{"class":442,"line":1309},[440,5729,5507],{},[440,5731,5732],{"class":442,"line":1314},[440,5733,5512],{},[440,5735,5736],{"class":442,"line":1320},[440,5737,477],{"emptyLinePlaceholder":476},[440,5739,5740],{"class":442,"line":1326},[440,5741,5742],{},"  // Run with error handling (crucial for prod!)\n",[440,5744,5745],{"class":442,"line":1332},[440,5746,5747],{},"  runZonedGuarded(\n",[440,5749,5750],{"class":442,"line":1338},[440,5751,5752],{},"    () {\n",[440,5754,5755],{"class":442,"line":1343},[440,5756,5757],{},"      runApp(MyApp(config: config));\n",[440,5759,5760],{"class":442,"line":1349},[440,5761,888],{},[440,5763,5764],{"class":442,"line":1355},[440,5765,5766],{},"    (error, stackTrace) {\n",[440,5768,5769],{"class":442,"line":1361},[440,5770,5771],{},"      AppLogger.fatal('Uncaught error', error: error, stackTrace: stackTrace);\n",[440,5773,5774],{"class":442,"line":1367},[440,5775,5776],{},"      FirebaseService.instance.recordException(\n",[440,5778,5779],{"class":442,"line":1372},[440,5780,5781],{},"        error,\n",[440,5783,5784],{"class":442,"line":1378},[440,5785,5786],{},"        stackTrace,\n",[440,5788,5789],{"class":442,"line":1384},[440,5790,5791],{},"        reason: 'Uncaught error',\n",[440,5793,5794],{"class":442,"line":1390},[440,5795,5796],{},"        fatal: true,\n",[440,5798,5799],{"class":442,"line":1396},[440,5800,5801],{},"      );\n",[440,5803,5804],{"class":442,"line":1401},[440,5805,888],{},[440,5807,5808],{"class":442,"line":1406},[440,5809,921],{},[440,5811,5812],{"class":442,"line":1411},[440,5813,470],{},[52,5815,5816],{},[77,5817,5818],{},"Key differences that hit different:",[93,5820,5821,5829,5832,5839],{},[96,5822,5823,5824,5826,5827],{},"Dev loads from ",[437,5825,4424],{},", prod needs ",[437,5828,4897],{},[96,5830,5831],{},"Prod disables console logging (cleaner)",[96,5833,5834,5835,5838],{},"Prod uses ",[437,5836,5837],{},"runZonedGuarded"," for catching crashes",[96,5840,5841],{},"Same app widget, different vibes",[82,5843],{},[85,5845,5847],{"id":5846},"step-7-your-app-widget-stays-chill-just-receives-config","📱 Step 7: Your App Widget (Stays Chill, Just Receives Config)",[52,5849,5850],{},"Your actual app widget doesn't care about environments — it just vibes with whatever config it gets:",[431,5852,5854],{"className":433,"code":5853,"language":435,"meta":46,"style":46},"import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\n\nimport 'config/app_config.dart';\nimport 'core/di/injection_container.dart';\nimport 'core/router/app_router.dart';\nimport 'features/auth/presentation/bloc/auth_bloc.dart';\nimport 'features/auth/presentation/bloc/auth_event.dart';\n\n/// Main app widget - receives configuration via dependency injection\nclass MyApp extends StatelessWidget {\n  final AppConfig config;\n\n  const MyApp({\n    super.key,\n    required this.config,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    return MultiBlocProvider(\n      providers: [\n        BlocProvider(\n          create: (context) => sl\u003CAuthBloc>()..add(const AuthCheckRequested()),\n        ),\n      ],\n      child: MaterialApp.router(\n        title: config.appName,\n        debugShowCheckedModeBanner: config.debugMode,\n        theme: ThemeData(\n          colorScheme: ColorScheme.fromSeed(\n            seedColor: Colors.blue,\n            brightness: Brightness.light,\n          ),\n          useMaterial3: true,\n        ),\n        routerConfig: router,\n      ),\n    );\n  }\n}\n",[437,5855,5856,5860,5865,5869,5874,5878,5883,5888,5893,5897,5902,5907,5912,5916,5921,5926,5931,5935,5939,5943,5947,5952,5957,5962,5967,5972,5977,5982,5987,5992,5997,6002,6007,6012,6016,6021,6025,6030,6034,6038,6042],{"__ignoreMap":46},[440,5857,5858],{"class":442,"line":443},[440,5859,1661],{},[440,5861,5862],{"class":442,"line":449},[440,5863,5864],{},"import 'package:flutter_bloc/flutter_bloc.dart';\n",[440,5866,5867],{"class":442,"line":455},[440,5868,477],{"emptyLinePlaceholder":476},[440,5870,5871],{"class":442,"line":461},[440,5872,5873],{},"import 'config/app_config.dart';\n",[440,5875,5876],{"class":442,"line":467},[440,5877,5316],{},[440,5879,5880],{"class":442,"line":473},[440,5881,5882],{},"import 'core/router/app_router.dart';\n",[440,5884,5885],{"class":442,"line":480},[440,5886,5887],{},"import 'features/auth/presentation/bloc/auth_bloc.dart';\n",[440,5889,5890],{"class":442,"line":486},[440,5891,5892],{},"import 'features/auth/presentation/bloc/auth_event.dart';\n",[440,5894,5895],{"class":442,"line":492},[440,5896,477],{"emptyLinePlaceholder":476},[440,5898,5899],{"class":442,"line":497},[440,5900,5901],{},"/// Main app widget - receives configuration via dependency injection\n",[440,5903,5904],{"class":442,"line":503},[440,5905,5906],{},"class MyApp extends StatelessWidget {\n",[440,5908,5909],{"class":442,"line":508},[440,5910,5911],{},"  final AppConfig config;\n",[440,5913,5914],{"class":442,"line":514},[440,5915,477],{"emptyLinePlaceholder":476},[440,5917,5918],{"class":442,"line":520},[440,5919,5920],{},"  const MyApp({\n",[440,5922,5923],{"class":442,"line":526},[440,5924,5925],{},"    super.key,\n",[440,5927,5928],{"class":442,"line":531},[440,5929,5930],{},"    required this.config,\n",[440,5932,5933],{"class":442,"line":537},[440,5934,740],{},[440,5936,5937],{"class":442,"line":543},[440,5938,477],{"emptyLinePlaceholder":476},[440,5940,5941],{"class":442,"line":648},[440,5942,2768],{},[440,5944,5945],{"class":442,"line":654},[440,5946,2773],{},[440,5948,5949],{"class":442,"line":660},[440,5950,5951],{},"    return MultiBlocProvider(\n",[440,5953,5954],{"class":442,"line":665},[440,5955,5956],{},"      providers: [\n",[440,5958,5959],{"class":442,"line":671},[440,5960,5961],{},"        BlocProvider(\n",[440,5963,5964],{"class":442,"line":677},[440,5965,5966],{},"          create: (context) => sl\u003CAuthBloc>()..add(const AuthCheckRequested()),\n",[440,5968,5969],{"class":442,"line":683},[440,5970,5971],{},"        ),\n",[440,5973,5974],{"class":442,"line":689},[440,5975,5976],{},"      ],\n",[440,5978,5979],{"class":442,"line":695},[440,5980,5981],{},"      child: MaterialApp.router(\n",[440,5983,5984],{"class":442,"line":701},[440,5985,5986],{},"        title: config.appName,\n",[440,5988,5989],{"class":442,"line":707},[440,5990,5991],{},"        debugShowCheckedModeBanner: config.debugMode,\n",[440,5993,5994],{"class":442,"line":713},[440,5995,5996],{},"        theme: ThemeData(\n",[440,5998,5999],{"class":442,"line":719},[440,6000,6001],{},"          colorScheme: ColorScheme.fromSeed(\n",[440,6003,6004],{"class":442,"line":725},[440,6005,6006],{},"            seedColor: Colors.blue,\n",[440,6008,6009],{"class":442,"line":731},[440,6010,6011],{},"            brightness: Brightness.light,\n",[440,6013,6014],{"class":442,"line":737},[440,6015,2887],{},[440,6017,6018],{"class":442,"line":743},[440,6019,6020],{},"          useMaterial3: true,\n",[440,6022,6023],{"class":442,"line":748},[440,6024,5971],{},[440,6026,6027],{"class":442,"line":754},[440,6028,6029],{},"        routerConfig: router,\n",[440,6031,6032],{"class":442,"line":760},[440,6033,1212],{},[440,6035,6036],{"class":442,"line":765},[440,6037,1217],{},[440,6039,6040],{"class":442,"line":1280},[440,6041,523],{},[440,6043,6044],{"class":442,"line":1286},[440,6045,470],{},[52,6047,6048],{},[77,6049,6050],{},"Peep this:",[93,6052,6053,6056,6059,6062],{},[96,6054,6055],{},"Config comes through the constructor",[96,6057,6058],{},"App name? From config",[96,6060,6061],{},"Debug banner? Controlled by config",[96,6063,6064],{},"The widget itself has ZERO environment logic (chef's kiss)",[52,6066,6067,6068,6071],{},"This is ",[77,6069,6070],{},"dependency injection"," in action — the app gets what it needs, doesn't go looking for it.",[82,6073],{},[85,6075,6077],{"id":6076},"how-to-actually-run-this-thing","🔧 How to Actually Run This Thing",[280,6079,6081],{"id":6080},"from-your-ide-easy-mode","From Your IDE (Easy Mode):",[52,6083,6084,6085,6088,6089,6091],{},"Just hit run! The default ",[437,6086,6087],{},"main.dart"," loads ",[437,6090,4424],{}," automatically.",[431,6093,6095],{"className":1865,"code":6094,"language":1867,"meta":46,"style":46},"# Or specify the target\nflutter run -t lib/main_dev.dart\n",[437,6096,6097,6102],{"__ignoreMap":46},[440,6098,6099],{"class":442,"line":443},[440,6100,6101],{"class":1874},"# Or specify the target\n",[440,6103,6104,6106,6108,6110],{"class":442,"line":449},[440,6105,1881],{"class":1880},[440,6107,1885],{"class":1884},[440,6109,1888],{"class":1884},[440,6111,1891],{"class":1884},[280,6113,6115],{"id":6114},"from-terminal-also-easy","From Terminal (Also Easy):",[52,6117,6118],{},[77,6119,6120],{},"Development:",[431,6122,6124],{"className":1865,"code":6123,"language":1867,"meta":46,"style":46},"flutter run -t lib/main_dev.dart --flavor dev\n",[437,6125,6126],{"__ignoreMap":46},[440,6127,6128,6130,6132,6134,6137,6140],{"class":442,"line":443},[440,6129,1881],{"class":1880},[440,6131,1885],{"class":1884},[440,6133,1888],{"class":1884},[440,6135,6136],{"class":1884}," lib/main_dev.dart",[440,6138,6139],{"class":1884}," --flavor",[440,6141,6142],{"class":1884}," dev\n",[52,6144,6145],{},[77,6146,6147],{},"Production (local testing):",[431,6149,6151],{"className":1865,"code":6150,"language":1867,"meta":46,"style":46},"# You'll need to pass secrets via --dart-define\nflutter run -t lib/main_prod.dart --flavor prod \\\n  --dart-define=API_BASE_URL=https://api.yourapp.com \\\n  --dart-define=FIREBASE_API_KEY=your_key \\\n  # ... more secrets\n",[437,6152,6153,6158,6178,6185,6192],{"__ignoreMap":46},[440,6154,6155],{"class":442,"line":443},[440,6156,6157],{"class":1874},"# You'll need to pass secrets via --dart-define\n",[440,6159,6160,6162,6164,6166,6169,6171,6174],{"class":442,"line":449},[440,6161,1881],{"class":1880},[440,6163,1885],{"class":1884},[440,6165,1888],{"class":1884},[440,6167,6168],{"class":1884}," lib/main_prod.dart",[440,6170,6139],{"class":1884},[440,6172,6173],{"class":1884}," prod",[440,6175,6177],{"class":6176},"sTEyZ"," \\\n",[440,6179,6180,6183],{"class":442,"line":455},[440,6181,6182],{"class":1884},"  --dart-define=API_BASE_URL=https://api.yourapp.com",[440,6184,6177],{"class":6176},[440,6186,6187,6190],{"class":442,"line":461},[440,6188,6189],{"class":1884},"  --dart-define=FIREBASE_API_KEY=your_key",[440,6191,6177],{"class":6176},[440,6193,6194],{"class":442,"line":467},[440,6195,6196],{"class":1874},"  # ... more secrets\n",[280,6198,6200],{"id":6199},"building-for-release","Building for Release:",[52,6202,6203],{},[77,6204,6205],{},"Development Build (for testing):",[431,6207,6209],{"className":1865,"code":6208,"language":1867,"meta":46,"style":46},"flutter build apk -t lib/main_dev.dart --flavor dev\n",[437,6210,6211],{"__ignoreMap":46},[440,6212,6213,6215,6217,6219,6221,6223,6225],{"class":442,"line":443},[440,6214,1881],{"class":1880},[440,6216,1918],{"class":1884},[440,6218,1921],{"class":1884},[440,6220,1888],{"class":1884},[440,6222,6136],{"class":1884},[440,6224,6139],{"class":1884},[440,6226,6142],{"class":1884},[52,6228,6229],{},[77,6230,6231],{},"Production Build (the real deal):",[431,6233,6235],{"className":1865,"code":6234,"language":1867,"meta":46,"style":46},"flutter build appbundle -t lib/main_prod.dart --flavor prod \\\n  --dart-define=API_BASE_URL=https://api.yourapp.com \\\n  --dart-define=FIREBASE_API_KEY=your_prod_key \\\n  --dart-define=FIREBASE_APP_ID=your_prod_app_id \\\n  --dart-define=FIREBASE_MESSAGING_SENDER_ID=your_sender_id \\\n  --dart-define=FIREBASE_PROJECT_ID=your-prod-project \\\n  --dart-define=ENCRYPTION_KEY=your_super_secret_32_char_key\n",[437,6236,6237,6255,6261,6268,6275,6282,6289],{"__ignoreMap":46},[440,6238,6239,6241,6243,6245,6247,6249,6251,6253],{"class":442,"line":443},[440,6240,1881],{"class":1880},[440,6242,1918],{"class":1884},[440,6244,3287],{"class":1884},[440,6246,1888],{"class":1884},[440,6248,6168],{"class":1884},[440,6250,6139],{"class":1884},[440,6252,6173],{"class":1884},[440,6254,6177],{"class":6176},[440,6256,6257,6259],{"class":442,"line":449},[440,6258,6182],{"class":1884},[440,6260,6177],{"class":6176},[440,6262,6263,6266],{"class":442,"line":455},[440,6264,6265],{"class":1884},"  --dart-define=FIREBASE_API_KEY=your_prod_key",[440,6267,6177],{"class":6176},[440,6269,6270,6273],{"class":442,"line":461},[440,6271,6272],{"class":1884},"  --dart-define=FIREBASE_APP_ID=your_prod_app_id",[440,6274,6177],{"class":6176},[440,6276,6277,6280],{"class":442,"line":467},[440,6278,6279],{"class":1884},"  --dart-define=FIREBASE_MESSAGING_SENDER_ID=your_sender_id",[440,6281,6177],{"class":6176},[440,6283,6284,6287],{"class":442,"line":473},[440,6285,6286],{"class":1884},"  --dart-define=FIREBASE_PROJECT_ID=your-prod-project",[440,6288,6177],{"class":6176},[440,6290,6291],{"class":442,"line":480},[440,6292,6293],{"class":1884},"  --dart-define=ENCRYPTION_KEY=your_super_secret_32_char_key\n",[52,6295,6296,6298,6299,6302],{},[77,6297,4574],{}," Use a Makefile or build script so you don't have to type all that every time. This project has scripts in the ",[437,6300,6301],{},"scripts/"," folder!",[280,6304,6306],{"id":6305},"using-the-build-scripts","Using the Build Scripts:",[431,6308,6310],{"className":1865,"code":6309,"language":1867,"meta":46,"style":46},"# Run dev\n./scripts/run_dev.sh\n\n# Run prod\n./scripts/run_prod.sh\n\n# Build dev APK\n./scripts/build_apk_dev.sh\n\n# Build prod app bundle\n./scripts/build_appbundle_prod.sh\n",[437,6311,6312,6317,6322,6326,6331,6336,6340,6345,6350,6354,6359],{"__ignoreMap":46},[440,6313,6314],{"class":442,"line":443},[440,6315,6316],{"class":1874},"# Run dev\n",[440,6318,6319],{"class":442,"line":449},[440,6320,6321],{"class":1880},"./scripts/run_dev.sh\n",[440,6323,6324],{"class":442,"line":455},[440,6325,477],{"emptyLinePlaceholder":476},[440,6327,6328],{"class":442,"line":461},[440,6329,6330],{"class":1874},"# Run prod\n",[440,6332,6333],{"class":442,"line":467},[440,6334,6335],{"class":1880},"./scripts/run_prod.sh\n",[440,6337,6338],{"class":442,"line":473},[440,6339,477],{"emptyLinePlaceholder":476},[440,6341,6342],{"class":442,"line":480},[440,6343,6344],{"class":1874},"# Build dev APK\n",[440,6346,6347],{"class":442,"line":486},[440,6348,6349],{"class":1880},"./scripts/build_apk_dev.sh\n",[440,6351,6352],{"class":442,"line":492},[440,6353,477],{"emptyLinePlaceholder":476},[440,6355,6356],{"class":442,"line":497},[440,6357,6358],{"class":1874},"# Build prod app bundle\n",[440,6360,6361],{"class":442,"line":503},[440,6362,6363],{"class":1880},"./scripts/build_appbundle_prod.sh\n",[52,6365,6366,6368,6370,6371,6373,6374,6376],{},[77,6367,3550],{},[61,6369],{},"\nNo complex environment variables setup.",[61,6372],{},"\nNo confusing build configurations.",[61,6375],{},"\nJust different entry points and clean configs.",[82,6378],{},[85,6380,6382],{"id":6381},"android-setup-product-flavors-are-your-friend","📱 Android Setup (Product Flavors are Your Friend)",[52,6384,6385,6386,6389,6390,4089],{},"To make different builds work on Android, you need ",[77,6387,6388],{},"product flavors",". Edit ",[437,6391,6392],{},"android/app/build.gradle.kts",[431,6394,6398],{"className":6395,"code":6396,"language":6397,"meta":46,"style":46},"language-kotlin shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","android {\n    // ... other config\n\n    // Define flavor dimensions\n    flavorDimensions += \"environment\"\n\n    productFlavors {\n        create(\"dev\") {\n            dimension = \"environment\"\n            applicationIdSuffix = \".dev\"\n            versionNameSuffix = \"-dev\"\n            resValue(\"string\", \"app_name\", \"Social App Dev\")\n            isDefault = true\n        }\n\n        create(\"prod\") {\n            dimension = \"environment\"\n            resValue(\"string\", \"app_name\", \"Social App\")\n        }\n    }\n}\n","kotlin",[437,6399,6400,6405,6410,6414,6419,6424,6428,6433,6438,6443,6448,6453,6458,6463,6467,6471,6476,6480,6485,6489,6493],{"__ignoreMap":46},[440,6401,6402],{"class":442,"line":443},[440,6403,6404],{},"android {\n",[440,6406,6407],{"class":442,"line":449},[440,6408,6409],{},"    // ... other config\n",[440,6411,6412],{"class":442,"line":455},[440,6413,477],{"emptyLinePlaceholder":476},[440,6415,6416],{"class":442,"line":461},[440,6417,6418],{},"    // Define flavor dimensions\n",[440,6420,6421],{"class":442,"line":467},[440,6422,6423],{},"    flavorDimensions += \"environment\"\n",[440,6425,6426],{"class":442,"line":473},[440,6427,477],{"emptyLinePlaceholder":476},[440,6429,6430],{"class":442,"line":480},[440,6431,6432],{},"    productFlavors {\n",[440,6434,6435],{"class":442,"line":486},[440,6436,6437],{},"        create(\"dev\") {\n",[440,6439,6440],{"class":442,"line":492},[440,6441,6442],{},"            dimension = \"environment\"\n",[440,6444,6445],{"class":442,"line":497},[440,6446,6447],{},"            applicationIdSuffix = \".dev\"\n",[440,6449,6450],{"class":442,"line":503},[440,6451,6452],{},"            versionNameSuffix = \"-dev\"\n",[440,6454,6455],{"class":442,"line":508},[440,6456,6457],{},"            resValue(\"string\", \"app_name\", \"Social App Dev\")\n",[440,6459,6460],{"class":442,"line":514},[440,6461,6462],{},"            isDefault = true\n",[440,6464,6465],{"class":442,"line":520},[440,6466,4267],{},[440,6468,6469],{"class":442,"line":526},[440,6470,477],{"emptyLinePlaceholder":476},[440,6472,6473],{"class":442,"line":531},[440,6474,6475],{},"        create(\"prod\") {\n",[440,6477,6478],{"class":442,"line":537},[440,6479,6442],{},[440,6481,6482],{"class":442,"line":543},[440,6483,6484],{},"            resValue(\"string\", \"app_name\", \"Social App\")\n",[440,6486,6487],{"class":442,"line":648},[440,6488,4267],{},[440,6490,6491],{"class":442,"line":654},[440,6492,1289],{},[440,6494,6495],{"class":442,"line":660},[440,6496,470],{},[52,6498,6499],{},[77,6500,6501],{},"What this does:",[93,6503,6504,6507,6513,6516],{},[96,6505,6506],{},"Creates two build variants: dev and prod",[96,6508,6509,6510,6512],{},"Dev gets ",[437,6511,4878],{}," suffix on the package name",[96,6514,6515],{},"Different app names for each",[96,6517,6518],{},"They can coexist on the same device (so convenient!)",[280,6520,6522],{"id":6521},"firebase-setup-for-android","Firebase Setup for Android",[52,6524,6525],{},"Create separate folders for each flavor:",[431,6527,6530],{"className":6528,"code":6529,"language":3615},[3613],"android/app/src/\n├── dev/\n│   └── google-services.json   # Dev Firebase config\n└── prod/\n    └── google-services.json   # Prod Firebase config\n",[437,6531,6529],{"__ignoreMap":46},[52,6533,6534],{},"Android will automatically pick the right Firebase config based on the flavor. It just works™",[82,6536],{},[85,6538,6540],{"id":6539},"ios-setup-schemes-and-xcconfig-files","🍎 iOS Setup (Schemes and xcconfig Files)",[52,6542,6543,6544,6547,6548,168],{},"For iOS, we use ",[77,6545,6546],{},"schemes"," and ",[77,6549,6550],{},"xcconfig files",[280,6552,6554],{"id":6553},"create-devxcconfig","Create Dev.xcconfig",[52,6556,6557,6558,4089],{},"In ",[437,6559,6560],{},"ios/Runner/Dev.xcconfig",[431,6562,6565],{"className":6563,"code":6564,"language":3615},[3613],"#include \"Generated.xcconfig\"\n\n// Development Environment Configuration\nPRODUCT_BUNDLE_IDENTIFIER = com.example.flutter_bloc.dev\nAPP_DISPLAY_NAME = Social App Dev\n",[437,6566,6564],{"__ignoreMap":46},[280,6568,6570],{"id":6569},"create-prodxcconfig","Create Prod.xcconfig",[52,6572,6557,6573,4089],{},[437,6574,6575],{},"ios/Runner/Prod.xcconfig",[431,6577,6580],{"className":6578,"code":6579,"language":3615},[3613],"#include \"Generated.xcconfig\"\n\n// Production Environment Configuration\nPRODUCT_BUNDLE_IDENTIFIER = com.example.flutter_bloc\nAPP_DISPLAY_NAME = Social App\n",[437,6581,6579],{"__ignoreMap":46},[280,6583,6585],{"id":6584},"firebase-setup-for-ios","Firebase Setup for iOS",[52,6587,6588],{},"Similar to Android, create separate Firebase configurations:",[431,6590,6593],{"className":6591,"code":6592,"language":3615},[3613],"ios/Runner/Firebase/\n├── Dev/\n│   └── GoogleService-Info.plist   # Dev Firebase\n└── Prod/\n    └── GoogleService-Info.plist   # Prod Firebase\n",[437,6594,6592],{"__ignoreMap":46},[52,6596,6597],{},"Then in Xcode:",[241,6599,6600,6606,6609,6612],{},[96,6601,6602,6603],{},"Open ",[437,6604,6605],{},"ios/Runner.xcworkspace",[96,6607,6608],{},"Create two schemes: \"Dev\" and \"Prod\"",[96,6610,6611],{},"For each scheme, select the appropriate xcconfig file",[96,6613,6614],{},"Add a build phase to copy the correct GoogleService-Info.plist",[52,6616,6617],{},[77,6618,6619],{},"Xcode is a bit more manual, but you only do this setup once.",[82,6621],{},[85,6623,6625],{"id":6624},"bonus-environment-aware-logging","🎨 Bonus: Environment-Aware Logging",[52,6627,6628],{},"Here's how the logger uses environment config to be smart about what it logs:",[431,6630,6632],{"className":433,"code":6631,"language":435,"meta":46,"style":46},"import 'dart:developer' as developer;\nimport '../../config/environment.dart';\n\n/// Logger that's actually aware of its environment\n///\n/// Log Levels:\n/// - 0: DEBUG (Dev only - all the things)\n/// - 1: INFO (Important stuff)\n/// - 2: WARNING (Uh oh)\n/// - 3: ERROR (Something broke)\n/// - 4: FATAL (Everything is on fire)\nclass AppLogger {\n  static int _logLevel = 0;\n  static bool _enableConsoleOutput = true;\n  static Environment _environment = Environment.development;\n\n  /// Initialize with config\n  static void init({\n    required int logLevel,\n    required bool enableConsoleOutput,\n    required Environment environment,\n  }) {\n    _logLevel = logLevel;\n    _enableConsoleOutput = enableConsoleOutput;\n    _environment = environment;\n  }\n\n  /// Debug logs (dev only)\n  static void debug(String message, {Map\u003CString, dynamic>? context}) {\n    if (_logLevel \u003C= 0) {\n      _log('DEBUG', message, level: 500, context: context);\n    }\n  }\n\n  /// Info logs (show in both environments)\n  static void info(String message, {Map\u003CString, dynamic>? context}) {\n    if (_logLevel \u003C= 1) {\n      _log('INFO', message, level: 800, context: context);\n    }\n  }\n\n  /// Error logs (always important)\n  static void error(\n    String message, {\n    Object? error,\n    StackTrace? stackTrace,\n  }) {\n    if (_logLevel \u003C= 3) {\n      _log(\n        'ERROR',\n        message,\n        level: 1000,\n        error: error,\n        stackTrace: stackTrace,\n      );\n    }\n  }\n\n  /// Fatal logs (oh no)\n  static void fatal(\n    String message, {\n    Object? error,\n    StackTrace? stackTrace,\n  }) {\n    _log(\n      'FATAL',\n      message,\n      level: 1200,\n      error: error,\n      stackTrace: stackTrace,\n    );\n  }\n\n  static void _log(\n    String level,\n    String message, {\n    required int level,\n    Map\u003CString, dynamic>? context,\n    Object? error,\n    StackTrace? stackTrace,\n  }) {\n    if (_enableConsoleOutput) {\n      developer.log(\n        message,\n        name: 'SocialApp',\n        level: level,\n        error: error,\n        stackTrace: stackTrace,\n      );\n    }\n  }\n}\n",[437,6633,6634,6639,6644,6648,6653,6657,6662,6667,6672,6677,6682,6687,6691,6695,6700,6704,6708,6713,6718,6723,6728,6733,6737,6741,6746,6751,6755,6759,6764,6769,6774,6779,6783,6787,6791,6796,6801,6805,6810,6814,6818,6822,6827,6831,6835,6839,6843,6847,6851,6856,6861,6866,6871,6876,6881,6885,6889,6893,6897,6902,6907,6911,6915,6919,6923,6928,6933,6938,6943,6948,6952,6956,6960,6964,6969,6974,6978,6983,6988,6992,6996,7000,7005,7010,7014,7019,7024,7028,7032,7036,7040,7044],{"__ignoreMap":46},[440,6635,6636],{"class":442,"line":443},[440,6637,6638],{},"import 'dart:developer' as developer;\n",[440,6640,6641],{"class":442,"line":449},[440,6642,6643],{},"import '../../config/environment.dart';\n",[440,6645,6646],{"class":442,"line":455},[440,6647,477],{"emptyLinePlaceholder":476},[440,6649,6650],{"class":442,"line":461},[440,6651,6652],{},"/// Logger that's actually aware of its environment\n",[440,6654,6655],{"class":442,"line":467},[440,6656,5339],{},[440,6658,6659],{"class":442,"line":473},[440,6660,6661],{},"/// Log Levels:\n",[440,6663,6664],{"class":442,"line":480},[440,6665,6666],{},"/// - 0: DEBUG (Dev only - all the things)\n",[440,6668,6669],{"class":442,"line":486},[440,6670,6671],{},"/// - 1: INFO (Important stuff)\n",[440,6673,6674],{"class":442,"line":492},[440,6675,6676],{},"/// - 2: WARNING (Uh oh)\n",[440,6678,6679],{"class":442,"line":497},[440,6680,6681],{},"/// - 3: ERROR (Something broke)\n",[440,6683,6684],{"class":442,"line":503},[440,6685,6686],{},"/// - 4: FATAL (Everything is on fire)\n",[440,6688,6689],{"class":442,"line":508},[440,6690,2487],{},[440,6692,6693],{"class":442,"line":514},[440,6694,2492],{},[440,6696,6697],{"class":442,"line":520},[440,6698,6699],{},"  static bool _enableConsoleOutput = true;\n",[440,6701,6702],{"class":442,"line":526},[440,6703,489],{},[440,6705,6706],{"class":442,"line":531},[440,6707,477],{"emptyLinePlaceholder":476},[440,6709,6710],{"class":442,"line":537},[440,6711,6712],{},"  /// Initialize with config\n",[440,6714,6715],{"class":442,"line":543},[440,6716,6717],{},"  static void init({\n",[440,6719,6720],{"class":442,"line":648},[440,6721,6722],{},"    required int logLevel,\n",[440,6724,6725],{"class":442,"line":654},[440,6726,6727],{},"    required bool enableConsoleOutput,\n",[440,6729,6730],{"class":442,"line":660},[440,6731,6732],{},"    required Environment environment,\n",[440,6734,6735],{"class":442,"line":665},[440,6736,2618],{},[440,6738,6739],{"class":442,"line":671},[440,6740,2506],{},[440,6742,6743],{"class":442,"line":677},[440,6744,6745],{},"    _enableConsoleOutput = enableConsoleOutput;\n",[440,6747,6748],{"class":442,"line":683},[440,6749,6750],{},"    _environment = environment;\n",[440,6752,6753],{"class":442,"line":689},[440,6754,523],{},[440,6756,6757],{"class":442,"line":695},[440,6758,477],{"emptyLinePlaceholder":476},[440,6760,6761],{"class":442,"line":701},[440,6762,6763],{},"  /// Debug logs (dev only)\n",[440,6765,6766],{"class":442,"line":707},[440,6767,6768],{},"  static void debug(String message, {Map\u003CString, dynamic>? context}) {\n",[440,6770,6771],{"class":442,"line":713},[440,6772,6773],{},"    if (_logLevel \u003C= 0) {\n",[440,6775,6776],{"class":442,"line":719},[440,6777,6778],{},"      _log('DEBUG', message, level: 500, context: context);\n",[440,6780,6781],{"class":442,"line":725},[440,6782,1289],{},[440,6784,6785],{"class":442,"line":731},[440,6786,523],{},[440,6788,6789],{"class":442,"line":737},[440,6790,477],{"emptyLinePlaceholder":476},[440,6792,6793],{"class":442,"line":743},[440,6794,6795],{},"  /// Info logs (show in both environments)\n",[440,6797,6798],{"class":442,"line":748},[440,6799,6800],{},"  static void info(String message, {Map\u003CString, dynamic>? context}) {\n",[440,6802,6803],{"class":442,"line":754},[440,6804,2529],{},[440,6806,6807],{"class":442,"line":760},[440,6808,6809],{},"      _log('INFO', message, level: 800, context: context);\n",[440,6811,6812],{"class":442,"line":765},[440,6813,1289],{},[440,6815,6816],{"class":442,"line":1280},[440,6817,523],{},[440,6819,6820],{"class":442,"line":1286},[440,6821,477],{"emptyLinePlaceholder":476},[440,6823,6824],{"class":442,"line":1292},[440,6825,6826],{},"  /// Error logs (always important)\n",[440,6828,6829],{"class":442,"line":1297},[440,6830,2598],{},[440,6832,6833],{"class":442,"line":1303},[440,6834,2603],{},[440,6836,6837],{"class":442,"line":1309},[440,6838,2608],{},[440,6840,6841],{"class":442,"line":1314},[440,6842,2613],{},[440,6844,6845],{"class":442,"line":1320},[440,6846,2618],{},[440,6848,6849],{"class":442,"line":1326},[440,6850,2623],{},[440,6852,6853],{"class":442,"line":1332},[440,6854,6855],{},"      _log(\n",[440,6857,6858],{"class":442,"line":1338},[440,6859,6860],{},"        'ERROR',\n",[440,6862,6863],{"class":442,"line":1343},[440,6864,6865],{},"        message,\n",[440,6867,6868],{"class":442,"line":1349},[440,6869,6870],{},"        level: 1000,\n",[440,6872,6873],{"class":442,"line":1355},[440,6874,6875],{},"        error: error,\n",[440,6877,6878],{"class":442,"line":1361},[440,6879,6880],{},"        stackTrace: stackTrace,\n",[440,6882,6883],{"class":442,"line":1367},[440,6884,5801],{},[440,6886,6887],{"class":442,"line":1372},[440,6888,1289],{},[440,6890,6891],{"class":442,"line":1378},[440,6892,523],{},[440,6894,6895],{"class":442,"line":1384},[440,6896,477],{"emptyLinePlaceholder":476},[440,6898,6899],{"class":442,"line":1390},[440,6900,6901],{},"  /// Fatal logs (oh no)\n",[440,6903,6904],{"class":442,"line":1396},[440,6905,6906],{},"  static void fatal(\n",[440,6908,6909],{"class":442,"line":1401},[440,6910,2603],{},[440,6912,6913],{"class":442,"line":1406},[440,6914,2608],{},[440,6916,6917],{"class":442,"line":1411},[440,6918,2613],{},[440,6920,6921],{"class":442,"line":1417},[440,6922,2618],{},[440,6924,6925],{"class":442,"line":1423},[440,6926,6927],{},"    _log(\n",[440,6929,6930],{"class":442,"line":1429},[440,6931,6932],{},"      'FATAL',\n",[440,6934,6935],{"class":442,"line":1435},[440,6936,6937],{},"      message,\n",[440,6939,6940],{"class":442,"line":1440},[440,6941,6942],{},"      level: 1200,\n",[440,6944,6945],{"class":442,"line":1445},[440,6946,6947],{},"      error: error,\n",[440,6949,6950],{"class":442,"line":1451},[440,6951,5490],{},[440,6953,6954],{"class":442,"line":1457},[440,6955,1217],{},[440,6957,6958],{"class":442,"line":1462},[440,6959,523],{},[440,6961,6962],{"class":442,"line":1468},[440,6963,477],{"emptyLinePlaceholder":476},[440,6965,6966],{"class":442,"line":1473},[440,6967,6968],{},"  static void _log(\n",[440,6970,6971],{"class":442,"line":1478},[440,6972,6973],{},"    String level,\n",[440,6975,6976],{"class":442,"line":1484},[440,6977,2603],{},[440,6979,6980],{"class":442,"line":1490},[440,6981,6982],{},"    required int level,\n",[440,6984,6985],{"class":442,"line":1495},[440,6986,6987],{},"    Map\u003CString, dynamic>? context,\n",[440,6989,6990],{"class":442,"line":1501},[440,6991,2608],{},[440,6993,6994],{"class":442,"line":1506},[440,6995,2613],{},[440,6997,6998],{"class":442,"line":1511},[440,6999,2618],{},[440,7001,7002],{"class":442,"line":1517},[440,7003,7004],{},"    if (_enableConsoleOutput) {\n",[440,7006,7007],{"class":442,"line":1523},[440,7008,7009],{},"      developer.log(\n",[440,7011,7012],{"class":442,"line":1528},[440,7013,6865],{},[440,7015,7016],{"class":442,"line":1534},[440,7017,7018],{},"        name: 'SocialApp',\n",[440,7020,7021],{"class":442,"line":1539},[440,7022,7023],{},"        level: level,\n",[440,7025,7026],{"class":442,"line":1544},[440,7027,6875],{},[440,7029,7030],{"class":442,"line":1550},[440,7031,6880],{},[440,7033,7034],{"class":442,"line":1556},[440,7035,5801],{},[440,7037,7038],{"class":442,"line":1562},[440,7039,1289],{},[440,7041,7042],{"class":442,"line":1568},[440,7043,523],{},[440,7045,7046],{"class":442,"line":1574},[440,7047,470],{},[52,7049,7050],{},[77,7051,7052],{},"In practice:",[431,7054,7056],{"className":433,"code":7055,"language":435,"meta":46,"style":46},"// Only shows in dev (logLevel = 0)\nAppLogger.debug('User tapped the login button');\n\n// Shows in both dev and prod (logLevel \u003C= 1)\nAppLogger.info('User logged in successfully');\n\n// Always shows (logLevel \u003C= 3)\nAppLogger.error('API call failed', error: exception);\n",[437,7057,7058,7063,7068,7072,7077,7081,7085,7090],{"__ignoreMap":46},[440,7059,7060],{"class":442,"line":443},[440,7061,7062],{},"// Only shows in dev (logLevel = 0)\n",[440,7064,7065],{"class":442,"line":449},[440,7066,7067],{},"AppLogger.debug('User tapped the login button');\n",[440,7069,7070],{"class":442,"line":455},[440,7071,477],{"emptyLinePlaceholder":476},[440,7073,7074],{"class":442,"line":461},[440,7075,7076],{},"// Shows in both dev and prod (logLevel \u003C= 1)\n",[440,7078,7079],{"class":442,"line":467},[440,7080,2693],{},[440,7082,7083],{"class":442,"line":473},[440,7084,477],{"emptyLinePlaceholder":476},[440,7086,7087],{"class":442,"line":480},[440,7088,7089],{},"// Always shows (logLevel \u003C= 3)\n",[440,7091,7092],{"class":442,"line":486},[440,7093,7094],{},"AppLogger.error('API call failed', error: exception);\n",[52,7096,7097],{},"The logger respects your environment automatically. No manual checks needed!",[82,7099],{},[85,7101,7103],{"id":7102},"using-feature-flags-kill-switches-ftw","🎯 Using Feature Flags (Kill Switches FTW)",[52,7105,7106],{},"Your config has feature flags built in — here's how to actually use them:",[431,7108,7110],{"className":433,"code":7109,"language":435,"meta":46,"style":46},"// In your UI code\nif (config.isFeatureEnabled('enable_dark_mode')) {\n  // Show dark mode toggle\n  // Only shows if the flag is true\n}\n\nif (config.isFeatureEnabled('enable_beta_features')) {\n  // Show that experimental stuff\n  // Enabled in dev, disabled in prod\n}\n\n// Direct checking also works\nif (config.featureFlags['enable_payments'] == true) {\n  // Initialize Stripe or whatever\n}\n",[437,7111,7112,7117,7122,7127,7132,7136,7140,7145,7150,7155,7159,7163,7168,7173,7178],{"__ignoreMap":46},[440,7113,7114],{"class":442,"line":443},[440,7115,7116],{},"// In your UI code\n",[440,7118,7119],{"class":442,"line":449},[440,7120,7121],{},"if (config.isFeatureEnabled('enable_dark_mode')) {\n",[440,7123,7124],{"class":442,"line":455},[440,7125,7126],{},"  // Show dark mode toggle\n",[440,7128,7129],{"class":442,"line":461},[440,7130,7131],{},"  // Only shows if the flag is true\n",[440,7133,7134],{"class":442,"line":467},[440,7135,470],{},[440,7137,7138],{"class":442,"line":473},[440,7139,477],{"emptyLinePlaceholder":476},[440,7141,7142],{"class":442,"line":480},[440,7143,7144],{},"if (config.isFeatureEnabled('enable_beta_features')) {\n",[440,7146,7147],{"class":442,"line":486},[440,7148,7149],{},"  // Show that experimental stuff\n",[440,7151,7152],{"class":442,"line":492},[440,7153,7154],{},"  // Enabled in dev, disabled in prod\n",[440,7156,7157],{"class":442,"line":497},[440,7158,470],{},[440,7160,7161],{"class":442,"line":503},[440,7162,477],{"emptyLinePlaceholder":476},[440,7164,7165],{"class":442,"line":508},[440,7166,7167],{},"// Direct checking also works\n",[440,7169,7170],{"class":442,"line":514},[440,7171,7172],{},"if (config.featureFlags['enable_payments'] == true) {\n",[440,7174,7175],{"class":442,"line":520},[440,7176,7177],{},"  // Initialize Stripe or whatever\n",[440,7179,7180],{"class":442,"line":526},[440,7181,470],{},[52,7183,7184],{},[77,7185,7186],{},"Why feature flags are goated:",[93,7188,7189,7192,7195,7198,7201],{},[96,7190,7191],{},"Turn features on/off without rebuilding",[96,7193,7194],{},"Test in dev before unleashing on prod",[96,7196,7197],{},"Kill switch for features that break in prod",[96,7199,7200],{},"Gradual rollouts (turn on for some users, not all)",[96,7202,7203],{},"A/B testing made easy",[52,7205,7206],{},"Literally one of the best patterns ever invented, no cap.",[82,7208],{},[85,7210,7212],{"id":7211},"common-mistakes-learn-from-others-pain","🚨 Common Mistakes (Learn from Others' Pain)",[280,7214,7216],{"id":7215},"dont-do-this","❌ DON'T Do This:",[431,7218,7220],{"className":433,"code":7219,"language":435,"meta":46,"style":46},"// Checking debug mode everywhere like it's an environment\nif (kDebugMode) {\n  apiUrl = 'https://dev.api.com';\n} else {\n  apiUrl = 'https://prod.api.com';\n}\n",[437,7221,7222,7227,7232,7237,7242,7247],{"__ignoreMap":46},[440,7223,7224],{"class":442,"line":443},[440,7225,7226],{},"// Checking debug mode everywhere like it's an environment\n",[440,7228,7229],{"class":442,"line":449},[440,7230,7231],{},"if (kDebugMode) {\n",[440,7233,7234],{"class":442,"line":455},[440,7235,7236],{},"  apiUrl = 'https://dev.api.com';\n",[440,7238,7239],{"class":442,"line":461},[440,7240,7241],{},"} else {\n",[440,7243,7244],{"class":442,"line":467},[440,7245,7246],{},"  apiUrl = 'https://prod.api.com';\n",[440,7248,7249],{"class":442,"line":473},[440,7250,470],{},[280,7252,7254],{"id":7253},"do-this-instead","✅ DO This Instead:",[431,7256,7258],{"className":433,"code":7257,"language":435,"meta":46,"style":46},"// Let the config handle it\nfinal apiUrl = config.apiBaseUrl;\n",[437,7259,7260,7265],{"__ignoreMap":46},[440,7261,7262],{"class":442,"line":443},[440,7263,7264],{},"// Let the config handle it\n",[440,7266,7267],{"class":442,"line":449},[440,7268,7269],{},"final apiUrl = config.apiBaseUrl;\n",[52,7271,7272,7275,7276,7279],{},[77,7273,7274],{},"Why:"," ",[437,7277,7278],{},"kDebugMode"," is about build mode, not environment. You can build prod in debug mode for testing. Don't confuse the two!",[82,7281],{},[280,7283,7216],{"id":7284},"dont-do-this-1",[431,7286,7288],{"className":433,"code":7287,"language":435,"meta":46,"style":46},"// Using the same Firebase project for everything\nfirebaseProjectId: 'my-app-12345',\n",[437,7289,7290,7295],{"__ignoreMap":46},[440,7291,7292],{"class":442,"line":443},[440,7293,7294],{},"// Using the same Firebase project for everything\n",[440,7296,7297],{"class":442,"line":449},[440,7298,7299],{},"firebaseProjectId: 'my-app-12345',\n",[280,7301,7254],{"id":7302},"do-this-instead-1",[431,7304,7306],{"className":433,"code":7305,"language":435,"meta":46,"style":46},"// Dev config\nfirebaseProjectId: 'my-app-dev',\n\n// Prod config\nfirebaseProjectId: 'my-app-prod',\n",[437,7307,7308,7313,7318,7322,7327],{"__ignoreMap":46},[440,7309,7310],{"class":442,"line":443},[440,7311,7312],{},"// Dev config\n",[440,7314,7315],{"class":442,"line":449},[440,7316,7317],{},"firebaseProjectId: 'my-app-dev',\n",[440,7319,7320],{"class":442,"line":455},[440,7321,477],{"emptyLinePlaceholder":476},[440,7323,7324],{"class":442,"line":461},[440,7325,7326],{},"// Prod config\n",[440,7328,7329],{"class":442,"line":467},[440,7330,7331],{},"firebaseProjectId: 'my-app-prod',\n",[52,7333,7334,7336],{},[77,7335,7274],{}," Test crashes should NOT pollute your production Crashlytics dashboard. Keep them completely separate, bestie.",[82,7338],{},[280,7340,7216],{"id":7341},"dont-do-this-2",[431,7343,7345],{"className":433,"code":7344,"language":435,"meta":46,"style":46},"// Checking environment all over your code\nif (EnvironmentConfig.isDevelopment) {\n  showDebugInfo();\n}\n",[437,7346,7347,7352,7357,7362],{"__ignoreMap":46},[440,7348,7349],{"class":442,"line":443},[440,7350,7351],{},"// Checking environment all over your code\n",[440,7353,7354],{"class":442,"line":449},[440,7355,7356],{},"if (EnvironmentConfig.isDevelopment) {\n",[440,7358,7359],{"class":442,"line":455},[440,7360,7361],{},"  showDebugInfo();\n",[440,7363,7364],{"class":442,"line":461},[440,7365,470],{},[280,7367,7254],{"id":7368},"do-this-instead-2",[431,7370,7372],{"className":433,"code":7371,"language":435,"meta":46,"style":46},"// Use feature flags (more flexible)\nif (config.isFeatureEnabled('enable_debug_panel')) {\n  showDebugInfo();\n}\n",[437,7373,7374,7379,7384,7388],{"__ignoreMap":46},[440,7375,7376],{"class":442,"line":443},[440,7377,7378],{},"// Use feature flags (more flexible)\n",[440,7380,7381],{"class":442,"line":449},[440,7382,7383],{},"if (config.isFeatureEnabled('enable_debug_panel')) {\n",[440,7385,7386],{"class":442,"line":455},[440,7387,7361],{},[440,7389,7390],{"class":442,"line":461},[440,7391,470],{},[52,7393,7394,7396],{},[77,7395,7274],{}," Feature flags let you control features independently from environments. Way more flexible.",[82,7398],{},[280,7400,7216],{"id":7401},"dont-do-this-3",[431,7403,7405],{"className":433,"code":7404,"language":435,"meta":46,"style":46},"// Hardcoding prod secrets in your code\nconst prodApiKey = 'sk_live_actual_key_dont_do_this';\n",[437,7406,7407,7412],{"__ignoreMap":46},[440,7408,7409],{"class":442,"line":443},[440,7410,7411],{},"// Hardcoding prod secrets in your code\n",[440,7413,7414],{"class":442,"line":449},[440,7415,7416],{},"const prodApiKey = 'sk_live_actual_key_dont_do_this';\n",[280,7418,7254],{"id":7419},"do-this-instead-3",[431,7421,7423],{"className":433,"code":7422,"language":435,"meta":46,"style":46},"// Get from --dart-define\nfinal apiKey = const String.fromEnvironment('API_KEY');\nassert(apiKey.isNotEmpty, 'API_KEY required!');\n",[437,7424,7425,7430,7435],{"__ignoreMap":46},[440,7426,7427],{"class":442,"line":443},[440,7428,7429],{},"// Get from --dart-define\n",[440,7431,7432],{"class":442,"line":449},[440,7433,7434],{},"final apiKey = const String.fromEnvironment('API_KEY');\n",[440,7436,7437],{"class":442,"line":455},[440,7438,7439],{},"assert(apiKey.isNotEmpty, 'API_KEY required!');\n",[52,7441,7442,7444],{},[77,7443,7274],{}," Secrets in code = secrets in git = secrets leaked = very bad time. Always use --dart-define for prod secrets.",[82,7446],{},[85,7448,7450],{"id":7449},"pro-tips-level-up-your-game","🎓 Pro Tips (Level Up Your Game)",[280,7452,7454,7455],{"id":7453},"_1-vs-code-launch-configurations-game-changer","1. ",[77,7456,7457],{},"VS Code Launch Configurations (Game Changer)",[52,7459,7460,7461,4089],{},"Stop typing commands every time. Create ",[437,7462,7463],{},".vscode/launch.json",[431,7465,7469],{"className":7466,"code":7467,"language":7468,"meta":46,"style":46},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Dev\",\n      \"request\": \"launch\",\n      \"type\": \"dart\",\n      \"program\": \"lib/main_dev.dart\",\n      \"args\": [\"--flavor\", \"dev\"]\n    },\n    {\n      \"name\": \"Prod\",\n      \"request\": \"launch\",\n      \"type\": \"dart\",\n      \"program\": \"lib/main_prod.dart\",\n      \"args\": [\"--flavor\", \"prod\"]\n    }\n  ]\n}\n","json",[437,7470,7471,7477,7502,7516,7521,7542,7562,7581,7600,7634,7638,7642,7661,7679,7697,7715,7744,7748,7753],{"__ignoreMap":46},[440,7472,7473],{"class":442,"line":443},[440,7474,7476],{"class":7475},"sMK4o","{\n",[440,7478,7479,7482,7486,7489,7491,7494,7497,7499],{"class":442,"line":449},[440,7480,7481],{"class":7475},"  \"",[440,7483,7485],{"class":7484},"spNyl","version",[440,7487,7488],{"class":7475},"\"",[440,7490,4089],{"class":7475},[440,7492,7493],{"class":7475}," \"",[440,7495,7496],{"class":1884},"0.2.0",[440,7498,7488],{"class":7475},[440,7500,7501],{"class":7475},",\n",[440,7503,7504,7506,7509,7511,7513],{"class":442,"line":455},[440,7505,7481],{"class":7475},[440,7507,7508],{"class":7484},"configurations",[440,7510,7488],{"class":7475},[440,7512,4089],{"class":7475},[440,7514,7515],{"class":7475}," [\n",[440,7517,7518],{"class":442,"line":461},[440,7519,7520],{"class":7475},"    {\n",[440,7522,7523,7526,7529,7531,7533,7535,7538,7540],{"class":442,"line":467},[440,7524,7525],{"class":7475},"      \"",[440,7527,7528],{"class":1880},"name",[440,7530,7488],{"class":7475},[440,7532,4089],{"class":7475},[440,7534,7493],{"class":7475},[440,7536,7537],{"class":1884},"Dev",[440,7539,7488],{"class":7475},[440,7541,7501],{"class":7475},[440,7543,7544,7546,7549,7551,7553,7555,7558,7560],{"class":442,"line":473},[440,7545,7525],{"class":7475},[440,7547,7548],{"class":1880},"request",[440,7550,7488],{"class":7475},[440,7552,4089],{"class":7475},[440,7554,7493],{"class":7475},[440,7556,7557],{"class":1884},"launch",[440,7559,7488],{"class":7475},[440,7561,7501],{"class":7475},[440,7563,7564,7566,7569,7571,7573,7575,7577,7579],{"class":442,"line":480},[440,7565,7525],{"class":7475},[440,7567,7568],{"class":1880},"type",[440,7570,7488],{"class":7475},[440,7572,4089],{"class":7475},[440,7574,7493],{"class":7475},[440,7576,435],{"class":1884},[440,7578,7488],{"class":7475},[440,7580,7501],{"class":7475},[440,7582,7583,7585,7588,7590,7592,7594,7596,7598],{"class":442,"line":486},[440,7584,7525],{"class":7475},[440,7586,7587],{"class":1880},"program",[440,7589,7488],{"class":7475},[440,7591,4089],{"class":7475},[440,7593,7493],{"class":7475},[440,7595,5285],{"class":1884},[440,7597,7488],{"class":7475},[440,7599,7501],{"class":7475},[440,7601,7602,7604,7607,7609,7611,7614,7616,7619,7621,7624,7626,7629,7631],{"class":442,"line":492},[440,7603,7525],{"class":7475},[440,7605,7606],{"class":1880},"args",[440,7608,7488],{"class":7475},[440,7610,4089],{"class":7475},[440,7612,7613],{"class":7475}," [",[440,7615,7488],{"class":7475},[440,7617,7618],{"class":1884},"--flavor",[440,7620,7488],{"class":7475},[440,7622,7623],{"class":7475},",",[440,7625,7493],{"class":7475},[440,7627,7628],{"class":1884},"dev",[440,7630,7488],{"class":7475},[440,7632,7633],{"class":7475},"]\n",[440,7635,7636],{"class":442,"line":497},[440,7637,888],{"class":7475},[440,7639,7640],{"class":442,"line":503},[440,7641,7520],{"class":7475},[440,7643,7644,7646,7648,7650,7652,7654,7657,7659],{"class":442,"line":508},[440,7645,7525],{"class":7475},[440,7647,7528],{"class":1880},[440,7649,7488],{"class":7475},[440,7651,4089],{"class":7475},[440,7653,7493],{"class":7475},[440,7655,7656],{"class":1884},"Prod",[440,7658,7488],{"class":7475},[440,7660,7501],{"class":7475},[440,7662,7663,7665,7667,7669,7671,7673,7675,7677],{"class":442,"line":514},[440,7664,7525],{"class":7475},[440,7666,7548],{"class":1880},[440,7668,7488],{"class":7475},[440,7670,4089],{"class":7475},[440,7672,7493],{"class":7475},[440,7674,7557],{"class":1884},[440,7676,7488],{"class":7475},[440,7678,7501],{"class":7475},[440,7680,7681,7683,7685,7687,7689,7691,7693,7695],{"class":442,"line":520},[440,7682,7525],{"class":7475},[440,7684,7568],{"class":1880},[440,7686,7488],{"class":7475},[440,7688,4089],{"class":7475},[440,7690,7493],{"class":7475},[440,7692,435],{"class":1884},[440,7694,7488],{"class":7475},[440,7696,7501],{"class":7475},[440,7698,7699,7701,7703,7705,7707,7709,7711,7713],{"class":442,"line":526},[440,7700,7525],{"class":7475},[440,7702,7587],{"class":1880},[440,7704,7488],{"class":7475},[440,7706,4089],{"class":7475},[440,7708,7493],{"class":7475},[440,7710,5536],{"class":1884},[440,7712,7488],{"class":7475},[440,7714,7501],{"class":7475},[440,7716,7717,7719,7721,7723,7725,7727,7729,7731,7733,7735,7737,7740,7742],{"class":442,"line":531},[440,7718,7525],{"class":7475},[440,7720,7606],{"class":1880},[440,7722,7488],{"class":7475},[440,7724,4089],{"class":7475},[440,7726,7613],{"class":7475},[440,7728,7488],{"class":7475},[440,7730,7618],{"class":1884},[440,7732,7488],{"class":7475},[440,7734,7623],{"class":7475},[440,7736,7493],{"class":7475},[440,7738,7739],{"class":1884},"prod",[440,7741,7488],{"class":7475},[440,7743,7633],{"class":7475},[440,7745,7746],{"class":442,"line":537},[440,7747,1289],{"class":7475},[440,7749,7750],{"class":442,"line":543},[440,7751,7752],{"class":7475},"  ]\n",[440,7754,7755],{"class":442,"line":648},[440,7756,470],{"class":7475},[52,7758,7759],{},"Now just pick \"Dev\" or \"Prod\" from the dropdown. So clean.",[82,7761],{},[280,7763,7765,7766],{"id":7764},"_2-add-a-dev-environment-indicator-youll-thank-me","2. ",[77,7767,7768],{},"Add a Dev Environment Indicator (You'll Thank Me)",[52,7770,7771],{},"Ever confused which build you're running? Add this to your app:",[431,7773,7775],{"className":433,"code":7774,"language":435,"meta":46,"style":46},"Widget build(BuildContext context) {\n  return Stack(\n    children: [\n      // Your normal app\n      MaterialApp.router(...),\n      \n      // Dev indicator (only shows in dev)\n      if (config.debugMode)\n        Positioned(\n          top: 0,\n          right: 0,\n          child: SafeArea(\n            child: Container(\n              color: Colors.red,\n              padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),\n              child: Text(\n                'DEV',\n                style: TextStyle(\n                  color: Colors.white,\n                  fontSize: 12,\n                  fontWeight: FontWeight.bold,\n                ),\n              ),\n            ),\n          ),\n        ),\n    ],\n  );\n}\n",[437,7776,7777,7782,7787,7792,7797,7802,7807,7812,7817,7822,7827,7832,7837,7842,7847,7852,7857,7862,7867,7872,7877,7882,7887,7892,7897,7901,7905,7910,7914],{"__ignoreMap":46},[440,7778,7779],{"class":442,"line":443},[440,7780,7781],{},"Widget build(BuildContext context) {\n",[440,7783,7784],{"class":442,"line":449},[440,7785,7786],{},"  return Stack(\n",[440,7788,7789],{"class":442,"line":455},[440,7790,7791],{},"    children: [\n",[440,7793,7794],{"class":442,"line":461},[440,7795,7796],{},"      // Your normal app\n",[440,7798,7799],{"class":442,"line":467},[440,7800,7801],{},"      MaterialApp.router(...),\n",[440,7803,7804],{"class":442,"line":473},[440,7805,7806],{},"      \n",[440,7808,7809],{"class":442,"line":480},[440,7810,7811],{},"      // Dev indicator (only shows in dev)\n",[440,7813,7814],{"class":442,"line":486},[440,7815,7816],{},"      if (config.debugMode)\n",[440,7818,7819],{"class":442,"line":492},[440,7820,7821],{},"        Positioned(\n",[440,7823,7824],{"class":442,"line":497},[440,7825,7826],{},"          top: 0,\n",[440,7828,7829],{"class":442,"line":503},[440,7830,7831],{},"          right: 0,\n",[440,7833,7834],{"class":442,"line":508},[440,7835,7836],{},"          child: SafeArea(\n",[440,7838,7839],{"class":442,"line":514},[440,7840,7841],{},"            child: Container(\n",[440,7843,7844],{"class":442,"line":520},[440,7845,7846],{},"              color: Colors.red,\n",[440,7848,7849],{"class":442,"line":526},[440,7850,7851],{},"              padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),\n",[440,7853,7854],{"class":442,"line":531},[440,7855,7856],{},"              child: Text(\n",[440,7858,7859],{"class":442,"line":537},[440,7860,7861],{},"                'DEV',\n",[440,7863,7864],{"class":442,"line":543},[440,7865,7866],{},"                style: TextStyle(\n",[440,7868,7869],{"class":442,"line":648},[440,7870,7871],{},"                  color: Colors.white,\n",[440,7873,7874],{"class":442,"line":654},[440,7875,7876],{},"                  fontSize: 12,\n",[440,7878,7879],{"class":442,"line":660},[440,7880,7881],{},"                  fontWeight: FontWeight.bold,\n",[440,7883,7884],{"class":442,"line":665},[440,7885,7886],{},"                ),\n",[440,7888,7889],{"class":442,"line":671},[440,7890,7891],{},"              ),\n",[440,7893,7894],{"class":442,"line":677},[440,7895,7896],{},"            ),\n",[440,7898,7899],{"class":442,"line":683},[440,7900,2887],{},[440,7902,7903],{"class":442,"line":689},[440,7904,5971],{},[440,7906,7907],{"class":442,"line":695},[440,7908,7909],{},"    ],\n",[440,7911,7912],{"class":442,"line":701},[440,7913,921],{},[440,7915,7916],{"class":442,"line":707},[440,7917,470],{},[52,7919,7920],{},"Now you'll ALWAYS know when you're in dev. No more accidental prod testing.",[82,7922],{},[280,7924,7926,7927],{"id":7925},"_3-use-a-makefile-so-much-better","3. ",[77,7928,7929],{},"Use a Makefile (So Much Better)",[52,7931,7932,7933,7936],{},"Create a ",[437,7934,7935],{},"Makefile"," in your project root:",[431,7938,7942],{"className":7939,"code":7940,"language":7941,"meta":46,"style":46},"language-makefile shiki shiki-themes material-theme-lighter material-theme material-theme-palenight",".PHONY: dev-run prod-run build-dev build-prod\n\ndev-run:\n    flutter run -t lib/main_dev.dart --flavor dev\n\nprod-run:\n    flutter run -t lib/main_prod.dart --flavor prod\n\nbuild-dev:\n    flutter build apk -t lib/main_dev.dart --flavor dev\n\nbuild-prod:\n    flutter build appbundle -t lib/main_prod.dart --flavor prod \\\n        --dart-define=API_BASE_URL=${API_BASE_URL} \\\n        --dart-define=FIREBASE_API_KEY=${FIREBASE_API_KEY} \\\n        --dart-define=FIREBASE_APP_ID=${FIREBASE_APP_ID} \\\n        --dart-define=FIREBASE_MESSAGING_SENDER_ID=${FIREBASE_MESSAGING_SENDER_ID} \\\n        --dart-define=FIREBASE_PROJECT_ID=${FIREBASE_PROJECT_ID} \\\n        --dart-define=ENCRYPTION_KEY=${ENCRYPTION_KEY}\n","makefile",[437,7943,7944,7949,7953,7958,7963,7967,7972,7977,7981,7986,7991,7995,8000,8005,8010,8015,8020,8025,8030],{"__ignoreMap":46},[440,7945,7946],{"class":442,"line":443},[440,7947,7948],{},".PHONY: dev-run prod-run build-dev build-prod\n",[440,7950,7951],{"class":442,"line":449},[440,7952,477],{"emptyLinePlaceholder":476},[440,7954,7955],{"class":442,"line":455},[440,7956,7957],{},"dev-run:\n",[440,7959,7960],{"class":442,"line":461},[440,7961,7962],{},"    flutter run -t lib/main_dev.dart --flavor dev\n",[440,7964,7965],{"class":442,"line":467},[440,7966,477],{"emptyLinePlaceholder":476},[440,7968,7969],{"class":442,"line":473},[440,7970,7971],{},"prod-run:\n",[440,7973,7974],{"class":442,"line":480},[440,7975,7976],{},"    flutter run -t lib/main_prod.dart --flavor prod\n",[440,7978,7979],{"class":442,"line":486},[440,7980,477],{"emptyLinePlaceholder":476},[440,7982,7983],{"class":442,"line":492},[440,7984,7985],{},"build-dev:\n",[440,7987,7988],{"class":442,"line":497},[440,7989,7990],{},"    flutter build apk -t lib/main_dev.dart --flavor dev\n",[440,7992,7993],{"class":442,"line":503},[440,7994,477],{"emptyLinePlaceholder":476},[440,7996,7997],{"class":442,"line":508},[440,7998,7999],{},"build-prod:\n",[440,8001,8002],{"class":442,"line":514},[440,8003,8004],{},"    flutter build appbundle -t lib/main_prod.dart --flavor prod \\\n",[440,8006,8007],{"class":442,"line":520},[440,8008,8009],{},"        --dart-define=API_BASE_URL=${API_BASE_URL} \\\n",[440,8011,8012],{"class":442,"line":526},[440,8013,8014],{},"        --dart-define=FIREBASE_API_KEY=${FIREBASE_API_KEY} \\\n",[440,8016,8017],{"class":442,"line":531},[440,8018,8019],{},"        --dart-define=FIREBASE_APP_ID=${FIREBASE_APP_ID} \\\n",[440,8021,8022],{"class":442,"line":537},[440,8023,8024],{},"        --dart-define=FIREBASE_MESSAGING_SENDER_ID=${FIREBASE_MESSAGING_SENDER_ID} \\\n",[440,8026,8027],{"class":442,"line":543},[440,8028,8029],{},"        --dart-define=FIREBASE_PROJECT_ID=${FIREBASE_PROJECT_ID} \\\n",[440,8031,8032],{"class":442,"line":648},[440,8033,8034],{},"        --dart-define=ENCRYPTION_KEY=${ENCRYPTION_KEY}\n",[52,8036,8037],{},"Now just run:",[431,8039,8041],{"className":1865,"code":8040,"language":1867,"meta":46,"style":46},"make dev-run      # Run dev\nmake build-prod   # Build prod\n",[437,8042,8043,8054],{"__ignoreMap":46},[440,8044,8045,8048,8051],{"class":442,"line":443},[440,8046,8047],{"class":1880},"make",[440,8049,8050],{"class":1884}," dev-run",[440,8052,8053],{"class":1874},"      # Run dev\n",[440,8055,8056,8058,8061],{"class":442,"line":449},[440,8057,8047],{"class":1880},[440,8059,8060],{"class":1884}," build-prod",[440,8062,8063],{"class":1874},"   # Build prod\n",[52,8065,8066],{},"Way easier than remembering all those commands.",[82,8068],{},[280,8070,8072,8073],{"id":8071},"_4-keep-secrets-safe-seriously","4. ",[77,8074,8075],{},"Keep Secrets Safe (Seriously)",[52,8077,8078],{},[77,8079,8080],{},"Never commit:",[93,8082,8083,8087,8090],{},[96,8084,8085],{},[437,8086,4578],{},[96,8088,8089],{},"Production Firebase configs",[96,8091,8092],{},"Production API keys",[52,8094,8095],{},[77,8096,8097],{},"Add to .gitignore:",[431,8099,8103],{"className":8100,"code":8101,"language":8102,"meta":46,"style":46},"language-gitignore shiki shiki-themes material-theme-lighter material-theme material-theme-palenight",".env.prod\nandroid/app/src/prod/google-services.json\nios/Runner/Firebase/Prod/GoogleService-Info.plist\n","gitignore",[437,8104,8105,8110,8115],{"__ignoreMap":46},[440,8106,8107],{"class":442,"line":443},[440,8108,8109],{},".env.prod\n",[440,8111,8112],{"class":442,"line":449},[440,8113,8114],{},"android/app/src/prod/google-services.json\n",[440,8116,8117],{"class":442,"line":455},[440,8118,8119],{},"ios/Runner/Firebase/Prod/GoogleService-Info.plist\n",[52,8121,8122],{},[77,8123,8124],{},"For CI/CD:",[93,8126,8127,8130,8133],{},[96,8128,8129],{},"Store secrets in GitHub Secrets / GitLab CI Variables",[96,8131,8132],{},"Pass via --dart-define during builds",[96,8134,8135],{},"Keep them encrypted at rest",[52,8137,8138],{},"Your future self will thank you when your secrets don't get leaked.",[82,8140],{},[280,8142,8144,8145],{"id":8143},"_5-test-both-environments-locally","5. ",[77,8146,8147],{},"Test Both Environments Locally",[52,8149,8150],{},"Before pushing:",[431,8152,8154],{"className":1865,"code":8153,"language":1867,"meta":46,"style":46},"# Test dev build\nflutter run -t lib/main_dev.dart --flavor dev\n\n# Test prod build (with test secrets)\nflutter run -t lib/main_prod.dart --flavor prod \\\n  --dart-define=API_BASE_URL=https://staging.api.com \\\n  # ... other test values\n",[437,8155,8156,8161,8175,8179,8184,8200,8207],{"__ignoreMap":46},[440,8157,8158],{"class":442,"line":443},[440,8159,8160],{"class":1874},"# Test dev build\n",[440,8162,8163,8165,8167,8169,8171,8173],{"class":442,"line":449},[440,8164,1881],{"class":1880},[440,8166,1885],{"class":1884},[440,8168,1888],{"class":1884},[440,8170,6136],{"class":1884},[440,8172,6139],{"class":1884},[440,8174,6142],{"class":1884},[440,8176,8177],{"class":442,"line":455},[440,8178,477],{"emptyLinePlaceholder":476},[440,8180,8181],{"class":442,"line":461},[440,8182,8183],{"class":1874},"# Test prod build (with test secrets)\n",[440,8185,8186,8188,8190,8192,8194,8196,8198],{"class":442,"line":467},[440,8187,1881],{"class":1880},[440,8189,1885],{"class":1884},[440,8191,1888],{"class":1884},[440,8193,6168],{"class":1884},[440,8195,6139],{"class":1884},[440,8197,6173],{"class":1884},[440,8199,6177],{"class":6176},[440,8201,8202,8205],{"class":442,"line":473},[440,8203,8204],{"class":1884},"  --dart-define=API_BASE_URL=https://staging.api.com",[440,8206,6177],{"class":6176},[440,8208,8209],{"class":442,"line":480},[440,8210,8211],{"class":1874},"  # ... other test values\n",[52,8213,8214],{},"Catch issues before they hit CI/CD.",[82,8216],{},[85,8218,8220],{"id":8219},"pre-ship-checklist-dont-deploy-without-this","✅ Pre-Ship Checklist (Don't Deploy Without This)",[52,8222,8223],{},"Before you yeet your app to production:",[93,8225,8228,8240,8249,8258,8267,8276,8285,8294,8303,8312,8321,8330,8341],{"className":8226},[8227],"contains-task-list",[96,8229,8232,7275,8236,8239],{"className":8230},[8231],"task-list-item",[8233,8234],"input",{"disabled":476,"type":8235},"checkbox",[77,8237,8238],{},"Separate Firebase projects"," for dev and prod (most important!)",[96,8241,8243,7275,8245,8248],{"className":8242},[8231],[8233,8244],{"disabled":476,"type":8235},[77,8246,8247],{},"Different API endpoints"," configured correctly",[96,8250,8252,7275,8254,8257],{"className":8251},[8231],[8233,8253],{"disabled":476,"type":8235},[77,8255,8256],{},"Production logs"," are INFO level or higher (no debug spam)",[96,8259,8261,7275,8263,8266],{"className":8260},[8231],[8233,8262],{"disabled":476,"type":8235},[77,8264,8265],{},"Debug mode disabled"," in prod config",[96,8268,8270,7275,8272,8275],{"className":8269},[8231],[8233,8271],{"disabled":476,"type":8235},[77,8273,8274],{},"Feature flags"," configured for each environment",[96,8277,8279,7275,8281,8284],{"className":8278},[8231],[8233,8280],{"disabled":476,"type":8235},[77,8282,8283],{},"Different encryption keys"," (never use the same key!)",[96,8286,8288,7275,8290,8293],{"className":8287},[8231],[8233,8289],{"disabled":476,"type":8235},[77,8291,8292],{},"App names differ"," (dev has \"Dev\" suffix or similar)",[96,8295,8297,7275,8299,8302],{"className":8296},[8231],[8233,8298],{"disabled":476,"type":8235},[77,8300,8301],{},"Bundle IDs/Package names differ"," (can install both at once)",[96,8304,8306,7275,8308,8311],{"className":8305},[8231],[8233,8307],{"disabled":476,"type":8235},[77,8309,8310],{},"Tested crashes"," in both environments",[96,8313,8315,7275,8317,8320],{"className":8314},[8231],[8233,8316],{"disabled":476,"type":8235},[77,8318,8319],{},"Verified Crashlytics"," reports go to the right project",[96,8322,8324,7275,8326,8329],{"className":8323},[8231],[8233,8325],{"disabled":476,"type":8235},[77,8327,8328],{},"All prod secrets"," passed via --dart-define (not hardcoded)",[96,8331,8333,7275,8335,8340],{"className":8332},[8231],[8233,8334],{"disabled":476,"type":8235},[77,8336,8337,8339],{},[437,8338,4578],{}," is in .gitignore"," (if you're using it)",[96,8342,8344,7275,8346,8349],{"className":8343},[8231],[8233,8345],{"disabled":476,"type":8235},[77,8347,8348],{},"Firebase config files"," for prod are not in git",[52,8351,8352],{},"If you can check all these boxes, you're good to ship. 📦",[82,8354],{},[85,8356,8358],{"id":8357},"the-tldr","🎯 The TL;DR",[52,8360,8361,8362,168],{},"Environment setup really isn't that complicated — it's just ",[77,8363,8364],{},"staying organized",[52,8366,8367,8368,8370,8371,168],{},"You're not building two different apps.",[61,8369],{},"\nYou're building ",[77,8372,8373],{},"one app that knows how to adapt",[52,8375,8376],{},"The pattern is literally just:",[241,8378,8379,8382,8385,8388,8391,8394,8397,8400],{},[96,8380,8381],{},"✅ Define your environments (enum)",[96,8383,8384],{},"✅ Create a config model (one source of truth)",[96,8386,8387],{},"✅ Make an env loader (for .env files)",[96,8389,8390],{},"✅ Fill in values per environment (dev + prod configs)",[96,8392,8393],{},"✅ Create entry points (main_dev + main_prod)",[96,8395,8396],{},"✅ Pass config through your app (dependency injection)",[96,8398,8399],{},"✅ Setup Android flavors and iOS schemes",[96,8401,8402],{},"✅ Keep prod secrets secure (--dart-define)",[52,8404,8405],{},"Do this once, and you're set for the entire project.",[52,8407,8408],{},"Your future self will be grateful when:",[93,8410,8411,8414,8417,8420,8423],{},[96,8412,8413],{},"✨ You can test without worrying about breaking prod",[96,8415,8416],{},"✨ Production releases are smooth and stress-free",[96,8418,8419],{},"✨ Bugs stay contained to dev",[96,8421,8422],{},"✨ Features roll out gradually",[96,8424,8425],{},"✨ You're not getting paged at 2 AM",[52,8427,8428,8429,168],{},"This isn't \"senior dev flex\" territory — it's ",[77,8430,8431],{},"the bare minimum for production apps",[52,8433,8434],{},"And now you've got it down. 💪",[82,8436],{},[85,8438,8440],{"id":8439},"whats-next","🚀 What's Next?",[52,8442,8443],{},[77,8444,8445],{},"Take action today:",[93,8447,8449,8455,8461,8467],{"className":8448},[8227],[96,8450,8452,8454],{"className":8451},[8231],[8233,8453],{"disabled":476,"type":8235}," Set up this pattern in your current project",[96,8456,8458,8460],{"className":8457},[8231],[8233,8459],{"disabled":476,"type":8235}," Test a simple feature flag (start small)",[96,8462,8464,8466],{"className":8463},[8231],[8233,8465],{"disabled":476,"type":8235}," Add Crashlytics and verify they stay separated",[96,8468,8470,8472],{"className":8469},[8231],[8233,8471],{"disabled":476,"type":8235}," Sleep better after your next deploy 😴",[52,8474,8475,8476,8478,8479,8481,8482,8485],{},"You're not overengineering.",[61,8477],{},"\nYou're not being extra.",[61,8480],{},"\nYou're building apps that ",[77,8483,8484],{},"actually deserve to be in production",". 💙",[52,8487,8488],{},"Now go forth and build something that doesn't catch fire in prod! 🔥",[82,8490],{},[52,8492,8493],{},[3111,8494,8495],{},"Built with real production experience. No theoretical BS, just patterns that actually work in the wild. If this helped you, share it with someone who's struggling with environment setup!",[3390,8497,8498],{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}",{"title":46,"searchDepth":449,"depth":449,"links":8500},[8501,8502,8506,8507,8508,8509,8514,8515,8516,8522,8523,8529,8532,8537,8538,8539,8549,8561,8562,8563],{"id":3489,"depth":449,"text":3490},{"id":3555,"depth":449,"text":3556,"children":8503},[8504,8505],{"id":3559,"depth":455,"text":3560},{"id":3578,"depth":455,"text":3579},{"id":3605,"depth":449,"text":3606},{"id":3633,"depth":449,"text":3634},{"id":3787,"depth":449,"text":3788},{"id":4045,"depth":449,"text":4046,"children":8510},[8511,8512,8513],{"id":4063,"depth":455,"text":4064},{"id":4081,"depth":455,"text":4082},{"id":4417,"depth":455,"text":4418},{"id":4588,"depth":449,"text":4589},{"id":4887,"depth":449,"text":4888},{"id":5274,"depth":449,"text":5275,"children":8517},[8518,8520],{"id":5281,"depth":455,"text":8519},"Development Entry Point (lib/main_dev.dart)",{"id":5532,"depth":455,"text":8521},"Production Entry Point (lib/main_prod.dart)",{"id":5846,"depth":449,"text":5847},{"id":6076,"depth":449,"text":6077,"children":8524},[8525,8526,8527,8528],{"id":6080,"depth":455,"text":6081},{"id":6114,"depth":455,"text":6115},{"id":6199,"depth":455,"text":6200},{"id":6305,"depth":455,"text":6306},{"id":6381,"depth":449,"text":6382,"children":8530},[8531],{"id":6521,"depth":455,"text":6522},{"id":6539,"depth":449,"text":6540,"children":8533},[8534,8535,8536],{"id":6553,"depth":455,"text":6554},{"id":6569,"depth":455,"text":6570},{"id":6584,"depth":455,"text":6585},{"id":6624,"depth":449,"text":6625},{"id":7102,"depth":449,"text":7103},{"id":7211,"depth":449,"text":7212,"children":8540},[8541,8542,8543,8544,8545,8546,8547,8548],{"id":7215,"depth":455,"text":7216},{"id":7253,"depth":455,"text":7254},{"id":7284,"depth":455,"text":7216},{"id":7302,"depth":455,"text":7254},{"id":7341,"depth":455,"text":7216},{"id":7368,"depth":455,"text":7254},{"id":7401,"depth":455,"text":7216},{"id":7419,"depth":455,"text":7254},{"id":7449,"depth":449,"text":7450,"children":8550},[8551,8553,8555,8557,8559],{"id":7453,"depth":455,"text":8552},"1. VS Code Launch Configurations (Game Changer)",{"id":7764,"depth":455,"text":8554},"2. Add a Dev Environment Indicator (You'll Thank Me)",{"id":7925,"depth":455,"text":8556},"3. Use a Makefile (So Much Better)",{"id":8071,"depth":455,"text":8558},"4. Keep Secrets Safe (Seriously)",{"id":8143,"depth":455,"text":8560},"5. Test Both Environments Locally",{"id":8219,"depth":449,"text":8220},{"id":8357,"depth":449,"text":8358},{"id":8439,"depth":449,"text":8440},"2026-01-30","A straightforward guide to setting up dev and production environments in Flutter — with real code examples that actually work in the real world.","/img/flutter-environment-setup.png",{},{"title":22,"description":8565},[1881,8570,199,8571,8572],"environment","mobile-development","beginners","FJz6YR7t38DQJw8ncLPc9qOeas5Q8RPiFJfFlTdyEis",1769949237309]