{"version":1,"pages":[{"id":"c5t2gjkgBocZiL1tjUQv","title":"My Dev","pathname":"/flutter","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"hand-wave","description":"My Dev — practical lessons about Flutter, AI, and ReactJS."},{"id":"1wLdFVpLfDScdpGSD6nO","title":"My Flutter","pathname":"/flutter/my-flutter/flutter","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"mobile-screen","description":"Practical Flutter lessons on architecture, realtime systems, security, quality, and production operations.","breadcrumbs":[{"label":"My Flutter"}]},{"id":"MfsErmI8ZiNpVUoRmI6K","title":"Foundations & Clean Code","pathname":"/flutter/my-flutter/foundations","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"Tools, habits, and Dart foundations for writing Flutter code quickly without sacrificing maintainability.","breadcrumbs":[{"label":"My Flutter"}]},{"id":"y0H2DpuawHJCACFywoPe","title":"Tip Code Faster","pathname":"/flutter/my-flutter/foundations/tip-code-faster","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"comet","description":"","breadcrumbs":[{"label":"My Flutter"},{"label":"Foundations & Clean Code"}]},{"id":"757ESPKGR9SwyJPqwpIM","title":"FVM","pathname":"/flutter/my-flutter/foundations/fvm","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code-branch","description":"Fix Flutter version for your team with FVM","breadcrumbs":[{"label":"My Flutter"},{"label":"Foundations & Clean Code"}]},{"id":"PG14RfyD6nuNYL68vG7H","title":"Make","pathname":"/flutter/my-flutter/foundations/make","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"terminal","description":"Use Make to run many Flutter commands with one short command","breadcrumbs":[{"label":"My Flutter"},{"label":"Foundations & Clean Code"}]},{"id":"8mfrjG04MVDFXtJQbSsu","title":"Easy Maintain","pathname":"/flutter/my-flutter/foundations/easy-maintain","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"person-digging","description":"Reducing Maintenance and Sustaining Code","breadcrumbs":[{"label":"My Flutter"},{"label":"Foundations & Clean Code"}]},{"id":"6Yh2LXIXAdzRX2g1isw5","title":"Mason","pathname":"/flutter/my-flutter/foundations/mason","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"explosion","description":"Code Flutter Faster with Mason","breadcrumbs":[{"label":"My Flutter"},{"label":"Foundations & Clean Code"}]},{"id":"9K2cFvWJZkj1En1mS41Y","title":"Log Color","pathname":"/flutter/my-flutter/foundations/log-color","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"palette","description":"Setting Up Colored Logs and Saving Logs to Device Storage","breadcrumbs":[{"label":"My Flutter"},{"label":"Foundations & Clean Code"}]},{"id":"NLO1FMlDB7QtAs4FAA8k","title":"Activity Diagram","pathname":"/flutter/my-flutter/foundations/activity-diagram","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"head-side-brain","description":"","breadcrumbs":[{"label":"My Flutter"},{"label":"Foundations & Clean Code"}]},{"id":"GoLrUH02g4WSVray7nHP","title":"Clean code","pathname":"/flutter/my-flutter/foundations/clean-code","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"broom-wide","description":"Best Practices for Writing Clean and Understandable Code in Flutter Team Development","breadcrumbs":[{"label":"My Flutter"},{"label":"Foundations & Clean Code"}]},{"id":"GYRjxkG3zMjUYpCTRcv4","title":"Coverage","pathname":"/flutter/my-flutter/foundations/coverage-codecov","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"chart-simple","description":"Upload Flutter test coverage to Codecov and show a badge in README","breadcrumbs":[{"label":"My Flutter"},{"label":"Foundations & Clean Code"}]},{"id":"tbmomLDMDlD9EJkGgiw7","title":"Git hook","pathname":"/flutter/my-flutter/foundations/git-hook","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code-branch","description":"Run commands automatically when using Git commands","breadcrumbs":[{"label":"My Flutter"},{"label":"Foundations & Clean Code"}]},{"id":"v7aRB1u6516kfIK3yStm","title":"Enum","pathname":"/flutter/my-flutter/foundations/enum","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"spider-web","description":"The Power of Enums in Simplifying Code","breadcrumbs":[{"label":"My Flutter"},{"label":"Foundations & Clean Code"}]},{"id":"esCGUntBay5V7YKAwaxn","title":"Architecture & State","pathname":"/flutter/my-flutter/architecture-state","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"Application architecture, package boundaries, migration, and state management for Flutter at scale.","breadcrumbs":[{"label":"My Flutter"}]},{"id":"0WC9Kg79sKDw0COGDLUj","title":"Plugin","pathname":"/flutter/my-flutter/architecture-state/plugin","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"puzzle-piece-simple","description":"Plugin: Communicating with Native Code for Efficient Flutter App Maintenance","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"DOQf7tbR65m4o5Jlz62x","title":"Flutter Clean Architecture","pathname":"/flutter/my-flutter/architecture-state/flutter-clean-architecture","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"ram","description":"Easier Maintenance and Expansion of Flutter Code with Clean Architecture","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"awFEXKYydCCmZKw6vQIk","title":"Base Project","pathname":"/flutter/my-flutter/architecture-state/base-project","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"atom","description":"Creating a Base Project in Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"1lpIWX1RW20PkI7TGvxs","title":"Flavor","pathname":"/flutter/my-flutter/architecture-state/flavor","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"sliders","description":"Set up 3 environments (dev, staging, production) for mobile in Flutter (3 separate mobile apps)","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"QMkTqQbLXYMSzWOrpNtw","title":"Package","pathname":"/flutter/my-flutter/architecture-state/package","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"arrows-to-circle","description":"Package - Store the Best of Your Code for Your Projects","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"xhCc6xkN0EOAzEhnIdww","title":"Dart Workspace and Melos","pathname":"/flutter/my-flutter/architecture-state/dart-workspace-melos","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"boxes-stacked","description":"Use Dart Workspace for consistent dependency resolution and Melos to orchestrate commands in a Flutter monorepo","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"MnpADg71Yuu0vcuuCWTo","title":"Context Anywhere","pathname":"/flutter/my-flutter/architecture-state/context-anywhere","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"message-middle","description":"Guide to Setting Up and Accessing BuildContext Anywhere in a Flutter Project","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"V3SeIz7l08DCG5hi9prc","title":"Bloc","pathname":"/flutter/my-flutter/architecture-state/bloc","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"rectangles-mixed","description":"","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"tFi0DZUoGC2jkEso9Mqu","title":"ChangeNotifier","pathname":"/flutter/my-flutter/architecture-state/changenotifier","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"light-ceiling","description":"Controlling Widgets with ChangeNotifier","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"flT55X8RgxKD0XpLXtUC","title":"Redux/Flutter Redux at Scale","pathname":"/flutter/my-flutter/architecture-state/redux-flutter-redux-large-app","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"diagram-project","description":"Organize Redux and Flutter Redux by feature so a global store remains manageable as the application grows","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"YyM552Bk6JgngO4Jb0D9","title":"Redux Epics and RxDart","pathname":"/flutter/my-flutter/architecture-state/redux-epics-rxdart","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"wave-square","description":"Choose the correct concurrency strategy in Redux Epics to prevent duplicate requests and stale results from overwriting state","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"rmFKA2Mf6X0rir3aOGF7","title":"Redux Persist and State Migration","pathname":"/flutter/my-flutter/architecture-state/redux-persist-state-migration","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"database","description":"How I limit persisted Redux state, migrate versioned schemas, and stop saving until storage loads successfully","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"1Z2MpTyQSwl5Y7CFKgbq","title":"Incremental Fish Redux Migration","pathname":"/flutter/my-flutter/architecture-state/incremental-fish-redux-migration","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"arrows-rotate","description":"How I migrate Fish Redux screens to Flutter Redux while preserving routes, arguments, deep links, and the back stack","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"kRwPCji1Su5SDCA281L1","title":"Systems & Realtime","pathname":"/flutter/my-flutter/systems-realtime","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"APIs, networking, realtime systems, lifecycle, and navigation boundaries in production Flutter apps.","breadcrumbs":[{"label":"My Flutter"}]},{"id":"3Eh62eld4JjEvdiZuUZE","title":"MQTT and App Lifecycle","pathname":"/flutter/my-flutter/systems-realtime/mqtt-realtime-app-lifecycle","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"tower-broadcast","description":"How I organize MQTT when the app enters the background, preserve subscriptions, and restore data when it returns to the foreground","breadcrumbs":[{"label":"My Flutter"},{"label":"Systems & Realtime"}]},{"id":"6ImuQSzalnf2siRLk5jN","title":"Typed Realtime with Protobuf and Nakama","pathname":"/flutter/my-flutter/systems-realtime/nakama-protobuf-market-realtime","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"How I use topics as schema contracts, separate state from events, and keep Nakama outside the market gateway so realtime data stays typed","breadcrumbs":[{"label":"My Flutter"},{"label":"Systems & Realtime"}]},{"id":"jkt93wLJkd13Zc8LTlcz","title":"Aggregating Realtime Data with Reactive Streams","pathname":"/flutter/my-flutter/systems-realtime/reactive-realtime-aggregation-flutter","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"chart-network","description":"Design derived realtime state with a typed adapter, freshness gates, immutable snapshots, and a testable lifecycle in Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"Systems & Realtime"}]},{"id":"r1BG7cXgqoay4tvlyEeO","title":"Production HTTP Client for Flutter","pathname":"/flutter/my-flutter/systems-realtime/production-http-client","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"network-wired","description":"How I attach a 401 failure to the request auth context so a stale response cannot log out a newer session, while also standardizing JWT handling and HTTP failures","breadcrumbs":[{"label":"My Flutter"},{"label":"Systems & Realtime"}]},{"id":"kThPOkuxgcDBnbaVwp31","title":"Flutter Connectivity and Network Failures","pathname":"/flutter/my-flutter/systems-realtime/connectivity-offline-ux-vpn","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"wifi","description":"How I separate transport, Internet reachability, timeouts, service errors, captive portals, and VPNs so offline UX does not report the wrong cause","breadcrumbs":[{"label":"My Flutter"},{"label":"Systems & Realtime"}]},{"id":"XuzrnRXJWWpiiB1XhH1m","title":"Multi-Source Deep Links in Flutter","pathname":"/flutter/my-flutter/systems-realtime/deep-link-app-links-adjust-onesignal","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"link","description":"How I route App Links, Adjust, and OneSignal through a typed pipeline that validates input, prevents duplicate navigation, and waits for app readiness","breadcrumbs":[{"label":"My Flutter"},{"label":"Systems & Realtime"}]},{"id":"s8U9u3J5vFczgod711Oc","title":"UI & Media","pathname":"/flutter/my-flutter/ui-media","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"UI, WebViews, charts, cameras, media, and server-driven content in Flutter.","breadcrumbs":[{"label":"My Flutter"}]},{"id":"nOyMKoFdRsvzloZZ19PO","title":"FFmpeg Flutter","pathname":"/flutter/my-flutter/ui-media/ffmpeg-flutter","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"monero","description":"Handling Video with FFmpeg in Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"UI & Media"}]},{"id":"Bd3JWH0rQHix4q2QX4rP","title":"Secure Documents and Attachments","pathname":"/flutter/my-flutter/ui-media/secure-documents-attachments-flutter","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"file-shield","description":"How I put pickers, downloads, exports, and media through one policy before previewing, uploading, saving, opening, or sharing","breadcrumbs":[{"label":"My Flutter"},{"label":"UI & Media"}]},{"id":"DDwBamhA1zlGZaY4h0sH","title":"Dark Mode","pathname":"/flutter/my-flutter/ui-media/dark-mode","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"circle-half-stroke","description":"Setting Up Light/Dark Mode and Fonts in a Flutter App","breadcrumbs":[{"label":"My Flutter"},{"label":"UI & Media"}]},{"id":"6hDqpC429EsGfW5oXVfG","title":"TradingView in a Flutter WebView","pathname":"/flutter/my-flutter/ui-media/tradingview-webview-javascript-bridge","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"chart-simple","description":"How to package TradingView in a Flutter WebView with local assets, a versioned JavaScript bridge, and safe Android/iOS lifecycle handling","breadcrumbs":[{"label":"My Flutter"},{"label":"UI & Media"}]},{"id":"jO3P7o8XQ6S8E0URgaYn","title":"Choosing a Financial Chart Renderer","pathname":"/flutter/my-flutter/ui-media/financial-chart-renderer","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"chart-line","description":"How to choose among FL Chart, ECharts, and an MPChart-style renderer based on capabilities, realtime updates, gestures, testing, and WebView cost","breadcrumbs":[{"label":"My Flutter"},{"label":"UI & Media"}]},{"id":"CDrwgU4VSXIkYOjtqAGg","title":"Building a Custom Trading Keyboard in Flutter","pathname":"/flutter/my-flutter/ui-media/custom-trading-keyboard","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"keyboard","description":"Build a custom numeric keyboard in Flutter with a controller, active binding, formatters, focus, and accessibility instead of only drawing a key grid","breadcrumbs":[{"label":"My Flutter"},{"label":"UI & Media"}]},{"id":"twFPlbi5JMfwEKL2J8tP","title":"Safe QR/Barcode Scanning","pathname":"/flutter/my-flutter/ui-media/qr-barcode-scanner-camera-permission","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"qrcode","description":"Build a Flutter QR/barcode scanner with explicit permissions, serialized camera lifecycle, and a pipeline that treats raw payloads as untrusted input","breadcrumbs":[{"label":"My Flutter"},{"label":"UI & Media"}]},{"id":"Dmrpb9Co8S9XlsOiNBvQ","title":"Rendering Server-Driven HTML Safely in Flutter","pathname":"/flutter/my-flutter/ui-media/safe-server-driven-html-flutter","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"shield-halved","description":"How to design bounded ingress, a policy compiler, and typed intents for rendering server-managed HTML without giving network or navigation authority to the widget","breadcrumbs":[{"label":"My Flutter"},{"label":"UI & Media"}]},{"id":"CTKWji67N7nUi8hjGxHc","title":"Responsive","pathname":"/flutter/my-flutter/ui-media/responsive","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"arrow-up-right-and-arrow-down-left-from-center","description":"Responsive Screen Guide in Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"UI & Media"}]},{"id":"4HPxogOT3HRVQ8Hwj6mG","title":"Multi-Language","pathname":"/flutter/my-flutter/ui-media/multi-language","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"earth-asia","description":"Language Switching in Flutter Without Third-Party Packages","breadcrumbs":[{"label":"My Flutter"},{"label":"UI & Media"}]},{"id":"nTBlb18opkIcuVJhsaxA","title":"Core UI","pathname":"/flutter/my-flutter/ui-media/core-ui","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"transporter","description":"Reusing the UI You Have Built","breadcrumbs":[{"label":"My Flutter"},{"label":"UI & Media"}]},{"id":"e4HRzrOO92UPLIVLJhpL","title":"Security & Observability","pathname":"/flutter/my-flutter/security-observability","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"Protecting identity and data while observing crashes, traces, analytics, configuration, and engagement safely.","breadcrumbs":[{"label":"My Flutter"}]},{"id":"89PR5qCrqkpCHnbR1iiD","title":"Salt","pathname":"/flutter/my-flutter/security-observability/salt","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"salt-shaker","description":"Password Security in Flutter Apps: AES Encryption with Salt and IV","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"Fbl8YWIUovHWvjb7NUlz","title":"Secure Storage: Keychain and Keystore","pathname":"/flutter/my-flutter/security-observability/secure-storage-keychain-keystore","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"key","description":"How I preserve the old state when iOS Keychain is temporarily unavailable and prevent a Secure Storage write from destroying data","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"svjjp8ZWjKE9gh0H7k7o","title":"Biometric Authentication with local_auth","pathname":"/flutter/my-flutter/security-observability/biometric-authentication-local-auth","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"fingerprint","description":"How I use local_auth as a local gate before the real sign-in, make fallback explicit, and keep transient errors from destroying user preferences","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"AJ1ktMh2typpt89CbMu3","title":"Smart OTP/TOTP Architecture in Flutter","pathname":"/flutter/my-flutter/security-observability/smart-otp-totp-flutter-architecture","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"clock","description":"How I separate enrollment, secrets, time sources, and server verification so TOTP in Flutter has clear replay protection and failure paths","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"qCO67hUmb5IbFezVsRGr","title":"Secure Multi-Provider eKYC in Flutter","pathname":"/flutter/my-flutter/security-observability/secure-multi-provider-ekyc-flutter","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"id-card","description":"How I separate camera, QR, MRZ, NFC, consent, liveness, and backend verification into explicit boundaries when integrating multiple eKYC providers in Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"qjE6UMIKIbqVTsDVJlzD","title":"Screenshot Detection and Background Privacy in Flutter","pathname":"/flutter/my-flutter/security-observability/screenshot-background-privacy-flutter","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"shield-halved","description":"How I separated screenshot detection, screen recording, Android capture prevention, and app-switcher privacy into testable Flutter contracts","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"0DLgCNDBcLATtINEcs10","title":"Device Integrity and App Shielding in Flutter","pathname":"/flutter/my-flutter/security-observability/device-integrity-app-shielding-flutter","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"shield-halved","description":"How I separate root and jailbreak signals, app shielding, Play Integrity, App Attest, and backend policy into testable Flutter contracts","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"sV33grRH4smgOszSjwTR","title":"Google and Apple Sign-In in Flutter","pathname":"/flutter/my-flutter/security-observability/google-apple-sign-in-flutter","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"fingerprint","description":"Design a Google and Apple flow where Flutter only receives a provider credential, the backend verifies it, and only then issues an application session","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"gtBrhuggo7Sq8xEiudKW","title":"reCAPTCHA Enterprise Token Lifecycle in Flutter","pathname":"/flutter/my-flutter/security-observability/recaptcha-enterprise-token-lifecycle-flutter","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"shield-halved","description":"How I separate the RecaptchaClient lifecycle, one-shot tokens, submit idempotency, and backend assessment into testable Flutter contracts","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"ATOHUDA9JCzn2wmCbZD9","title":"Sentry for Crashes and Tracing","pathname":"/flutter/my-flutter/security-observability/sentry-flutter-crash-http-navigation-tracing","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"bug","description":"How I assign ownership for Sentry crashes, HTTP, navigation, and transaction tracing while controlling sampling and data in Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"7FxGn5quNwHeyTJDP6IJ","title":"Multi-Provider Analytics in Flutter","pathname":"/flutter/my-flutter/security-observability/multi-provider-analytics-flutter","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"chart-line","description":"How I put Firebase Analytics, Snowplow, and Adjust behind a typed gateway to control events, consent, identity, and delivery evidence in Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"VlHUWEnrJDCc9sRZw2rf","title":"Firebase Remote Config and feature flags","pathname":"/flutter/my-flutter/security-observability/firebase-remote-config-feature-flags","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"sliders","description":"How I turn Firebase Remote Config into a typed snapshot, keep safe fallbacks, and control real-time updates in Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"6qARxZcQKpqR3JK7pxwm","title":"Firebase Performance and Custom Traces","pathname":"/flutter/my-flutter/security-observability/firebase-performance-custom-trace","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"gauge-high","description":"How I design Firebase Performance custom traces per operation while separating readiness, collection, sampling, and runtime evidence in Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"8aTmf7QiEUqTDX5DsiMb","title":"OneSignal Push and iOS NSE","pathname":"/flutter/my-flutter/security-observability/onesignal-push-ios-notification-service-extension","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"bell","description":"How I organize OneSignal around app and user lifecycles, permission handling, click routing, and an iOS Notification Service Extension in Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"zC75RE0JsbPPSkrM6dTB","title":"Quality & Delivery","pathname":"/flutter/my-flutter/quality-delivery","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"Testing, benchmarking, CI/CD, code signing, and release operations for Flutter.","breadcrumbs":[{"label":"My Flutter"}]},{"id":"5gKOCHnCinMIWgGm3uxB","title":"BDD with Flutter Gherkin","pathname":"/flutter/my-flutter/quality-delivery/bdd-flutter-gherkin","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"list-check","description":"How I keep Gherkin feature files while migrating BDD flows from Flutter Driver to integration_test and WidgetTester","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"OXzEEJ7gphdUcYxkfusW","title":"Widget Tests and Golden Regression","pathname":"/flutter/my-flutter/quality-delivery/widget-test-golden-regression","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"image","description":"How I combine widget tests with golden PNGs, stabilize rendering, and review visual regressions without hiding failures behind update-goldens","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"iwqvNcdIuoIMnTEG7T2p","title":"Mock Web Server for Service/API Tests","pathname":"/flutter/my-flutter/quality-delivery/mock-web-server-service-api-test","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"server","description":"How I use a local HTTP server to verify request/response contracts, timeouts, and service error mapping without calling a real backend","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"qU5E39hLv81uKyI3yaOO","title":"Blocking Missing Translations with a Slang i18n Guard in CI","pathname":"/flutter/my-flutter/quality-delivery/slang-i18n-guard-missing-translations-ci","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"language","description":"How I separate the Slang missing report, translator-MR policy, and semantic tests so CI blocks missing keys even when the app falls back to its base locale","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"HtGuGjHl7HTq3EkFWITw","title":"Benchmarking Startup and Scrolling Performance","pathname":"/flutter/my-flutter/quality-delivery/startup-scrolling-performance-benchmark","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"gauge-high","description":"How I separate startup traces, scrolling timelines, and runtime telemetry, then turn artifacts into fail-closed quality gates on real Flutter devices","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"HypOCwTwWXgu1R35it6V","title":"Tracking APK/IPA Size in CI","pathname":"/flutter/my-flutter/quality-delivery/automated-apk-ipa-size-tracking","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"weight-hanging","description":"How I measure exact bytes for release APKs and IPAs, block regressions with budgets, and retain metric artifacts when GitLab CI fails","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"YDwBUEGX4E6DR6Ah10rH","title":"A Safe In-App Network Inspector","pathname":"/flutter/my-flutter/quality-delivery/safe-in-app-network-inspector","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"magnifying-glass-chart","description":"How I gate a network inspector at compile time, preserve HTTP transport, and retain only typed projections with safe memory and TTL limits","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"iXaQgqQ1eqF71OtJywau","title":"GitLab CI for a Flutter Monorepo","pathname":"/flutter/my-flutter/quality-delivery/gitlab-ci-flutter-monorepo","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code-branch","description":"Separate GitLab CI, Makefile, and Melos responsibilities to validate a Flutter monorepo consistently while preserving exit codes and reports on failure","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"AfcP6VFNqQRoYmvOMT1Z","title":"Fastlane iOS, Code Signing, and TestFlight","pathname":"/flutter/my-flutter/quality-delivery/fastlane-ios-code-signing-testflight","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"apple","description":"Separate code signing, IPA building, and TestFlight upload in Fastlane so an iOS pipeline uses the right artifact, fewer privileges, and accurate status reporting","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"ZZRdEyLYqf40AkIrL89T","title":"Sonar Quality Gate for Flutter Monorepo","pathname":"/flutter/my-flutter/quality-delivery/sonar-quality-gate-flutter","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code-branch","description":"Turn Sonar analysis into a required quality gate for a Flutter monorepo using commit-specific LCOV, gate waiting, and GitLab merge policy","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"7IqFqMIX0fRSYR6VedwG","title":"Release Orchestration and Scheduled Go-Live for Android and iOS","pathname":"/flutter/my-flutter/quality-delivery/release-orchestration-scheduled-golive-android-ios","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code-branch","description":"Orchestrate Android and iOS releases with immutable artifacts, protected environments, scheduled gates, and explicit store states","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"Uxl2ZCTTHotwyeBqW6SB","title":"Fastlane - Google Play","pathname":"/flutter/my-flutter/quality-delivery/fastlane-google-play","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code-branch","description":"Build Flutter apps and automatically upload to Google Play with Fastlane (free)","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"g61dHdAGfBEB5glZyihO","title":"Firebase App Distribution (Android)","pathname":"/flutter/my-flutter/quality-delivery/firebase-app-distribution","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"cloud-arrow-up","description":"Upload Flutter Android apps to Firebase App Distribution for manual and automated testing with GitHub Actions","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"KjLigkqSnQPDdKaQBWp3","title":"Pain Points","pathname":"/flutter/my-flutter/pain-points","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"Real-world pain points and methods for defining the problem boundary before changing code.","breadcrumbs":[{"label":"My Flutter"}]},{"id":"4e9GljIu9iyAhYIPgfEq","title":"Web","pathname":"/flutter/my-flutter/pain-points/web","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"browser","description":"Flutter Web Issues: Performance, SEO, and More","breadcrumbs":[{"label":"My Flutter"},{"label":"Pain Points"}]},{"id":"vSH3iVR1srS6t7CyGPBK","title":"My AI","pathname":"/flutter/my-ai/ai","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"sparkles","description":"Building AI products and using AI for coding with explicit contracts, controlled data, and technical evidence.","breadcrumbs":[{"label":"My AI"}]},{"id":"zi4tm6LVsM6BaU4rCDb8","title":"Chat & Realtime","pathname":"/flutter/my-ai/chat-realtime","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"AI Chat connections, subscription ownership, typed events, streaming, and message reconciliation.","breadcrumbs":[{"label":"My AI"}]},{"id":"7R6s56U9inoguDoB0tSU","title":"AI Chat with REST and WebSocket","pathname":"/flutter/my-ai/chat-realtime/ai-chat-rest-websocket","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"comments","description":"How to split session, history, and cancel over REST from RPC and WebSocket publications so an AI Chat has an explicit, recoverable lifecycle","breadcrumbs":[{"label":"My AI"},{"label":"Chat & Realtime"}]},{"id":"DRWEYnrrBuJFYSIjFD0d","title":"Subscription Lifecycle for AI Chat","pathname":"/flutter/my-ai/chat-realtime/subscription-lifecycle-ai-chat","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"arrows-rotate","description":"How to wait for subscription readiness before RPC, share it through consumer leases, and recover AI Chat safely across reconnects","breadcrumbs":[{"label":"My AI"},{"label":"Chat & Realtime"}]},{"id":"vXhILOUHvdTTH9ZxwECb","title":"Typed Events for Realtime AI","pathname":"/flutter/my-ai/chat-realtime/typed-events-realtime-ai","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"brackets-curly","description":"Turn untrusted realtime data into a versioned, validated typed event union with an exhaustive reducer for AI Chat","breadcrumbs":[{"label":"My AI"},{"label":"Chat & Realtime"}]},{"id":"3vIk27COsT29QtdRo7zn","title":"Streaming Reducers for AI Chat","pathname":"/flutter/my-ai/chat-realtime/streaming-reducers-ai-chat","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"arrows-repeat","description":"Design a deterministic AI Chat reducer with per-stream sequences, a bounded reorder buffer, gap recovery, and absorbing terminal states","breadcrumbs":[{"label":"My AI"},{"label":"Chat & Realtime"}]},{"id":"ACI6K7h4cgSOn7Sfse2u","title":"Reconciling Messages in AI Chat","pathname":"/flutter/my-ai/chat-realtime/optimistic-realtime-history-reconciliation","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"arrows-rotate","description":"Design identity, authority, and atomic reconciliation for optimistic UI, realtime streams, and REST history in AI Chat","breadcrumbs":[{"label":"My AI"},{"label":"Chat & Realtime"}]},{"id":"pWx2GoG7GHgtMK03XqFc","title":"Context & Tools","pathname":"/flutter/my-ai/context-tools","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"Prepare context, files, skills, and input; manage resources, agents, and tools within AI products.","breadcrumbs":[{"label":"My AI"}]},{"id":"LqbIVitf6kFkn35ky9n4","title":"Safe Context for AI Chat","pathname":"/flutter/my-ai/context-tools/selection-file-canvas-resource-context","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"shield-halved","description":"Design a trust boundary for selection, file, canvas, and resource context before sending an AI question","breadcrumbs":[{"label":"My AI"},{"label":"Context & Tools"}]},{"id":"x7F49xHmt9bi0KcSUPD5","title":"Safe File Uploads for AI Chat","pathname":"/flutter/my-ai/context-tools/safe-file-upload-ai-chat","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"file-shield","description":"A finite lifecycle design for AI Chat file uploads that separates upload acceptance from terminal readiness and publishes context only after the final CAS","breadcrumbs":[{"label":"My AI"},{"label":"Context & Tools"}]},{"id":"FUgZrDKwtvVv33y4XSBn","title":"Safe Skill Selection for AI Chat","pathname":"/flutter/my-ai/context-tools/safe-skill-selection-ai-chat","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"shield","description":"Separate the display catalog, selection, execution authority, and receipts so AI Chat slash commands cannot cross the authorization boundary","breadcrumbs":[{"label":"My AI"},{"label":"Context & Tools"}]},{"id":"RloXClroX9xnfyxEc0R3","title":"Normalize Input Before Calling AI","pathname":"/flutter/my-ai/context-tools/normalize-input-before-ai","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"filter","description":"Lock the prompt, template, domain value, and attachment context into an immutable typed intent before handing the request to AI","breadcrumbs":[{"label":"My AI"},{"label":"Context & Tools"}]},{"id":"EbpCGe9wLg55hBLPFOgc","title":"Open AI Resources Safely During Autosave","pathname":"/flutter/my-ai/context-tools/open-ai-created-resource-autosave","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"file-shield","description":"Protect the current document when opening an AI-created resource with authority receipts, a save barrier, and latest-intent ownership","breadcrumbs":[{"label":"My AI"},{"label":"Context & Tools"}]},{"id":"rcYniO2QpLRsX72m0AIM","title":"Manage Agents and Skills on the Web","pathname":"/flutter/my-ai/context-tools/agent-skill-web-editor","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"pen-to-square","description":"Design an Agent and Skill editor with finite paths, dirty guards, and async ownership","breadcrumbs":[{"label":"My AI"},{"label":"Context & Tools"}]},{"id":"EU0VW8XGS8BsGonvOf0b","title":"AI Editing","pathname":"/flutter/my-ai/ai-editing","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"Review AI diffs, validate proposals, resolve conflicts, and edit documents or Canvas through explicit contracts.","breadcrumbs":[{"label":"My AI"}]},{"id":"nor9u1RlgmODXEukXAIW","title":"Render AI Diffs Safely in TipTap","pathname":"/flutter/my-ai/ai-editing/tiptap-prosemirror-decoration-ai-diff","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"highlighter","description":"Render AI diffs in TipTap with scoped projections, ProseMirror decorations, and a lifecycle that cannot corrupt the document","breadcrumbs":[{"label":"My AI"},{"label":"AI Editing"}]},{"id":"H3Z3sGxOnddrNhQfp2JU","title":"A Safe State Machine for AI Edits","pathname":"/flutter/my-ai/ai-editing/apply-reject-focus-undo-state-machine","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"arrows-rotate","description":"Coordinate Apply, Reject, Focus, and Undo with a state machine, receipts, CAS, and safe reconciliation","breadcrumbs":[{"label":"My AI"},{"label":"AI Editing"}]},{"id":"Lk6Ov3IIPPMtoealsKol","title":"Safely Rebase AI Suggestions","pathname":"/flutter/my-ai/ai-editing/rebase-ai-suggestions-conflict-detection","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code-merge","description":"Rebase multiple AI text edits with explicit coordinates, exact revisions, a conflict graph, and owned receipts","breadcrumbs":[{"label":"My AI"},{"label":"AI Editing"}]},{"id":"a05FK9nQCLAqn0DMipU1","title":"Stale AI Proposals: Path, Before, and Revision","pathname":"/flutter/my-ai/ai-editing/stale-ai-proposal-path-before-revision","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"shield-halved","description":"Prevent stale AI proposals with capabilities, exact snapshots, validation leases, and backend CAS","breadcrumbs":[{"label":"My AI"},{"label":"AI Editing"}]},{"id":"89wguC6SEQO24zlalSA7","title":"Compile Preview Before Keep","pathname":"/flutter/my-ai/ai-editing/compile-preview-before-keep","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"shield-check","description":"Enable Keep only after bounded compilation, a canonical fixed point, and exact render proof","breadcrumbs":[{"label":"My AI"},{"label":"AI Editing"}]},{"id":"SIBnayjty1fW7zo05B46","title":"Proposal vs. Change Identity in Batches","pathname":"/flutter/my-ai/ai-editing/proposal-change-identity-batches","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"shield-check","description":"Separate proposal, change, and delivery identity for replay-safe AI batches","breadcrumbs":[{"label":"My AI"},{"label":"AI Editing"}]},{"id":"649yMrgMeJWY6Xjl84z8","title":"Versioned Contracts for AI Update, Insert, and Delete Operations","pathname":"/flutter/my-ai/ai-editing/versioned-ai-update-insert-delete-contract","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code-branch","description":"Version update, insert, and delete without turning AI data into edit authority","breadcrumbs":[{"label":"My AI"},{"label":"AI Editing"}]},{"id":"T2wUeEckBpo9TRHZ3KjF","title":"Edit Canvas with Typed AI Commands","pathname":"/flutter/my-ai/ai-editing/typed-canvas-commands-ai-edit","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"shapes","description":"Keep AI commands typed and renderer-neutral while treating Canvas as a projection","breadcrumbs":[{"label":"My AI"},{"label":"AI Editing"}]},{"id":"34ObWpxUTC2XTbX1mya6","title":"Render Citations, Charts, and Follow-up Questions","pathname":"/flutter/my-ai/ai-editing/render-citations-charts-followups","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"","breadcrumbs":[{"label":"My AI"},{"label":"AI Editing"}]},{"id":"IrP8sExQoKhS6Irhblb6","title":"Coding Agents","pathname":"/flutter/my-ai/coding-agents","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"Organize coding-agent rules, context, and skills; choose workflows and work safely in repositories.","breadcrumbs":[{"label":"My AI"}]},{"id":"DxQl1BlRCBWspuagJb4l","title":"Share Rules Across Coding Agents","pathname":"/flutter/my-ai/coding-agents/shared-provider-coding-agent-rules","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"scale-balanced","description":"One finite catalog, multiple adapters, and three separate evidence levels","breadcrumbs":[{"label":"My AI"},{"label":"Coding Agents"}]},{"id":"PlVswaKGzQ58r4RNl9au","title":"Progressive Context Loading","pathname":"/flutter/my-ai/coding-agents/progressive-context-loading-token-optimization","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"layer-group","description":"Reduce context through a finite router without dropping evidence or QA","breadcrumbs":[{"label":"My AI"},{"label":"Coding Agents"}]},{"id":"eMymhKqowbusU1jmo4JX","title":"Save AI Tokens Through Test Structure","pathname":"/flutter/my-ai/coding-agents/test-splitting-ai-token-savings","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"scissors","description":"Split tests by behavior, route context, and read scoped reports to reduce what an AI needs to process while preserving necessary checks.","breadcrumbs":[{"label":"My AI"},{"label":"Coding Agents"}]},{"id":"6tjWdkg8vHjGbThTfclS","title":"Repo-Native Skills as Executable Playbooks","pathname":"/flutter/my-ai/coding-agents/repo-native-skill-engineering-playbook","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"list-check","description":"Turn repository Skills into finite plans with dry-run, approval, and receipts","breadcrumbs":[{"label":"My AI"},{"label":"Coding Agents"}]},{"id":"af0ilxX3Cd3AFXiZGHJG","title":"Guardrails for AI Feature Generation","pathname":"/flutter/my-ai/coding-agents/feature-generator-ai-code-guardrails","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"shield-check","description":"Generate React features safely with dry-run, approval, and atomic apply","breadcrumbs":[{"label":"My AI"},{"label":"Coding Agents"}]},{"id":"rjDoK6ZeaZFbi5h0hnGc","title":"Safe AI in a Dirty Worktree","pathname":"/flutter/my-ai/coding-agents/safe-ai-dirty-worktree","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code-branch","description":"Protect other people's changes while AI works in a dirty worktree","breadcrumbs":[{"label":"My AI"},{"label":"Coding Agents"}]},{"id":"hP2pGOsHE7m8gmgMhli7","title":"Choosing BMAD or a Direct Agent","pathname":"/flutter/my-ai/coding-agents/bmad-vs-direct-agent","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"route","description":"A finite rubric for choosing BMAD or a direct agent and switching safely as evidence changes","breadcrumbs":[{"label":"My AI"},{"label":"Coding Agents"}]},{"id":"W1c9FVBE0HFDttYStnRy","title":"Quality & Safety","pathname":"/flutter/my-ai/quality-safety","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"Distinguish evidence levels, run quality gates, connect diagrams to source, and limit MCP permissions.","breadcrumbs":[{"label":"My AI"}]},{"id":"5OGQojC8CcQGO93R4PFJ","title":"Distinguish Mocks, Scaffolds, and Runtime Evidence","pathname":"/flutter/my-ai/quality-safety/mock-scaffold-configured-runtime-evidence","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"microscope","description":"Separate declarations, scaffolds, configuration, and runtime evidence","breadcrumbs":[{"label":"My AI"},{"label":"Quality & Safety"}]},{"id":"fBdXCt18jyUsQ56foKOV","title":"Quality Gates for AI","pathname":"/flutter/my-ai/quality-safety/focused-tests-full-quality-gate","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"shield-check","description":"Separate focused checks, full gates, and runtime evidence when AI verifies code","breadcrumbs":[{"label":"My AI"},{"label":"Quality & Safety"}]},{"id":"6JyEFY43yE7A3z6romcH","title":"CI/CD for AI-Generated Tests","pathname":"/flutter/my-ai/quality-safety/ci-cd-ai-generated-tests","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"gears","description":"Review the value of tests, reduce repeated pipeline work, and test CI configuration as AI helps generate more code and tests.","breadcrumbs":[{"label":"My AI"},{"label":"Quality & Safety"}]},{"id":"JZvoTsTioQx7ZIkKSVAZ","title":"Flow IDs for Diagrams and Source","pathname":"/flutter/my-ai/quality-safety/flow-diagram-id-source-markers","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"diagram-project","description":"Connect Mermaid diagrams to production code with Flow IDs, source markers, and generation-bound receipts","breadcrumbs":[{"label":"My AI"},{"label":"Quality & Safety"}]},{"id":"G5UPEtV81N0EsrIxOfbT","title":"Least-Privilege MCP","pathname":"/flutter/my-ai/quality-safety/least-privilege-mcp","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"shield-halved","description":"Design MCP with finite capabilities, exact approval, OAuth binding, and safe reconciliation","breadcrumbs":[{"label":"My AI"},{"label":"Quality & Safety"}]},{"id":"gHlzOs3FYXXmBGiE2mUi","title":"My ReactJS","pathname":"/flutter/my-reactjs/reactjs","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"atom","description":"Source-backed ReactJS and Web Engineering lessons rewritten safely for the community.","breadcrumbs":[{"label":"My ReactJS"}]},{"id":"DfMDelVwmoYsO1Fq5VIb","title":"Foundations & Architecture","pathname":"/flutter/my-reactjs/foundations-architecture","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"Pragmatic Clean Architecture, MVVM, dependency injection, repositories, and React feature boundaries.","breadcrumbs":[{"label":"My ReactJS"}]},{"id":"zDcs7CniH8yzWgsyO7Q1","title":"Pragmatic Clean Architecture for React","pathname":"/flutter/my-reactjs/foundations-architecture/pragmatic-clean-architecture-react","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"layer-group","description":"Choose useful dependency boundaries for React features without forcing every small screen through a full set of layers","breadcrumbs":[{"label":"My ReactJS"},{"label":"Foundations & Architecture"}]},{"id":"joYeJO1fX0S8crTm5vg6","title":"Feature-Based MVVM in React","pathname":"/flutter/my-reactjs/foundations-architecture/feature-based-mvvm-react","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"diagram-project","description":"Put Pages, ViewModels, state, and async lifecycles under the right owner in a React feature without creating a God ViewModel","breadcrumbs":[{"label":"My ReactJS"},{"label":"Foundations & Architecture"}]},{"id":"LrgjavHo1kpHOkxaIm6O","title":"Composition Root for React","pathname":"/flutter/my-reactjs/foundations-architecture/composition-root-dependency-injection-react","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"diagram-project","description":"Connect use cases to adapters in a pure composition root, substitute dependencies in tests, and preserve ownership without a DI framework","breadcrumbs":[{"label":"My ReactJS"},{"label":"Foundations & Architecture"}]},{"id":"LNgBPBfhZOCQOHHuhb5F","title":"RTK Query Behind a Repository","pathname":"/flutter/my-reactjs/foundations-architecture/rtk-query-repository-contract","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"database","description":"Keep RTK Query behind a Repository while making cache, request-handle, cancellation, and error ownership explicit","breadcrumbs":[{"label":"My ReactJS"},{"label":"Foundations & Architecture"}]},{"id":"OkQ4YRvDeRtXS3M2lvjE","title":"Map DTOs to Domain Entities","pathname":"/flutter/my-reactjs/foundations-architecture/dto-to-domain-entity-mapper","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"arrows-rotate","description":"Turn unknown payloads into Domain Entities with finite alias, identity, pagination, and error policies","breadcrumbs":[{"label":"My ReactJS"},{"label":"Foundations & Architecture"}]},{"id":"MQ4iNUpLZp5W14SavnKD","title":"Public APIs for React Features","pathname":"/flutter/my-reactjs/foundations-architecture/feature-public-api-react","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Separate a React feature's public entry points from its implementation, check imports by resolved target, and distinguish architecture coupling from runtime cycles.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Foundations & Architecture"}]},{"id":"fXaeOIMpWvSy4B5c96vn","title":"React Features with Nx Generators","pathname":"/flutter/my-reactjs/foundations-architecture/react-feature-generator-nx","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Turn React architecture conventions into Nx templates, then test the generated code before wiring it into the app","breadcrumbs":[{"label":"My ReactJS"},{"label":"Foundations & Architecture"}]},{"id":"OQ3RmuWp3MWSFY5Z6gYO","title":"React Architecture Fitness Tests","pathname":"/flutter/my-reactjs/foundations-architecture/react-architecture-fitness-tests","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"diagram-project","description":"Compare React diagrams, imports, and call paths with counterexample tests so scaffolds and passing UI assertions do not hide unexpected wiring","breadcrumbs":[{"label":"My ReactJS"},{"label":"Foundations & Architecture"}]},{"id":"sIRi1wK9szARphb7mpku","title":"Source-Linked React Diagrams","pathname":"/flutter/my-reactjs/foundations-architecture/source-linked-react-diagrams","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"diagram-project","description":"Link Mermaid to owning functions with markers, test regex limits, and separate React drafts from saved source.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Foundations & Architecture"}]},{"id":"uA8hOCSEFu8CtxEA2ScK","title":"UI & Performance","pathname":"/flutter/my-reactjs/ui-performance","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"React Compiler, lazy loading, lifecycle, forms, design systems, and locale handling for React interfaces.","breadcrumbs":[{"label":"My ReactJS"}]},{"id":"GrGI2Z7O3f5dP3Dh6KhL","title":"React Compiler in Large Applications","pathname":"/flutter/my-reactjs/ui-performance/react-compiler-large-app","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"microchip","description":"Rolling out React Compiler with finite modes, owned opt-outs, artifact proof, and browser profiling","breadcrumbs":[{"label":"My ReactJS"},{"label":"UI & Performance"}]},{"id":"QLuRd9rcwtaDhR6CJDRT","title":"Safe Lazy Routes in React","pathname":"/flutter/my-reactjs/ui-performance/react-lazy-suspense-route-loading","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"route","description":"Design lazy routes with access gates, preload budgets, release recovery, and browser evidence in React","breadcrumbs":[{"label":"My ReactJS"},{"label":"UI & Performance"}]},{"id":"nIHhQVvsURfYtqbAEBuj","title":"Layered Error Boundaries in React","pathname":"/flutter/my-reactjs/ui-performance/layered-react-error-boundaries","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"bug","description":"Design ownership, bounded resets, safe fallbacks, and evidence for layered Error Boundaries in React","breadcrumbs":[{"label":"My ReactJS"},{"label":"UI & Performance"}]},{"id":"Zw7nBTlAXkyzlFqnISJy","title":"Safe Side Effects in Custom Hooks","pathname":"/flutter/my-reactjs/ui-performance/custom-hooks-side-effect-cleanup","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"broom","description":"Design custom hooks with transactional setup, finite cleanup, and stale-work guards in React","breadcrumbs":[{"label":"My ReactJS"},{"label":"UI & Performance"}]},{"id":"HlisQ94xYFr1jbWVYGm3","title":"ResizeObserver Without Layout Thrashing","pathname":"/flutter/my-reactjs/ui-performance/resize-observer-layout-thrashing","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"maximize","description":"Design ResizeObserver with ownership, read-write batching, bounded feedback, and proportionate performance evidence","breadcrumbs":[{"label":"My ReactJS"},{"label":"UI & Performance"}]},{"id":"My7rLyCXA3NLAGmOFWLX","title":"Infinite Scroll with IntersectionObserver","pathname":"/flutter/my-reactjs/ui-performance/intersection-observer-infinite-scroll","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"arrow-down","description":"Designing infinite scroll with ownership, bounded pagination, scroll anchoring, and appropriately scoped evidence","breadcrumbs":[{"label":"My ReactJS"},{"label":"UI & Performance"}]},{"id":"V8fqmgiqXM7xl7vz6Go2","title":"Complex Form Architecture with React Hook Form","pathname":"/flutter/my-reactjs/ui-performance/complex-forms-react-hook-form","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"rectangle-list","description":"Separate form state, domain commands, and request ownership in multi-step React forms with dynamic fields","breadcrumbs":[{"label":"My ReactJS"},{"label":"UI & Performance"}]},{"id":"ZJkTXuxuM2M1i24pHwSY","title":"Building a Design System with Storybook","pathname":"/flutter/my-reactjs/ui-performance/design-system-storybook","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"palette","description":"Build a Design System with package contracts, reproducible stories, and correctly scoped test evidence","breadcrumbs":[{"label":"My ReactJS"},{"label":"UI & Performance"}]},{"id":"Jwr13okqyKxR6v4vSz9I","title":"Synchronized Locale in React","pathname":"/flutter/my-reactjs/ui-performance/react-i18n-locale-data-formatting","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"language","description":"Synchronize locale, catalogs, API caches, formatting, and widgets through one finite stale-safe snapshot","breadcrumbs":[{"label":"My ReactJS"},{"label":"UI & Performance"}]},{"id":"lcHj920TthQWBN8Xa9Yl","title":"State & API","pathname":"/flutter/my-reactjs/state-api","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"State ownership, API caches, RxJS workflows, typed errors, feature flags, ACL, and cross-tab sessions.","breadcrumbs":[{"label":"My ReactJS"}]},{"id":"yArmJoZy8PwPissdZmT9","title":"Async Workflows with Redux-Observable","pathname":"/flutter/my-reactjs/state-api/redux-observable-workflow","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"arrows-rotate","description":"Coordinate bounded React and Redux workflows with exact-scope cancellation, safe retries, and testable teardown","breadcrumbs":[{"label":"My ReactJS"},{"label":"State & API"}]},{"id":"6XgeBIT0inpWNTNUr0jr","title":"Multi-API RTK Query","pathname":"/flutter/my-reactjs/state-api/rtk-query-multi-api","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"diagram-project","description":"Organize multiple RTK Query API slices by cache and transport boundaries, with controlled runtime config, auth recovery, and lifecycle","breadcrumbs":[{"label":"My ReactJS"},{"label":"State & API"}]},{"id":"cfYDAbLapjWitARirQ3b","title":"Choosing a React State Owner","pathname":"/flutter/my-reactjs/state-api/rtk-query-redux-observable-local-state","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"arrows-to-circle","description":"Choose one lifetime-based owner for server cache, workflows, UI drafts, and derived React data","breadcrumbs":[{"label":"My ReactJS"},{"label":"State & API"}]},{"id":"wfTtFwHkwA1Ns0nUEgCh","title":"RxJS Cancellation Boundaries","pathname":"/flutter/my-reactjs/state-api/rxjs-race-takeuntil-cancellation","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"arrows-spin","description":"Separate subscription, signal, and authority to cancel RxJS workflows without killing an Epic or overwriting a newer generation","breadcrumbs":[{"label":"My ReactJS"},{"label":"State & API"}]},{"id":"w5qrR5lPXzTOXK241Swt","title":"Dependency Injection for Redux-Observable","pathname":"/flutter/my-reactjs/state-api/redux-observable-epic-dependency-injection","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"diagram-project","description":"Design finite dependency injection for Redux-Observable Epics with testable readiness, generations, cancellation, and teardown","breadcrumbs":[{"label":"My ReactJS"},{"label":"State & API"}]},{"id":"NIRB2T3Ud4YCtaVlLTX1","title":"Normalize Data Before Redux","pathname":"/flutter/my-reactjs/state-api/normalize-data-before-redux","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"database","description":"Design a finite boundary to decode, identify, and normalize data before writing it to Redux","breadcrumbs":[{"label":"My ReactJS"},{"label":"State & API"}]},{"id":"9D6lkDSDEtVyopQSzjjg","title":"Coordinating a Realtime Cache","pathname":"/flutter/my-reactjs/state-api/realtime-cache-invalidation","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"rotate","description":"Coordinate RTK Query, mutations, and realtime data with finite cache keys, generations, revisions, and refresh ownership","breadcrumbs":[{"label":"My ReactJS"},{"label":"State & API"}]},{"id":"5Cn2kZZmn0kjkPCwj362","title":"Typed Errors from API to UI","pathname":"/flutter/my-reactjs/state-api/typed-errors-api-to-ui","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"triangle-exclamation","description":"Normalize Axios, RTK Query, and Redux Observable errors into a finite taxonomy before they reach state, UI, or telemetry","breadcrumbs":[{"label":"My ReactJS"},{"label":"State & API"}]},{"id":"sp2FuuIwfnqLEGtQt2vg","title":"Safe Feature Flags in React","pathname":"/flutter/my-reactjs/state-api/feature-flags-remote-config","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"sliders","description":"Turn Firebase Remote Config into a typed, atomic snapshot while separating client feature flags from backend authority in React","breadcrumbs":[{"label":"My ReactJS"},{"label":"State & API"}]},{"id":"Lndk9Rss4YpwPLVrcrWf","title":"Route Guards and ACL in React","pathname":"/flutter/my-reactjs/state-api/react-router-route-guard-acl","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"shield-halved","description":"Design a fail-closed Route Guard with finite ACLs, safe return-to, and stale-navigation checks in React","breadcrumbs":[{"label":"My ReactJS"},{"label":"State & API"}]},{"id":"DftixLu3QbbuTNdGa7np","title":"React Sessions Across Tabs","pathname":"/flutter/my-reactjs/state-api/react-sessions-across-tabs","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"shield-halved","description":"Synchronize React sessions across tabs, reject stale responses, and separate local sign-out from server-side session revocation.","breadcrumbs":[{"label":"My ReactJS"},{"label":"State & API"}]},{"id":"OgGAyGgj1vdiiJVBlSX5","title":"Realtime & Charts","pathname":"/flutter/my-reactjs/realtime-charts","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"Web Workers, MQTT, reconnect, backpressure, market data, and chart-renderer lifecycles.","breadcrumbs":[{"label":"My ReactJS"}]},{"id":"qbLmprbMKujJFVaRHqmr","title":"MQTT with Web Workers and RxJS","pathname":"/flutter/my-reactjs/realtime-charts/mqtt-web-worker-rxjs","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"arrows-rotate","description":"How to assign reconnect, subscription, and backpressure ownership when MQTT runs in a Web Worker and RxJS shares data with React","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"8IXrNmz4lPlobCk8kpCz","title":"Client-Server Time Sync","pathname":"/flutter/my-reactjs/realtime-charts/client-server-time-sync","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"clock","description":"Synchronize client and server time with monotonic RTT, uncertainty intervals, and a bounded lifecycle instead of trusting an absolute offset","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"wCGFItlbTAHCfbPBTQ3d","title":"Realtime Tables in React","pathname":"/flutter/my-reactjs/realtime-charts/realtime-table-react","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"table-list","description":"Design realtime tables with virtualization, frame coalescing, row-scoped updates, and bounded performance evidence","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"0sI7kZFhnzIA50GPJJdg","title":"State Machine for MQTT Subscriptions","pathname":"/flutter/my-reactjs/realtime-charts/mqtt-subscription-state-machine","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"diagram-project","description":"Design MQTT subscriptions in React with owners, epochs, ACK correlation, and finite recovery","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"TD95Kyl8M0FfymSfwDLF","title":"Backpressure for Realtime Data","pathname":"/flutter/my-reactjs/realtime-charts/realtime-batching-dedup-backpressure","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"gauge-high","description":"Design finite batching, deduplication, and overload policies for RxJS, MQTT, and realtime streams without confusing time windows with backpressure","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"r9VMaUPXwlvtSbf6uxT3","title":"Reconnect and Subscription Recovery","pathname":"/flutter/my-reactjs/realtime-charts/mqtt-reconnect-subscription-recovery","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Separate reconnect, subscription restoration and data readiness; control late completions, retries and cleanup in a React application using MQTT.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"y0psDUSRZqiQCenkMUPJ","title":"Measuring WebSocket and MQTT Latency","pathname":"/flutter/my-reactjs/realtime-charts/websocket-mqtt-latency","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"gauge-high","description":"Separate data age, RTT, and processing time; design realtime measurements with explicit limits, ownership, and evidence","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"xerx466etQetG9ufov9h","title":"Merging Historical OHLC with Live Ticks","pathname":"/flutter/my-reactjs/realtime-charts/ohlc-live-ticks","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"chart-line","description":"Connect historical OHLC with matched-trade ticks or provider bars without mixing authority, time, or volume semantics","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"Vz3nyXdbFKCyJAYTUWvg","title":"Choosing a Fallback Datafeed","pathname":"/flutter/my-reactjs/realtime-charts/choosing-fallback-datafeed","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Separate HTTP probes, saved preferences, and datafeeds that are actually ready; make bounded fallback choices without switching feeds based on a single latency number.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"owAK8zIv9BDwSDq6lXhe","title":"Chart Listener Lifecycle","pathname":"/flutter/my-reactjs/realtime-charts/chart-listener-lifecycle","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"chart-line","description":"From a project's listener pool to a per-chart adapter with explicit ownership for overlap, late callbacks, and cleanup.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"oFvF4xGokYfNiM1V1yOQ","title":"Chart Adapters and Domain Ports","pathname":"/flutter/my-reactjs/realtime-charts/chart-adapter-domain-ports","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"chart-line","description":"Separate history providers from the chart SDK with a domain port, explicit data mapping, and owned callbacks and cleanup.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"iH1UnwSaL4mtPhVzBeaT","title":"Saving and Restoring Chart Layouts","pathname":"/flutter/my-reactjs/realtime-charts/saving-restoring-chart-layouts","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"chart-line","description":"Manage sessions, snapshots, and save acknowledgements so stale operations cannot overwrite chart layouts.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"svZSsGBvD8vmJB2FtlFG","title":"Chart Contracts and Renderer Adapters","pathname":"/flutter/my-reactjs/realtime-charts/chart-contracts-renderer-adapters","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"chart-line","description":"Preserve data meaning across ECharts Canvas and React SVG with a shared chart model, validation, and explicit renderer lifecycle.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"3AmUjbG84ZNR89cHWxl9","title":"Testing & Quality","pathname":"/flutter/my-reactjs/testing-quality","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"BDD, Playwright, mocks, RxJS tests, lifecycle checks, accessibility, and browser APIs.","breadcrumbs":[{"label":"My ReactJS"}]},{"id":"DKdzJyIqduiZeXQt8Vq4","title":"Keeping Gherkin and Playwright in Sync","pathname":"/flutter/my-reactjs/testing-quality/gherkin-playwright-sync","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"list-check","description":"Designing stable identity, two-way reconciliation, and a CI gate so a Gherkin catalog cannot silently drift from Playwright","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"ECNNCsZlKoBTG0Dsc7Zu","title":"Testing Browser Permissions in React","pathname":"/flutter/my-reactjs/testing-quality/testing-browser-permissions-react","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"lock","description":"Separate permission state, browser capability, prompts, and resource ownership to test React at the right level","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"D6ZEAhhdmL4CKvOS2lim","title":"Visual Regression Testing with Chromatic","pathname":"/flutter/my-reactjs/testing-quality/visual-regression-chromatic","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"eye","description":"Design finite, reproducible visual regression with explicit authority in Storybook and Chromatic","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"T1w6d56pozfOM38eMhSm","title":"Marble Testing for RxJS Workflows","pathname":"/flutter/my-reactjs/testing-quality/rxjs-marble-testing","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"wave-square","description":"Design a finite TestScheduler harness that verifies values, completion, and subscription lifecycle in RxJS workflows","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"dQtAIjRnGqptXlsOoJeR","title":"Checking Test Contracts with ASTs","pathname":"/flutter/my-reactjs/testing-quality/test-contracts-typescript-ast","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Compare Features, Scenarios, and steps with TypeScript ASTs without confusing a name match with a test that ran and passed","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"GLDSCdmill7xY9IJGue9","title":"Safer Playwright Skeleton Generation","pathname":"/flutter/my-reactjs/testing-quality/playwright-scenario-outline-skeleton","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Generate Playwright skeletons from Scenario Outlines with explicit parameter binding, code ownership, and quality gates","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"BTGrldCHQllY1Uhgy7y5","title":"Stateful API Mocks in Playwright","pathname":"/flutter/my-reactjs/testing-quality/stateful-api-mocks-playwright","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Organize Playwright mocks by service, isolate state per test, and verify mutations, responses, and route lifecycles","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"8nPWNTKJ1BYYG7yqNNZP","title":"Mocking Realtime with Web Workers","pathname":"/flutter/my-reactjs/testing-quality/realtime-worker-mocks-playwright","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Test realtime behavior in Playwright at the Worker boundary, with owned readiness, subscriptions, control ACKs, and cleanup.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"ThAAslciwdrkIo52wpd0","title":"Missing vs. Incomplete BDD Scenarios","pathname":"/flutter/my-reactjs/testing-quality/missing-incomplete-bdd-scenarios","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Separate scenarios without tests, tests with incomplete contracts, and execution results so a quality gate does not pass on the wrong evidence","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"pzWzVKfaTY4Xsa0B6dMz","title":"Stable Realtime UI Tests","pathname":"/flutter/my-reactjs/testing-quality/stable-realtime-ui-tests","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Wait for the right data and lifecycle phase in realtime tests with owned locators, render signals, and a safe persistence probe.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"oYcolgk4CXPcDtEn4VY5","title":"Testing React Cleanup","pathname":"/flutter/my-reactjs/testing-quality/testing-react-cleanup","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Test listeners, observers, and subscriptions with exact resource ownership, positive controls, and post-cleanup stimuli; distinguish local release from task or connection cancellation.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"l4WehJkgpoD0bX6ktHu7","title":"Accessibility Testing in React","pathname":"/flutter/my-reactjs/testing-quality/accessibility-testing-react","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Move from click tests to roles, accessible names and portal scans while preserving jest-axe limits, keyboard checks and the need for manual review.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"8Svdp8aUIK7ZQCNv4v2P","title":"Testing Browser APIs in JSDOM","pathname":"/flutter/my-reactjs/testing-quality/testing-browser-apis-jsdom","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"From permission queries to scrolling and storage, build controlled fakes and know when evidence from a real browser is required.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"NQlA9hpQriAPeK8D5Opr","title":"Platform & Delivery","pathname":"/flutter/my-reactjs/platform-delivery","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"Runtime configuration, Nx packages, build caches, bundles, versioning, and frontend deployment.","breadcrumbs":[{"label":"My ReactJS"}]},{"id":"S04ykyOf2qgBcmZ0Hik1","title":"Runtime Config for Vite","pathname":"/flutter/my-reactjs/platform-delivery/runtime-config-vite","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"sliders","description":"How to separate public runtime config from the Vite bundle to build once and deploy to multiple environments with explicit schema, bootstrap, and cache policies","breadcrumbs":[{"label":"My ReactJS"},{"label":"Platform & Delivery"}]},{"id":"znS807ed61w66WRjGzsd","title":"Runtime Config Startup Gate","pathname":"/flutter/my-reactjs/platform-delivery/runtime-config-startup-gate","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Separate validation from the application graph, verify import ordering, and give late startup work an explicit owner.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Platform & Delivery"}]},{"id":"ECdYUAeUmc40GsgF5CKT","title":"Browser Config Is Public","pathname":"/flutter/my-reactjs/platform-delivery/browser-config-is-public","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Select explicitly public fields and check build artifacts instead of treating runtime env as a credential store.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Platform & Delivery"}]},{"id":"jweTAcZBnt1usWoVhxih","title":"Package Boundaries in Nx","pathname":"/flutter/my-reactjs/platform-delivery/nx-package-boundaries","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Assign roles, verify graph producers, and turn apps/core/services/ui/utils boundaries into a tested gate instead of folder names.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Platform & Delivery"}]},{"id":"YGQOOGmTwaaDWSeuiyB7","title":"Affected Builds and Nx Cache","pathname":"/flutter/my-reactjs/platform-delivery/nx-affected-build-cache","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Separate affected selection, computation inputs, output restoration, and cache write access using a real Nx workspace.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Platform & Delivery"}]},{"id":"rAEeQ7D5J48XYzRf5UIc","title":"Package Versioning with Changesets","pathname":"/flutter/my-reactjs/platform-delivery/changesets-package-versioning","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Separate release intent, version/changelog edits, and published artifacts with Changesets, checking package scope and partial writes.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Platform & Delivery"}]},{"id":"vldagbaXHXUMH4WyFDtT","title":"Vite Chunks and Bundle Analysis","pathname":"/flutter/my-reactjs/platform-delivery/vite-chunks-bundle-analysis","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Verify manual chunking with dependency graphs, emitted bytes and browser runtime checks, while respecting the limits of bundle visualizers.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Platform & Delivery"}]},{"id":"kILl5Daq88tIXfHJupu2","title":"Loading Libraries on Demand","pathname":"/flutter/my-reactjs/platform-delivery/on-demand-library-loading","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Separate chart, analytics, and realtime loading from instance lifetimes, with demand gates, cleanup, and browser verification.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Platform & Delivery"}]},{"id":"AOXJf5Ea4idA0nZ1Io74","title":"Production Source Maps","pathname":"/flutter/my-reactjs/platform-delivery/source-maps-production","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Keep source maps matched to their artifacts while separating public output from maps and verifying build, upload, and origin boundaries.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Platform & Delivery"}]},{"id":"N89yMLJ1PTCnddfdnwol","title":"Traceable Build Metadata","pathname":"/flutter/my-reactjs/platform-delivery/traceable-build-metadata","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Separate versions, commits, and build IDs to trace the right artifact, minimize public metadata, and verify Git, HTML, and browser boundaries.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Platform & Delivery"}]},{"id":"dcETSMvPdfcmDx36r59g","title":"Static Deployment and Caching","pathname":"/flutter/my-reactjs/platform-delivery/static-deployment-caching","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Separate asset base, runtime config, and cache policy to deploy a new release while keeping lazy chunks available to old tabs.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Platform & Delivery"}]},{"id":"1ZKIsTDgHvYk3Ssqg9IZ","title":"Financial JavaScript","pathname":"/flutter/my-reactjs/financial-javascript","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"Precision, units, and rounding; idempotency, duplicate-submit prevention, and expiry.","breadcrumbs":[{"label":"My ReactJS"}]},{"id":"gyS9EpAfESQiMbtoA84t","title":"Precise Financial Math in TypeScript","pathname":"/flutter/my-reactjs/financial-javascript/precise-financial-math-typescript","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"calculator","description":"Design decimal boundaries with units, scales, rounding policies, and exact wire contracts for TypeScript applications","breadcrumbs":[{"label":"My ReactJS"},{"label":"Financial JavaScript"}]},{"id":"1L3meBmxIOBQsSIDLTEi","title":"Money and Rate Unit Boundaries","pathname":"/flutter/my-reactjs/financial-javascript/money-rate-unit-boundaries","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"Keep money, price, and rate units consistent from APIs through React forms to requests, using typed adapters and runtime checks.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Financial JavaScript"}]},{"id":"3PjbJRWrOtwOVLr7LBnQ","title":"Rounding at the Right Boundary","pathname":"/flutter/my-reactjs/financial-javascript/rounding-truncation-boundaries","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"Choose the rounding stage, mode, and owner explicitly; separate previews from request values in a React application.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Financial JavaScript"}]},{"id":"l2ihKmxhMRoaBYBI1p3A","title":"Request IDs and Idempotency","pathname":"/flutter/my-reactjs/financial-javascript/request-id-idempotency","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"Separate operation identity from individual request attempts, preserve intent across retries, and handle uncertain outcomes without assuming the server has not committed.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Financial JavaScript"}]},{"id":"kGqWUB4L3WUVssZwlkp5","title":"Preventing Double Submits in React","pathname":"/flutter/my-reactjs/financial-javascript/prevent-double-submit-react","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"Hold one submission admission across validation, confirmation, and the request; separate React loading state from operation ownership.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Financial JavaScript"}]},{"id":"VXAZcIUi5HHJ3JoSp4qX","title":"Countdowns and Expiry in React","pathname":"/flutter/my-reactjs/financial-javascript/countdown-expiry-react","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"clock","description":"Bind a countdown to the right deadline and clock reading, distinguish uncertainty from expiry, and verify lifecycle behavior with real React","breadcrumbs":[{"label":"My ReactJS"},{"label":"Financial JavaScript"}]},{"id":"u5NOuistnGiLtCnHkJQ7","title":"Precise Number Display in React","pathname":"/flutter/my-reactjs/financial-javascript/precise-number-display-react","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Preserve exact decimals through React text, distinguish zero from unavailable, and switch locale without changing the underlying data.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Financial JavaScript"}]},{"id":"drr5s3HI7t6Bf7EUdzIT","title":"Editors & Canvas","pathname":"/flutter/my-reactjs/editors-canvas","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"Markdown, TipTap, canonical sources, Canvas compilers, print layouts, and editing history.","breadcrumbs":[{"label":"My ReactJS"}]},{"id":"mmaPV8C3hlNNqLwJkqB1","title":"Canonical Markdown with TipTap","pathname":"/flutter/my-reactjs/editors-canvas/canonical-markdown-tiptap","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"file-code","description":"Keep application-owned Markdown as the content format, synchronize TipTap deliberately, and avoid saving a conversion that has already lost meaning.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Editors & Canvas"}]},{"id":"Gox30vMB7ACNdhqwU1F6","title":"Synchronizing Editor Modes","pathname":"/flutter/my-reactjs/editors-canvas/synchronizing-editor-modes","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Keep one Markdown draft across Source, Rich Editor and Preview; reject stale intents, late callbacks and mode changes before editor readiness.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Editors & Canvas"}]},{"id":"Q97L8BReHyDKALG2j1ZM","title":"Markdown–TipTap Round Trips","pathname":"/flutter/my-reactjs/editors-canvas/markdown-tiptap-semantic-roundtrip","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"file-code","description":"Test Markdown round trips with authored semantic expectations, real schemas and negative cases; distinguish visible text or stable output from preserved content.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Editors & Canvas"}]},{"id":"BTqn7x7gq4l0khRj8MXZ","title":"One TipTap Tree and History","pathname":"/flutter/my-reactjs/editors-canvas/single-tiptap-tree-history","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"file-code","description":"Use one TipTap document across multiple regions, separate history events, and define a session boundary for external document replacements.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Editors & Canvas"}]},{"id":"B184vOwWMRVggit19A2Y","title":"A4 as a Derived Print View","pathname":"/flutter/my-reactjs/editors-canvas/derived-a4-print-view","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"Keep one editable TipTap tree, build a bounded print view and verify A4 PDFs without writing page artifacts into the document.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Editors & Canvas"}]},{"id":"DA6iHzqeoDw22Db3MKk0","title":"Canonical Source and Fabric Snapshots","pathname":"/flutter/my-reactjs/editors-canvas/canonical-source-fabric-snapshot","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Separate canonical Markdown/YAML from Fabric snapshots and choose cache and restore rules that keep an old projection from becoming a new source of truth.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Editors & Canvas"}]},{"id":"QLZXJhhbMyXkm5XqGuoF","title":"Bidirectional Compilers for Canvas","pathname":"/flutter/my-reactjs/editors-canvas/bidirectional-canvas-compiler","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Use lessons from a React Markdown–Canvas compiler to define a capability profile, check semantic round trips, and reject lossy edits before committing.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Editors & Canvas"}]},{"id":"N88d8twDLeFz9BWP6XeM","title":"Composite Sources with Stable IDs","pathname":"/flutter/my-reactjs/editors-canvas/composite-source-stable-object-id","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Split design.json and content.md, join them by stable object ID, and check ownership, revisions, and composite-source boundaries.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Editors & Canvas"}]},{"id":"OIgTST54SGKum6HX1PFn","title":"Editor Commands and History","pathname":"/flutter/my-reactjs/editors-canvas/editor-commands-history","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Separate commands, transactions, and Undo/Redo from the renderer; check history capacity, generation, and model-commit limits during asynchronous Canvas hydration.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Editors & Canvas"}]},{"id":"M1eUyBppdTMrT4eU17y6","title":"Files & Documents","pathname":"/flutter/my-reactjs/files-documents","siteSpaceId":"sitesp_0rtZe","lang":"en","description":"File reading and export, citations, autosave, block error isolation, and File Explorer workflows.","breadcrumbs":[{"label":"My ReactJS"}]},{"id":"HV5AMocG3dD2Ic6vZ9fr","title":"Large File Exports in the Browser","pathname":"/flutter/my-reactjs/files-documents/large-file-exports-browser","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Validate responses before downloading, bound the payload retained by the client, and manage download-link lifetimes in React.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Files & Documents"}]},{"id":"v7EfhK6tnv3VF428fDRb","title":"Exporting Documents from Snapshots","pathname":"/flutter/my-reactjs/files-documents/document-snapshot-exports","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Capture a snapshot, separate PDF/DOCX/PNG capabilities, and own the export job; check bytes, late results, and the limits of download requests.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Files & Documents"}]},{"id":"PHuQLzEakvXVKk39GJ6o","title":"Reading Files with HTTP Range","pathname":"/flutter/my-reactjs/files-documents/reading-files-http-range","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"file-code","description":"From a file preview with Range disabled to a reader that checks ETag, Content-Range, and UTF-8 before publishing complete content to the right React lifecycle.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Files & Documents"}]},{"id":"mRm6CtiNDUgKOABFdqDq","title":"Citations for Markdown and PDF","pathname":"/flutter/my-reactjs/files-documents/markdown-pdf-citation-contract","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"file-code","description":"Separate locators from file types, bind citations to the right artifact, and show the actual precision of Markdown or PDF in React.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Files & Documents"}]},{"id":"PYjaJAkqmJRLeHdsSbF3","title":"Autosave Across Document Switches","pathname":"/flutter/my-reactjs/files-documents/autosave-document-switches","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"file-code","description":"Preserve the current draft through autosave, check the exact snapshot before switching documents, and distinguish saved writes from unknown outcomes.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Files & Documents"}]},{"id":"sCD4HKysFPIw5KErD6SE","title":"Isolating Block Errors","pathname":"/flutter/my-reactjs/files-documents/isolating-block-errors","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"code","description":"Preserve broken blocks for repair, protect document structure, and allow export only when the snapshot is genuinely complete.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Files & Documents"}]},{"id":"CtkWfxr3ganuV6omoXCx","title":"File Explorer Without Stale Results","pathname":"/flutter/my-reactjs/files-documents/file-explorer-upload-pagination","siteSpaceId":"sitesp_0rtZe","lang":"en","icon":"folder-open","description":"Preserve upload destinations, merge pages within their context, and reject stale responses when users switch React folders.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Files & Documents"}]},{"id":"iyowa0ioX6DQ7pJNsmJk","title":"My Dev","pathname":"/flutter/tieng-viet","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"hand-wave","description":"My Dev — nơi chia sẻ kinh nghiệm thực chiến về Flutter, AI và ReactJS."},{"id":"Q96eOad1XMVzC6p2eWG2","title":"My Flutter","pathname":"/flutter/tieng-viet/my-flutter/flutter","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"mobile-screen","description":"Kinh nghiệm Flutter thực chiến về kiến trúc, realtime, bảo mật, chất lượng và vận hành ứng dụng production.","breadcrumbs":[{"label":"My Flutter"}]},{"id":"OoFjBdYbjzVwFVYD2fD4","title":"Foundations & Clean Code","pathname":"/flutter/tieng-viet/my-flutter/foundations","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"Công cụ, thói quen và nền tảng Dart giúp viết Flutter nhanh hơn nhưng vẫn dễ bảo trì.","breadcrumbs":[{"label":"My Flutter"}]},{"id":"LhBkNdlWs4s7vwxPy41d","title":"Tip Code Faster","pathname":"/flutter/tieng-viet/my-flutter/foundations/tip-code-faster","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"comet","description":"","breadcrumbs":[{"label":"My Flutter"},{"label":"Foundations & Clean Code"}]},{"id":"MqMetTVBVJZv2ziVK6cV","title":"FVM","pathname":"/flutter/tieng-viet/my-flutter/foundations/fvm","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code-branch","description":"Cố định phiên bản Flutter cho nhóm của bạn với FVM","breadcrumbs":[{"label":"My Flutter"},{"label":"Foundations & Clean Code"}]},{"id":"avWBt8m7YYWaWKzP4m63","title":"Make","pathname":"/flutter/tieng-viet/my-flutter/foundations/make","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"terminal","description":"Sử dụng Make để chạy nhiều lệnh Flutter chỉ bằng một lệnh ngắn","breadcrumbs":[{"label":"My Flutter"},{"label":"Foundations & Clean Code"}]},{"id":"BZxU0uMvFSnvb7iIlAoE","title":"Easy Maintain","pathname":"/flutter/tieng-viet/my-flutter/foundations/easy-maintain","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"person-digging","description":"Giảm khối lượng công việc bảo trì và duy trì","breadcrumbs":[{"label":"My Flutter"},{"label":"Foundations & Clean Code"}]},{"id":"5srjGksGo7VZhxUHoUsm","title":"Mason","pathname":"/flutter/tieng-viet/my-flutter/foundations/mason","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"explosion","description":"Code Flutter Nhanh hơn với Mason","breadcrumbs":[{"label":"My Flutter"},{"label":"Foundations & Clean Code"}]},{"id":"SPxjpFiWNKo8chmOREFO","title":"Log Color","pathname":"/flutter/tieng-viet/my-flutter/foundations/log-color","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"palette","description":"Thiết lập log màu và lưu log vào bộ nhớ thiết bị","breadcrumbs":[{"label":"My Flutter"},{"label":"Foundations & Clean Code"}]},{"id":"oKAXzhhYQ5NBc4OxQbOm","title":"Activity Diagram","pathname":"/flutter/tieng-viet/my-flutter/foundations/activity-diagram","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"head-side-brain","description":"","breadcrumbs":[{"label":"My Flutter"},{"label":"Foundations & Clean Code"}]},{"id":"MtOV7xbzk1axacaQHCe3","title":"Clean code","pathname":"/flutter/tieng-viet/my-flutter/foundations/clean-code","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"broom-wide","description":"Các phương pháp tốt nhất để viết Clean Code rõ ràng, dễ hiểu khi phát triển Flutter theo team","breadcrumbs":[{"label":"My Flutter"},{"label":"Foundations & Clean Code"}]},{"id":"h9feLtxoklHc7Bheuw0C","title":"Coverage","pathname":"/flutter/tieng-viet/my-flutter/foundations/coverage-codecov","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"chart-simple","description":"Tải test coverage Flutter lên Codecov và hiển thị huy hiệu trong README","breadcrumbs":[{"label":"My Flutter"},{"label":"Foundations & Clean Code"}]},{"id":"wuuXszd3izJ4iT3WXfmn","title":"Git hook","pathname":"/flutter/tieng-viet/my-flutter/foundations/git-hook","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code-branch","description":"Chạy lệnh tự động khi sử dụng lệnh Git","breadcrumbs":[{"label":"My Flutter"},{"label":"Foundations & Clean Code"}]},{"id":"AMfIbARKhAU4zoW94NWZ","title":"Enum","pathname":"/flutter/tieng-viet/my-flutter/foundations/enum","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"spider-web","description":"Sức mạnh của Enums trong việc đơn giản hóa Code","breadcrumbs":[{"label":"My Flutter"},{"label":"Foundations & Clean Code"}]},{"id":"VQ7FElIMkFxEi0BkBgb7","title":"Architecture & State","pathname":"/flutter/tieng-viet/my-flutter/architecture-state","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"Kiến trúc ứng dụng, package boundary, migration và state management cho Flutter ở quy mô lớn.","breadcrumbs":[{"label":"My Flutter"}]},{"id":"Ljda9TIhyoWyAOkfPEp7","title":"Plugin","pathname":"/flutter/tieng-viet/my-flutter/architecture-state/plugin","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"puzzle-piece-simple","description":"Plugin: Giao tiếp với code native để bảo trì app Flutter hiệu quả","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"ViSS9f3QYjTsiffTL9D0","title":"Flutter Clean Architecture","pathname":"/flutter/tieng-viet/my-flutter/architecture-state/flutter-clean-architecture","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"ram","description":"Dễ dàng bảo trì và mở rộng code Flutter với Clean Architecture","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"XvPIjyKnRoIX3EqGtWPM","title":"Base Project","pathname":"/flutter/tieng-viet/my-flutter/architecture-state/base-project","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"atom","description":"Tạo một Base Project trong Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"laKGZvIGOclFqBLPK7Wp","title":"Flavor","pathname":"/flutter/tieng-viet/my-flutter/architecture-state/flavor","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"sliders","description":"Thiết lập 3 môi trường (dev, staging, production) cho mobile trong Flutter (3 apps riêng biệt)","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"gmpXWgFdCeCNoXvjUBFD","title":"Package","pathname":"/flutter/tieng-viet/my-flutter/architecture-state/package","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"arrows-to-circle","description":"Package - Lưu trữ code tốt nhất cho bạn Dự án","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"XsK6Wu3b5bUHseUvSGIi","title":"Dart Workspace và Melos","pathname":"/flutter/tieng-viet/my-flutter/architecture-state/dart-workspace-melos","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"boxes-stacked","description":"Dùng Dart Workspace để thống nhất dependency và Melos để điều phối command trong Flutter monorepo","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"oDLVcKklQYxUTUKkGqA5","title":"Context Anywhere","pathname":"/flutter/tieng-viet/my-flutter/architecture-state/context-anywhere","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"message-middle","description":"Hướng dẫn thiết lập và truy cập BuildContext mọi nơi trong dự án Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"7AmPwNg3DjB3TqNy4DLs","title":"Bloc","pathname":"/flutter/tieng-viet/my-flutter/architecture-state/bloc","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"rectangles-mixed","description":"","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"MaZr4HNaUI1zBiJrZ14x","title":"ChangeNotifier","pathname":"/flutter/tieng-viet/my-flutter/architecture-state/changenotifier","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"light-ceiling","description":"Kiểm soát Widget bằng ChangeNotifier","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"wBMCVgywK0KHFY2xfIAm","title":"Redux/Flutter Redux ở quy mô lớn","pathname":"/flutter/tieng-viet/my-flutter/architecture-state/redux-flutter-redux-large-app","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"diagram-project","description":"Tổ chức Redux và Flutter Redux theo feature để global store vẫn dễ kiểm soát khi ứng dụng phát triển lớn","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"tTdynMtjfRKxROJ4K1AG","title":"Redux Epics và RxDart","pathname":"/flutter/tieng-viet/my-flutter/architecture-state/redux-epics-rxdart","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"wave-square","description":"Chọn đúng concurrency strategy trong Redux Epics để tránh request trùng và kết quả cũ ghi đè state","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"rO93qeGao1iVYvPPIdFo","title":"Redux Persist và State Migration","pathname":"/flutter/tieng-viet/my-flutter/architecture-state/redux-persist-state-migration","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"database","description":"Cách tôi giới hạn Redux state được lưu, migrate schema theo version và ngừng persist khi storage chưa load thành công","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"ItHwDvIalV97txBXh1Mo","title":"Migrate Fish Redux từng phần","pathname":"/flutter/tieng-viet/my-flutter/architecture-state/incremental-fish-redux-migration","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"arrows-rotate","description":"Cách tôi migrate từng màn hình Fish Redux sang Flutter Redux mà vẫn giữ nguyên route, arguments, deep link và back stack","breadcrumbs":[{"label":"My Flutter"},{"label":"Architecture & State"}]},{"id":"EKjSIsn13aZzsa9bA6fr","title":"Systems & Realtime","pathname":"/flutter/tieng-viet/my-flutter/systems-realtime","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"API, networking, realtime, lifecycle và navigation boundary trong ứng dụng Flutter production.","breadcrumbs":[{"label":"My Flutter"}]},{"id":"T29uurcgn1sW9NojEYEk","title":"MQTT và App Lifecycle","pathname":"/flutter/tieng-viet/my-flutter/systems-realtime/mqtt-realtime-app-lifecycle","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"tower-broadcast","description":"Cách tôi tổ chức hệ thống MQTT khi app vào background, giữ subscription và khôi phục dữ liệu lúc quay lại foreground","breadcrumbs":[{"label":"My Flutter"},{"label":"Systems & Realtime"}]},{"id":"al6etpooHDUTLTE7zeDp","title":"Realtime typed với protobuf và Nakama","pathname":"/flutter/tieng-viet/my-flutter/systems-realtime/nakama-protobuf-market-realtime","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Cách tôi dùng topic làm schema contract, tách state khỏi event và giữ Nakama ngoài market gateway để dữ liệu realtime luôn typed","breadcrumbs":[{"label":"My Flutter"},{"label":"Systems & Realtime"}]},{"id":"d9l7wPJ4TkKvRHy4S1aK","title":"Tổng hợp dữ liệu realtime bằng reactive streams","pathname":"/flutter/tieng-viet/my-flutter/systems-realtime/reactive-realtime-aggregation-flutter","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"chart-network","description":"Thiết kế derived realtime state có typed adapter, freshness gate, snapshot bất biến và lifecycle kiểm thử được trong Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"Systems & Realtime"}]},{"id":"l9rqwu4slPzQEjKfLdAN","title":"HTTP Client cho Flutter production","pathname":"/flutter/tieng-viet/my-flutter/systems-realtime/production-http-client","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"network-wired","description":"Cách tôi gắn lỗi 401 với auth context của request để response cũ không đăng xuất phiên mới, đồng thời chuẩn hóa JWT và HTTP failure","breadcrumbs":[{"label":"My Flutter"},{"label":"Systems & Realtime"}]},{"id":"ao8f2IqUYHv1VfnnYORk","title":"Connectivity và lỗi mạng trong Flutter","pathname":"/flutter/tieng-viet/my-flutter/systems-realtime/connectivity-offline-ux-vpn","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"wifi","description":"Cách tôi tách transport, Internet reachability, timeout, service error, captive portal và VPN để offline UX không thông báo sai nguyên nhân","breadcrumbs":[{"label":"My Flutter"},{"label":"Systems & Realtime"}]},{"id":"SW8m6ByfCovHdO1n2nuq","title":"Deep link đa nguồn trong Flutter","pathname":"/flutter/tieng-viet/my-flutter/systems-realtime/deep-link-app-links-adjust-onesignal","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"link","description":"Cách tôi đưa App Links, Adjust và OneSignal qua một typed pipeline để validate, chống điều hướng trùng và chờ app sẵn sàng","breadcrumbs":[{"label":"My Flutter"},{"label":"Systems & Realtime"}]},{"id":"gwmk60RgreVLuxxyw69e","title":"UI & Media","pathname":"/flutter/tieng-viet/my-flutter/ui-media","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"UI, WebView, chart, camera, media và nội dung server-driven trong Flutter.","breadcrumbs":[{"label":"My Flutter"}]},{"id":"7u99hvMKoyFLBI1NWET3","title":"FFmpeg Flutter","pathname":"/flutter/tieng-viet/my-flutter/ui-media/ffmpeg-flutter","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"monero","description":"Xử lý video bằng FFmpeg trong Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"UI & Media"}]},{"id":"0G8nJDxjMcELKbaMEVvU","title":"Tài liệu và attachment an toàn","pathname":"/flutter/tieng-viet/my-flutter/ui-media/secure-documents-attachments-flutter","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"file-shield","description":"Cách tôi đưa picker, download, export và media qua một policy chung trước khi preview, upload, lưu, mở hoặc chia sẻ","breadcrumbs":[{"label":"My Flutter"},{"label":"UI & Media"}]},{"id":"rSDmu6kQxU406E0dOxiC","title":"Dark Mode","pathname":"/flutter/tieng-viet/my-flutter/ui-media/dark-mode","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"circle-half-stroke","description":"Thiết lập chế độ sáng/tối và phông chữ trong app Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"UI & Media"}]},{"id":"Ywrf5Px15XUjYIGcc77m","title":"TradingView trong Flutter WebView","pathname":"/flutter/tieng-viet/my-flutter/ui-media/tradingview-webview-javascript-bridge","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"chart-simple","description":"Cách đóng gói TradingView trong Flutter WebView với asset local, JavaScript bridge có schema và lifecycle an toàn trên Android/iOS","breadcrumbs":[{"label":"My Flutter"},{"label":"UI & Media"}]},{"id":"F98QJcMs9qNdSTCtvXsE","title":"Chọn renderer cho chart tài chính","pathname":"/flutter/tieng-viet/my-flutter/ui-media/financial-chart-renderer","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"chart-line","description":"Cách chọn giữa FL Chart, ECharts và renderer kiểu MPChart theo capability, realtime, gesture, testing và chi phí WebView","breadcrumbs":[{"label":"My Flutter"},{"label":"UI & Media"}]},{"id":"FzMXwdetQNQVaRXlc2bz","title":"Bàn phím nhập lệnh tùy chỉnh trong Flutter","pathname":"/flutter/tieng-viet/my-flutter/ui-media/custom-trading-keyboard","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"keyboard","description":"Xây bàn phím số tùy chỉnh trong Flutter theo controller, active binding, formatter, focus và accessibility thay vì chỉ vẽ một lưới phím","breadcrumbs":[{"label":"My Flutter"},{"label":"UI & Media"}]},{"id":"CgRnOylnJ0A7MM5YIb3H","title":"Quét QR/barcode an toàn","pathname":"/flutter/tieng-viet/my-flutter/ui-media/qr-barcode-scanner-camera-permission","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"qrcode","description":"Xây QR/barcode scanner trong Flutter với permission rõ ràng, camera lifecycle tuần tự và một pipeline không tin cậy raw payload","breadcrumbs":[{"label":"My Flutter"},{"label":"UI & Media"}]},{"id":"JCLjXdXrjkUbu4pzKMLI","title":"Render HTML từ server có kiểm soát trong Flutter","pathname":"/flutter/tieng-viet/my-flutter/ui-media/safe-server-driven-html-flutter","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"shield-halved","description":"Cách thiết kế bounded ingress, policy compiler và typed intent để render HTML do server quản lý mà không trao network hoặc navigation cho widget","breadcrumbs":[{"label":"My Flutter"},{"label":"UI & Media"}]},{"id":"qYBP2s2tbhzAoC1t8zTw","title":"Responsive","pathname":"/flutter/tieng-viet/my-flutter/ui-media/responsive","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"arrow-up-right-and-arrow-down-left-from-center","description":"Hướng dẫn về Responsive trong Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"UI & Media"}]},{"id":"lsX0YxMOW5jhaQk6mEnn","title":"Multi-Language","pathname":"/flutter/tieng-viet/my-flutter/ui-media/multi-language","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"earth-asia","description":"Chuyển đổi ngôn ngữ trong Flutter mà không cần plugin","breadcrumbs":[{"label":"My Flutter"},{"label":"UI & Media"}]},{"id":"qTZwLroP289MyP3Iy08b","title":"Core UI","pathname":"/flutter/tieng-viet/my-flutter/ui-media/core-ui","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"transporter","description":"Sử dụng lại giao diện UI mà bạn đã xây dựng","breadcrumbs":[{"label":"My Flutter"},{"label":"UI & Media"}]},{"id":"uwzGa2CVBsjwto3BJSXx","title":"Security & Observability","pathname":"/flutter/tieng-viet/my-flutter/security-observability","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"Bảo vệ identity và dữ liệu, đồng thời quan sát crash, tracing, analytics, config và engagement an toàn.","breadcrumbs":[{"label":"My Flutter"}]},{"id":"7EKuPaqGQzkS85MM4wzU","title":"Salt","pathname":"/flutter/tieng-viet/my-flutter/security-observability/salt","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"salt-shaker","description":"Bảo mật mật khẩu trong app Flutter: Mã hóa AES bằng Salt và IV","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"9ZiwRYPRTf0ann29VBsg","title":"Secure Storage: Keychain và Keystore","pathname":"/flutter/tieng-viet/my-flutter/security-observability/secure-storage-keychain-keystore","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"key","description":"Cách tôi giữ state cũ khi iOS Keychain tạm thời không phản hồi và ngăn một lần ghi Secure Storage làm mất dữ liệu","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"r4dVYnXm36XSmuSqk21m","title":"Biometric authentication với local_auth","pathname":"/flutter/tieng-viet/my-flutter/security-observability/biometric-authentication-local-auth","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"fingerprint","description":"Cách tôi dùng local_auth làm cổng xác thực cục bộ trước đăng nhập thật, chọn rõ fallback và giữ lỗi tạm thời không phá preference của user","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"GuuPACc8XBtaekV6rbBT","title":"Kiến trúc Smart OTP/TOTP trong Flutter","pathname":"/flutter/tieng-viet/my-flutter/security-observability/smart-otp-totp-flutter-architecture","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"clock","description":"Cách tôi tách enrollment, secret, nguồn thời gian và server verification để TOTP trong Flutter có replay protection và failure path rõ ràng","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"TC46kQGvlo4BR3wheAVY","title":"Tích hợp eKYC đa provider an toàn trong Flutter","pathname":"/flutter/tieng-viet/my-flutter/security-observability/secure-multi-provider-ekyc-flutter","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"id-card","description":"Cách tôi tách camera, QR, MRZ, NFC, consent, liveness và backend verification thành các boundary rõ ràng khi tích hợp nhiều eKYC provider trong Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"bYDuDFoMsRAJ49mgUOov","title":"Screenshot và quyền riêng tư khi app chạy nền trong Flutter","pathname":"/flutter/tieng-viet/my-flutter/security-observability/screenshot-background-privacy-flutter","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"shield-halved","description":"Cách tôi tách screenshot detection, screen recording, Android capture prevention và app-switcher privacy thành các contract có thể kiểm thử trong Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"qaELu58MQSJ4r8jiuCeM","title":"Device integrity và app shielding trong Flutter","pathname":"/flutter/tieng-viet/my-flutter/security-observability/device-integrity-app-shielding-flutter","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"shield-halved","description":"Cách tôi tách root jailbreak signal, app shielding, Play Integrity, App Attest và backend policy thành các contract có thể kiểm thử trong Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"DmUzePEihtyC8vBXjM7N","title":"Đăng nhập Google và Apple trong Flutter","pathname":"/flutter/tieng-viet/my-flutter/security-observability/google-apple-sign-in-flutter","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"fingerprint","description":"Thiết kế luồng Google và Apple trong đó Flutter chỉ nhận provider credential, backend xác minh rồi mới phát application session","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"ntdvkj6BhduZvEOMrCOm","title":"Vòng đời token reCAPTCHA Enterprise trong Flutter","pathname":"/flutter/tieng-viet/my-flutter/security-observability/recaptcha-enterprise-token-lifecycle-flutter","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"shield-halved","description":"Cách tôi tách vòng đời RecaptchaClient, one-shot token, submit idempotency và backend assessment thành các contract có thể kiểm thử trong Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"qGASkIUMcS4kLQ3bm4ae","title":"Sentry cho crash và tracing","pathname":"/flutter/tieng-viet/my-flutter/security-observability/sentry-flutter-crash-http-navigation-tracing","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"bug","description":"Cách tôi tách ownership cho Sentry crash, HTTP, navigation và transaction tracing, đồng thời kiểm soát sampling và dữ liệu trong Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"TbWqDBcNIbP1H40Iu7QT","title":"Analytics đa provider trong Flutter","pathname":"/flutter/tieng-viet/my-flutter/security-observability/multi-provider-analytics-flutter","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"chart-line","description":"Cách tôi đặt Firebase Analytics, Snowplow và Adjust sau một typed gateway để kiểm soát event, consent, identity và delivery evidence trong Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"yKPToEHA1r6yULetim6e","title":"Firebase Remote Config và feature flags","pathname":"/flutter/tieng-viet/my-flutter/security-observability/firebase-remote-config-feature-flags","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"sliders","description":"Cách tôi đưa Firebase Remote Config về một snapshot typed, giữ fallback an toàn và kiểm soát update realtime trong Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"sdbPLeujQdCR4EYdLG9j","title":"Firebase Performance và custom trace","pathname":"/flutter/tieng-viet/my-flutter/security-observability/firebase-performance-custom-trace","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"gauge-high","description":"Cách tôi thiết kế Firebase Performance custom trace theo từng operation, tách readiness, collection, sampling và runtime evidence trong Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"sg5rsVpzO6oa5s1uNAIQ","title":"OneSignal push và iOS NSE","pathname":"/flutter/tieng-viet/my-flutter/security-observability/onesignal-push-ios-notification-service-extension","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"bell","description":"Cách tôi tổ chức OneSignal theo app và user lifecycle, xử lý permission, click routing và iOS Notification Service Extension trong Flutter","breadcrumbs":[{"label":"My Flutter"},{"label":"Security & Observability"}]},{"id":"PEjRL62G0tgYeVR7FSh1","title":"Quality & Delivery","pathname":"/flutter/tieng-viet/my-flutter/quality-delivery","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"Testing, benchmark, CI/CD, code signing và release operations cho Flutter.","breadcrumbs":[{"label":"My Flutter"}]},{"id":"IyI3mRDrQ0ZD2DrBKrD6","title":"BDD với Flutter Gherkin","pathname":"/flutter/tieng-viet/my-flutter/quality-delivery/bdd-flutter-gherkin","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"list-check","description":"Cách tôi giữ Gherkin feature file nhưng migrate từng luồng BDD từ Flutter Driver sang integration_test và WidgetTester","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"DZh8MgRab13oT2FebS0J","title":"Widget Test và Golden Regression","pathname":"/flutter/tieng-viet/my-flutter/quality-delivery/widget-test-golden-regression","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"image","description":"Cách tôi kết hợp widget test với golden PNG, cố định môi trường render và review visual regression mà không che lỗi bằng update-goldens","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"llSP0urXx8npTj2YMUTq","title":"Mock Web Server cho Service/API Test","pathname":"/flutter/tieng-viet/my-flutter/quality-delivery/mock-web-server-service-api-test","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"server","description":"Cách tôi dùng local HTTP server để kiểm tra request/response contract, timeout và error mapping của service mà không gọi backend thật","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"3jBhuFS4MgW4MkRnuStn","title":"Chặn thiếu bản dịch với Slang i18n guard trong CI","pathname":"/flutter/tieng-viet/my-flutter/quality-delivery/slang-i18n-guard-missing-translations-ci","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"language","description":"Cách tôi tách Slang missing report, translator-MR policy và semantic test để CI chặn key thiếu dù app vẫn fallback về base locale","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"jLXHeV0qlfkcbIS9DVbj","title":"Benchmark startup và scrolling performance","pathname":"/flutter/tieng-viet/my-flutter/quality-delivery/startup-scrolling-performance-benchmark","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"gauge-high","description":"Cách tôi tách startup trace, scrolling timeline và runtime telemetry, rồi biến artifact thành quality gate fail-closed trên thiết bị Flutter thật","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"VgCSokKyraxdX2tPX0D8","title":"Theo dõi kích thước APK/IPA trong CI","pathname":"/flutter/tieng-viet/my-flutter/quality-delivery/automated-apk-ipa-size-tracking","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"weight-hanging","description":"Cách tôi đo exact bytes của APK/IPA release, chặn regression bằng budget và giữ metric artifact khi GitLab CI thất bại","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"hPyR0nhtYkoCgpJPGQES","title":"Network inspector an toàn ngay trong Flutter app","pathname":"/flutter/tieng-viet/my-flutter/quality-delivery/safe-in-app-network-inspector","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"magnifying-glass-chart","description":"Cách tôi khóa network inspector ở compile time, bảo toàn HTTP transport và chỉ lưu projection typed với giới hạn memory, TTL an toàn","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"iZ4x0Gn5YlTqqAgOxMBA","title":"GitLab CI cho Flutter monorepo","pathname":"/flutter/tieng-viet/my-flutter/quality-delivery/gitlab-ci-flutter-monorepo","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code-branch","description":"Tách GitLab CI, Makefile và Melos để kiểm tra Flutter monorepo nhất quán, giữ đúng exit code và report khi job lỗi","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"c0yhgDO73RFJOEcNFhvS","title":"Fastlane iOS, code signing và TestFlight","pathname":"/flutter/tieng-viet/my-flutter/quality-delivery/fastlane-ios-code-signing-testflight","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"apple","description":"Tách code signing, build IPA và upload TestFlight trong Fastlane để pipeline iOS dùng đúng artifact, ít quyền và báo đúng trạng thái","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"xkrGu37ijACf4jZxYw5I","title":"Sonar quality gate cho Flutter monorepo","pathname":"/flutter/tieng-viet/my-flutter/quality-delivery/sonar-quality-gate-flutter","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code-branch","description":"Biến phân tích Sonar thành quality gate bắt buộc cho Flutter monorepo bằng LCOV đúng commit, wait gate và GitLab merge policy","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"9UO93KCMYwMxMyEjFio2","title":"Release orchestration và scheduled go-live Android/iOS","pathname":"/flutter/tieng-viet/my-flutter/quality-delivery/release-orchestration-scheduled-golive-android-ios","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code-branch","description":"Điều phối release Android/iOS bằng artifact bất biến, protected environment, scheduled gate và trạng thái store rõ ràng","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"PUFmfLfpHag5qXZy4UPf","title":"Fastlane - Google Play","pathname":"/flutter/tieng-viet/my-flutter/quality-delivery/fastlane-google-play","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code-branch","description":"Tự động tải app Flutter lên Google Play với Fastlane (miễn phí)","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"dMD5i35qcUb7MkqiPbRK","title":"Firebase App Distribution (Android)","pathname":"/flutter/tieng-viet/my-flutter/quality-delivery/firebase-app-distribution","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"cloud-arrow-up","description":"Tải app Flutter Android lên Firebase App Distribution tự động để kiểm tra thủ công","breadcrumbs":[{"label":"My Flutter"},{"label":"Quality & Delivery"}]},{"id":"gjrWNFAndzIIeYjkFvk5","title":"Pain Points","pathname":"/flutter/tieng-viet/my-flutter/pain-points","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"Những pain point thực tế và cách xác định đúng ranh giới vấn đề trước khi sửa.","breadcrumbs":[{"label":"My Flutter"}]},{"id":"TpIEFuNHe6IKNKnUgegt","title":"Web","pathname":"/flutter/tieng-viet/my-flutter/pain-points/web","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"browser","description":"Flutter Các vấn đề về web: Hiệu suất, SEO và hơn thế nữa","breadcrumbs":[{"label":"My Flutter"},{"label":"Pain Points"}]},{"id":"PNORdVUFlAqGDSJb3dAX","title":"My AI","pathname":"/flutter/tieng-viet/my-ai/ai","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"sparkles","description":"Xây sản phẩm AI và dùng AI hỗ trợ lập trình với contract rõ ràng, kiểm soát dữ liệu và bằng chứng kỹ thuật.","breadcrumbs":[{"label":"My AI"}]},{"id":"Bp0MZrwx5vNyMEYfARLk","title":"Chat & Realtime","pathname":"/flutter/tieng-viet/my-ai/chat-realtime","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"Kết nối AI Chat, quản lý subscription, typed event, streaming và hòa giải message.","breadcrumbs":[{"label":"My AI"}]},{"id":"CeqDSDAn7CVmGDRKd886","title":"AI Chat với REST và WebSocket","pathname":"/flutter/tieng-viet/my-ai/chat-realtime/ai-chat-rest-websocket","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"comments","description":"Cách phân chia session, history và cancel qua REST với RPC, publication qua WebSocket để AI Chat có lifecycle rõ ràng và phục hồi được","breadcrumbs":[{"label":"My AI"},{"label":"Chat & Realtime"}]},{"id":"3CT2Ckkjq8mfVmh7k251","title":"Subscription lifecycle cho AI Chat","pathname":"/flutter/tieng-viet/my-ai/chat-realtime/subscription-lifecycle-ai-chat","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"arrows-rotate","description":"Cách chờ subscription sẵn sàng trước RPC, chia sẻ bằng consumer lease và phục hồi AI Chat an toàn qua reconnect","breadcrumbs":[{"label":"My AI"},{"label":"Chat & Realtime"}]},{"id":"hTJdvqNagQhYgKmj3Bf0","title":"Typed event cho AI realtime","pathname":"/flutter/tieng-viet/my-ai/chat-realtime/typed-events-realtime-ai","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"brackets-curly","description":"Cách biến dữ liệu realtime không đáng tin thành typed event union có version, validation và reducer exhaustive cho AI Chat","breadcrumbs":[{"label":"My AI"},{"label":"Chat & Realtime"}]},{"id":"1WTtYGQLXCqmOa0xghFe","title":"Streaming reducer cho AI Chat","pathname":"/flutter/tieng-viet/my-ai/chat-realtime/streaming-reducer-ai-chat","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"arrows-repeat","description":"Thiết kế reducer xác định cho AI Chat với sequence theo stream, bounded reorder buffer, gap recovery và terminal absorbing","breadcrumbs":[{"label":"My AI"},{"label":"Chat & Realtime"}]},{"id":"hGeUdsWaBThvs97SI5Ub","title":"Hòa giải message trong AI Chat","pathname":"/flutter/tieng-viet/my-ai/chat-realtime/optimistic-realtime-history-reconciliation","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"arrows-rotate","description":"Thiết kế identity, authority và atomic reconciliation cho optimistic UI, realtime stream và REST history trong AI Chat","breadcrumbs":[{"label":"My AI"},{"label":"Chat & Realtime"}]},{"id":"SmgQ3dgtveWvF0u3SL3y","title":"Context & Tools","pathname":"/flutter/tieng-viet/my-ai/context-tools","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"Chuẩn bị context, file, skill và input; quản lý resource, agent và công cụ trong sản phẩm AI.","breadcrumbs":[{"label":"My AI"}]},{"id":"LrclrT7qzRbdy0c03zBx","title":"Context an toàn cho AI Chat","pathname":"/flutter/tieng-viet/my-ai/context-tools/selection-file-canvas-resource-context","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"shield-halved","description":"Thiết kế trust boundary cho selection, file, canvas và resource context trước khi gửi câu hỏi AI","breadcrumbs":[{"label":"My AI"},{"label":"Context & Tools"}]},{"id":"qQLYKzsHk1dmICineykM","title":"File upload an toàn cho AI Chat","pathname":"/flutter/tieng-viet/my-ai/context-tools/safe-file-upload-ai-chat","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"file-shield","description":"Thiết kế lifecycle file upload hữu hạn cho AI Chat, tách upload accepted khỏi terminal readiness và chỉ publish context sau final CAS","breadcrumbs":[{"label":"My AI"},{"label":"Context & Tools"}]},{"id":"0JoR9GvSW0u9MMNidXOa","title":"Chọn skill an toàn cho AI Chat","pathname":"/flutter/tieng-viet/my-ai/context-tools/safe-skill-selection-ai-chat","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"shield","description":"Tách catalog hiển thị, lựa chọn, quyền thực thi và receipt để slash command trong AI Chat không vượt qua authorization boundary","breadcrumbs":[{"label":"My AI"},{"label":"Context & Tools"}]},{"id":"tnAEERRITJrhAulr4Hfr","title":"Chuẩn hóa input trước khi gọi AI","pathname":"/flutter/tieng-viet/my-ai/context-tools/normalize-input-before-ai","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"filter","description":"Khóa prompt, template, domain value và attachment context thành một typed intent bất biến trước khi giao request cho AI","breadcrumbs":[{"label":"My AI"},{"label":"Context & Tools"}]},{"id":"Pu7MjQsb5AkcBfgTWtuE","title":"Mở resource AI an toàn khi autosave","pathname":"/flutter/tieng-viet/my-ai/context-tools/open-ai-created-resource-autosave","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"file-shield","description":"Giữ document hiện tại an toàn khi mở resource do AI tạo bằng authority receipt, save barrier và latest-intent ownership","breadcrumbs":[{"label":"My AI"},{"label":"Context & Tools"}]},{"id":"9gYy3JxwT1Y4EnLWSVBH","title":"Quản lý Agent và Skill trên web","pathname":"/flutter/tieng-viet/my-ai/context-tools/agent-skill-web-editor","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"pen-to-square","description":"Thiết kế editor Agent và Skill với path hữu hạn, dirty guard và async ownership","breadcrumbs":[{"label":"My AI"},{"label":"Context & Tools"}]},{"id":"u6QPqp7EmDp2atSlm9Tv","title":"AI Editing","pathname":"/flutter/tieng-viet/my-ai/ai-editing","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"Review AI diff, kiểm proposal, xử lý conflict và chỉnh tài liệu hoặc Canvas bằng contract rõ ràng.","breadcrumbs":[{"label":"My AI"}]},{"id":"73krXb8vzF96uO2WSxfD","title":"Hiển thị AI diff an toàn trong TipTap","pathname":"/flutter/tieng-viet/my-ai/ai-editing/tiptap-prosemirror-decoration-ai-diff","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"highlighter","description":"Hiển thị AI diff trong TipTap bằng projection có scope, ProseMirror Decoration và lifecycle không làm sai document","breadcrumbs":[{"label":"My AI"},{"label":"AI Editing"}]},{"id":"O4q57rnmVxdXmkP1eej0","title":"State machine cho AI edit an toàn","pathname":"/flutter/tieng-viet/my-ai/ai-editing/apply-reject-focus-undo-state-machine","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"arrows-rotate","description":"Điều phối Apply, Reject, Focus và Undo bằng state machine có receipt, CAS và reconcile an toàn","breadcrumbs":[{"label":"My AI"},{"label":"AI Editing"}]},{"id":"LZ7ch3mcm9ffolpHN5yY","title":"Rebase AI suggestion an toàn","pathname":"/flutter/tieng-viet/my-ai/ai-editing/rebase-ai-suggestions-conflict-detection","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code-merge","description":"Rebase nhiều AI text edit bằng coordinate rõ ràng, exact revision, conflict graph và receipt có ownership","breadcrumbs":[{"label":"My AI"},{"label":"AI Editing"}]},{"id":"YjoktcW8kRC7WX2FizeN","title":"Stale AI proposal: path, before và revision","pathname":"/flutter/tieng-viet/my-ai/ai-editing/stale-ai-proposal-path-before-revision","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"shield-halved","description":"Chặn stale AI proposal bằng capability, exact snapshot, validation lease và backend CAS","breadcrumbs":[{"label":"My AI"},{"label":"AI Editing"}]},{"id":"XcG7wORSNNJui5ZHIZ3Q","title":"Compile Preview trước khi Keep","pathname":"/flutter/tieng-viet/my-ai/ai-editing/compile-preview-before-keep","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"shield-check","description":"Chỉ cho phép Keep sau bounded compile, canonical fixed point và exact render proof","breadcrumbs":[{"label":"My AI"},{"label":"AI Editing"}]},{"id":"zbc5WGMB4w2YrBfBDm59","title":"Proposal identity và change identity trong batch","pathname":"/flutter/tieng-viet/my-ai/ai-editing/proposal-change-identity-batches","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"shield-check","description":"Tách proposal, change và delivery identity để batch AI replay an toàn","breadcrumbs":[{"label":"My AI"},{"label":"AI Editing"}]},{"id":"ShCoKiRCKilhRJTpioQA","title":"Contract có version cho AI update, insert và delete object","pathname":"/flutter/tieng-viet/my-ai/ai-editing/versioned-ai-update-insert-delete-contract","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code-branch","description":"Version hóa update, insert và delete mà không biến dữ liệu AI thành quyền chỉnh sửa","breadcrumbs":[{"label":"My AI"},{"label":"AI Editing"}]},{"id":"jHYD2k4EhLcvQvsrLwz7","title":"AI chỉnh Canvas bằng typed command","pathname":"/flutter/tieng-viet/my-ai/ai-editing/typed-canvas-commands-ai-edit","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"shapes","description":"Tách typed AI command khỏi renderer state và giữ Canvas là projection","breadcrumbs":[{"label":"My AI"},{"label":"AI Editing"}]},{"id":"JiNAM4tCAWovzjllUj34","title":"Render citation, chart và câu hỏi follow-up","pathname":"/flutter/tieng-viet/my-ai/ai-editing/render-citations-charts-followups","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"","breadcrumbs":[{"label":"My AI"},{"label":"AI Editing"}]},{"id":"m5SejoyvUnva1cpUXJfz","title":"Coding Agents","pathname":"/flutter/tieng-viet/my-ai/coding-agents","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"Tổ chức rule, context và skill cho coding agent; chọn workflow và làm việc an toàn trong repository.","breadcrumbs":[{"label":"My AI"}]},{"id":"ZwycvW9RmU32PyOEkO86","title":"Chia sẻ rule giữa các coding agent","pathname":"/flutter/tieng-viet/my-ai/coding-agents/shared-provider-coding-agent-rules","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"scale-balanced","description":"Một catalog hữu hạn, nhiều adapter và ba mức bằng chứng tách biệt","breadcrumbs":[{"label":"My AI"},{"label":"Coding Agents"}]},{"id":"VsmUoGb9SS8Lg6sywQeL","title":"Nạp context từng bước","pathname":"/flutter/tieng-viet/my-ai/coding-agents/progressive-context-loading-token-optimization","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"layer-group","description":"Giảm context bằng một router hữu hạn mà vẫn giữ đầy đủ bằng chứng và QA","breadcrumbs":[{"label":"My AI"},{"label":"Coding Agents"}]},{"id":"hTX4EPdwxMlG2DzunLEj","title":"Tiết kiệm token từ bộ test","pathname":"/flutter/tieng-viet/my-ai/coding-agents/test-splitting-ai-token-savings","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"scissors","description":"Tách test theo hành vi, định tuyến context và đọc báo cáo đúng phạm vi để giảm lượng thông tin AI phải xử lý mà vẫn giữ kiểm tra cần thiết.","breadcrumbs":[{"label":"My AI"},{"label":"Coding Agents"}]},{"id":"eabawteGt5D6ynabVFAO","title":"Skill repo-native như playbook thực thi","pathname":"/flutter/tieng-viet/my-ai/coding-agents/repo-native-skill-engineering-playbook","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"list-check","description":"Biến Skill trong repository thành plan hữu hạn có dry-run, approval và receipt","breadcrumbs":[{"label":"My AI"},{"label":"Coding Agents"}]},{"id":"DG7e3sRJXW5HnVop1dYc","title":"Guardrail cho AI sinh feature","pathname":"/flutter/tieng-viet/my-ai/coding-agents/feature-generator-ai-code-guardrails","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"shield-check","description":"Sinh feature React an toàn với dry-run, approval và atomic apply","breadcrumbs":[{"label":"My AI"},{"label":"Coding Agents"}]},{"id":"c6tS3mc729jIifEfMffQ","title":"AI an toàn trong dirty worktree","pathname":"/flutter/tieng-viet/my-ai/coding-agents/safe-ai-dirty-worktree","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code-branch","description":"Bảo vệ thay đổi của người khác khi AI làm việc trong dirty worktree","breadcrumbs":[{"label":"My AI"},{"label":"Coding Agents"}]},{"id":"OrOFP9kLgQeMs75W5Zl1","title":"Chọn BMAD hay direct agent","pathname":"/flutter/tieng-viet/my-ai/coding-agents/bmad-vs-direct-agent","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"route","description":"Rubric hữu hạn để chọn BMAD hay direct agent và đổi hướng an toàn theo evidence","breadcrumbs":[{"label":"My AI"},{"label":"Coding Agents"}]},{"id":"AkRoKGX1M79kQSb6dGTD","title":"Quality & Safety","pathname":"/flutter/tieng-viet/my-ai/quality-safety","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"Phân biệt các mức bằng chứng, vận hành quality gate, nối sơ đồ với source và giới hạn quyền MCP.","breadcrumbs":[{"label":"My AI"}]},{"id":"VGvGsI4dIpB8tS7vHT8B","title":"Phân biệt mock, scaffold và runtime","pathname":"/flutter/tieng-viet/my-ai/quality-safety/mock-scaffold-configured-runtime-evidence","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"microscope","description":"Đo đúng mức bằng chứng từ declaration đến production observation","breadcrumbs":[{"label":"My AI"},{"label":"Quality & Safety"}]},{"id":"e4tidLOON9QDAKVdYWfZ","title":"Quality gate cho AI","pathname":"/flutter/tieng-viet/my-ai/quality-safety/focused-tests-full-quality-gate","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"shield-check","description":"Phân biệt focused checks, full gate và bằng chứng runtime khi AI kiểm tra code","breadcrumbs":[{"label":"My AI"},{"label":"Quality & Safety"}]},{"id":"uhn15uxWZ282Go6x6B4Y","title":"CI/CD khi AI viết nhiều test","pathname":"/flutter/tieng-viet/my-ai/quality-safety/ci-cd-ai-generated-tests","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"gears","description":"Rà soát giá trị của test, giảm việc lặp trong pipeline và kiểm tra chính cấu hình CI khi AI giúp tạo ngày càng nhiều code và test.","breadcrumbs":[{"label":"My AI"},{"label":"Quality & Safety"}]},{"id":"WOK3IqZIEnTYCB6np9Yt","title":"Flow ID nối sơ đồ và source","pathname":"/flutter/tieng-viet/my-ai/quality-safety/flow-diagram-id-source-markers","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"diagram-project","description":"Nối Mermaid với code production bằng Flow ID, source marker và receipt theo source generation","breadcrumbs":[{"label":"My AI"},{"label":"Quality & Safety"}]},{"id":"WnZxVorCdTZ8IBPuBYt9","title":"MCP theo nguyên tắc least privilege","pathname":"/flutter/tieng-viet/my-ai/quality-safety/least-privilege-mcp","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"shield-halved","description":"Thiết kế MCP với capability hữu hạn, exact approval, OAuth binding và reconciliation an toàn","breadcrumbs":[{"label":"My AI"},{"label":"Quality & Safety"}]},{"id":"2XBYw1sDzJPxuP8sG8qZ","title":"My ReactJS","pathname":"/flutter/tieng-viet/my-reactjs/reactjs","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"atom","description":"Kinh nghiệm ReactJS và Web Engineering được kiểm chứng từ source thực tế và viết lại an toàn cho cộng đồng.","breadcrumbs":[{"label":"My ReactJS"}]},{"id":"OvPuEgeiMtkabZaTyo4r","title":"Foundations & Architecture","pathname":"/flutter/tieng-viet/my-reactjs/foundations-architecture","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"Clean Architecture vừa đủ, MVVM, dependency injection, repository và ranh giới feature trong React.","breadcrumbs":[{"label":"My ReactJS"}]},{"id":"xIvjgik4clHFAxNHxvSs","title":"Clean Architecture vừa đủ cho React","pathname":"/flutter/tieng-viet/my-reactjs/foundations-architecture/pragmatic-clean-architecture-react","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"layer-group","description":"Chọn dependency boundary có ích cho feature React mà không biến mọi màn hình nhỏ thành đủ bộ layer","breadcrumbs":[{"label":"My ReactJS"},{"label":"Foundations & Architecture"}]},{"id":"uss0uZflxpjTac3nXLpl","title":"MVVM theo feature trong React","pathname":"/flutter/tieng-viet/my-reactjs/foundations-architecture/feature-based-mvvm-react","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"diagram-project","description":"Đặt Page, ViewModel, state và async lifecycle đúng owner trong một feature React mà không tạo God ViewModel","breadcrumbs":[{"label":"My ReactJS"},{"label":"Foundations & Architecture"}]},{"id":"YNDRYlcC68PxV830Cius","title":"Composition Root cho React","pathname":"/flutter/tieng-viet/my-reactjs/foundations-architecture/composition-root-dependency-injection-react","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"diagram-project","description":"Nối use case với adapter ở một composition root thuần, thay dependency trong test và giữ lifetime đúng owner mà không cần DI framework","breadcrumbs":[{"label":"My ReactJS"},{"label":"Foundations & Architecture"}]},{"id":"NWRWsjRzARRk1eLkgzgD","title":"RTK Query sau Repository","pathname":"/flutter/tieng-viet/my-reactjs/foundations-architecture/rtk-query-repository-contract","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"database","description":"Giữ RTK Query phía sau Repository mà vẫn làm rõ cache, request handle, cancellation và error ownership","breadcrumbs":[{"label":"My ReactJS"},{"label":"Foundations & Architecture"}]},{"id":"7Bo8JcKCGFnzFYPVGkIP","title":"Map DTO thành Domain Entity","pathname":"/flutter/tieng-viet/my-reactjs/foundations-architecture/dto-to-domain-entity-mapper","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"arrows-rotate","description":"Biến payload unknown thành Domain Entity bằng mapper có alias, identity, pagination và error policy hữu hạn","breadcrumbs":[{"label":"My ReactJS"},{"label":"Foundations & Architecture"}]},{"id":"UWzLxYgQAGl21kzVQWBX","title":"Public API cho React feature","pathname":"/flutter/tieng-viet/my-reactjs/foundations-architecture/feature-public-api-react","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Tách public entry point của React feature khỏi implementation, kiểm import bằng resolved target và phân biệt architecture coupling với runtime cycle.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Foundations & Architecture"}]},{"id":"1C0vtJdhZsv5W5DdysjH","title":"Sinh React feature bằng Nx","pathname":"/flutter/tieng-viet/my-reactjs/foundations-architecture/react-feature-generator-nx","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Biến quy ước kiến trúc React thành template Nx, rồi kiểm code được sinh ra trước khi nối vào app","breadcrumbs":[{"label":"My ReactJS"},{"label":"Foundations & Architecture"}]},{"id":"e2CZ9jrkKrV38qUyBKr2","title":"Kiểm thử kiến trúc React","pathname":"/flutter/tieng-viet/my-reactjs/foundations-architecture/react-architecture-fitness-tests","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"diagram-project","description":"Đối chiếu sơ đồ, import và đường gọi React bằng test có đối chứng, để scaffold và UI xanh không che khuất wiring khác dự kiến","breadcrumbs":[{"label":"My ReactJS"},{"label":"Foundations & Architecture"}]},{"id":"sKLRejSpENHOT78y7e7c","title":"Sơ đồ bám sát code React","pathname":"/flutter/tieng-viet/my-reactjs/foundations-architecture/source-linked-react-diagrams","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"diagram-project","description":"Nối Mermaid với hàm sở hữu bằng marker, kiểm giới hạn regex và tách React draft khỏi source đã lưu.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Foundations & Architecture"}]},{"id":"JhdQ6vV1jM81uxAmGq5J","title":"UI & Performance","pathname":"/flutter/tieng-viet/my-reactjs/ui-performance","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"React Compiler, lazy loading, lifecycle, form, Design System và locale cho giao diện React.","breadcrumbs":[{"label":"My ReactJS"}]},{"id":"IvXHQAbAcjnfQQIEJPeq","title":"React Compiler trong ứng dụng lớn","pathname":"/flutter/tieng-viet/my-reactjs/ui-performance/react-compiler-large-app","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"microchip","description":"Triển khai React Compiler bằng rollout hữu hạn, opt-out có owner, artifact proof và browser profiling","breadcrumbs":[{"label":"My ReactJS"},{"label":"UI & Performance"}]},{"id":"k7MTWjgrvU2XyJMXpENA","title":"Lazy route an toàn với React","pathname":"/flutter/tieng-viet/my-reactjs/ui-performance/react-lazy-suspense-route-loading","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"route","description":"Thiết kế lazy route có access gate, preload budget, release recovery và browser evidence trong React","breadcrumbs":[{"label":"My ReactJS"},{"label":"UI & Performance"}]},{"id":"TYJF2lHefW61b2neN9Cg","title":"Error Boundary nhiều tầng trong React","pathname":"/flutter/tieng-viet/my-reactjs/ui-performance/layered-react-error-boundaries","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"bug","description":"Thiết kế ownership, reset hữu hạn, fallback an toàn và evidence cho Error Boundary nhiều tầng trong React","breadcrumbs":[{"label":"My ReactJS"},{"label":"UI & Performance"}]},{"id":"J4jyD4IEF8avJGLwvqNY","title":"Side effect an toàn trong custom hook","pathname":"/flutter/tieng-viet/my-reactjs/ui-performance/custom-hooks-side-effect-cleanup","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"broom","description":"Thiết kế custom hook với setup giao dịch, cleanup hữu hạn và stale-work guard trong React","breadcrumbs":[{"label":"My ReactJS"},{"label":"UI & Performance"}]},{"id":"p1iU5IFretLodaT35VSd","title":"ResizeObserver không layout thrashing","pathname":"/flutter/tieng-viet/my-reactjs/ui-performance/resize-observer-layout-thrashing","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"maximize","description":"Thiết kế ResizeObserver với ownership, read-write batching, feedback bound và bằng chứng hiệu năng đúng mức","breadcrumbs":[{"label":"My ReactJS"},{"label":"UI & Performance"}]},{"id":"NLCvgodHnENlVKzEPq3h","title":"Infinite scroll với IntersectionObserver","pathname":"/flutter/tieng-viet/my-reactjs/ui-performance/intersection-observer-infinite-scroll","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"arrow-down","description":"Thiết kế infinite scroll với ownership, pagination hữu hạn, scroll anchoring và bằng chứng đúng mức","breadcrumbs":[{"label":"My ReactJS"},{"label":"UI & Performance"}]},{"id":"eWjFj0RDTeg1NMM5DgzR","title":"Kiến trúc form phức tạp với React Hook Form","pathname":"/flutter/tieng-viet/my-reactjs/ui-performance/complex-forms-react-hook-form","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"rectangle-list","description":"Tách form state, domain command và request ownership cho form React nhiều bước, field động","breadcrumbs":[{"label":"My ReactJS"},{"label":"UI & Performance"}]},{"id":"0BytZiTGdDO3nXoSJ7ej","title":"Xây Design System bằng Storybook","pathname":"/flutter/tieng-viet/my-reactjs/ui-performance/design-system-storybook","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"palette","description":"Xây Design System có package contract, story tái lập và bằng chứng kiểm thử đúng tầng","breadcrumbs":[{"label":"My ReactJS"},{"label":"UI & Performance"}]},{"id":"5gfIeXKBDtTYy74VRAII","title":"Đồng bộ locale trong React","pathname":"/flutter/tieng-viet/my-reactjs/ui-performance/react-i18n-locale-data-formatting","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"language","description":"Đồng bộ locale, catalog, API cache, định dạng và widget bằng một snapshot hữu hạn, stale-safe","breadcrumbs":[{"label":"My ReactJS"},{"label":"UI & Performance"}]},{"id":"hmff14T8Mt5vFufFfUr9","title":"State & API","pathname":"/flutter/tieng-viet/my-reactjs/state-api","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"State ownership, API cache, workflow RxJS, typed error, feature flag, ACL và session đa tab.","breadcrumbs":[{"label":"My ReactJS"}]},{"id":"AxN2jvL6lzjDwJ7DxxQx","title":"Workflow bất đồng bộ với Redux-Observable","pathname":"/flutter/tieng-viet/my-reactjs/state-api/redux-observable-workflow","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"arrows-rotate","description":"Điều phối workflow React và Redux có giới hạn, hủy đúng scope, retry an toàn và teardown kiểm thử được","breadcrumbs":[{"label":"My ReactJS"},{"label":"State & API"}]},{"id":"HOobkaKb2wDQoSgncE1l","title":"RTK Query đa API","pathname":"/flutter/tieng-viet/my-reactjs/state-api/rtk-query-multi-api","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"diagram-project","description":"Tổ chức nhiều RTK Query API slice theo cache và transport boundary, với runtime config, auth recovery và lifecycle được kiểm soát","breadcrumbs":[{"label":"My ReactJS"},{"label":"State & API"}]},{"id":"qiDyYiRHrqllu0UsOi6U","title":"Chọn owner cho React state","pathname":"/flutter/tieng-viet/my-reactjs/state-api/rtk-query-redux-observable-local-state","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"arrows-to-circle","description":"Chọn một owner theo lifetime cho server cache, workflow, UI draft và dữ liệu dẫn xuất trong React","breadcrumbs":[{"label":"My ReactJS"},{"label":"State & API"}]},{"id":"2QuQ0spcC2T79J5KYI80","title":"Hủy workflow RxJS đúng ranh giới","pathname":"/flutter/tieng-viet/my-reactjs/state-api/rxjs-race-takeuntil-cancellation","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"arrows-spin","description":"Phân biệt subscription, signal và authority để hủy workflow RxJS mà không làm Epic chết hoặc ghi đè generation mới","breadcrumbs":[{"label":"My ReactJS"},{"label":"State & API"}]},{"id":"K1VodY016ejA62PxGD4f","title":"Dependency injection cho Redux-Observable","pathname":"/flutter/tieng-viet/my-reactjs/state-api/redux-observable-epic-dependency-injection","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"diagram-project","description":"Thiết kế dependency injection hữu hạn cho Redux-Observable Epic với readiness, generation, cancellation và teardown kiểm thử được","breadcrumbs":[{"label":"My ReactJS"},{"label":"State & API"}]},{"id":"kgCNv7M0tyHSkmm3ZQRb","title":"Chuẩn hóa dữ liệu trước Redux","pathname":"/flutter/tieng-viet/my-reactjs/state-api/normalize-data-before-redux","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"database","description":"Thiết kế boundary hữu hạn để decode, định danh và chuẩn hóa dữ liệu trước khi ghi vào Redux","breadcrumbs":[{"label":"My ReactJS"},{"label":"State & API"}]},{"id":"orOzES1fqni5M17JSKhG","title":"Điều phối cache realtime","pathname":"/flutter/tieng-viet/my-reactjs/state-api/realtime-cache-invalidation","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"rotate","description":"Điều phối RTK Query, mutation và realtime bằng cache key, generation, revision cùng refresh owner hữu hạn","breadcrumbs":[{"label":"My ReactJS"},{"label":"State & API"}]},{"id":"eL2xII77RmFkAh8Ygo5H","title":"Lỗi typed từ API đến UI","pathname":"/flutter/tieng-viet/my-reactjs/state-api/typed-errors-api-to-ui","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"triangle-exclamation","description":"Chuẩn hóa lỗi Axios, RTK Query và Redux Observable thành taxonomy hữu hạn trước khi đi vào state, UI hoặc telemetry","breadcrumbs":[{"label":"My ReactJS"},{"label":"State & API"}]},{"id":"4PFquJu2NoTDxv58DPOb","title":"Feature flag an toàn trong React","pathname":"/flutter/tieng-viet/my-reactjs/state-api/feature-flags-remote-config","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"sliders","description":"Đưa Firebase Remote Config về một snapshot typed, atomic và tách feature flag phía client khỏi quyền backend trong React","breadcrumbs":[{"label":"My ReactJS"},{"label":"State & API"}]},{"id":"siI69MAEyWj6U6zZkguU","title":"Route Guard và ACL trong React","pathname":"/flutter/tieng-viet/my-reactjs/state-api/react-router-route-guard-acl","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"shield-halved","description":"Thiết kế Route Guard fail-closed với ACL hữu hạn, return-to an toàn và kiểm tra stale navigation trong React","breadcrumbs":[{"label":"My ReactJS"},{"label":"State & API"}]},{"id":"i10jfhguOo8R84Hc0lGo","title":"Session React qua nhiều tab","pathname":"/flutter/tieng-viet/my-reactjs/state-api/react-sessions-across-tabs","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"shield-halved","description":"Đồng bộ session giữa các tab React, chặn phản hồi cũ và tách đăng xuất cục bộ khỏi thu hồi session ở server.","breadcrumbs":[{"label":"My ReactJS"},{"label":"State & API"}]},{"id":"jq10hIbC5ZhVTPOOzmsO","title":"Realtime & Charts","pathname":"/flutter/tieng-viet/my-reactjs/realtime-charts","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"Web Worker, MQTT, reconnect, backpressure, dữ liệu thị trường và vòng đời chart renderer.","breadcrumbs":[{"label":"My ReactJS"}]},{"id":"KxwVl3RUoF7rIgJit7F8","title":"MQTT với Web Worker và RxJS","pathname":"/flutter/tieng-viet/my-reactjs/realtime-charts/mqtt-web-worker-rxjs","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"arrows-rotate","description":"Cách phân định reconnect, subscription và backpressure khi đưa MQTT vào Web Worker rồi chia sẻ dữ liệu qua RxJS trong React","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"Dnm8Z6ZUwa9N1SFbPqbI","title":"Đồng bộ thời gian client-server","pathname":"/flutter/tieng-viet/my-reactjs/realtime-charts/client-server-time-sync","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"clock","description":"Đồng bộ thời gian client-server bằng RTT monotonic, uncertainty interval và lifecycle hữu hạn thay vì tin một offset tuyệt đối","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"ZxdCrzDHepIVrWj61vGb","title":"Bảng realtime với React","pathname":"/flutter/tieng-viet/my-reactjs/realtime-charts/realtime-table-react","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"table-list","description":"Thiết kế bảng realtime với virtualization, frame coalescing, row-scoped updates và bằng chứng hiệu năng có giới hạn","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"NVWvX1TYE2Djte4lnB1V","title":"State machine cho MQTT subscription","pathname":"/flutter/tieng-viet/my-reactjs/realtime-charts/mqtt-subscription-state-machine","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"diagram-project","description":"Thiết kế MQTT subscription bằng owner, epoch, ACK correlation và recovery hữu hạn trong React","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"rJdRDHKgGp6dxTVZXj3K","title":"Backpressure cho dữ liệu realtime","pathname":"/flutter/tieng-viet/my-reactjs/realtime-charts/realtime-batching-dedup-backpressure","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"gauge-high","description":"Thiết kế batch, dedupe và overload policy hữu hạn cho luồng RxJS, MQTT và dữ liệu realtime mà không nhầm time window với backpressure","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"lnTgh0M2wfdIsP0ZQFYd","title":"Reconnect và khôi phục subscription","pathname":"/flutter/tieng-viet/my-reactjs/realtime-charts/mqtt-reconnect-subscription-recovery","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Tách reconnect, khôi phục subscription và dữ liệu sẵn sàng; kiểm soát completion muộn, retry và cleanup trong ứng dụng React dùng MQTT.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"6DqX2vbQYOk2baSlFs45","title":"Đo latency WebSocket và MQTT","pathname":"/flutter/tieng-viet/my-reactjs/realtime-charts/websocket-mqtt-latency","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"gauge-high","description":"Phân biệt tuổi dữ liệu, RTT và thời gian xử lý; thiết kế phép đo realtime có giới hạn, ownership và bằng chứng rõ ràng","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"6HX9BgrAsU2CnVMN521E","title":"Ghép OHLC lịch sử với live ticks","pathname":"/flutter/tieng-viet/my-reactjs/realtime-charts/ohlc-live-ticks","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"chart-line","description":"Cách nối lịch sử OHLC với matched-trade tick hoặc provider bar mà không trộn authority, thời gian và volume semantics","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"LScwAYQ1OpMaX4HEiNAZ","title":"Chọn datafeed dự phòng","pathname":"/flutter/tieng-viet/my-reactjs/realtime-charts/choosing-fallback-datafeed","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Tách HTTP probe, lựa chọn đã lưu và datafeed thật sự sẵn sàng; chọn dự phòng có giới hạn mà không đổi feed theo một con số độ trễ.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"4evWfBQ4PYNSMOU0OtG3","title":"Vòng đời listener của chart","pathname":"/flutter/tieng-viet/my-reactjs/realtime-charts/chart-listener-lifecycle","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"chart-line","description":"Từ listener pool trong dự án đến adapter theo từng chart, với overlap, callback đến muộn và cleanup có chủ sở hữu.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"L4tWxSJ7SgefsGquieMI","title":"Chart adapter qua domain port","pathname":"/flutter/tieng-viet/my-reactjs/realtime-charts/chart-adapter-domain-ports","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"chart-line","description":"Tách history provider khỏi chart SDK bằng domain port, với mapping dữ liệu, callback và cleanup có chủ sở hữu.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"yBIrrHxo1cbUhpID6B1T","title":"Lưu và khôi phục chart layout","pathname":"/flutter/tieng-viet/my-reactjs/realtime-charts/saving-restoring-chart-layouts","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"chart-line","description":"Quản lý phiên, snapshot và xác nhận lưu để chart layout không bị ghi đè bởi tác vụ cũ.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"0nICUqrEFIq7kaGUAT57","title":"Chart contract và renderer adapter","pathname":"/flutter/tieng-viet/my-reactjs/realtime-charts/chart-contracts-renderer-adapters","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"chart-line","description":"Giữ đúng ý nghĩa dữ liệu khi cùng một chart được vẽ bằng ECharts Canvas và React SVG, với validation và lifecycle riêng.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Realtime & Charts"}]},{"id":"OdNuaU83Pj8fFL50l51C","title":"Testing & Quality","pathname":"/flutter/tieng-viet/my-reactjs/testing-quality","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"BDD, Playwright, mocks, kiểm thử RxJS, lifecycle, accessibility và browser API.","breadcrumbs":[{"label":"My ReactJS"}]},{"id":"XOGvHAAECGY6ZquF5Rn5","title":"Giữ Gherkin và Playwright đồng bộ","pathname":"/flutter/tieng-viet/my-reactjs/testing-quality/gherkin-playwright-sync","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"list-check","description":"Thiết kế stable identity, đối chiếu hai chiều và CI gate để catalog Gherkin không âm thầm lệch khỏi Playwright","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"oUySOnVJKoHjCI5TNbBt","title":"Testing browser permissions trong React","pathname":"/flutter/tieng-viet/my-reactjs/testing-quality/testing-browser-permissions-react","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"lock","description":"Tách permission state, browser capability, prompt và resource ownership để kiểm thử React đúng mức","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"EHcJC7cxvB9hycdam3rY","title":"Visual regression testing với Chromatic","pathname":"/flutter/tieng-viet/my-reactjs/testing-quality/visual-regression-chromatic","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"eye","description":"Thiết kế visual regression hữu hạn, tái lập và có authority rõ ràng với Storybook và Chromatic","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"8JIV1fw96tIx8zKUVC8O","title":"Marble test cho luồng RxJS","pathname":"/flutter/tieng-viet/my-reactjs/testing-quality/rxjs-marble-testing","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"wave-square","description":"Thiết kế TestScheduler hữu hạn để kiểm giá trị, completion và subscription lifecycle của workflow RxJS","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"muMaWZyGhX9BGa21db9Y","title":"Kiểm tra test contract bằng AST","pathname":"/flutter/tieng-viet/my-reactjs/testing-quality/test-contracts-typescript-ast","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Đối chiếu Feature, Scenario và step bằng TypeScript AST mà không nhầm khớp tên với test đã chạy và pass","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"yxbtBXtbpNnShXc7lVvE","title":"Sinh skeleton Playwright an toàn","pathname":"/flutter/tieng-viet/my-reactjs/testing-quality/playwright-scenario-outline-skeleton","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Sinh Playwright skeleton từ Scenario Outline với parameter binding, quyền sở hữu code và quality gate rõ ràng","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"y1vHJTKNYDLFBlsSG2aD","title":"Mock API có trạng thái","pathname":"/flutter/tieng-viet/my-reactjs/testing-quality/stateful-api-mocks-playwright","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Tổ chức mock Playwright theo service, giữ state riêng từng test và kiểm rõ mutation, response cùng vòng đời route","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"BkK82HT4XicpnCegkFy2","title":"Mock realtime qua Web Worker","pathname":"/flutter/tieng-viet/my-reactjs/testing-quality/realtime-worker-mocks-playwright","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Kiểm thử realtime trong Playwright tại ranh giới Worker, với readiness, subscription, control ACK và cleanup có chủ sở hữu.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"99Uh3lLvhR1Eoav1fFzI","title":"Missing và incomplete trong BDD","pathname":"/flutter/tieng-viet/my-reactjs/testing-quality/missing-incomplete-bdd-scenarios","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Tách scenario chưa có test, test chưa đủ contract và kết quả thực thi để quality gate không xanh sai","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"6ybRyxzOJrChNSHdQoQU","title":"Ổn định test realtime","pathname":"/flutter/tieng-viet/my-reactjs/testing-quality/stable-realtime-ui-tests","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Chờ đúng dữ liệu và đúng giai đoạn trong test realtime bằng locator có ownership, tín hiệu render và probe lưu trạng thái an toàn.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"ziWE4MoFGS1784Qm7Oik","title":"Kiểm thử cleanup trong React","pathname":"/flutter/tieng-viet/my-reactjs/testing-quality/testing-react-cleanup","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Kiểm thử listener, observer và subscription bằng đúng resource owner, positive control và stimulus sau cleanup; phân biệt local release với việc hủy tác vụ hoặc kết nối.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"SMeFp6ESvTY6lSSK5woE","title":"Kiểm thử accessibility trong React","pathname":"/flutter/tieng-viet/my-reactjs/testing-quality/accessibility-testing-react","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Từ test click tới role, accessible name và portal scan; giữ rõ giới hạn của jest-axe, kiểm bàn phím và phần cần review thủ công.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"wYHOWGuMIg4XipmuodcU","title":"Kiểm thử browser API với JSDOM","pathname":"/flutter/tieng-viet/my-reactjs/testing-quality/testing-browser-apis-jsdom","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Từ permission query tới scroll và storage, thiết kế fake có kiểm soát và biết khi nào cần bằng chứng từ trình duyệt thật.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Testing & Quality"}]},{"id":"ne1UvVoAvWA0VLqFIAEX","title":"Platform & Delivery","pathname":"/flutter/tieng-viet/my-reactjs/platform-delivery","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"Runtime config, package Nx, build cache, bundle, versioning và triển khai frontend.","breadcrumbs":[{"label":"My ReactJS"}]},{"id":"RPe1Fzy3jd99lKiHQG0U","title":"Runtime config cho Vite","pathname":"/flutter/tieng-viet/my-reactjs/platform-delivery/runtime-config-vite","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"sliders","description":"Cách tách public runtime config khỏi bundle Vite để build một lần, deploy nhiều môi trường với schema, bootstrap và cache policy rõ ràng","breadcrumbs":[{"label":"My ReactJS"},{"label":"Platform & Delivery"}]},{"id":"drJnxNIeKoeo6McyXqZL","title":"Chặn startup khi config sai","pathname":"/flutter/tieng-viet/my-reactjs/platform-delivery/runtime-config-startup-gate","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Tách validation khỏi application graph, kiểm thứ tự import và quản lý startup đến muộn bằng một owner rõ ràng.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Platform & Delivery"}]},{"id":"dVeDdVY0cEkpws939uRZ","title":"Browser config không giữ secret","pathname":"/flutter/tieng-viet/my-reactjs/platform-delivery/browser-config-is-public","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Chọn field được phép công khai và kiểm artifact sau build, thay vì coi runtime env là nơi giấu credential.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Platform & Delivery"}]},{"id":"9o650skFW6OapDP6iUNr","title":"Ranh giới package trong Nx","pathname":"/flutter/tieng-viet/my-reactjs/platform-delivery/nx-package-boundaries","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Đặt role, kiểm graph producer và biến ranh giới apps/core/services/ui/utils thành gate có đối chứng, không chỉ là tên thư mục.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Platform & Delivery"}]},{"id":"r1CwXFIPpSjW8isR0y7F","title":"Build affected và cache Nx","pathname":"/flutter/tieng-viet/my-reactjs/platform-delivery/nx-affected-build-cache","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Tách affected selection, computation inputs, output restore và quyền ghi cache từ một workspace Nx thực tế.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Platform & Delivery"}]},{"id":"OTgcO9Ly9NQP3O70q0LP","title":"Quản lý version bằng Changesets","pathname":"/flutter/tieng-viet/my-reactjs/platform-delivery/changesets-package-versioning","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Tách release intent, version/changelog và artifact publish bằng Changesets, với kiểm tra phạm vi package và lỗi ghi dở.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Platform & Delivery"}]},{"id":"5EflEqrQjuDmnAmxCPU6","title":"Chia chunk và đọc bundle Vite","pathname":"/flutter/tieng-viet/my-reactjs/platform-delivery/vite-chunks-bundle-analysis","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Kiểm tra manual chunking bằng dependency graph, emitted bytes và browser runtime, đồng thời đọc đúng giới hạn của bundle visualizer.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Platform & Delivery"}]},{"id":"OhPhEvJ25Z8kvticW28b","title":"Tải thư viện theo nhu cầu","pathname":"/flutter/tieng-viet/my-reactjs/platform-delivery/on-demand-library-loading","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Tách thời điểm tải chart, analytics và realtime khỏi vòng đời instance, với demand gate, cleanup và kiểm chứng trên trình duyệt.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Platform & Delivery"}]},{"id":"ixRUpUBkvV2bieaHBxBe","title":"Source maps cho production","pathname":"/flutter/tieng-viet/my-reactjs/platform-delivery/source-maps-production","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Giữ source map khớp artifact để debug, đồng thời tách bản public khỏi map và kiểm đúng ranh giới build, upload, origin.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Platform & Delivery"}]},{"id":"gYfGaSgX6GIhvAIifMqo","title":"Truy vết build metadata","pathname":"/flutter/tieng-viet/my-reactjs/platform-delivery/traceable-build-metadata","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Tách version, commit và build ID để tra đúng artifact, giữ metadata public tối thiểu và kiểm chứng ranh giới Git, HTML, browser.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Platform & Delivery"}]},{"id":"fX1eTLnx9ZfUoWacdAEi","title":"Static deployment và cache","pathname":"/flutter/tieng-viet/my-reactjs/platform-delivery/static-deployment-caching","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Tách asset base, runtime config và cache policy để deploy bản mới mà vẫn giữ đường tải lazy chunk cho tab cũ.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Platform & Delivery"}]},{"id":"YFRwefQLA25uHlTrm5CT","title":"Financial JavaScript","pathname":"/flutter/tieng-viet/my-reactjs/financial-javascript","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"Precision, đơn vị và làm tròn; idempotency, chống gửi trùng và thời điểm hết hạn.","breadcrumbs":[{"label":"My ReactJS"}]},{"id":"TV9PB2VccPqXAVSLQq8Z","title":"Tính toán tài chính chính xác trong TypeScript","pathname":"/flutter/tieng-viet/my-reactjs/financial-javascript/precise-financial-math-typescript","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"calculator","description":"Thiết kế decimal boundary với unit, scale, rounding policy và exact wire contract cho ứng dụng TypeScript","breadcrumbs":[{"label":"My ReactJS"},{"label":"Financial JavaScript"}]},{"id":"4zjiNtUCgFs1L7TbAxvA","title":"Ranh giới đơn vị tiền và tỷ lệ","pathname":"/flutter/tieng-viet/my-reactjs/financial-javascript/money-rate-unit-boundaries","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"Giữ đúng đơn vị tiền, giá và tỷ lệ từ API qua form React đến request, với adapter có kiểu và kiểm tra runtime.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Financial JavaScript"}]},{"id":"LF7e92MFg0uV8cNd0L5a","title":"Làm tròn đúng ranh giới","pathname":"/flutter/tieng-viet/my-reactjs/financial-javascript/rounding-truncation-boundaries","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"Chọn đúng thời điểm, chế độ và chủ sở hữu làm tròn; tách preview khỏi giá trị dùng để tạo request trong ứng dụng React.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Financial JavaScript"}]},{"id":"IUhZrSV4hYniQ0zshXkK","title":"Request ID và idempotency","pathname":"/flutter/tieng-viet/my-reactjs/financial-javascript/request-id-idempotency","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"Tách ID của thao tác khỏi ID của từng lần gửi, giữ đúng ý định khi retry và xử lý kết quả chưa rõ mà không giả định server chưa ghi.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Financial JavaScript"}]},{"id":"kDBhcyRCQlHdQoRqHQnv","title":"Ngăn double submit trong React","pathname":"/flutter/tieng-viet/my-reactjs/financial-javascript/prevent-double-submit-react","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"Giữ một quyền submit xuyên suốt validation, confirmation và request; tách trạng thái loading của React khỏi ownership của thao tác.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Financial JavaScript"}]},{"id":"7HMgiNWL8Mft5HEgf14M","title":"Countdown và expiry trong React","pathname":"/flutter/tieng-viet/my-reactjs/financial-javascript/countdown-expiry-react","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"clock","description":"Gắn countdown với đúng deadline và clock reading, giữ trạng thái chưa chắc chắn riêng với hết hạn, và kiểm lifecycle bằng React thật","breadcrumbs":[{"label":"My ReactJS"},{"label":"Financial JavaScript"}]},{"id":"3RS8e6h50ReZp1VDtRN2","title":"Hiển thị số chính xác trong React","pathname":"/flutter/tieng-viet/my-reactjs/financial-javascript/precise-number-display-react","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Giữ decimal chính xác đến text React, tách zero khỏi unavailable và đổi locale mà không đổi dữ liệu gốc.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Financial JavaScript"}]},{"id":"wSKyXEMcV69mgsT6PVxg","title":"Editors & Canvas","pathname":"/flutter/tieng-viet/my-reactjs/editors-canvas","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"Markdown, TipTap, nguồn canonical, Canvas compiler, layout in và lịch sử chỉnh sửa.","breadcrumbs":[{"label":"My ReactJS"}]},{"id":"7eNSw2ZkhhGv509g1bw8","title":"Markdown canonical với TipTap","pathname":"/flutter/tieng-viet/my-reactjs/editors-canvas/canonical-markdown-tiptap","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"file-code","description":"Giữ Markdown làm nội dung do ứng dụng sở hữu, đồng bộ TipTap có kiểm soát và tránh lưu lại một bản chuyển đổi đã mất ngữ nghĩa.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Editors & Canvas"}]},{"id":"ti6Cj9MsJ9V0LK0g5LbH","title":"Đồng bộ các chế độ editor","pathname":"/flutter/tieng-viet/my-reactjs/editors-canvas/synchronizing-editor-modes","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Giữ một Markdown draft khi đổi Source, Rich Editor và Preview; chặn intent cũ, callback muộn và chuyển mode khi editor chưa sẵn sàng.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Editors & Canvas"}]},{"id":"ZAqsMWFsFEGnHY3n4lgN","title":"Round-trip Markdown và TipTap","pathname":"/flutter/tieng-viet/my-reactjs/editors-canvas/markdown-tiptap-semantic-roundtrip","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"file-code","description":"Kiểm round-trip Markdown bằng ngữ nghĩa kỳ vọng, schema thật và corpus có ca âm; không nhầm visible text hoặc output ổn định với bảo toàn nội dung.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Editors & Canvas"}]},{"id":"SDSUL5A16leXOYylMCdz","title":"TipTap một cây, một history","pathname":"/flutter/tieng-viet/my-reactjs/editors-canvas/single-tiptap-tree-history","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"file-code","description":"Dùng một TipTap document cho nhiều vùng, tách đúng history event và đặt ranh giới session khi nhận tài liệu bên ngoài.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Editors & Canvas"}]},{"id":"XgfcwromgzquecOy9ftq","title":"A4 là bản in dẫn xuất","pathname":"/flutter/tieng-viet/my-reactjs/editors-canvas/derived-a4-print-view","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"Giữ một cây TipTap để sửa, tạo bản in có giới hạn và kiểm chứng PDF A4 mà không ghi page artifact vào document.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Editors & Canvas"}]},{"id":"xCsAc6F5PPX2exM6ha8y","title":"Canonical source và Fabric snapshot","pathname":"/flutter/tieng-viet/my-reactjs/editors-canvas/canonical-source-fabric-snapshot","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Phân biệt Markdown/YAML canonical với Fabric snapshot, chọn quy tắc cache và khôi phục để không biến bản dựng cũ thành nguồn dữ liệu mới.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Editors & Canvas"}]},{"id":"CQFI5q4QvP6BQLOpHrvl","title":"Compiler hai chiều cho Canvas","pathname":"/flutter/tieng-viet/my-reactjs/editors-canvas/bidirectional-canvas-compiler","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Từ compiler Markdown–Canvas trong dự án React, xây profile hỗ trợ rõ ràng, kiểm semantic round-trip và từ chối edit mất dữ liệu trước khi commit.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Editors & Canvas"}]},{"id":"Z11i6IlpJ6tQx2Y41Ge1","title":"Ghép source bằng stable ID","pathname":"/flutter/tieng-viet/my-reactjs/editors-canvas/composite-source-stable-object-id","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Tách design.json và content.md, ghép bằng stable object ID và kiểm ownership, revision cùng giới hạn của composite source.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Editors & Canvas"}]},{"id":"XovvCTrNH7uKnAP1tEMN","title":"Command và lịch sử editor","pathname":"/flutter/tieng-viet/my-reactjs/editors-canvas/editor-commands-history","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Tách command, transaction và Undo/Redo khỏi renderer; kiểm history capacity, generation và giới hạn của model commit khi Canvas hydrate bất đồng bộ.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Editors & Canvas"}]},{"id":"IskswwXCUpV18GyIzvtR","title":"Files & Documents","pathname":"/flutter/tieng-viet/my-reactjs/files-documents","siteSpaceId":"sitesp_ugPNg","lang":"vi","description":"Đọc và export file, citation, autosave, cô lập block lỗi và workflow File Explorer.","breadcrumbs":[{"label":"My ReactJS"}]},{"id":"IfhmCedpKnh1Spd6svM5","title":"Export file lớn từ trình duyệt","pathname":"/flutter/tieng-viet/my-reactjs/files-documents/large-file-exports-browser","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Kiểm response trước khi tải, giới hạn payload giữ ở client và quản lý vòng đời link download trong React.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Files & Documents"}]},{"id":"BThlN7LoAka2BoAJOcl0","title":"Xuất tài liệu từ snapshot","pathname":"/flutter/tieng-viet/my-reactjs/files-documents/document-snapshot-exports","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Chốt snapshot, tách khả năng PDF/DOCX/PNG và sở hữu export job; kiểm bytes, kết quả đến muộn và giới hạn của download request.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Files & Documents"}]},{"id":"YA9FPQT08VlmmDdqvsD8","title":"Đọc file bằng HTTP Range","pathname":"/flutter/tieng-viet/my-reactjs/files-documents/reading-files-http-range","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"file-code","description":"Từ file preview đang tắt Range đến reader kiểm ETag, Content-Range và UTF-8, chỉ công bố nội dung đầy đủ cho đúng vòng đời React.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Files & Documents"}]},{"id":"Byh6zlcYZzVanc6IdnVq","title":"Citation cho Markdown và PDF","pathname":"/flutter/tieng-viet/my-reactjs/files-documents/markdown-pdf-citation-contract","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"file-code","description":"Tách locator khỏi loại file, bind citation vào đúng artifact và hiển thị mức chính xác thực sự của Markdown hoặc PDF trong React.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Files & Documents"}]},{"id":"6b8pmEyKvhXjU2NKgtr3","title":"Autosave khi đổi tài liệu","pathname":"/flutter/tieng-viet/my-reactjs/files-documents/autosave-document-switches","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"file-code","description":"Giữ draft hiện tại qua autosave, kiểm đúng snapshot trước khi đổi tài liệu và phân biệt lưu thành công với kết quả ghi chưa rõ.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Files & Documents"}]},{"id":"Ee68wm3aEkUzgc5WsGdv","title":"Cô lập lỗi từng block","pathname":"/flutter/tieng-viet/my-reactjs/files-documents/isolating-block-errors","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"code","description":"Giữ block lỗi để sửa, bảo vệ cấu trúc document và chỉ cho export khi snapshot thực sự đầy đủ.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Files & Documents"}]},{"id":"m4FYeRIsF6aVfhPF7sum","title":"File Explorer không nhận response cũ","pathname":"/flutter/tieng-viet/my-reactjs/files-documents/file-explorer-upload-pagination","siteSpaceId":"sitesp_ugPNg","lang":"vi","icon":"folder-open","description":"Giữ đúng folder đích khi upload, ghép trang theo context và chặn response cũ khi người dùng đổi thư mục trong React.","breadcrumbs":[{"label":"My ReactJS"},{"label":"Files & Documents"}]}]}