[{"data":1,"prerenderedAt":4009},["ShallowReactive",2],{"navigation_docs":3,"-tu-hoc-database-supabase-interview":420,"-tu-hoc-database-supabase-interview-surround":4004},[4,153],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":26},"Phỏng vấn .NET","i-lucide-briefcase","\u002Fphong-van","1.phong-van",[10,27,66,111,128],{"title":11,"icon":12,"path":13,"stem":14,"children":15,"page":26},"Tổng quan","i-lucide-compass","\u002Fphong-van\u002Ftong-quan","1.phong-van\u002F1.tong-quan",[16,21],{"title":17,"path":18,"stem":19,"icon":20},"Thị trường HCM","\u002Fphong-van\u002Ftong-quan\u002Fthi-truong","1.phong-van\u002F1.tong-quan\u002F1.thi-truong","i-lucide-trending-up",{"title":22,"path":23,"stem":24,"icon":25},"Lộ trình 7 ngày","\u002Fphong-van\u002Ftong-quan\u002Flo-trinh","1.phong-van\u002F1.tong-quan\u002F2.lo-trinh","i-lucide-calendar-days",false,{"title":22,"icon":25,"path":28,"stem":29,"children":30,"page":26},"\u002Fphong-van\u002Flo-trinh","1.phong-van\u002F2.lo-trinh",[31,36,41,46,51,56,61],{"title":32,"path":33,"stem":34,"icon":35},"Ngày 1 — C# cơ bản","\u002Fphong-van\u002Flo-trinh\u002Fngay-1-csharp-co-ban","1.phong-van\u002F2.lo-trinh\u002F1.ngay-1-csharp-co-ban","i-lucide-1",{"title":37,"path":38,"stem":39,"icon":40},"Ngày 2 — OOP và SOLID","\u002Fphong-van\u002Flo-trinh\u002Fngay-2-oop-solid","1.phong-van\u002F2.lo-trinh\u002F2.ngay-2-oop-solid","i-lucide-2",{"title":42,"path":43,"stem":44,"icon":45},"Ngày 3 — C# nâng cao","\u002Fphong-van\u002Flo-trinh\u002Fngay-3-csharp-nang-cao","1.phong-van\u002F2.lo-trinh\u002F3.ngay-3-csharp-nang-cao","i-lucide-3",{"title":47,"path":48,"stem":49,"icon":50},"Ngày 4 — Database và SQL","\u002Fphong-van\u002Flo-trinh\u002Fngay-4-database-sql","1.phong-van\u002F2.lo-trinh\u002F4.ngay-4-database-sql","i-lucide-4",{"title":52,"path":53,"stem":54,"icon":55},"Ngày 5 — ASP.NET Core và EF Core","\u002Fphong-van\u002Flo-trinh\u002Fngay-5-aspnet-efcore","1.phong-van\u002F2.lo-trinh\u002F5.ngay-5-aspnet-efcore","i-lucide-5",{"title":57,"path":58,"stem":59,"icon":60},"Ngày 6 — DSA coding","\u002Fphong-van\u002Flo-trinh\u002Fngay-6-dsa","1.phong-van\u002F2.lo-trinh\u002F6.ngay-6-dsa","i-lucide-6",{"title":62,"path":63,"stem":64,"icon":65},"Ngày 7 — Mock và HR","\u002Fphong-van\u002Flo-trinh\u002Fngay-7-mock-interview","1.phong-van\u002F2.lo-trinh\u002F7.ngay-7-mock-interview","i-lucide-7",{"title":67,"icon":68,"path":69,"stem":70,"children":71,"page":26},"Ngân hàng câu hỏi","i-lucide-database","\u002Fphong-van\u002Fngan-hang-cau-hoi","1.phong-van\u002F3.ngan-hang-cau-hoi",[72,77,82,87,92,97,102,107],{"title":73,"path":74,"stem":75,"icon":76},"C# (60+ câu)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fcsharp","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F1.csharp","i-lucide-hash",{"title":78,"path":79,"stem":80,"icon":81},"OOP và SOLID (40+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Foop","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F2.oop","i-lucide-shapes",{"title":83,"path":84,"stem":85,"icon":86},"SQL (40+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fsql","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F3.sql","i-lucide-database-zap",{"title":88,"path":89,"stem":90,"icon":91},"ASP.NET và EF (50+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Faspnet-ef","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F4.aspnet-ef","i-lucide-server",{"title":93,"path":94,"stem":95,"icon":96},"DSA và Coding (30+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fdsa-coding","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F5.dsa-coding","i-lucide-binary",{"title":98,"path":99,"stem":100,"icon":101},"HR và Soft skill (25+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fhr-behavior","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F6.hr-behavior","i-lucide-users",{"title":103,"path":104,"stem":105,"icon":106},"Design Pattern (55+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fdesign-pattern","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F7.design-pattern","i-lucide-puzzle",{"title":108,"path":109,"stem":110,"icon":91},"ASP.NET MVC và Web API","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Faspnet-mvc-webapi","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F8.aspnet-mvc-webapi",{"title":112,"itle":113,"icon":114,"path":115,"stem":116,"children":117,"page":26},"Tai Lieu","Tài liệu và Cheat sheet","i-lucide-book-marked","\u002Fphong-van\u002Ftai-lieu","1.phong-van\u002F4.tai-lieu",[118,123],{"title":119,"path":120,"stem":121,"icon":122},"Cheat Sheet","\u002Fphong-van\u002Ftai-lieu\u002Fcheatsheet","1.phong-van\u002F4.tai-lieu\u002F1.cheatsheet","i-lucide-clipboard-list",{"title":124,"path":125,"stem":126,"icon":127},"Nguồn tham khảo","\u002Fphong-van\u002Ftai-lieu\u002Fnguon","1.phong-van\u002F4.tai-lieu\u002F2.nguon","i-lucide-link",{"title":129,"icon":130,"path":131,"stem":132,"children":133,"page":26},"Phỏng vấn English","i-lucide-globe","\u002Fphong-van\u002Fenglish-interview","1.phong-van\u002F5.english-interview",[134,138,143,148],{"title":135,"path":136,"stem":137,"icon":130},"Tổng quan English","\u002Fphong-van\u002Fenglish-interview\u002Ftong-quan","1.phong-van\u002F5.english-interview\u002F1.tong-quan",{"title":139,"path":140,"stem":141,"icon":142},"Vocabulary","\u002Fphong-van\u002Fenglish-interview\u002Fvocabulary","1.phong-van\u002F5.english-interview\u002F2.vocabulary","i-lucide-book-a",{"title":144,"path":145,"stem":146,"icon":147},"Technical Q và A (EN)","\u002Fphong-van\u002Fenglish-interview\u002Ftechnical-en","1.phong-van\u002F5.english-interview\u002F3.technical-en","i-lucide-code",{"title":149,"path":150,"stem":151,"icon":152},"Behavioral (EN)","\u002Fphong-van\u002Fenglish-interview\u002Fbehavioral-en","1.phong-van\u002F5.english-interview\u002F4.behavioral-en","i-lucide-message-square-text",{"title":154,"icon":155,"path":156,"stem":157,"children":158},"Tự học","i-lucide-graduation-cap","\u002Ftu-hoc","2.tu-hoc",[159,161,287,310,333,357,384],{"title":154,"path":156,"stem":160,"icon":155},"2.tu-hoc\u002Findex",{"title":162,"icon":68,"path":163,"stem":164,"children":165},"Database","\u002Ftu-hoc\u002Fdatabase","2.tu-hoc\u002F1.database\u002Findex",[166,167,197,222,243,248],{"title":162,"path":163,"stem":164,"icon":68},{"title":168,"icon":91,"path":169,"stem":170,"children":171,"page":26},"SQL Server","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server","2.tu-hoc\u002F1.database\u002F2.sql-server",[172,177,182,187,192],{"title":173,"path":174,"stem":175,"icon":176},"1. Giới thiệu và Cài đặt","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F1.gioi-thieu-cai-dat","i-lucide-play-circle",{"title":178,"path":179,"stem":180,"icon":181},"2. Cú pháp cơ bản","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fcu-phap-co-ban","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F2.cu-phap-co-ban","i-lucide-code-2",{"title":183,"path":184,"stem":185,"icon":186},"3. Truy vấn nâng cao","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Ftruy-van-nang-cao","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F3.truy-van-nang-cao","i-lucide-git-merge",{"title":188,"path":189,"stem":190,"icon":191},"4. Đặc thù và Performance","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fdac-thu-performance","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F4.dac-thu-performance","i-lucide-gauge",{"title":193,"path":194,"stem":195,"icon":196},"5. Q và A phỏng vấn","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fcau-hoi-phong-van","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F5.cau-hoi-phong-van","i-lucide-message-circle-question",{"title":198,"icon":199,"path":200,"stem":201,"children":202,"page":26},"PostgreSQL","i-simple-icons-postgresql","\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql","2.tu-hoc\u002F1.database\u002F3.postgresql",[203,206,209,212,215,218],{"title":173,"path":204,"stem":205,"icon":176},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F1.gioi-thieu-cai-dat",{"title":178,"path":207,"stem":208,"icon":181},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fcu-phap-co-ban","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F2.cu-phap-co-ban",{"title":183,"path":210,"stem":211,"icon":186},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Ftruy-van-nang-cao","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F3.truy-van-nang-cao",{"title":188,"path":213,"stem":214,"icon":191},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fdac-thu-performance","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F4.dac-thu-performance",{"title":193,"path":216,"stem":217,"icon":196},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fcau-hoi-phong-van","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F5.cau-hoi-phong-van",{"title":219,"path":220,"stem":221,"icon":96},"6. Tích hợp C# và Postgres","\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Ftich-hop-csharp","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F6.tich-hop-csharp",{"title":223,"icon":224,"path":225,"stem":226,"children":227,"page":26},"MySQL","i-simple-icons-mysql","\u002Ftu-hoc\u002Fdatabase\u002Fmysql","2.tu-hoc\u002F1.database\u002F4.mysql",[228,231,234,237,240],{"title":173,"path":229,"stem":230,"icon":176},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F1.database\u002F4.mysql\u002F1.gioi-thieu-cai-dat",{"title":178,"path":232,"stem":233,"icon":181},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fcu-phap-co-ban","2.tu-hoc\u002F1.database\u002F4.mysql\u002F2.cu-phap-co-ban",{"title":183,"path":235,"stem":236,"icon":186},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Ftruy-van-nang-cao","2.tu-hoc\u002F1.database\u002F4.mysql\u002F3.truy-van-nang-cao",{"title":188,"path":238,"stem":239,"icon":191},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fdac-thu-performance","2.tu-hoc\u002F1.database\u002F4.mysql\u002F4.dac-thu-performance",{"title":193,"path":241,"stem":242,"icon":196},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fcau-hoi-phong-van","2.tu-hoc\u002F1.database\u002F4.mysql\u002F5.cau-hoi-phong-van",{"title":244,"path":245,"stem":246,"icon":247},"So sánh 3 RDBMS","\u002Ftu-hoc\u002Fdatabase\u002Fso-sanh","2.tu-hoc\u002F1.database\u002F5.so-sanh","i-lucide-columns-3",{"title":249,"path":250,"stem":251,"children":252,"icon":254},"Supabase (BaaS)","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase","2.tu-hoc\u002F1.database\u002F6.supabase\u002Findex",[253,255,259,264,269,274,278,283],{"title":249,"path":250,"stem":251,"icon":254},"i-simple-icons-supabase",{"title":256,"path":257,"stem":258,"icon":68},"1. Database","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fdatabase","2.tu-hoc\u002F1.database\u002F6.supabase\u002F1.database",{"title":260,"path":261,"stem":262,"icon":263},"2. Authentication","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fauthentication","2.tu-hoc\u002F1.database\u002F6.supabase\u002F2.authentication","i-lucide-key",{"title":265,"path":266,"stem":267,"icon":268},"3. Storage & Realtime","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fstorage-realtime","2.tu-hoc\u002F1.database\u002F6.supabase\u002F3.storage-realtime","i-lucide-zap",{"title":270,"path":271,"stem":272,"icon":273},"4. Edge Functions & AI","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Ffunctions-ai","2.tu-hoc\u002F1.database\u002F6.supabase\u002F4.functions-ai","i-lucide-brain",{"title":275,"path":276,"stem":277,"icon":181},"5. API & SDKs","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fapi-sdk","2.tu-hoc\u002F1.database\u002F6.supabase\u002F5.api-sdk",{"title":279,"path":280,"stem":281,"icon":282},"6. Platform & Deploy","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fplatform-deploy","2.tu-hoc\u002F1.database\u002F6.supabase\u002F6.platform-deploy","i-lucide-cloud",{"title":284,"path":285,"stem":286,"icon":196},"7. Interview & Q&A","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Finterview","2.tu-hoc\u002F1.database\u002F6.supabase\u002F7.interview",{"title":288,"icon":289,"path":290,"stem":291,"children":292},"TypeScript","i-simple-icons-typescript","\u002Ftu-hoc\u002Ftypescript","2.tu-hoc\u002F2.typescript\u002Findex",[293,294,297,301,306],{"title":288,"path":290,"stem":291,"icon":289},{"title":173,"path":295,"stem":296,"icon":176},"\u002Ftu-hoc\u002Ftypescript\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F2.typescript\u002F1.gioi-thieu-cai-dat",{"title":298,"path":299,"stem":300,"icon":81},"2. Type System","\u002Ftu-hoc\u002Ftypescript\u002Ftype-system","2.tu-hoc\u002F2.typescript\u002F2.type-system",{"title":302,"path":303,"stem":304,"icon":305},"3. Advanced types","\u002Ftu-hoc\u002Ftypescript\u002Fadvanced-types","2.tu-hoc\u002F2.typescript\u002F3.advanced-types","i-lucide-braces",{"title":307,"path":308,"stem":309,"icon":196},"4. Q và A phỏng vấn","\u002Ftu-hoc\u002Ftypescript\u002Fcau-hoi-phong-van","2.tu-hoc\u002F2.typescript\u002F4.cau-hoi-phong-van",{"title":311,"icon":81,"path":312,"stem":313,"children":314},"OOP","\u002Ftu-hoc\u002Foop","2.tu-hoc\u002F3.oop\u002Findex",[315,316,321,326,330],{"title":311,"path":312,"stem":313,"icon":81},{"title":317,"path":318,"stem":319,"icon":320},"1. Bốn tính chất","\u002Ftu-hoc\u002Foop\u002F4-tinh-chat","2.tu-hoc\u002F3.oop\u002F1.4-tinh-chat","i-lucide-circle-dot",{"title":322,"path":323,"stem":324,"icon":325},"2. SOLID","\u002Ftu-hoc\u002Foop\u002Fsolid","2.tu-hoc\u002F3.oop\u002F2.solid","i-lucide-shield",{"title":327,"path":328,"stem":329,"icon":106},"3. Design Pattern","\u002Ftu-hoc\u002Foop\u002Fdesign-pattern","2.tu-hoc\u002F3.oop\u002F3.design-pattern",{"title":307,"path":331,"stem":332,"icon":196},"\u002Ftu-hoc\u002Foop\u002Fcau-hoi-phong-van","2.tu-hoc\u002F3.oop\u002F4.cau-hoi-phong-van",{"title":334,"icon":305,"path":335,"stem":336,"children":337},"Generic","\u002Ftu-hoc\u002Fgeneric","2.tu-hoc\u002F4.generic\u002Findex",[338,339,344,349,354],{"title":334,"path":335,"stem":336,"icon":305},{"title":340,"path":341,"stem":342,"icon":343},"1. Khái niệm và cú pháp","\u002Ftu-hoc\u002Fgeneric\u002Fkhai-niem","2.tu-hoc\u002F4.generic\u002F1.khai-niem","i-lucide-book",{"title":345,"path":346,"stem":347,"icon":348},"2. Constraint và Variance","\u002Ftu-hoc\u002Fgeneric\u002Fconstraint-variance","2.tu-hoc\u002F4.generic\u002F2.constraint-variance","i-lucide-filter",{"title":350,"path":351,"stem":352,"icon":353},"3. C# vs TS","\u002Ftu-hoc\u002Fgeneric\u002Fso-sanh","2.tu-hoc\u002F4.generic\u002F3.so-sanh","i-lucide-git-compare",{"title":307,"path":355,"stem":356,"icon":196},"\u002Ftu-hoc\u002Fgeneric\u002Fcau-hoi-phong-van","2.tu-hoc\u002F4.generic\u002F4.cau-hoi-phong-van",{"title":358,"icon":359,"path":360,"stem":361,"children":362},"Nuxt 4","i-simple-icons-nuxt","\u002Ftu-hoc\u002Fnuxt-4","2.tu-hoc\u002F5.nuxt-4\u002Findex",[363,364,367,372,376,379],{"title":358,"path":360,"stem":361,"icon":359},{"title":173,"path":365,"stem":366,"icon":176},"\u002Ftu-hoc\u002Fnuxt-4\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F5.nuxt-4\u002F1.gioi-thieu-cai-dat",{"title":368,"path":369,"stem":370,"icon":371},"2. Routing và Rendering","\u002Ftu-hoc\u002Fnuxt-4\u002Frouting-rendering","2.tu-hoc\u002F5.nuxt-4\u002F2.routing-rendering","i-lucide-route",{"title":373,"path":374,"stem":375,"icon":91},"3. Data và Server","\u002Ftu-hoc\u002Fnuxt-4\u002Fdata-server","2.tu-hoc\u002F5.nuxt-4\u002F3.data-server",{"title":307,"path":377,"stem":378,"icon":196},"\u002Ftu-hoc\u002Fnuxt-4\u002Fcau-hoi-phong-van","2.tu-hoc\u002F5.nuxt-4\u002F4.cau-hoi-phong-van",{"title":380,"path":381,"stem":382,"icon":383},"5. Practical Todo App","\u002Ftu-hoc\u002Fnuxt-4\u002Fpractical-todo-app","2.tu-hoc\u002F5.nuxt-4\u002F5.practical-todo-app","i-lucide-check-square",{"title":385,"path":386,"stem":387,"children":388,"icon":390},"Tailwind CSS","\u002Ftu-hoc\u002Ftailwindcss","2.tu-hoc\u002F6.tailwindcss\u002Findex",[389,391,396,401,406,411,416],{"title":385,"path":386,"stem":387,"icon":390},"i-simple-icons-tailwindcss",{"title":392,"path":393,"stem":394,"icon":395},"1. Layout & Spacing","\u002Ftu-hoc\u002Ftailwindcss\u002Flayout-spacing","2.tu-hoc\u002F6.tailwindcss\u002F1.layout-spacing","i-lucide-layout",{"title":397,"path":398,"stem":399,"icon":400},"2. Typography & Colors","\u002Ftu-hoc\u002Ftailwindcss\u002Ftypography-colors","2.tu-hoc\u002F6.tailwindcss\u002F2.typography-colors","i-lucide-type",{"title":402,"path":403,"stem":404,"icon":405},"3. Interactive & Effects","\u002Ftu-hoc\u002Ftailwindcss\u002Finteractive-effects","2.tu-hoc\u002F6.tailwindcss\u002F3.interactive-effects","i-lucide-sparkles",{"title":407,"path":408,"stem":409,"icon":410},"4. Responsive & Dark Mode","\u002Ftu-hoc\u002Ftailwindcss\u002Fresponsive-darkmode","2.tu-hoc\u002F6.tailwindcss\u002F4.responsive-darkmode","i-lucide-monitor-smartphone",{"title":412,"path":413,"stem":414,"icon":415},"5. Customization & Theme","\u002Ftu-hoc\u002Ftailwindcss\u002Fcustomization","2.tu-hoc\u002F6.tailwindcss\u002F5.customization","i-lucide-settings-2",{"title":417,"path":418,"stem":419,"icon":181},"6. Practical Projects","\u002Ftu-hoc\u002Ftailwindcss\u002Fpractical-projects","2.tu-hoc\u002F6.tailwindcss\u002F6.practical-projects",{"id":421,"title":422,"body":423,"description":3997,"extension":3998,"links":3999,"meta":4000,"navigation":4001,"path":285,"seo":4002,"stem":286,"__hash__":4003},"docs\u002F2.tu-hoc\u002F1.database\u002F6.supabase\u002F7.interview.md","Supabase Interview — So sánh, Best Practices, Q&A",{"type":424,"value":425,"toc":3975},"minimark",[426,431,436,628,646,650,774,778,882,886,1086,1089,1093,1096,1109,1179,1183,1204,1246,1249,1259,1283,1286,1299,1349,1353,1359,1427,1467,1471,1513,1517,1684,1686,1690,1694,1699,1709,1714,1742,1748,1752,1762,1767,1801,1861,1868,1872,1878,1888,2601,2607,2611,2621,2650,2665,2816,2826,2830,2895,2900,2927,2931,2935,2938,3027,3033,3037,3129,3134,3160,3164,3167,3172,3216,3227,3232,3268,3273,3281,3288,3292,3423,3428,3436,3440,3449,3454,3486,3564,3570,3574,3578,3581,3618,3623,3637,3641,3692,3696,3702,3739,3744,3755,3759,3889,3895,3899,3949,3951,3963,3965,3971],[427,428,430],"h2",{"id":429},"so-sánh-supabase-vs-các-giải-pháp-khác","So sánh Supabase vs các giải pháp khác",[432,433,435],"h3",{"id":434},"supabase-vs-firebase","Supabase vs Firebase",[437,438,439,455],"table",{},[440,441,442],"thead",{},[443,444,445,449,452],"tr",{},[446,447,448],"th",{},"Tiêu chí",[446,450,451],{},"Supabase",[446,453,454],{},"Firebase",[456,457,458,472,485,498,511,524,537,550,563,576,589,602,615],"tbody",{},[443,459,460,466,469],{},[461,462,463],"td",{},[464,465,162],"strong",{},[461,467,468],{},"PostgreSQL (SQL quan hệ, full-featured)",[461,470,471],{},"Firestore (NoSQL document, limited query)",[443,473,474,479,482],{},[461,475,476],{},[464,477,478],{},"Auth",[461,480,481],{},"Built-in -- JWT, 50+ OAuth providers, MFA, SAML SSO",[461,483,484],{},"Built-in -- Proprietary, nhiều providers, MFA",[443,486,487,492,495],{},[461,488,489],{},[464,490,491],{},"Storage",[461,493,494],{},"S3-compatible, CDN toàn cầu, image transformation",[461,496,497],{},"Google Cloud Storage, CDN",[443,499,500,505,508],{},[461,501,502],{},[464,503,504],{},"Realtime",[461,506,507],{},"WebSocket -- Broadcast, Presence, Postgres Changes (CDC)",[461,509,510],{},"Firestore listeners (proprietary protocol)",[443,512,513,518,521],{},[461,514,515],{},[464,516,517],{},"Functions",[461,519,520],{},"Edge Functions (Deno, TypeScript, global edge)",[461,522,523],{},"Cloud Functions (Node.js, regional)",[443,525,526,531,534],{},[461,527,528],{},[464,529,530],{},"Open-source",[461,532,533],{},"Có -- toàn bộ stack",[461,535,536],{},"Không -- proprietary",[443,538,539,544,547],{},[461,540,541],{},[464,542,543],{},"Self-host",[461,545,546],{},"Có (Docker, Kubernetes)",[461,548,549],{},"Không",[443,551,552,557,560],{},[461,553,554],{},[464,555,556],{},"Free tier",[461,558,559],{},"2 projects, 500MB DB, 50K MAU, 5GB bandwidth",[461,561,562],{},"1GB Firestore, 50K reads\u002Fday, 1GB storage",[443,564,565,570,573],{},[461,566,567],{},[464,568,569],{},"Pricing model",[461,571,572],{},"Theo MAU + storage GB + compute",[461,574,575],{},"Theo reads\u002Fwrites\u002Fdeletes + bandwidth",[443,577,578,583,586],{},[461,579,580],{},[464,581,582],{},"Vector\u002FSearch",[461,584,585],{},"pgvector + hybrid search built-in",[461,587,588],{},"Vector Search (Firestore add-on)",[443,590,591,596,599],{},[461,592,593],{},[464,594,595],{},"API",[461,597,598],{},"REST + GraphQL auto-generated từ schema",[461,600,601],{},"REST + gRPC",[443,603,604,609,612],{},[461,605,606],{},[464,607,608],{},"Vendor lock-in",[461,610,611],{},"Thấp -- PostgreSQL chuẩn, dễ migrate",[461,613,614],{},"Cao -- lock-in Google Cloud ecosystem",[443,616,617,622,625],{},[461,618,619],{},[464,620,621],{},"SQL support",[461,623,624],{},"Đầy đủ PostgreSQL",[461,626,627],{},"Không (NoSQL)",[629,630,633,640],"callout",{"color":631,"icon":632},"warning","i-lucide-lightbulb",[634,635,636,639],"p",{},[464,637,638],{},"Khi nào chọn Supabase?"," Khi bạn cần SQL quan hệ (JOINs, transactions, constraints), muốn open-source và self-host option, đã quen với PostgreSQL, hoặc cần pgvector cho AI apps.",[634,641,642,645],{},[464,643,644],{},"Khi nào chọn Firebase?"," Khi bạn cần NoSQL flexible schema, deep integration với Google Cloud ecosystem, cần Cloud Messaging (FCM) cho push notifications, hoặc ứng dụng mobile-first với Firebase Analytics\u002FCrashlytics.",[432,647,649],{"id":648},"supabase-vs-neon","Supabase vs Neon",[437,651,652,663],{},[440,653,654],{},[443,655,656,658,660],{},[446,657,448],{},[446,659,451],{},[446,661,662],{},"Neon",[456,664,665,678,689,700,711,723,736,748,761],{},[443,666,667,672,675],{},[461,668,669],{},[464,670,671],{},"Database model",[461,673,674],{},"PostgreSQL đầy đủ (managed instance)",[461,676,677],{},"PostgreSQL serverless (branching-first)",[443,679,680,684,687],{},[461,681,682],{},[464,683,478],{},[461,685,686],{},"Built-in (GoTrue)",[461,688,549],{},[443,690,691,695,698],{},[461,692,693],{},[464,694,491],{},[461,696,697],{},"Có (S3-compatible)",[461,699,549],{},[443,701,702,706,709],{},[461,703,704],{},[464,705,504],{},[461,707,708],{},"Có (WebSocket CDC)",[461,710,549],{},[443,712,713,718,721],{},[461,714,715],{},[464,716,717],{},"Edge Functions",[461,719,720],{},"Có (Deno, global edge)",[461,722,549],{},[443,724,725,730,733],{},[461,726,727],{},[464,728,729],{},"Branching",[461,731,732],{},"Preview Branches",[461,734,735],{},"Database Branches (core feature, mạnh hơn)",[443,737,738,742,745],{},[461,739,740],{},[464,741,556],{},[461,743,744],{},"2 projects, 500MB DB, 50K MAU",[461,746,747],{},"0.5GB storage, 1 project",[443,749,750,755,758],{},[461,751,752],{},[464,753,754],{},"Scaling",[461,756,757],{},"Fixed compute sizes (Micro -> 16XL)",[461,759,760],{},"Auto-scaling (serverless)",[443,762,763,768,771],{},[461,764,765],{},[464,766,767],{},"Best for",[461,769,770],{},"Full-stack apps cần auth + DB + storage + realtime",[461,772,773],{},"Database-only, branching workflows, serverless apps",[432,775,777],{"id":776},"supabase-vs-planetscale","Supabase vs PlanetScale",[437,779,780,791],{},[440,781,782],{},[443,783,784,786,788],{},[446,785,448],{},[446,787,451],{},[446,789,790],{},"PlanetScale",[456,792,793,804,815,826,836,847,858,870],{},[443,794,795,799,801],{},[461,796,797],{},[464,798,162],{},[461,800,198],{},[461,802,803],{},"MySQL (Vitess-based, serverless)",[443,805,806,810,813],{},[461,807,808],{},[464,809,478],{},[461,811,812],{},"Built-in",[461,814,549],{},[443,816,817,821,824],{},[461,818,819],{},[464,820,491],{},[461,822,823],{},"Có",[461,825,549],{},[443,827,828,832,834],{},[461,829,830],{},[464,831,504],{},[461,833,823],{},[461,835,549],{},[443,837,838,842,845],{},[461,839,840],{},[464,841,717],{},[461,843,844],{},"Có (Deno)",[461,846,549],{},[443,848,849,853,855],{},[461,850,851],{},[464,852,729],{},[461,854,732],{},[461,856,857],{},"Database Branches (mạnh hơn, deploy request workflow)",[443,859,860,864,867],{},[461,861,862],{},[464,863,556],{},[461,865,866],{},"2 projects, 500MB",[461,868,869],{},"5GB storage, 1 billion row reads\u002Fmonth",[443,871,872,876,879],{},[461,873,874],{},[464,875,767],{},[461,877,878],{},"Full-stack apps",[461,880,881],{},"MySQL-based apps, branching workflows, high-scale reads",[432,883,885],{"id":884},"so-sánh-tổng-hợp-5-nền-tảng","So sánh tổng hợp 5 nền tảng",[437,887,888,905],{},[440,889,890],{},[443,891,892,894,896,898,900,902],{},[446,893],{},[446,895,451],{},[446,897,454],{},[446,899,662],{},[446,901,790],{},[446,903,904],{},"Appwrite",[456,906,907,927,943,961,978,996,1012,1028,1046,1064],{},[443,908,909,913,915,918,921,924],{},[461,910,911],{},[464,912,162],{},[461,914,198],{},[461,916,917],{},"Firestore (NoSQL)",[461,919,920],{},"PostgreSQL (serverless)",[461,922,923],{},"MySQL (Vitess)",[461,925,926],{},"MariaDB",[443,928,929,933,935,937,939,941],{},[461,930,931],{},[464,932,478],{},[461,934,812],{},[461,936,812],{},[461,938,549],{},[461,940,549],{},[461,942,812],{},[443,944,945,949,952,955,957,959],{},[461,946,947],{},[464,948,491],{},[461,950,951],{},"S3",[461,953,954],{},"GCS",[461,956,549],{},[461,958,549],{},[461,960,823],{},[443,962,963,967,970,972,974,976],{},[461,964,965],{},[464,966,504],{},[461,968,969],{},"WebSocket",[461,971,823],{},[461,973,549],{},[461,975,549],{},[461,977,969],{},[443,979,980,984,987,990,992,994],{},[461,981,982],{},[464,983,517],{},[461,985,986],{},"Deno Edge",[461,988,989],{},"Cloud Functions",[461,991,549],{},[461,993,549],{},[461,995,989],{},[443,997,998,1002,1004,1006,1008,1010],{},[461,999,1000],{},[464,1001,530],{},[461,1003,823],{},[461,1005,549],{},[461,1007,549],{},[461,1009,549],{},[461,1011,823],{},[443,1013,1014,1018,1020,1022,1024,1026],{},[461,1015,1016],{},[464,1017,543],{},[461,1019,823],{},[461,1021,549],{},[461,1023,549],{},[461,1025,549],{},[461,1027,823],{},[443,1029,1030,1035,1038,1040,1042,1044],{},[461,1031,1032],{},[464,1033,1034],{},"GraphQL",[461,1036,1037],{},"Có (pg_graphql)",[461,1039,549],{},[461,1041,549],{},[461,1043,549],{},[461,1045,823],{},[443,1047,1048,1053,1056,1058,1060,1062],{},[461,1049,1050],{},[464,1051,1052],{},"Vector Search",[461,1054,1055],{},"pgvector",[461,1057,1052],{},[461,1059,1055],{},[461,1061,549],{},[461,1063,549],{},[443,1065,1066,1071,1074,1077,1080,1083],{},[461,1067,1068],{},[464,1069,1070],{},"Free tier DB",[461,1072,1073],{},"500MB",[461,1075,1076],{},"1GB",[461,1078,1079],{},"0.5GB",[461,1081,1082],{},"5GB",[461,1084,1085],{},"2GB",[1087,1088],"hr",{},[427,1090,1092],{"id":1091},"best-practices-cho-supabase","Best Practices cho Supabase",[432,1094,162],{"id":1095},"database",[629,1097,1100,1103,1104,1108],{"color":1098,"icon":1099},"primary","i-lucide-star",[464,1101,1102],{},"Luôn enable RLS"," trước khi expose bất kỳ bảng nào. RLS policies nên theo nguyên tắc \"least privilege\" -- chỉ grant đúng quyền cần thiết. Dùng ",[1105,1106,1107],"code",{},"auth.uid()"," để lấy user ID từ JWT trong policies.",[1110,1111,1112,1120,1134,1143,1154,1160,1167,1173],"ul",{},[1113,1114,1115,1116,1119],"li",{},"Dùng ",[464,1117,1118],{},"Supavisor transaction mode"," cho serverless apps (Next.js, Nuxt, Lambda) -- mỗi request là một transaction riêng, không giữ connection",[1113,1121,1122,1125,1126,1129,1130,1133],{},[464,1123,1124],{},"Migration-based workflow",": ",[1105,1127,1128],{},"supabase migration new"," -> chỉnh sửa SQL -> ",[1105,1131,1132],{},"supabase db push",". Không sửa schema trực tiếp trên production",[1113,1135,1136,1125,1139,1142],{},[464,1137,1138],{},"Type generation",[1105,1140,1141],{},"supabase gen types typescript"," để có type-safe queries -- phát hiện lỗi schema mismatch ngay khi compile",[1113,1144,1145,1146,1149,1150,1153],{},"Sử dụng ",[464,1147,1148],{},"computed columns"," và ",[464,1151,1152],{},"database views"," thay vì duplicate logic ở client -- giữ business logic gần data",[1113,1155,1156,1159],{},[464,1157,1158],{},"Backup Storage objects riêng"," -- backup của Supabase chỉ cover database, không cover Storage files",[1113,1161,1162,1163,1166],{},"Tạo ",[464,1164,1165],{},"indexes"," cho tất cả columns dùng trong WHERE, JOIN, ORDER BY",[1113,1168,1115,1169,1172],{},[464,1170,1171],{},"pg_stat_statements"," để phân tích slow queries",[1113,1174,1175,1178],{},[464,1176,1177],{},"Read Replicas"," cho read-heavy workloads (Pro plan add-on)",[432,1180,1182],{"id":1181},"authentication","Authentication",[629,1184,1185,1200,1201,1203],{"color":1098,"icon":1099},[464,1186,1187,1188,1191,1192,1195,1196,1199],{},"JWT chứa ",[1105,1189,1190],{},"sub"," (user ID), ",[1105,1193,1194],{},"role"," (authenticated\u002Fanon), và ",[1105,1197,1198],{},"email","."," RLS dùng ",[1105,1202,1107],{}," để extract user ID từ JWT. Service role key bypass RLS -- chỉ dùng trong Edge Functions hoặc backend.",[1110,1205,1206,1216,1222,1228,1234,1240],{},[1113,1207,1115,1208,1211,1212,1215],{},[464,1209,1210],{},"Magic Link"," hoặc ",[464,1213,1214],{},"OAuth"," thay vì password khi có thể -- bảo mật hơn, UX tốt hơn, không cần quản lý password",[1113,1217,1218,1221],{},[464,1219,1220],{},"MFA"," (TOTP) cho ứng dụng nhạy cảm (finance, healthcare)",[1113,1223,1224,1227],{},[464,1225,1226],{},"Auth Hooks"," để customize flow mà không cần tự host GoTrue -- gửi email tùy chỉnh, thêm claims vào JWT",[1113,1229,1230,1233],{},[1105,1231,1232],{},"onAuthStateChange()"," để sync auth state với UI -- handle SIGNED_IN, SIGNED_OUT, TOKEN_REFRESHED events",[1113,1235,1236,1239],{},[464,1237,1238],{},"Custom SMTP"," cho transactional emails -- tránh spam filters, tăng deliverability",[1113,1241,1242,1245],{},[464,1243,1244],{},"CAPTCHA (Turnstile)"," cho auth endpoints để chống bot",[432,1247,504],{"id":1248},"realtime",[629,1250,1251,1254,1255,1258],{"color":1098,"icon":1099},[464,1252,1253],{},"Postgres Changes dùng logical replication của PostgreSQL (WAL)."," Chỉ hoạt động với bảng đã được thêm vào publication ",[1105,1256,1257],{},"supabase_realtime",". Filter server-side để giảm băng thông.",[1110,1260,1261,1268,1274,1280],{},[1113,1262,1263,1264,1267],{},"Enable ",[464,1265,1266],{},"RLS trên bảng subscribed"," để user chỉ nhận events họ được phép xem",[1113,1269,1115,1270,1273],{},[464,1271,1272],{},"Broadcast"," cho ephemeral data (cursor positions, typing indicators) -- không cần persist",[1113,1275,1115,1276,1279],{},[464,1277,1278],{},"Presence"," cho online status tracking -- tự động sync, tự động clean up khi disconnect",[1113,1281,1282],{},"Rate limiting: Free 2 msg\u002Fs, Pro 5 msg\u002Fs -- thiết kế app không spam quá rate limit",[432,1284,717],{"id":1285},"edge-functions",[629,1287,1288,1291,1292,1211,1295,1298],{"color":1098,"icon":1099},[464,1289,1290],{},"Edge Functions dùng Deno, không phải Node.js."," Import từ ",[1105,1293,1294],{},"jsr:",[1105,1296,1297],{},"npm:"," specifiers. Cold starts có thể xảy ra -- thiết kế function ngắn, idempotent. Dùng service role key trong Edge Function để bypass RLS khi cần.",[1110,1300,1301,1307,1317,1323,1329,1335],{},[1113,1302,1303,1306],{},[464,1304,1305],{},"Không bao giờ expose service role key ra client"," -- nó bypass RLS hoàn toàn",[1113,1308,1115,1309,1312,1313,1316],{},[464,1310,1311],{},"Secrets manager"," (",[1105,1314,1315],{},"supabase secrets set",") thay vì hardcode API keys trong code",[1113,1318,1319,1322],{},[464,1320,1321],{},"Background Tasks và Queues"," cho long-running jobs -- Edge Functions có timeout (dưới 10 phút)",[1113,1324,1325,1328],{},[464,1326,1327],{},"CORS"," cần được handle trong function nếu gọi từ browser",[1113,1330,1331,1334],{},[464,1332,1333],{},"Error handling",": trả về meaningful HTTP status codes, không leak internal errors",[1113,1336,1337,1340,1341,1344,1345,1348],{},[464,1338,1339],{},"Logging",": dùng ",[1105,1342,1343],{},"console.log"," \u002F ",[1105,1346,1347],{},"console.error"," trong function, logs sẽ hiển thị trong Dashboard",[432,1350,1352],{"id":1351},"security","Security",[629,1354,1355,1358],{"color":631,"icon":325},[464,1356,1357],{},"Service role key và JWT secret không bao giờ được expose ra client."," Chúng bypass RLS. Chỉ dùng ở backend\u002FEdge Functions. Publishable key (anon key) là key duy nhất safe để dùng ở frontend.",[437,1360,1361,1377],{},[440,1362,1363],{},[443,1364,1365,1368,1371,1374],{},[446,1366,1367],{},"Key",[446,1369,1370],{},"Quyền hạn",[446,1372,1373],{},"Dùng ở đâu",[446,1375,1376],{},"RLS",[456,1378,1379,1395,1411],{},[443,1380,1381,1386,1389,1392],{},[461,1382,1383],{},[464,1384,1385],{},"Publishable key (anon key)",[461,1387,1388],{},"Chỉ truy cập dữ liệu được RLS cho phép",[461,1390,1391],{},"Frontend (safe với RLS)",[461,1393,1394],{},"Tôn trọng RLS",[443,1396,1397,1402,1405,1408],{},[461,1398,1399],{},[464,1400,1401],{},"JWT Secret",[461,1403,1404],{},"Ký custom JWT tokens",[461,1406,1407],{},"Backend\u002FEdge Functions",[461,1409,1410],{},"Tùy thuộc vào JWT claims",[443,1412,1413,1418,1421,1424],{},[461,1414,1415],{},[464,1416,1417],{},"Service role key",[461,1419,1420],{},"Full access, bypass RLS",[461,1422,1423],{},"Backend\u002FEdge Functions, admin tools",[461,1425,1426],{},"Bỏ qua RLS",[1110,1428,1429,1435,1438,1444,1450,1455,1461],{},[1113,1430,1431,1432,1434],{},"Luôn enable ",[464,1433,1376],{}," cho tất cả public tables -- đây là lớp bảo mật quan trọng nhất",[1113,1436,1437],{},"Revoke unnecessary grants -- mặc định grants có thể quá rộng",[1113,1439,1115,1440,1443],{},[464,1441,1442],{},"Column Level Security"," cho dữ liệu nhạy cảm (email, phone)",[1113,1445,1446,1449],{},[464,1447,1448],{},"CAPTCHA"," (Turnstile) cho auth endpoints",[1113,1451,1452,1454],{},[464,1453,1238],{}," cho transactional emails (tránh spam filters)",[1113,1456,1457,1460],{},[464,1458,1459],{},"Rate limiting"," trên auth endpoints qua Kong gateway config",[1113,1462,1463,1466],{},[464,1464,1465],{},"SSL enforcement"," bắt buộc trên production",[432,1468,1470],{"id":1469},"performance","Performance",[1110,1472,1473,1479,1485,1490,1496,1501,1507],{},[1113,1474,1115,1475,1478],{},[464,1476,1477],{},"connection pooling"," (Supavisor transaction mode) -- luôn dùng cho serverless",[1113,1480,1481,1484],{},[464,1482,1483],{},"Indexes",": Tạo index cho columns dùng trong WHERE, JOIN, ORDER BY",[1113,1486,1487,1489],{},[464,1488,1171],{},": Phân tích top slow queries",[1113,1491,1492,1495],{},[464,1493,1494],{},"EXPLAIN ANALYZE",": Test query performance trước khi deploy",[1113,1497,1498,1500],{},[464,1499,1177],{},": Phân tán read load (Pro plan add-on)",[1113,1502,1503,1506],{},[464,1504,1505],{},"Caching",": Storage CDN cache cho static files, Edge Function response caching",[1113,1508,1509,1512],{},[464,1510,1511],{},"Compute sizing",": Chọn compute phù hợp -- đừng dùng Micro cho production AI workloads",[432,1514,1516],{"id":1515},"development-workflow","Development Workflow",[1518,1519,1524],"pre",{"className":1520,"code":1521,"language":1522,"meta":1523,"style":1523},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# 1. Khởi tạo local project\nsupabase init\n\n# 2. Start local development (cần Docker)\nsupabase start\n\n# 3. Tạo migration cho thay đổi schema\nsupabase migration new add_users_table\n\n# 4. Code và test local\nsupabase functions serve\n\n# 5. Generate TypeScript types từ schema local\nsupabase gen types typescript --local > types\u002Fsupabase.ts\n\n# 6. Push lên production\nsupabase db push\nsupabase functions deploy my-function\n","bash","",[1105,1525,1526,1535,1546,1553,1559,1567,1572,1578,1592,1597,1603,1614,1619,1625,1649,1654,1660,1671],{"__ignoreMap":1523},[1527,1528,1531],"span",{"class":1529,"line":1530},"line",1,[1527,1532,1534],{"class":1533},"sHwdD","# 1. Khởi tạo local project\n",[1527,1536,1538,1542],{"class":1529,"line":1537},2,[1527,1539,1541],{"class":1540},"sBMFI","supabase",[1527,1543,1545],{"class":1544},"sfazB"," init\n",[1527,1547,1549],{"class":1529,"line":1548},3,[1527,1550,1552],{"emptyLinePlaceholder":1551},true,"\n",[1527,1554,1556],{"class":1529,"line":1555},4,[1527,1557,1558],{"class":1533},"# 2. Start local development (cần Docker)\n",[1527,1560,1562,1564],{"class":1529,"line":1561},5,[1527,1563,1541],{"class":1540},[1527,1565,1566],{"class":1544}," start\n",[1527,1568,1570],{"class":1529,"line":1569},6,[1527,1571,1552],{"emptyLinePlaceholder":1551},[1527,1573,1575],{"class":1529,"line":1574},7,[1527,1576,1577],{"class":1533},"# 3. Tạo migration cho thay đổi schema\n",[1527,1579,1581,1583,1586,1589],{"class":1529,"line":1580},8,[1527,1582,1541],{"class":1540},[1527,1584,1585],{"class":1544}," migration",[1527,1587,1588],{"class":1544}," new",[1527,1590,1591],{"class":1544}," add_users_table\n",[1527,1593,1595],{"class":1529,"line":1594},9,[1527,1596,1552],{"emptyLinePlaceholder":1551},[1527,1598,1600],{"class":1529,"line":1599},10,[1527,1601,1602],{"class":1533},"# 4. Code và test local\n",[1527,1604,1606,1608,1611],{"class":1529,"line":1605},11,[1527,1607,1541],{"class":1540},[1527,1609,1610],{"class":1544}," functions",[1527,1612,1613],{"class":1544}," serve\n",[1527,1615,1617],{"class":1529,"line":1616},12,[1527,1618,1552],{"emptyLinePlaceholder":1551},[1527,1620,1622],{"class":1529,"line":1621},13,[1527,1623,1624],{"class":1533},"# 5. Generate TypeScript types từ schema local\n",[1527,1626,1628,1630,1633,1636,1639,1642,1646],{"class":1529,"line":1627},14,[1527,1629,1541],{"class":1540},[1527,1631,1632],{"class":1544}," gen",[1527,1634,1635],{"class":1544}," types",[1527,1637,1638],{"class":1544}," typescript",[1527,1640,1641],{"class":1544}," --local",[1527,1643,1645],{"class":1644},"sMK4o"," >",[1527,1647,1648],{"class":1544}," types\u002Fsupabase.ts\n",[1527,1650,1652],{"class":1529,"line":1651},15,[1527,1653,1552],{"emptyLinePlaceholder":1551},[1527,1655,1657],{"class":1529,"line":1656},16,[1527,1658,1659],{"class":1533},"# 6. Push lên production\n",[1527,1661,1663,1665,1668],{"class":1529,"line":1662},17,[1527,1664,1541],{"class":1540},[1527,1666,1667],{"class":1544}," db",[1527,1669,1670],{"class":1544}," push\n",[1527,1672,1674,1676,1678,1681],{"class":1529,"line":1673},18,[1527,1675,1541],{"class":1540},[1527,1677,1610],{"class":1544},[1527,1679,1680],{"class":1544}," deploy",[1527,1682,1683],{"class":1544}," my-function\n",[1087,1685],{},[427,1687,1689],{"id":1688},"_15-câu-hỏi-phỏng-vấn-supabase","15+ Câu hỏi phỏng vấn Supabase",[432,1691,1693],{"id":1692},"cơ-bản","Cơ bản",[1695,1696,1698],"h4",{"id":1697},"_1-supabase-là-gì-khác-firebase-ở-điểm-nào","1. Supabase là gì? Khác Firebase ở điểm nào?",[634,1700,1701,1702,1705,1706,1708],{},"Supabase là ",[464,1703,1704],{},"open-source Backend-as-a-Service (BaaS)"," xây dựng trên nền ",[464,1707,198],{},". Nó cung cấp database, authentication, storage, realtime, edge functions, và AI\u002Fvector capabilities -- tất cả tích hợp chặt chẽ với nhau.",[634,1710,1711],{},[464,1712,1713],{},"Khác biệt cốt lõi với Firebase:",[1110,1715,1716,1721,1726,1731,1736],{},[1113,1717,1718,1720],{},[464,1719,162],{},": PostgreSQL (SQL quan hệ, JOINs, transactions, constraints, 70+ extensions) vs Firestore (NoSQL document, limited query, no JOINs)",[1113,1722,1723,1725],{},[464,1724,530],{},": Toàn bộ stack của Supabase là open-source, có thể self-host. Firebase hoàn toàn proprietary",[1113,1727,1728,1730],{},[464,1729,608],{},": Supabase dùng PostgreSQL chuẩn -- bạn có thể migrate sang bất kỳ Postgres provider nào. Firebase lock-in Google Cloud",[1113,1732,1733,1735],{},[464,1734,595],{},": Supabase auto-generate REST + GraphQL từ schema. Firebase cần viết Cloud Functions hoặc dùng Firestore SDK",[1113,1737,1738,1741],{},[464,1739,1740],{},"Pricing",": Supabase tính theo MAU + storage, Firebase tính theo operations (reads\u002Fwrites\u002Fdeletes)",[629,1743,1744,1747],{"color":1098,"icon":1099},[464,1745,1746],{},"Key point:"," Supabase cho phép bạn dùng tất cả sức mạnh của PostgreSQL (CTE, window functions, triggers, extensions, full-text search, materialized views) trong khi Firebase giới hạn bạn trong Firestore's query model.",[1695,1749,1751],{"id":1750},"_2-rls-trong-supabase-hoạt-động-như-thế-nào","2. RLS trong Supabase hoạt động như thế nào?",[634,1753,1754,1757,1758,1761],{},[464,1755,1756],{},"Row Level Security (RLS)"," là cơ chế bảo mật ở cấp hàng dữ liệu trong PostgreSQL. Nó cho phép bạn định nghĩa ",[464,1759,1760],{},"policies"," để kiểm soát user nào được đọc\u002Fghi hàng nào.",[634,1763,1764],{},[464,1765,1766],{},"Cách hoạt động:",[1768,1769,1770,1778,1785,1795,1798],"ol",{},[1113,1771,1772,1773,1775,1776],{},"User login -> Supabase Auth tạo JWT chứa ",[1105,1774,1190],{}," (user ID) và ",[1105,1777,1194],{},[1113,1779,1780,1781,1784],{},"Client gửi request kèm JWT trong ",[1105,1782,1783],{},"Authorization"," header",[1113,1786,1787,1788,1790,1791,1794],{},"PostgREST set ",[1105,1789,1107],{}," = user ID từ JWT, ",[1105,1792,1793],{},"auth.role()"," = role từ JWT",[1113,1796,1797],{},"PostgreSQL kiểm tra RLS policies trước khi thực thi query",[1113,1799,1800],{},"Nếu policy không cho phép -> row bị lọc khỏi kết quả (SELECT) hoặc query bị reject (INSERT\u002FUPDATE\u002FDELETE)",[1518,1802,1806],{"className":1803,"code":1804,"language":1805,"meta":1523,"style":1523},"language-sql shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","-- Ví dụ: user chỉ xem được post của chính mình\nALTER TABLE posts ENABLE ROW LEVEL SECURITY;\n\nCREATE POLICY \"Users can view own posts\"\nON posts FOR SELECT\nUSING (auth.uid() = user_id);\n\n-- Policy cho insert: user chỉ tạo post với user_id của chính mình\nCREATE POLICY \"Users can create own posts\"\nON posts FOR INSERT\nWITH CHECK (auth.uid() = user_id);\n","sql",[1105,1807,1808,1813,1818,1822,1827,1832,1837,1841,1846,1851,1856],{"__ignoreMap":1523},[1527,1809,1810],{"class":1529,"line":1530},[1527,1811,1812],{},"-- Ví dụ: user chỉ xem được post của chính mình\n",[1527,1814,1815],{"class":1529,"line":1537},[1527,1816,1817],{},"ALTER TABLE posts ENABLE ROW LEVEL SECURITY;\n",[1527,1819,1820],{"class":1529,"line":1548},[1527,1821,1552],{"emptyLinePlaceholder":1551},[1527,1823,1824],{"class":1529,"line":1555},[1527,1825,1826],{},"CREATE POLICY \"Users can view own posts\"\n",[1527,1828,1829],{"class":1529,"line":1561},[1527,1830,1831],{},"ON posts FOR SELECT\n",[1527,1833,1834],{"class":1529,"line":1569},[1527,1835,1836],{},"USING (auth.uid() = user_id);\n",[1527,1838,1839],{"class":1529,"line":1574},[1527,1840,1552],{"emptyLinePlaceholder":1551},[1527,1842,1843],{"class":1529,"line":1580},[1527,1844,1845],{},"-- Policy cho insert: user chỉ tạo post với user_id của chính mình\n",[1527,1847,1848],{"class":1529,"line":1594},[1527,1849,1850],{},"CREATE POLICY \"Users can create own posts\"\n",[1527,1852,1853],{"class":1529,"line":1599},[1527,1854,1855],{},"ON posts FOR INSERT\n",[1527,1857,1858],{"class":1529,"line":1605},[1527,1859,1860],{},"WITH CHECK (auth.uid() = user_id);\n",[629,1862,1864,1867],{"color":631,"icon":1863},"i-lucide-shield-alert",[464,1865,1866],{},"Service role key bypass RLS hoàn toàn."," Chỉ dùng service role ở backend\u002FEdge Functions. Publishable key (anon key) luôn đi qua RLS.",[1695,1869,1871],{"id":1870},"_3-làm-thế-nào-để-bảo-vệ-api-key-khi-gọi-openai-từ-frontend","3. Làm thế nào để bảo vệ API key khi gọi OpenAI từ frontend?",[634,1873,1874,1877],{},[464,1875,1876],{},"Không bao giờ gọi OpenAI trực tiếp từ frontend."," API key sẽ bị expose trong network tab.",[634,1879,1880,1883,1884,1887],{},[464,1881,1882],{},"Giải pháp đúng",": Dùng ",[464,1885,1886],{},"Edge Function"," làm proxy:",[1518,1889,1893],{"className":1890,"code":1891,"language":1892,"meta":1523,"style":1523},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F supabase\u002Ffunctions\u002Fchat\u002Findex.ts\nimport { createClient } from 'jsr:@supabase\u002Fsupabase-js@2'\n\nconst OPENAI_API_KEY = Deno.env.get('OPENAI_API_KEY')! \u002F\u002F Secret, không expose\n\nDeno.serve(async (req: Request) => {\n  const { message } = await req.json()\n\n  \u002F\u002F Verify user authentication\n  const supabase = createClient(\n    Deno.env.get('SUPABASE_URL')!,\n    Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!\n  )\n  const token = req.headers.get('Authorization')?.replace('Bearer ', '')\n  const { data: { user }, error } = await supabase.auth.getUser(token)\n  if (error || !user) {\n    return new Response('Unauthorized', { status: 401 })\n  }\n\n  \u002F\u002F Gọi OpenAI với API key từ secrets\n  const response = await fetch('https:\u002F\u002Fapi.openai.com\u002Fv1\u002Fchat\u002Fcompletions', {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application\u002Fjson',\n      'Authorization': `Bearer ${OPENAI_API_KEY}`\n    },\n    body: JSON.stringify({\n      model: 'gpt-4o',\n      messages: [{ role: 'user', content: message }]\n    })\n  })\n\n  const data = await response.json()\n  return new Response(JSON.stringify(data), {\n    headers: { 'Content-Type': 'application\u002Fjson' }\n  })\n})\n","typescript",[1105,1894,1895,1900,1928,1932,1978,1982,2017,2047,2051,2056,2070,2097,2123,2128,2182,2229,2254,2290,2295,2300,2306,2334,2352,2362,2384,2408,2414,2434,2451,2490,2498,2506,2511,2530,2560,2586,2593],{"__ignoreMap":1523},[1527,1896,1897],{"class":1529,"line":1530},[1527,1898,1899],{"class":1533},"\u002F\u002F supabase\u002Ffunctions\u002Fchat\u002Findex.ts\n",[1527,1901,1902,1906,1909,1913,1916,1919,1922,1925],{"class":1529,"line":1537},[1527,1903,1905],{"class":1904},"s7zQu","import",[1527,1907,1908],{"class":1644}," {",[1527,1910,1912],{"class":1911},"sTEyZ"," createClient",[1527,1914,1915],{"class":1644}," }",[1527,1917,1918],{"class":1904}," from",[1527,1920,1921],{"class":1644}," '",[1527,1923,1924],{"class":1544},"jsr:@supabase\u002Fsupabase-js@2",[1527,1926,1927],{"class":1644},"'\n",[1527,1929,1930],{"class":1529,"line":1548},[1527,1931,1552],{"emptyLinePlaceholder":1551},[1527,1933,1934,1938,1941,1944,1947,1949,1952,1954,1958,1961,1964,1967,1969,1972,1975],{"class":1529,"line":1555},[1527,1935,1937],{"class":1936},"spNyl","const",[1527,1939,1940],{"class":1911}," OPENAI_API_KEY ",[1527,1942,1943],{"class":1644},"=",[1527,1945,1946],{"class":1911}," Deno",[1527,1948,1199],{"class":1644},[1527,1950,1951],{"class":1911},"env",[1527,1953,1199],{"class":1644},[1527,1955,1957],{"class":1956},"s2Zo4","get",[1527,1959,1960],{"class":1911},"(",[1527,1962,1963],{"class":1644},"'",[1527,1965,1966],{"class":1544},"OPENAI_API_KEY",[1527,1968,1963],{"class":1644},[1527,1970,1971],{"class":1911},")",[1527,1973,1974],{"class":1644},"!",[1527,1976,1977],{"class":1533}," \u002F\u002F Secret, không expose\n",[1527,1979,1980],{"class":1529,"line":1561},[1527,1981,1552],{"emptyLinePlaceholder":1551},[1527,1983,1984,1987,1989,1992,1994,1997,1999,2003,2006,2009,2011,2014],{"class":1529,"line":1569},[1527,1985,1986],{"class":1911},"Deno",[1527,1988,1199],{"class":1644},[1527,1990,1991],{"class":1956},"serve",[1527,1993,1960],{"class":1911},[1527,1995,1996],{"class":1936},"async",[1527,1998,1312],{"class":1644},[1527,2000,2002],{"class":2001},"sHdIc","req",[1527,2004,2005],{"class":1644},":",[1527,2007,2008],{"class":1540}," Request",[1527,2010,1971],{"class":1644},[1527,2012,2013],{"class":1936}," =>",[1527,2015,2016],{"class":1644}," {\n",[1527,2018,2019,2022,2024,2027,2029,2032,2035,2038,2040,2043],{"class":1529,"line":1574},[1527,2020,2021],{"class":1936},"  const",[1527,2023,1908],{"class":1644},[1527,2025,2026],{"class":1911}," message",[1527,2028,1915],{"class":1644},[1527,2030,2031],{"class":1644}," =",[1527,2033,2034],{"class":1904}," await",[1527,2036,2037],{"class":1911}," req",[1527,2039,1199],{"class":1644},[1527,2041,2042],{"class":1956},"json",[1527,2044,2046],{"class":2045},"swJcz","()\n",[1527,2048,2049],{"class":1529,"line":1580},[1527,2050,1552],{"emptyLinePlaceholder":1551},[1527,2052,2053],{"class":1529,"line":1594},[1527,2054,2055],{"class":1533},"  \u002F\u002F Verify user authentication\n",[1527,2057,2058,2060,2063,2065,2067],{"class":1529,"line":1599},[1527,2059,2021],{"class":1936},[1527,2061,2062],{"class":1911}," supabase",[1527,2064,2031],{"class":1644},[1527,2066,1912],{"class":1956},[1527,2068,2069],{"class":2045},"(\n",[1527,2071,2072,2075,2077,2079,2081,2083,2085,2087,2090,2092,2094],{"class":1529,"line":1605},[1527,2073,2074],{"class":1911},"    Deno",[1527,2076,1199],{"class":1644},[1527,2078,1951],{"class":1911},[1527,2080,1199],{"class":1644},[1527,2082,1957],{"class":1956},[1527,2084,1960],{"class":2045},[1527,2086,1963],{"class":1644},[1527,2088,2089],{"class":1544},"SUPABASE_URL",[1527,2091,1963],{"class":1644},[1527,2093,1971],{"class":2045},[1527,2095,2096],{"class":1644},"!,\n",[1527,2098,2099,2101,2103,2105,2107,2109,2111,2113,2116,2118,2120],{"class":1529,"line":1616},[1527,2100,2074],{"class":1911},[1527,2102,1199],{"class":1644},[1527,2104,1951],{"class":1911},[1527,2106,1199],{"class":1644},[1527,2108,1957],{"class":1956},[1527,2110,1960],{"class":2045},[1527,2112,1963],{"class":1644},[1527,2114,2115],{"class":1544},"SUPABASE_SERVICE_ROLE_KEY",[1527,2117,1963],{"class":1644},[1527,2119,1971],{"class":2045},[1527,2121,2122],{"class":1644},"!\n",[1527,2124,2125],{"class":1529,"line":1621},[1527,2126,2127],{"class":2045},"  )\n",[1527,2129,2130,2132,2135,2137,2139,2141,2144,2146,2148,2150,2152,2154,2156,2158,2161,2164,2166,2168,2171,2173,2176,2179],{"class":1529,"line":1627},[1527,2131,2021],{"class":1936},[1527,2133,2134],{"class":1911}," token",[1527,2136,2031],{"class":1644},[1527,2138,2037],{"class":1911},[1527,2140,1199],{"class":1644},[1527,2142,2143],{"class":1911},"headers",[1527,2145,1199],{"class":1644},[1527,2147,1957],{"class":1956},[1527,2149,1960],{"class":2045},[1527,2151,1963],{"class":1644},[1527,2153,1783],{"class":1544},[1527,2155,1963],{"class":1644},[1527,2157,1971],{"class":2045},[1527,2159,2160],{"class":1644},"?.",[1527,2162,2163],{"class":1956},"replace",[1527,2165,1960],{"class":2045},[1527,2167,1963],{"class":1644},[1527,2169,2170],{"class":1544},"Bearer ",[1527,2172,1963],{"class":1644},[1527,2174,2175],{"class":1644},",",[1527,2177,2178],{"class":1644}," ''",[1527,2180,2181],{"class":2045},")\n",[1527,2183,2184,2186,2188,2191,2193,2195,2198,2201,2204,2206,2208,2210,2212,2214,2217,2219,2222,2224,2227],{"class":1529,"line":1651},[1527,2185,2021],{"class":1936},[1527,2187,1908],{"class":1644},[1527,2189,2190],{"class":2045}," data",[1527,2192,2005],{"class":1644},[1527,2194,1908],{"class":1644},[1527,2196,2197],{"class":1911}," user",[1527,2199,2200],{"class":1644}," },",[1527,2202,2203],{"class":1911}," error",[1527,2205,1915],{"class":1644},[1527,2207,2031],{"class":1644},[1527,2209,2034],{"class":1904},[1527,2211,2062],{"class":1911},[1527,2213,1199],{"class":1644},[1527,2215,2216],{"class":1911},"auth",[1527,2218,1199],{"class":1644},[1527,2220,2221],{"class":1956},"getUser",[1527,2223,1960],{"class":2045},[1527,2225,2226],{"class":1911},"token",[1527,2228,2181],{"class":2045},[1527,2230,2231,2234,2236,2239,2242,2245,2248,2251],{"class":1529,"line":1656},[1527,2232,2233],{"class":1904},"  if",[1527,2235,1312],{"class":2045},[1527,2237,2238],{"class":1911},"error",[1527,2240,2241],{"class":1644}," ||",[1527,2243,2244],{"class":1644}," !",[1527,2246,2247],{"class":1911},"user",[1527,2249,2250],{"class":2045},") ",[1527,2252,2253],{"class":1644},"{\n",[1527,2255,2256,2259,2261,2264,2266,2268,2271,2273,2275,2277,2280,2282,2286,2288],{"class":1529,"line":1662},[1527,2257,2258],{"class":1904},"    return",[1527,2260,1588],{"class":1644},[1527,2262,2263],{"class":1956}," Response",[1527,2265,1960],{"class":2045},[1527,2267,1963],{"class":1644},[1527,2269,2270],{"class":1544},"Unauthorized",[1527,2272,1963],{"class":1644},[1527,2274,2175],{"class":1644},[1527,2276,1908],{"class":1644},[1527,2278,2279],{"class":2045}," status",[1527,2281,2005],{"class":1644},[1527,2283,2285],{"class":2284},"sbssI"," 401",[1527,2287,1915],{"class":1644},[1527,2289,2181],{"class":2045},[1527,2291,2292],{"class":1529,"line":1673},[1527,2293,2294],{"class":1644},"  }\n",[1527,2296,2298],{"class":1529,"line":2297},19,[1527,2299,1552],{"emptyLinePlaceholder":1551},[1527,2301,2303],{"class":1529,"line":2302},20,[1527,2304,2305],{"class":1533},"  \u002F\u002F Gọi OpenAI với API key từ secrets\n",[1527,2307,2309,2311,2314,2316,2318,2321,2323,2325,2328,2330,2332],{"class":1529,"line":2308},21,[1527,2310,2021],{"class":1936},[1527,2312,2313],{"class":1911}," response",[1527,2315,2031],{"class":1644},[1527,2317,2034],{"class":1904},[1527,2319,2320],{"class":1956}," fetch",[1527,2322,1960],{"class":2045},[1527,2324,1963],{"class":1644},[1527,2326,2327],{"class":1544},"https:\u002F\u002Fapi.openai.com\u002Fv1\u002Fchat\u002Fcompletions",[1527,2329,1963],{"class":1644},[1527,2331,2175],{"class":1644},[1527,2333,2016],{"class":1644},[1527,2335,2337,2340,2342,2344,2347,2349],{"class":1529,"line":2336},22,[1527,2338,2339],{"class":2045},"    method",[1527,2341,2005],{"class":1644},[1527,2343,1921],{"class":1644},[1527,2345,2346],{"class":1544},"POST",[1527,2348,1963],{"class":1644},[1527,2350,2351],{"class":1644},",\n",[1527,2353,2355,2358,2360],{"class":1529,"line":2354},23,[1527,2356,2357],{"class":2045},"    headers",[1527,2359,2005],{"class":1644},[1527,2361,2016],{"class":1644},[1527,2363,2365,2368,2371,2373,2375,2377,2380,2382],{"class":1529,"line":2364},24,[1527,2366,2367],{"class":1644},"      '",[1527,2369,2370],{"class":2045},"Content-Type",[1527,2372,1963],{"class":1644},[1527,2374,2005],{"class":1644},[1527,2376,1921],{"class":1644},[1527,2378,2379],{"class":1544},"application\u002Fjson",[1527,2381,1963],{"class":1644},[1527,2383,2351],{"class":1644},[1527,2385,2387,2389,2391,2393,2395,2398,2400,2403,2405],{"class":1529,"line":2386},25,[1527,2388,2367],{"class":1644},[1527,2390,1783],{"class":2045},[1527,2392,1963],{"class":1644},[1527,2394,2005],{"class":1644},[1527,2396,2397],{"class":1644}," `",[1527,2399,2170],{"class":1544},[1527,2401,2402],{"class":1644},"${",[1527,2404,1966],{"class":1911},[1527,2406,2407],{"class":1644},"}`\n",[1527,2409,2411],{"class":1529,"line":2410},26,[1527,2412,2413],{"class":1644},"    },\n",[1527,2415,2417,2420,2422,2425,2427,2430,2432],{"class":1529,"line":2416},27,[1527,2418,2419],{"class":2045},"    body",[1527,2421,2005],{"class":1644},[1527,2423,2424],{"class":1911}," JSON",[1527,2426,1199],{"class":1644},[1527,2428,2429],{"class":1956},"stringify",[1527,2431,1960],{"class":2045},[1527,2433,2253],{"class":1644},[1527,2435,2437,2440,2442,2444,2447,2449],{"class":1529,"line":2436},28,[1527,2438,2439],{"class":2045},"      model",[1527,2441,2005],{"class":1644},[1527,2443,1921],{"class":1644},[1527,2445,2446],{"class":1544},"gpt-4o",[1527,2448,1963],{"class":1644},[1527,2450,2351],{"class":1644},[1527,2452,2454,2457,2459,2462,2465,2468,2470,2472,2474,2476,2478,2481,2483,2485,2487],{"class":1529,"line":2453},29,[1527,2455,2456],{"class":2045},"      messages",[1527,2458,2005],{"class":1644},[1527,2460,2461],{"class":2045}," [",[1527,2463,2464],{"class":1644},"{",[1527,2466,2467],{"class":2045}," role",[1527,2469,2005],{"class":1644},[1527,2471,1921],{"class":1644},[1527,2473,2247],{"class":1544},[1527,2475,1963],{"class":1644},[1527,2477,2175],{"class":1644},[1527,2479,2480],{"class":2045}," content",[1527,2482,2005],{"class":1644},[1527,2484,2026],{"class":1911},[1527,2486,1915],{"class":1644},[1527,2488,2489],{"class":2045},"]\n",[1527,2491,2493,2496],{"class":1529,"line":2492},30,[1527,2494,2495],{"class":1644},"    }",[1527,2497,2181],{"class":2045},[1527,2499,2501,2504],{"class":1529,"line":2500},31,[1527,2502,2503],{"class":1644},"  }",[1527,2505,2181],{"class":2045},[1527,2507,2509],{"class":1529,"line":2508},32,[1527,2510,1552],{"emptyLinePlaceholder":1551},[1527,2512,2514,2516,2518,2520,2522,2524,2526,2528],{"class":1529,"line":2513},33,[1527,2515,2021],{"class":1936},[1527,2517,2190],{"class":1911},[1527,2519,2031],{"class":1644},[1527,2521,2034],{"class":1904},[1527,2523,2313],{"class":1911},[1527,2525,1199],{"class":1644},[1527,2527,2042],{"class":1956},[1527,2529,2046],{"class":2045},[1527,2531,2533,2536,2538,2540,2542,2545,2547,2549,2551,2554,2556,2558],{"class":1529,"line":2532},34,[1527,2534,2535],{"class":1904},"  return",[1527,2537,1588],{"class":1644},[1527,2539,2263],{"class":1956},[1527,2541,1960],{"class":2045},[1527,2543,2544],{"class":1911},"JSON",[1527,2546,1199],{"class":1644},[1527,2548,2429],{"class":1956},[1527,2550,1960],{"class":2045},[1527,2552,2553],{"class":1911},"data",[1527,2555,1971],{"class":2045},[1527,2557,2175],{"class":1644},[1527,2559,2016],{"class":1644},[1527,2561,2563,2565,2567,2569,2571,2573,2575,2577,2579,2581,2583],{"class":1529,"line":2562},35,[1527,2564,2357],{"class":2045},[1527,2566,2005],{"class":1644},[1527,2568,1908],{"class":1644},[1527,2570,1921],{"class":1644},[1527,2572,2370],{"class":2045},[1527,2574,1963],{"class":1644},[1527,2576,2005],{"class":1644},[1527,2578,1921],{"class":1644},[1527,2580,2379],{"class":1544},[1527,2582,1963],{"class":1644},[1527,2584,2585],{"class":1644}," }\n",[1527,2587,2589,2591],{"class":1529,"line":2588},36,[1527,2590,2503],{"class":1644},[1527,2592,2181],{"class":2045},[1527,2594,2596,2599],{"class":1529,"line":2595},37,[1527,2597,2598],{"class":1644},"}",[1527,2600,2181],{"class":1911},[629,2602,2603,2606],{"color":1098,"icon":1099},[464,2604,2605],{},"Pattern chuẩn:"," Edge Function xác thực user (qua JWT) -> kiểm tra rate limit\u002Fquota -> gọi third-party API với secret key -> trả kết quả về client. API key không bao giờ rời khỏi server.",[1695,2608,2610],{"id":2609},"_4-postgres-changes-cdc-hoạt-động-thế-nào","4. Postgres Changes (CDC) hoạt động thế nào?",[634,2612,2613,2616,2617,2620],{},[464,2614,2615],{},"Postgres Changes"," dùng ",[464,2618,2619],{},"logical replication"," của PostgreSQL (WAL -- Write-Ahead Log):",[1768,2622,2623,2626,2632,2635],{},[1113,2624,2625],{},"Khi có INSERT\u002FUPDATE\u002FDELETE, PostgreSQL ghi thay đổi vào WAL",[1113,2627,2628,2629,2631],{},"Publication ",[1105,2630,1257],{}," lắng nghe WAL cho các bảng được đăng ký",[1113,2633,2634],{},"Supabase Realtime server đọc WAL records và broadcast qua WebSocket đến subscribed clients",[1113,2636,2637,2638,2641,2642,2645,2646,2649],{},"Client nhận payload với ",[1105,2639,2640],{},"eventType",", ",[1105,2643,2644],{},"new"," (row mới), ",[1105,2647,2648],{},"old"," (row cũ -- cho UPDATE\u002FDELETE)",[1518,2651,2653],{"className":1803,"code":2652,"language":1805,"meta":1523,"style":1523},"-- Đăng ký bảng vào realtime publication\nALTER PUBLICATION supabase_realtime ADD TABLE messages;\n",[1105,2654,2655,2660],{"__ignoreMap":1523},[1527,2656,2657],{"class":1529,"line":1530},[1527,2658,2659],{},"-- Đăng ký bảng vào realtime publication\n",[1527,2661,2662],{"class":1529,"line":1537},[1527,2663,2664],{},"ALTER PUBLICATION supabase_realtime ADD TABLE messages;\n",[1518,2666,2670],{"className":2667,"code":2668,"language":2669,"meta":1523,"style":1523},"language-javascript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F Client subscribe\nsupabase.channel('db-changes')\n  .on('postgres_changes',\n    { event: 'INSERT', schema: 'public', table: 'messages' },\n    (payload) => console.log('New message:', payload.new)\n  )\n  .subscribe()\n","javascript",[1105,2671,2672,2677,2697,2716,2764,2803,2807],{"__ignoreMap":1523},[1527,2673,2674],{"class":1529,"line":1530},[1527,2675,2676],{"class":1533},"\u002F\u002F Client subscribe\n",[1527,2678,2679,2681,2683,2686,2688,2690,2693,2695],{"class":1529,"line":1537},[1527,2680,1541],{"class":1911},[1527,2682,1199],{"class":1644},[1527,2684,2685],{"class":1956},"channel",[1527,2687,1960],{"class":1911},[1527,2689,1963],{"class":1644},[1527,2691,2692],{"class":1544},"db-changes",[1527,2694,1963],{"class":1644},[1527,2696,2181],{"class":1911},[1527,2698,2699,2702,2705,2707,2709,2712,2714],{"class":1529,"line":1548},[1527,2700,2701],{"class":1644},"  .",[1527,2703,2704],{"class":1956},"on",[1527,2706,1960],{"class":1911},[1527,2708,1963],{"class":1644},[1527,2710,2711],{"class":1544},"postgres_changes",[1527,2713,1963],{"class":1644},[1527,2715,2351],{"class":1644},[1527,2717,2718,2721,2724,2726,2728,2731,2733,2735,2738,2740,2742,2745,2747,2749,2752,2754,2756,2759,2761],{"class":1529,"line":1555},[1527,2719,2720],{"class":1644},"    {",[1527,2722,2723],{"class":2045}," event",[1527,2725,2005],{"class":1644},[1527,2727,1921],{"class":1644},[1527,2729,2730],{"class":1544},"INSERT",[1527,2732,1963],{"class":1644},[1527,2734,2175],{"class":1644},[1527,2736,2737],{"class":2045}," schema",[1527,2739,2005],{"class":1644},[1527,2741,1921],{"class":1644},[1527,2743,2744],{"class":1544},"public",[1527,2746,1963],{"class":1644},[1527,2748,2175],{"class":1644},[1527,2750,2751],{"class":2045}," table",[1527,2753,2005],{"class":1644},[1527,2755,1921],{"class":1644},[1527,2757,2758],{"class":1544},"messages",[1527,2760,1963],{"class":1644},[1527,2762,2763],{"class":1644}," },\n",[1527,2765,2766,2769,2772,2774,2776,2779,2781,2784,2786,2788,2791,2793,2795,2798,2800],{"class":1529,"line":1561},[1527,2767,2768],{"class":1644},"    (",[1527,2770,2771],{"class":2001},"payload",[1527,2773,1971],{"class":1644},[1527,2775,2013],{"class":1936},[1527,2777,2778],{"class":1911}," console",[1527,2780,1199],{"class":1644},[1527,2782,2783],{"class":1956},"log",[1527,2785,1960],{"class":1911},[1527,2787,1963],{"class":1644},[1527,2789,2790],{"class":1544},"New message:",[1527,2792,1963],{"class":1644},[1527,2794,2175],{"class":1644},[1527,2796,2797],{"class":1911}," payload",[1527,2799,1199],{"class":1644},[1527,2801,2802],{"class":1911},"new)\n",[1527,2804,2805],{"class":1529,"line":1569},[1527,2806,2127],{"class":1911},[1527,2808,2809,2811,2814],{"class":1529,"line":1574},[1527,2810,2701],{"class":1644},[1527,2812,2813],{"class":1956},"subscribe",[1527,2815,2046],{"class":1911},[629,2817,2818,2819,1312,2822,2825],{"color":1098,"icon":1099},"Filter được thực thi ",[464,2820,2821],{},"server-side",[1105,2823,2824],{},"filter: 'room_id=eq.123'","), giúp giảm băng thông -- client chỉ nhận events phù hợp. Kết hợp với RLS để đảm bảo user chỉ nhận events từ dữ liệu họ được phép xem.",[1695,2827,2829],{"id":2828},"_5-khi-nào-dùng-broadcast-vs-presence-vs-postgres-changes","5. Khi nào dùng Broadcast vs Presence vs Postgres Changes?",[437,2831,2832,2848],{},[440,2833,2834],{},[443,2835,2836,2839,2842,2845],{},[446,2837,2838],{},"Chế độ",[446,2840,2841],{},"Dùng khi",[446,2843,2844],{},"Dữ liệu",[446,2846,2847],{},"Ví dụ",[456,2849,2850,2865,2880],{},[443,2851,2852,2856,2859,2862],{},[461,2853,2854],{},[464,2855,2615],{},[461,2857,2858],{},"Cần sync dữ liệu đã persist vào database",[461,2860,2861],{},"Persistent, authoritative",[461,2863,2864],{},"Live feed, dashboard, collaborative docs",[443,2866,2867,2871,2874,2877],{},[461,2868,2869],{},[464,2870,1272],{},[461,2872,2873],{},"Cần gửi message realtime không cần persist",[461,2875,2876],{},"Ephemeral, low-latency",[461,2878,2879],{},"Chat messages, cursor tracking, game events",[443,2881,2882,2886,2889,2892],{},[461,2883,2884],{},[464,2885,1278],{},[461,2887,2888],{},"Cần theo dõi trạng thái online của user",[461,2890,2891],{},"Ephemeral, automatically cleaned up",[461,2893,2894],{},"Online users list, \"ai đang typing\", active participants",[634,2896,2897],{},[464,2898,2899],{},"Nguyên tắc chọn:",[1110,2901,2902,2909,2920],{},[1113,2903,2904,2905,2908],{},"Nếu dữ liệu cần ",[464,2906,2907],{},"lưu lại"," -> Postgres Changes",[1113,2910,2911,2912,2915,2916,2919],{},"Nếu dữ liệu là ",[464,2913,2914],{},"tạm thời",", cần ",[464,2917,2918],{},"low latency"," -> Broadcast",[1113,2921,2922,2923,2926],{},"Nếu cần biết ",[464,2924,2925],{},"ai đang online"," -> Presence",[432,2928,2930],{"id":2929},"trung-cấp","Trung cấp",[1695,2932,2934],{"id":2933},"_6-supabase-auth-flow-sign-up-email-verify-jwt-rls","6. Supabase Auth flow: sign up -> email verify -> JWT -> RLS",[634,2936,2937],{},"Toàn bộ flow auth trong Supabase:",[1768,2939,2940,2953,2962,2982,2988,3001,3018],{},[1113,2941,2942,2945,2946,2949,2950,1971],{},[464,2943,2944],{},"Sign Up",": User gửi email + password -> GoTrue tạo user trong ",[1105,2947,2948],{},"auth.users"," (status: ",[1105,2951,2952],{},"unconfirmed",[1113,2954,2955,2958,2959],{},[464,2956,2957],{},"Email Verify",": GoTrue gửi email xác nhận (qua SMTP của bạn hoặc Supabase default) -> User click link -> status chuyển thành ",[1105,2960,2961],{},"confirmed",[1113,2963,2964,2967,2968,2970,2971,1312,2973,2976,2977,2641,2979],{},[464,2965,2966],{},"Sign In",": User gửi email + password -> GoTrue verify -> Tạo JWT với claims: ",[1105,2969,1190],{}," (user UUID), ",[1105,2972,1194],{},[1105,2974,2975],{},"authenticated","), ",[1105,2978,1198],{},[1105,2980,2981],{},"aud",[1113,2983,2984,2987],{},[464,2985,2986],{},"Client lưu JWT",": localStorage (web) hoặc secure storage (mobile). Supabase client tự động attach JWT vào mọi request",[1113,2989,2990,2993,2994,2997,2998],{},[464,2991,2992],{},"API Request",": Client gọi ",[1105,2995,2996],{},"supabase.from('posts').select()"," -> JWT gửi trong ",[1105,2999,3000],{},"Authorization: Bearer [JWT]",[1113,3002,3003,3006,3007,3009,3010,3012,3013,3009,3015,3017],{},[464,3004,3005],{},"PostgREST",": Set ",[1105,3008,1107],{}," = ",[1105,3011,1190],{}," từ JWT, ",[1105,3014,1793],{},[1105,3016,1194],{}," từ JWT",[1113,3019,3020,3023,3024,3026],{},[464,3021,3022],{},"RLS Check",": PostgreSQL check policies dùng ",[1105,3025,1107],{}," -> chỉ trả về rows user được phép xem",[629,3028,3029,3032],{"color":1098,"icon":1099},[464,3030,3031],{},"Điểm mạnh của Supabase Auth:"," Tích hợp chặt với Database qua RLS. Bạn không cần viết middleware authorization -- policies ở database level đảm bảo bảo mật ngay cả khi gọi API trực tiếp.",[1695,3034,3036],{"id":3035},"_7-supavisor-session-mode-vs-transaction-mode","7. Supavisor session mode vs transaction mode?",[437,3038,3039,3051],{},[440,3040,3041],{},[443,3042,3043,3045,3048],{},[446,3044],{},[446,3046,3047],{},"Session Mode",[446,3049,3050],{},"Transaction Mode",[456,3052,3053,3066,3079,3090,3103,3116],{},[443,3054,3055,3060,3063],{},[461,3056,3057],{},[464,3058,3059],{},"Connection",[461,3061,3062],{},"Giữ connection suốt session",[461,3064,3065],{},"Mỗi transaction lấy connection mới",[443,3067,3068,3073,3076],{},[461,3069,3070],{},[464,3071,3072],{},"Prepared Statements",[461,3074,3075],{},"Hỗ trợ",[461,3077,3078],{},"Không hỗ trợ",[443,3080,3081,3086,3088],{},[461,3082,3083],{},[464,3084,3085],{},"Advisory Locks",[461,3087,3075],{},[461,3089,3078],{},[443,3091,3092,3097,3100],{},[461,3093,3094],{},[464,3095,3096],{},"SET statements",[461,3098,3099],{},"Persist trong session",[461,3101,3102],{},"Reset sau mỗi transaction",[443,3104,3105,3110,3113],{},[461,3106,3107],{},[464,3108,3109],{},"Serverless apps",[461,3111,3112],{},"Có thể cạn pool",[461,3114,3115],{},"Tối ưu",[443,3117,3118,3123,3126],{},[461,3119,3120],{},[464,3121,3122],{},"Port",[461,3124,3125],{},"6543",[461,3127,3128],{},"5432",[634,3130,3131],{},[464,3132,3133],{},"Khuyến nghị:",[1110,3135,3136,3145,3154],{},[1113,3137,3138,1883,3141,3144],{},[464,3139,3140],{},"Serverless (Next.js, Nuxt, Lambda)",[464,3142,3143],{},"transaction mode"," -- mỗi request là một transaction, pool hiệu quả hơn",[1113,3146,3147,1883,3150,3153],{},[464,3148,3149],{},"Long-running apps (Express, traditional servers)",[464,3151,3152],{},"session mode"," nếu cần prepared statements hoặc advisory locks",[1113,3155,3156,3159],{},[464,3157,3158],{},"Direct connection"," (port 5432): Cho ORMs, database tools, migrations",[1695,3161,3163],{"id":3162},"_8-làm-sao-migrate-từ-firebase-sang-supabase","8. Làm sao migrate từ Firebase sang Supabase?",[634,3165,3166],{},"Quy trình migration Firebase -> Supabase gồm 3 phần:",[634,3168,3169],{},[464,3170,3171],{},"1. Auth Migration:",[1518,3173,3175],{"className":1520,"code":3174,"language":1522,"meta":1523,"style":1523},"# Export Firebase users (bao gồm password hash parameters)\nnode firestoreusers2json.js users.json 100\n\n# Import vào Supabase Auth (giữ nguyên password hash)\nnode import_users.js users.json 100\n",[1105,3176,3177,3182,3196,3200,3205],{"__ignoreMap":1523},[1527,3178,3179],{"class":1529,"line":1530},[1527,3180,3181],{"class":1533},"# Export Firebase users (bao gồm password hash parameters)\n",[1527,3183,3184,3187,3190,3193],{"class":1529,"line":1537},[1527,3185,3186],{"class":1540},"node",[1527,3188,3189],{"class":1544}," firestoreusers2json.js",[1527,3191,3192],{"class":1544}," users.json",[1527,3194,3195],{"class":2284}," 100\n",[1527,3197,3198],{"class":1529,"line":1548},[1527,3199,1552],{"emptyLinePlaceholder":1551},[1527,3201,3202],{"class":1529,"line":1555},[1527,3203,3204],{"class":1533},"# Import vào Supabase Auth (giữ nguyên password hash)\n",[1527,3206,3207,3209,3212,3214],{"class":1529,"line":1561},[1527,3208,3186],{"class":1540},[1527,3210,3211],{"class":1544}," import_users.js",[1527,3213,3192],{"class":1544},[1527,3215,3195],{"class":2284},[1110,3217,3218,3221],{},[1113,3219,3220],{},"Giữ Firebase password hash parameters (scrypt config) để user không cần reset password",[1113,3222,3223,3224],{},"Map Firebase UID sang Supabase ",[1105,3225,3226],{},"auth.users.id",[634,3228,3229],{},[464,3230,3231],{},"2. Firestore Migration:",[1110,3233,3234,3237,3243,3249],{},[1113,3235,3236],{},"Export Firestore collections ra JSON",[1113,3238,3239,3242],{},[464,3240,3241],{},"Thiết kế lại schema"," -- \"flatten\" nested documents thành relational tables với foreign keys",[1113,3244,3245,3246],{},"Import vào Postgres bằng script ",[1105,3247,3248],{},"json2supabase.js",[1113,3250,3251,3252,3255,3256,3259,3260,3263,3264,3267],{},"Ví dụ: ",[1105,3253,3254],{},"posts\u002F{postId}\u002Fcomments\u002F{commentId}"," -> bảng ",[1105,3257,3258],{},"posts"," và bảng ",[1105,3261,3262],{},"comments"," với ",[1105,3265,3266],{},"post_id"," FK",[634,3269,3270],{},[464,3271,3272],{},"3. Storage Migration:",[1110,3274,3275,3278],{},[1113,3276,3277],{},"Download files từ Firebase Storage -> Upload lên Supabase Storage",[1113,3279,3280],{},"Map metadata và access controls sang RLS policies",[629,3282,3284,3287],{"color":631,"icon":3283},"i-lucide-alert-triangle",[464,3285,3286],{},"Thách thức lớn nhất:"," Chuyển từ NoSQL document model sang SQL relational model. Nested subcollections trong Firestore cần được tách thành các bảng riêng. Không có cách \"tự động\" hoàn hảo -- cần hiểu data model để thiết kế schema phù hợp.",[1695,3289,3291],{"id":3290},"_9-edge-functions-vs-traditional-backend","9. Edge Functions vs traditional backend?",[437,3293,3294,3306],{},[440,3295,3296],{},[443,3297,3298,3300,3303],{},[446,3299],{},[446,3301,3302],{},"Edge Functions (Supabase)",[446,3304,3305],{},"Traditional Backend (Express, FastAPI)",[456,3307,3308,3321,3334,3347,3360,3373,3385,3397,3410],{},[443,3309,3310,3315,3318],{},[461,3311,3312],{},[464,3313,3314],{},"Runtime",[461,3316,3317],{},"Deno (TypeScript native)",[461,3319,3320],{},"Node.js, Python, Go, etc.",[443,3322,3323,3328,3331],{},[461,3324,3325],{},[464,3326,3327],{},"Deployment",[461,3329,3330],{},"Global edge (gần user)",[461,3332,3333],{},"Regional server",[443,3335,3336,3341,3344],{},[461,3337,3338],{},[464,3339,3340],{},"Cold start",[461,3342,3343],{},"Có (vài ms đến vài trăm ms)",[461,3345,3346],{},"Không (luôn warm nếu dùng server)",[443,3348,3349,3354,3357],{},[461,3350,3351],{},[464,3352,3353],{},"Timeout",[461,3355,3356],{},"Giới hạn (vài phút)",[461,3358,3359],{},"Không giới hạn thực tế",[443,3361,3362,3367,3370],{},[461,3363,3364],{},[464,3365,3366],{},"State",[461,3368,3369],{},"Stateless",[461,3371,3372],{},"Có thể stateful",[443,3374,3375,3379,3382],{},[461,3376,3377],{},[464,3378,754],{},[461,3380,3381],{},"Tự động",[461,3383,3384],{},"Manual hoặc auto-scaling config",[443,3386,3387,3391,3394],{},[461,3388,3389],{},[464,3390,767],{},[461,3392,3393],{},"Webhooks, API proxies, lightweight logic",[461,3395,3396],{},"Complex business logic, long-running tasks, stateful apps",[443,3398,3399,3404,3407],{},[461,3400,3401],{},[464,3402,3403],{},"Database access",[461,3405,3406],{},"Qua supabase-js với service role",[461,3408,3409],{},"Direct connection hoặc ORM",[443,3411,3412,3417,3420],{},[461,3413,3414],{},[464,3415,3416],{},"Cost",[461,3418,3419],{},"Tính theo invocation",[461,3421,3422],{},"Tính theo server uptime",[634,3424,3425],{},[464,3426,3427],{},"Quy tắc chọn:",[1110,3429,3430,3433],{},[1113,3431,3432],{},"Edge Functions: webhook receivers, API key proxying (OpenAI, Stripe), lightweight transforms, sending emails",[1113,3434,3435],{},"Traditional backend: complex workflows, long-running jobs (video processing), stateful sessions, legacy integrations",[1695,3437,3439],{"id":3438},"_10-pgvector-trong-supabase-dùng-cho-gì","10. pgvector trong Supabase dùng cho gì?",[634,3441,3442,3444,3445,3448],{},[464,3443,1055],{}," là PostgreSQL extension cho phép lưu và query ",[464,3446,3447],{},"vector embeddings"," ngay trong database:",[634,3450,3451],{},[464,3452,3453],{},"Use cases chính:",[1110,3455,3456,3462,3468,3474,3480],{},[1113,3457,3458,3461],{},[464,3459,3460],{},"Semantic Search",": Tìm kiếm theo ý nghĩa, không phải keyword chính xác (FAQ, documentation)",[1113,3463,3464,3467],{},[464,3465,3466],{},"RAG (Retrieval Augmented Generation)",": Cung cấp context cho LLM từ knowledge base",[1113,3469,3470,3473],{},[464,3471,3472],{},"Recommendations",": Gợi ý sản phẩm\u002Fbài viết tương tự dựa trên embeddings",[1113,3475,3476,3479],{},[464,3477,3478],{},"Image\u002FVideo Search",": Tìm kiếm đa phương tiện bằng vector similarity",[1113,3481,3482,3485],{},[464,3483,3484],{},"Anomaly Detection",": Phát hiện bất thường bằng distance metrics",[1518,3487,3489],{"className":1803,"code":3488,"language":1805,"meta":1523,"style":1523},"-- Tạo bảng với vector column\nCREATE TABLE documents (\n  id BIGSERIAL PRIMARY KEY,\n  content TEXT,\n  embedding VECTOR(1536) -- OpenAI ada-002 embedding dimension\n);\n\n-- Tạo HNSW index cho fast approximate search\nCREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops);\n\n-- Similarity search\nSELECT content, 1 - (embedding \u003C=> query_embedding) AS similarity\nFROM documents\nORDER BY embedding \u003C=> query_embedding\nLIMIT 5;\n",[1105,3490,3491,3496,3501,3506,3511,3516,3521,3525,3530,3535,3539,3544,3549,3554,3559],{"__ignoreMap":1523},[1527,3492,3493],{"class":1529,"line":1530},[1527,3494,3495],{},"-- Tạo bảng với vector column\n",[1527,3497,3498],{"class":1529,"line":1537},[1527,3499,3500],{},"CREATE TABLE documents (\n",[1527,3502,3503],{"class":1529,"line":1548},[1527,3504,3505],{},"  id BIGSERIAL PRIMARY KEY,\n",[1527,3507,3508],{"class":1529,"line":1555},[1527,3509,3510],{},"  content TEXT,\n",[1527,3512,3513],{"class":1529,"line":1561},[1527,3514,3515],{},"  embedding VECTOR(1536) -- OpenAI ada-002 embedding dimension\n",[1527,3517,3518],{"class":1529,"line":1569},[1527,3519,3520],{},");\n",[1527,3522,3523],{"class":1529,"line":1574},[1527,3524,1552],{"emptyLinePlaceholder":1551},[1527,3526,3527],{"class":1529,"line":1580},[1527,3528,3529],{},"-- Tạo HNSW index cho fast approximate search\n",[1527,3531,3532],{"class":1529,"line":1594},[1527,3533,3534],{},"CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops);\n",[1527,3536,3537],{"class":1529,"line":1599},[1527,3538,1552],{"emptyLinePlaceholder":1551},[1527,3540,3541],{"class":1529,"line":1605},[1527,3542,3543],{},"-- Similarity search\n",[1527,3545,3546],{"class":1529,"line":1616},[1527,3547,3548],{},"SELECT content, 1 - (embedding \u003C=> query_embedding) AS similarity\n",[1527,3550,3551],{"class":1529,"line":1621},[1527,3552,3553],{},"FROM documents\n",[1527,3555,3556],{"class":1529,"line":1627},[1527,3557,3558],{},"ORDER BY embedding \u003C=> query_embedding\n",[1527,3560,3561],{"class":1529,"line":1651},[1527,3562,3563],{},"LIMIT 5;\n",[629,3565,3566,3569],{"color":1098,"icon":1099},[464,3567,3568],{},"Lợi thế của pgvector",": Embeddings và data gốc nằm trong cùng một database. Không cần sync giữa vector DB và application DB. RLS áp dụng cho cả vector search -- user chỉ search được documents họ có quyền truy cập.",[432,3571,3573],{"id":3572},"nâng-cao","Nâng cao",[1695,3575,3577],{"id":3576},"_11-tại-sao-nên-dùng-supabase-thay-vì-tự-build-backend","11. Tại sao nên dùng Supabase thay vì tự build backend?",[634,3579,3580],{},"Supabase phù hợp khi:",[1110,3582,3583,3589,3595,3601,3607,3612],{},[1113,3584,3585,3588],{},[464,3586,3587],{},"Team nhỏ"," (1-5 developers), muốn ship nhanh -- không có thời gian build auth, storage, realtime từ đầu",[1113,3590,3591,3594],{},[464,3592,3593],{},"MVP\u002FPOC",": Cần validate idea trong vài ngày\u002Ftuần -- Supabase cho phép có full backend trong vài giờ",[1113,3596,3597,3600],{},[464,3598,3599],{},"PostgreSQL là lựa chọn đúng",": Bạn cần SQL quan hệ, không phải NoSQL",[1113,3602,3603,3606],{},[464,3604,3605],{},"Cần auth + database tích hợp chặt",": RLS + JWT = authorization tự động không cần viết middleware",[1113,3608,3609],{},[464,3610,3611],{},"Dự án open-source hoặc muốn tránh vendor lock-in",[1113,3613,3614,3617],{},[464,3615,3616],{},"Cần realtime capabilities",": Postgres Changes, Broadcast, Presence có sẵn",[634,3619,3620],{},[464,3621,3622],{},"Không nên dùng Supabase khi:",[1110,3624,3625,3628,3631,3634],{},[1113,3626,3627],{},"Cần kiểm soát hoàn toàn infrastructure và kiến trúc",[1113,3629,3630],{},"Có team backend mạnh, đã có sẵn boilerplate\u002Fauth system",[1113,3632,3633],{},"Yêu cầu compliance đặc thù không được Supabase hỗ trợ",[1113,3635,3636],{},"High-frequency trading hoặc systems cần microsecond latency",[1695,3638,3640],{"id":3639},"_12-storage-trong-supabase-có-gì-đặc-biệt","12. Storage trong Supabase có gì đặc biệt?",[1110,3642,3643,3649,3659,3665,3671,3677,3683],{},[1113,3644,3645,3648],{},[464,3646,3647],{},"S3-compatible API",": Tương thích với mọi S3 client library",[1113,3650,3651,3654,3655,3658],{},[464,3652,3653],{},"RLS tích hợp",": Cùng cơ chế bảo mật với database -- ",[1105,3656,3657],{},"storage.objects"," policies",[1113,3660,3661,3664],{},[464,3662,3663],{},"CDN toàn cầu",": Phục vụ file từ 285+ thành phố",[1113,3666,3667,3670],{},[464,3668,3669],{},"Image Transformation",": Resize, compress, format conversion qua URL parameters (không cần xử lý server-side)",[1113,3672,3673,3676],{},[464,3674,3675],{},"TUS Resumable Uploads",": Upload file lớn với pause\u002Fresume",[1113,3678,3679,3682],{},[464,3680,3681],{},"Signed URLs",": Temporary access links với expiration",[1113,3684,3685,3688,3689,3691],{},[464,3686,3687],{},"Metadata trong Postgres",": Mọi file metadata được lưu trong bảng ",[1105,3690,3657],{},", có thể JOIN với data khác",[1695,3693,3695],{"id":3694},"_13-supabase-có-scale-được-không","13. Supabase có scale được không?",[634,3697,3698,3701],{},[464,3699,3700],{},"Có."," Supabase scale theo nhiều chiều:",[1110,3703,3704,3710,3716,3722,3727,3733],{},[1113,3705,3706,3709],{},[464,3707,3708],{},"Vertical scaling",": Compute add-ons từ Micro (2-core, 1GB) đến 16XL (64-core, 256GB)",[1113,3711,3712,3715],{},[464,3713,3714],{},"Horizontal scaling (reads)",": Read Replicas trên Pro plan",[1113,3717,3718,3721],{},[464,3719,3720],{},"Connection pooling",": Supavisor quản lý hàng nghìn connections hiệu quả",[1113,3723,3724,3726],{},[464,3725,717],{},": Tự động scale theo request volume trên edge network toàn cầu",[1113,3728,3729,3732],{},[464,3730,3731],{},"Storage CDN",": File được cache và phục vụ từ edge gần user nhất",[1113,3734,3735,3738],{},[464,3736,3737],{},"Disk",": General Purpose lên đến 16TB, High Performance lên đến 80,000 IOPS",[634,3740,3741],{},[464,3742,3743],{},"Giới hạn cần lưu ý:",[1110,3745,3746,3749,3752],{},[1113,3747,3748],{},"PostgreSQL là single-writer -- write throughput có giới hạn",[1113,3750,3751],{},"Realtime connections: Free 200, Pro 500 concurrent (có thể tăng)",[1113,3753,3754],{},"Edge Functions timeout (vài phút) -- không phù hợp cho long-running jobs",[1695,3756,3758],{"id":3757},"_14-self-host-vs-managed-proscons","14. Self-host vs Managed -- pros\u002Fcons?",[437,3760,3761,3773],{},[440,3762,3763],{},[443,3764,3765,3767,3770],{},[446,3766],{},[446,3768,3769],{},"Managed Supabase",[446,3771,3772],{},"Self-Hosted",[456,3774,3775,3788,3801,3814,3826,3838,3850,3863,3876],{},[443,3776,3777,3782,3785],{},[461,3778,3779],{},[464,3780,3781],{},"Setup time",[461,3783,3784],{},"Vài phút",[461,3786,3787],{},"Vài giờ đến vài ngày",[443,3789,3790,3795,3798],{},[461,3791,3792],{},[464,3793,3794],{},"Maintenance",[461,3796,3797],{},"Supabase lo",[461,3799,3800],{},"Bạn lo",[443,3802,3803,3808,3811],{},[461,3804,3805],{},[464,3806,3807],{},"Backups",[461,3809,3810],{},"Tự động daily + PITR",[461,3812,3813],{},"Tự cấu hình",[443,3815,3816,3820,3823],{},[461,3817,3818],{},[464,3819,754],{},[461,3821,3822],{},"Click upgrade compute",[461,3824,3825],{},"Tự provision server",[443,3827,3828,3833,3835],{},[461,3829,3830],{},[464,3831,3832],{},"Updates",[461,3834,3381],{},[461,3836,3837],{},"Tự cập nhật",[443,3839,3840,3844,3847],{},[461,3841,3842],{},[464,3843,3416],{},[461,3845,3846],{},"$0-$25\u002Ftháng (start)",[461,3848,3849],{},"Server cost + thời gian vận hành",[443,3851,3852,3857,3860],{},[461,3853,3854],{},[464,3855,3856],{},"Data control",[461,3858,3859],{},"Trên cloud của Supabase",[461,3861,3862],{},"Trên infrastructure của bạn",[443,3864,3865,3870,3873],{},[461,3866,3867],{},[464,3868,3869],{},"Compliance",[461,3871,3872],{},"SOC2, HIPAA (add-on)",[461,3874,3875],{},"Tự đáp ứng",[443,3877,3878,3883,3886],{},[461,3879,3880],{},[464,3881,3882],{},"Missing features",[461,3884,3885],{},"Đầy đủ",[461,3887,3888],{},"Không có Branching, Analytics Buckets, Vector Buckets, Log Drains, Pipelines",[629,3890,3891,3894],{"color":1098,"icon":1099},[464,3892,3893],{},"Rule of thumb:"," Start với managed (free tier) để validate product. Chỉ self-host khi có yêu cầu đặc thù về data sovereignty, compliance, hoặc team có DevOps mạnh.",[1695,3896,3898],{"id":3897},"_15-khi-nào-không-nên-dùng-supabase","15. Khi nào KHÔNG nên dùng Supabase?",[1768,3900,3901,3907,3913,3919,3925,3931,3937,3943],{},[1113,3902,3903,3906],{},[464,3904,3905],{},"Bạn cần NoSQL",": Dữ liệu unstructured, schema thay đổi liên tục, không cần JOINs\u002Ftransactions -> Firebase hoặc MongoDB phù hợp hơn",[1113,3908,3909,3912],{},[464,3910,3911],{},"High-frequency trading \u002F Gaming server",": Cần microsecond latency, in-memory state -> Dùng Redis, custom C++\u002FRust server",[1113,3914,3915,3918],{},[464,3916,3917],{},"Đã có team backend mạnh + hệ thống auth\u002Fstorage sẵn",": Không cần BaaS -> chỉ dùng PostgreSQL managed service (RDS, Neon)",[1113,3920,3921,3924],{},[464,3922,3923],{},"Yêu cầu compliance đặc thù",": On-premise only, air-gapped networks, FIPS 140-2 -> Cần enterprise solutions",[1113,3926,3927,3930],{},[464,3928,3929],{},"Cần push notifications (FCM\u002FAPNs)",": Supabase không có push notification service -> Cần Firebase Cloud Messaging hoặc third-party",[1113,3932,3933,3936],{},[464,3934,3935],{},"Time-series data ở scale lớn",": PostgreSQL có thể handle, nhưng TimescaleDB hoặc InfluxDB tối ưu hơn",[1113,3938,3939,3942],{},[464,3940,3941],{},"Cần full-text search engine cấp enterprise",": PostgreSQL full-text search tốt nhưng không bằng Elasticsearch\u002FAlgolia cho scale rất lớn",[1113,3944,3945,3948],{},[464,3946,3947],{},"Budget siêu hạn chế + traffic cao",": Firebase pricing có thể rẻ hơn cho app có nhiều reads nhưng ít users do tính theo operations",[1087,3950],{},[629,3952,3955,3958,3959,3962],{"color":3953,"icon":3954},"success","i-lucide-rocket",[464,3956,3957],{},"Tổng kết:"," Supabase là lựa chọn tuyệt vời cho hầu hết ứng dụng web\u002Fmobile hiện đại. Với PostgreSQL làm nền tảng, bạn có đầy đủ sức mạnh của SQL quan hệ cộng với Auth, Storage, Realtime, và Edge Functions tích hợp sẵn. Điểm mạnh nhất là ",[464,3960,3961],{},"RLS tích hợp Auth + Database"," -- authorization tự động không cần viết middleware. Hạn chế lớn nhất là PostgreSQL là single-writer -- không phù hợp cho write-heavy workloads ở scale cực lớn nếu không có kế hoạch sharding.",[1087,3964],{},[3966,3967],"navigation",{":next":3968,":prev":3969,"prevIcon":282,"prevTitle":279,"prevTo":3970},"false","true",".\u002F6.platform-deploy",[3972,3973,3974],"style",{},"html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":1523,"searchDepth":1537,"depth":1537,"links":3976},[3977,3983,3992],{"id":429,"depth":1537,"text":430,"children":3978},[3979,3980,3981,3982],{"id":434,"depth":1548,"text":435},{"id":648,"depth":1548,"text":649},{"id":776,"depth":1548,"text":777},{"id":884,"depth":1548,"text":885},{"id":1091,"depth":1537,"text":1092,"children":3984},[3985,3986,3987,3988,3989,3990,3991],{"id":1095,"depth":1548,"text":162},{"id":1181,"depth":1548,"text":1182},{"id":1248,"depth":1548,"text":504},{"id":1285,"depth":1548,"text":717},{"id":1351,"depth":1548,"text":1352},{"id":1469,"depth":1548,"text":1470},{"id":1515,"depth":1548,"text":1516},{"id":1688,"depth":1537,"text":1689,"children":3993},[3994,3995,3996],{"id":1692,"depth":1548,"text":1693},{"id":2929,"depth":1548,"text":2930},{"id":3572,"depth":1548,"text":3573},"So sánh Supabase vs Firebase vs Neon vs PlanetScale. Best practices, tips phỏng vấn, 15+ câu hỏi phỏng vấn Supabase.","md",null,{},{"title":284,"icon":196},{"title":422,"description":3997},"IRSc-N3QurZ-n-HaMTIubMTXORDXBU5Oq-nMqy2D3Ug",[4005,4007],{"title":279,"path":280,"stem":281,"description":4006,"icon":282,"children":-1},"Supabase Platform — Studio, organizations, branching, logs, self-hosting Docker\u002FK8s. Migration từ Firebase, Heroku, RDS, MySQL.",{"title":288,"path":290,"stem":291,"description":4008,"icon":289,"children":-1},"Học TypeScript 7.0 RC (Corsa) — compiler Go 10× nhanh hơn, type system nâng cao, generic, narrowing, utility types, decorator metadata.",1783490369429]