#09 O segredo do Real-Time que ninguém te conta (Angular + Supabase) | [Série] Criando SaaS do Zero

Samuel Rizon builds a barbershop SaaS with Angular and Supabase, replacing 30-second polling with Supabase Realtime so waitlist updates and shop status changes appear instantly across the dashboard and public storefront.
Chapters
E aí, meus amigos, tudo bem com vocês? Samuel Rizon por aqui e esse é mais um vídeo da série Criando um SaaS do zero com Angular e Supabase. Eu sou Samuel Rizon e por aqui eu falo sobre tecnologia, SaaS, carreira e várias outras coisas. Se inscreve no canal, deixa o seu like e já vamos direto para o vídeo porque hoje tem bastante coisa para a gente fazer. Primeira coisa que eu queria passar com vocês aqui são as próximas etapas. A gente já tá no finalzinho desse projeto, então hoje a minha ideia é cadastrar e configurar as tabelas no Supabase, as tabelas da parte da barbearia, integrar a UI da dashboard com o Supabase e desenvolver o timer em real time. Então a gente vai fazer as configurações necessárias, criar as tabelas, configurar a parte disso, né, no nosso front-end no Angular, e também fazer um real time. Vocês vão ver como que é fácil e como que é simples fazer um real time no Angular. Depois da gente terminar isso aqui, a gente já vai fazer o deploy. Eu já vou ensinar vocês a fazer o deploy a gente transformar esse site em PWA e configurar o domínio e essas coisas que a gente precisa fazer para já deixar o site no ar. E por último, a gente fazer um vídeo, pretendo fazer um vídeo com os últimos ajustes, correções de bugs que eu achar e algumas futuras melhorias que a gente pode pensar para o projeto ou ajustar algumas coisas, algumas pequenas coisas dentro do projeto. Então já estamos nas partes finais desse projeto, dessa série, e tá sendo bem legal. Então já tô com um projeto aqui rodando beleza, da forma que a gente deixou antes. Então a gente tem as nossas configurações, a página pública aqui, e a nossa ideia vai ser salvar essas configurações aqui no Supabase. Eu acho que aqui, em vez da gente usar, a gente pode, né, preencher o nome, o endereço aqui já automaticamente, mas eu acho que a gente pode criar um storefront, uma tabela, né, do storefront, para que o usuário consiga colocar essas informações dessa loja aqui no sistema. Então, pensando, né, no futuro, talvez o usuário pode ter mais de uma barbearia. Então, eu sou usuário, dono de uma empresa, eu pago um plano e eu posso ter mais de uma barbearia dentro desse sistema. Então, eu acho que é mais fácil a gente já fazer já uma tabela nova com essas configurações, né, o nome da barbearia, o endereço, horário de funcionamento, serviços oferecidos. E a gente deixa isso numa tabela nova, beleza? Então o que que a gente vai fazer? Eu vou pegar isso aqui, ó. Aqui a gente tem a foto também, né? Então eu vou pegar isso aqui, eu vou vir aqui no Supabase, dá uma olhadinha como que a gente vai fazer isso. A gente já tem algumas tabelas aqui, né? Mas eu vou usar— a gente já tem a nossa tabela de compra, a gente vai criar uma tabela de storefront, tá? A gente vai vir aqui E eu vou mandar aqui para ele, please create a storefront table with this data. E aí a única coisa que eu vou mandar aqui para ele é o base API aqui, ó, esse carinha aqui, ó. Eu vou mandar isso aqui, o ID, vou falar que é o ID para ele, e o resto aqui deixa ele criar. Vamos ver o que que ele vai me retornar aqui. Às vezes essa IA do Supabase dá umas viajadas, mas se ela não funcionar, a gente pode mandar tanto para o ChatGPT quanto para o Cloud Code para ele criar isso aqui para a gente. Mas a ideia é que ele já retorna tudo. Beleza, então aqui, ó, Storefront ID, a foto, beleza, o nome, endereço, working hours, services. You created by, you created by aqui, tudo junto com o auth/users. Beleza, aqui ele já coloca o role level security, cria alguns indexes e já criou uma função aqui para atualizar o updatedAt e updatedAt. Ele fez essas outras coisas aqui, pessoal. Por enquanto a gente não vai usar tudo isso aqui. Deixa eu ver as policies aqui, ó, as políticas. Quem cria? Beleza, beleza. Acho que tem problema a gente deixar isso aqui, não. Eu só não vou criar esses triggers aqui, ó. Isso aqui a gente não precisa criar agora, não. Então, Edit in SQL Editor, eu vou vir aqui nesses triggers, vou apagar. E vou rodar. Beleza, enquanto ele roda aqui, o que que eu vou fazer? Eu vou criar a nossa interface. Aqui a gente tem o dashboard e a gente vai vir aqui no shared interface storefront.ts, interface storefront, ele vai estender, extends e base. E aí aqui a gente vai pegar aqui, ó, foto, name, working hours, e por último é o services. Beleza, então a gente já tem o nosso storefront aqui, a gente pode fechar. Eu vou fechar esse base API aqui também. Agora a gente vai criar o nosso storefront API. Beleza, então storefront, storefront.api.ts. Deixa eu ver aqui se eu tenho algum outro API já criado só para mim pegar o componente aqui. Boilerplate storefront. Então com isso aqui, pessoal, a gente já tem esse storefront criado no banco de dados, beleza? Ele tá criado aqui no banco de dados. E agora o que que a gente vai fazer? A gente vai atualizar as nossas informações do formulário, né? A gente vai fazer com que o usuário ele vai cair nessa página e ele vai preencher essas configurações aqui. E aí assim que ele preencher esse formulário, a gente já vai salvar automaticamente lá no Storefront. Uma outra coisa que eu esqueci de adicionar aqui no Storefront é o Company ID. Esse aqui é bem importante, é isso, é através disso aqui que a gente vai linkar, né, que essa empresa, né, esse usuário dessa empresa, ele tem nesse caso aqui, a gente tem um company, exato. Então a gente tem usuários, a gente tem uma empresa em si, essa empresa pode ter várias lojas, beleza. Então esse usuário, essa loja tem que ser de uma empresa. To the table. Então aqui a gente só manda para criar do Superbase, deixa ali criando ali. Enquanto ela vai criando, o que que eu vou fazer? Eu vou vir aqui dar um private StoreFrontAPI, recebe inject StoreFrontAPI. Beleza. GetById. Beleza, a gente vai dar um GetById aqui, return this.superbase.from, posso dar um this.select aqui só, match. Beleza, olhando aqui no Superbase, vamos ver o que que ele fez. Deixa eu ver, add company, aqui, ó, ele já tá até atualizando as policies aqui, ó, que legal. Mas aqui, ó, ele já tá atualizando as policies, select from companies, a gente não tem a tabela companies. Tem que tomar muito cuidado com que as coisas que a IA faz, cara. E aí tem que sempre ficar de olho nisso. Mas beleza, a gente já tem aqui o StoreFront API e a gente vai aqui, ó, no onInitAsyncLoadData. Beleza, ele já implementou um init ali. Aqui ele tá só mostrando, né, altera com o componente atual. E aí, dando uma olhada aqui no que que a gente tem no auth, no nosso app.config. Que que a gente precisa fazer, né? Toda vez que o usuário entrar dentro do sistema, a gente precisa carregar a empresa dele junto. Então o usuário entra, e esse usuário, né, nesse caso que a gente tá aqui agora, esse usuário ele vai ter uma empresa vinculada a ele. Então eu tenho usuário, eu tenho uma company vinculada a esse usuário. Quando a gente fala de um SaaS multitenant, né, a gente fala de um usuário que tá vinculado a uma empresa. Então toda vez que eu entro no meu sistema, eu entre aspas tô logado naquela empresa. Se por algum dia eu mudar de empresa ou mudar de alguma coisa, eu vou conseguir, né, a gente pode colocar uma opção de alternar empresa ou alternar o tenant que a gente fala, né, mudar o tenant. Então eu logo usuário numa outra empresa. Mas por enquanto o que que a gente vai fazer? Como a gente tem esse usuário aqui, ó, a gente tá carregando os dados deste usuário. Então eu dou aqui, ó, um update user. Quando eu download, eu dou um getUser, eu pego os dados dele aqui. A gente precisa também carregar os dados da empresa. Então, além de um auth service aqui, o ideal é a gente ter também aqui em shared services, é, o ideal seria que a gente tem um company, e a gente vai ter um company .service.ts, ngService, CompanyService. A gente vai fazer aqui igual a gente fez com o auth service. Por quê? Porque a gente vai ter esse load aqui, ó, que vai ser a mesma coisa. A gente vai usar ele lá no OnInit. Então a gente vai ter um load aqui, a gente vai fazer exatamente isso aqui. Então eu vou dar um.select limit 1. Deixa eu só colocar um MaybeSingle para a gente ter um resultado. E aí aqui eu vou criar o quê? Eu vou criar uma company que vai ser um Signal de eCompany. Perfeito, agora eu tenho o nosso CompanyService. E onde que a gente vai carregar esse CompanyService? Aqui no início, nesse provideAppInitializer aqui, ó. Ele já até entendeu o que que eu tô querendo fazer. E aqui, quando eu salvar e a gente entrar aqui no sistema de novo, dá uma olhada aqui no que que a gente vai fazer. Então aqui eu vou abrir o Company Service, e quando eu der um F5, eu tenho os dados da minha empresa aqui, ó. Vamos ver, ele não tá pegando. Por quê? Que aqui ele tá buscando de companies. Eu não quero companies, quero company. Vamos ver, espera ele carregar. Company, beleza. Tô com os dados da minha empresa aqui, ó, nome. E por enquanto é só isso que eu tenho, o nome de teste da empresa que eu tô logado. Mas beleza, então agora quando a gente loga, quando a gente entra dentro do sistema, né, lá no app initializer do Angular ele carrega o auth service e ele também depois ele carrega o company service. Agora a gente já tem o estado da empresa que o usuário tá logado. Aqui a gente vai pegar uma empresa só do usuário que tá logado, porque o usuário sempre vai estar vinculado a uma empresa. Mas num SaaS, quando a gente tiver, né, mais de uma empresa, deixar o usuário mudar de empresa, a gente tem que fazer uma lógica diferente aqui. Então aqui a gente já tem o CompanyService, e agora fica fácil aqui quando eu precisar. Aqui eu vou dar um private CompanyService, recebe, inject CompanyService. Na verdade, deixa eu fazer diferente, deixa eu colocar isso aqui, ó. Edialments imports. Beleza, então aqui eu dou um company service porque o company é um Signal. Beleza, aqui eu posso tirar, aqui eu também posso tirar. E ele vai mostrar aqui agora o storefront. No caso, ele deu erro que ele tá tentando pegar aqui o storefront. Deixa eu ver, storefront company ID não existe porque eu não rodei o comando ainda do company ID, mas Dando uma olhada aqui, vamos ver se ele alterou aqui, ó. Storefronts, public Storefronts, company ID, beleza. Public company of UID. Então eu vou só run query, que agora a gente consegue rodar a query daqui mesmo. Ele já deu erro na query, olha que maravilha. Por enquanto vamos rodar isso aqui, beleza. E agora se eu rodar isso aqui, ele vai dar algum erro. Vamos debugar com assistente aqui. Não sei por que que ele tá dando erro aqui. Não tem isso aqui, eu já rodei. Vamos rodar aqui de novo. É porque já existe, né? Faz isso aqui, roda. Aí a dos publis às vezes me dá umas raiva desse negócio, cara. Ah, create index company. Isso aqui eu acho que já foi feito. Então beleza, depois a gente resolve essa questão do role level security. Vou mostrar vocês outro jeito da gente cuidar dessas partes do role level security, tá? Aí a dos plugins realmente não tem ajudado muito nessa questão. Mas agora já estamos rodando aqui os storefronts. Por enquanto a gente não tem nenhum. E aí o que que a gente vai fazer? A gente tem aqui o nosso config form. O que que eu gosto de fazer, cara? Eu não gosto de deixar esse form aqui. Eu gosto de criar aqui, ó, como a gente tá em dashboards, eu vou criar uma parte chamada constants. Deixa eu tirar aqui, dei um zoomzinho aqui, eu acho que Beleza, constantes. E aí aqui eu vou criar o store-front.transform.constant.ts e aqui export store-front-form-config. Deixa eu atualizar aqui, então return, deixa eu importar tudo aqui. Um detalhe, Eu sempre costumo criar essas constantes como uma função. Por quê? Porque eu já tive vários problemas de criar constante como uma constante mesmo, e eu abro o dialog, e quando eu abro ele de novo, ele tá com as mesmas, com os mesmos dados, ele não reseta. Então quando a gente faz uma função dessa forma, ele fica bem mais fácil, tá bom? Então a gente não tem esse problema aqui. Então ao invés de salvar tentar salvar isso automaticamente, né? Eu posso simplesmente criar um botão aqui embaixo. Então eu vou vir aqui então, um botão salvar configurações. Vamos ver ele aparecendo aqui, configurações. Então a gente vai criar esse botão e quando o usuário clicar nesse botão a gente vai dar um submit. Então eu vou vir aqui, vou dar um, deixa eu apagar aqui, handleValueChange, tá, submit. Então const formValues console .log. Então vamos ver isso aqui funcionando. Eu vou dar um clique, submit, e a gente vai ver aqui funcionando. Teste 1, 2, 3, salvar configurações. A gente já tem os detalhes do formulário aqui. Deixa eu dar um zoom aqui para vocês, para ficar fácil de vocês verem. Aqui na página barbearia também já tá com baita zoom. Deixa assim. Então a ideia vai ser: usuário vai vir aqui, vai clicar em configurações, salvar os dados da barbearia, E aqui a gente já tem os dados que a gente precisa da barbearia, tá? Então a gente já tem o Storefront API aqui, e aqui vai ser bem simples. A questão é, a gente tem esse Storefront aqui, eu tenho o form config, eu tenho o Dynamic Field, tenho Storefront, Storefront data, Signal, Storefront, meu Storefront aqui, get By company ID. Normalmente eu faço aqui no Supabase, tá? Data recebe await async. Eu não gosto da parte de tipagem do Supabase, então eu prefiro fazer dessa forma aqui, tá, meus amigos? Eu não gostei da parte de tipagem do Supabase, que ele tem, ele gera os types lá. Então eu prefiro criar os meus. loadData aqui, eu tenho o storefront data Então aqui, update storefront, insert, update, tá? Que os dados do formulário, Storefront Data, que que esse insert update faz? Eu mando o payload aqui para ele. Se o payload tiver o ID, tá vendo? Ele vai dar, ele vai fazer o upload, senão ele vai inserir. E aí que é exatamente o que a gente tá fazendo, tá? E eu vou dar uma olhada para ver se tá funcionando. Eu vou colocar aqui também um private NotificationService do próprio Ingesorro. NotificationService, NotificationService. E aqui eu vou colocar configurações salvas com sucesso. Beleza, então aqui o nome da barbearia, Dragantina. Endereço, Rua Teste. Horário de funcionamento, segunda a Sexta de 9 às 19 horas. Serviços oferecidos: corte. E agora a gente vai debugar isso aqui. Eu tô aqui no dashboard page, dashboard page, e a gente vai ver se isso aqui vai funcionar. Então clique em salvar. Eu peguei os dados do formulário, segunda a sexta, beleza. Vamos dar um F5 aqui. Network storefronts, ele tem um get aqui, não vai funcionar. Por quê? Porque eu não coloquei o await. Submit async const error, assim que a gente verifica, né, se no storefront, no, nos países a gente tem erro. Dessa forma aqui, vamos fazer de novo. Aqui a gente roda aqui de novo. Vai, deu erro, deu erro. O company ID não existe. Então, por enquanto aqui tá funcionando, tá, guys? Então, o que que a gente vai fazer aqui, ó? A gente vai vir aqui, company ID, this.companyService. A gente vai precisar do companyService aqui, ó. Private Company. Beleza, vamos mais uma vez. Eu vou colocar o breakpoint aqui, salvar. Não tive erro, então eu tive sucesso, sucesso total, meus amigos. Salvei aqui e agora se eu der um F5 de novo no Storefront, dá um preview, ele já trouxe aqui os nossos dados. Então a gente já tem os dados do Storefront aqui no nosso projeto. O que que a gente precisa fazer agora? A gente precisa carregar esses dados aqui no nosso formulário. Existem algumas formas da gente fazer isso, tá, que a gente tem aqui, ó. Lembra que a gente criou esse carinha aqui? E o que que eu posso fazer? Eu posso passar aqui o storefront e storefront. Eu preciso passar esse carinha aqui. E aí que eu vou colocar initial value storefront name, initial value address, initial value working hours e initial value storefront. Beleza. E aí aqui, ao invés de criar isso aqui, esse form config aqui a gente vai criar depois que a gente setar esse carinha aqui. A gente tem um storefront aqui, save storefront, salvei, carregou, e olha que maravilha, já tá tudo aqui, ó, gente, é simples. Eu amo Angular, é tudo muito certo, tudo muito fácil de fazer. Então a gente já tem o nosso formulário sendo carregado, ele já tá salvando corte, barba, cabelo. Se eu salvar as configurações aqui, ó, agora a gente tem, né, o ID, ele precisa, ao invés de dar um insert, ele dá um update. Então o que que ele fez aqui? Ele deu um patch, porque a gente passou o ID aqui e ele deu um patch ao invés de um update. Então se eu der um F5, ele vai vir aqui. Beleza, show! Já temos as informações da barbearia aqui funcionando. Sobre o upload de foto, eu acho que eu devo fazer um vídeo sobre isso. Acho que é melhor do que a gente tratar isso aqui dentro desse vídeo muito muito grande, tá? Isso aqui não é complexo, mas vai demandar um tempinho da gente fazer algumas configurações e deixar tudo funcionando aqui do nosso lado. Então eu prefiro fazer isso aqui em um outro vídeo. Beleza, agora vamos dar uma olhada nessa questão do tempo de espera e no status. Só que dessa vez eu vou chamar o meu amigo Cláudio para vocês verem como que o Cláudio pode resolver isso de forma rápida para gente. O que que é legal, cara? Eu tenho testado bastante o Claudio, Cloud Code. Eu falei Claudio, talvez vocês não estão entendendo, mas esse carinha aqui, ó, Cloud Code, eu tenho testado bastante ele e ele ajuda bastante nessas questões que a gente precisa fazer quando é algo mais focado em alguma tarefa específica. Por que que eu preferi fazer isso aqui na mão? Porque ele não entende muito o contexto, o projeto não é grande, ele não entende muitas coisas como que funciona. Mas agora que a gente já tem algo aqui um pouco funcional, o que que eu vou pedir ele para fazer? Eu vou pedir ele para adicionar isso na interface do nosso Storefront. Então eu vou pedir ele para adicionar esse tempo de espera e o status da loja na interface, e vou pedir ele para criar um serviço para gerenciar isso, ou um serviço, ou tentar fazer aqui no próprio componente dashboard mesmo, mas É essa lógica da gente diminuir e aumentar esse tempo aqui e mostrar esse tempo de espera aqui no front-end. Então o que que eu vou falar para ele? Então aqui eu já vou começar colocando um e falando sobre o dashboard, pages/dashboard. Beleza, então aqui eu tô passando para ele o contexto da minha página de dashboard. Eu acho que nem da página, eu acho que eu posso passar do módulo inteiro. Para ele ter esse contexto desse módulo dashboard. Eu também vou passar o contexto Storefront.interface. E aí é que agora eu vou falar com ele. Based on those files, I need to implement the waiting time and storefront status, add the properties to the interface, and create The Logic Dashboard Page. Esse aqui foi meu prompt, eu tô mandando para ele, né, o contexto dashboard. O que que eu vou fazer? Eu vou pedir ele para fazer só com plain mode primeiro e vamos ver o que que ele vai planejar. Então ele vai ler os meus arquivos e ele vai traçar um plano de ação, né, para como que a gente vai fazer isso. É bem importante primeiro fazer os planos com ele. Aqui eu tô usando o Opus, é o modelo bem mais avançado do Cloud Code. Então aqui ele vai ler os meus arquivos e Pessoal, essa tem sido a nova forma da gente programar, né? Acho que aí trouxe uma nova forma de programar as coisas, uma nova forma da gente fazer as coisas. Ele já veio com um plano. Então eu vou adicionar duas novas propriedades: waiting time, stores the current waiting time in minutes, e is open, se tá aberto. Aí aqui, ó, vou adicionar signals de waiting time e is open para gerenciamento de estado. Vou inicializar isso aqui quando a data tiver sido carregada. Eu vou adicionar os métodos, né, para colocar o waiting time no slider, increment buttons, adicionar o método toggle open/close e update the submit method include this, adicionar, atualizar, né, o dashboard, replace hardcoded waiting time dynamic. Beleza, data store from other method, update only waiting time in fields for real time. A única coisa que eu não achei legal é isso aqui, ó. Update Submit Editor to include these new fields. Que que eu vou falar com ele? These new properties should save automatically without clicking on Submit. Submit. Que eu tô falando? Que essas novas propriedades, elas devem ser salvas automaticamente. Então, se o cara tiver que clicar lá, mostrar o tempo, depois clicar em Salvar, isso não faz sentido nenhum. Então, isso tem que ser de forma automática. Então aqui ele chegou, né, ele atualizou o plano dele de atualizar e agora ele vai criar um método para automaticamente fazer isso. E beleza, eu acho que esse plano tá legal e eu vou dar um yes e accept edits on. E ficar de olho no que que ele vai começar a mexer, porque ele vai começar a mexer bastante coisa e a gente tem que tomar bastante cuidado, porque às vezes ele começa a mexer muito, muito, muito e ele começa a criar bugs. E para você desfazer o que ele fez, cara, é muito ruim. Você pode pedir para ele desfazer, mas você vai gastar mais um tempão. Para isso, tá bom? Mas aqui, ó, ele já criou o waiting time e o is open. Então ele já fez o tudo dele. Agora ele vai atualizar o Storefront API com update time em zeros, o método para isso. Então aqui ele já criou esse método para isso também. Então update, select. Aí aqui, aqui ele já tá dando um update, um select. Eu não sei por que que ele já Não deu um.limit. Assim que a gente faz para a gente já retornar uma data, tá bom? Para a gente não retornar um array de números. Beleza. Agora aqui, ó, ele atualizou lá no dashboard page. Então, se o storefront, ele já pega aqui, ele já vem com waiting time, o is_open, ele já seta baseado no status, né, dessa loja. E aqui, ó, ele já começou a criar mais código. Update Waiting Time, Set Waiting Time, Toggle Store Status, Debounced, Auto Saved, tá? É que ele não tá usando RxJS. Isso é algo legal também, Auto Save Time Status. Então, quando o StoreFront API, API que ele chamou, beleza. Agora ele vai atualizar HTML. Já atualizou com as coisas que a gente precisa. Gente, o tempo que eu ia gastar para fazer isso aqui, mostrar para vocês, era absurdo. Vocês tá ligado, vocês sabem disso, que eu ia gastar bastante tempo para conseguir fazer isso aqui com vocês. Eu quis fazer aquela outra parte do início, mas eu acho que é legal também mostrar, cara, como que a gente consegue adiantar, né, o nosso trabalho com o IA hoje em dia. Esses agentes de código, eles têm realmente feito um trabalho muito legal, cara. Aqui ele importou tudo aqui, só dou um espaço e salvo de novo para ele fazer a formatação, porque ele normalmente, né, altera os arquivos sem a formatação correta. Ele adicionou o forms_module para a gente ter esse aqui, esse ng-module aqui no switch. Agora ele tá adicionando mais algumas coisas aqui, ó. Ele deu um save timeout. Agora eu preciso da atualização do SQL para mim rodar lá no Supabase, né. Então eu vou falar com ele. I need the SQL to add the new properties to the storefronts table. E aí, o que que eu vou mandar para ele, cara? Só para ele ter uma noção. Acho que, acho que nem precisa não. Vamos ver aqui, porque eu tava pensando em vir aqui no storefronts. Aqui, ó, a gente consegue vir cá embaixo em definition. A gente tem o SQL criado pelo Supabase. Olha que legal, ele além de ter criado o SQL para mim. Ele criou também um check, ó, no storefront, no check waiting time. Ele verificou, waiting time tem que ser maior do que 0 e menor do que 120. Não sei se a gente precisa desse menor do que 120 aqui, não. Eu gosto dele tá maior que 0, isso aqui é legal. Já rodei ali no código, agora vamos dar uma olhada aqui no nosso sistema para ver se ele já tá pegando essas informações. Eu vou dar um F5. E eu vou adicionar aqui, ó, 15 minutos. Eita, já deu erro aqui, ó. Que que ele deu? Apply another using unique columns. Ah, tá, que que ele tá falando aqui, ó? Tá vendo, cara? Ele cria coisa, mas ele cria coisa e dá uns bug às vezes, cara. Por quê? Porque aqui ele tá entendendo que o company ID seria o ID do ID real, né? No nosso caso, a gente não vai usar o company ID, a gente vai usar o storefront ID. Então aqui, ó, Olha o que que eu vou fazer, eu vou só copiar isso aqui para ele, para o Cloud Code, mandar para ele. You should use storefront ID to update storefront. Aqui eu literalmente tô mandando o erro que eu tomei para ele, porque ele tava tentando usar o company ID ao invés do storefront ID. Agora que eu passo ID, beleza. E aqui também eu vou passar esse storefront ID aqui para ele, ele provavelmente vai atualizar aqui para mim. Beleza, então vou dar um F5 aqui novamente e vou adicionar, aumentar 10 minutos. 10, 20, 35, 40. Aí, que legal! Aí aqui eu tenho um slider também que eu vou para 70. Aqui ele tá dando esse configurações salvas automaticamente, eu não gostei disso, eu não acho que a gente tem que colocar isso aqui. Aqui console.error. Não quero também toda vez que der um erro, né, que ele for atualizar alguma coisa, ficar dando uma notificação. Então, na verdade, se caso der um erro, né, a gente tem que mostrar uma notificação para o usuário informando. A gente já tem aqui, ó, status da loja tá fechada e o status da loja tá aberta. Agora o que que eu vou falar? Now eu vou passar aqui, ó, storefront, storefront, o domínio para ele. Beleza. Now update storefront page. With database data. Beleza, então tô falando aqui para ele, cara, agora vai lá no Store Front Page que a gente tem aqui, né, a nossa página do Store Front, e atualiza com essas informações que a gente tem aqui salvo no banco de dados. Então, ó, this Store Front Page, eu faço um display real-time data from the database. Então ele vai adicionar lá no TypeScript. Aí que a gente tem que ficar bastante de olho na forma como ele vai fazer isso, mas eu acho que ele vai fazer do jeito que a gente tá fazendo lá no dashboard, porque ele já tem, já tá no contexto dele, né, o que que ele, como que a gente fez isso. Então ele tá usando a Storefront API, o Storefront, sempre já pegando do contexto que a gente tem, né. Adicionou o ID, então aqui ele atualizou o HTML, e agora aqui, ó, tá 70 minutos. Se eu vier aqui na página pública O estacionamento tá fechado. Estacionamento no estabelecimento. Deixa eu abrir a nossa loja, né, cara? Vou vir aqui na loja, ó. 70 minutos é quanto, cara? 70 minutos é 1 hora e 9 minutos. Será que é isso aqui mesmo? Deixa eu diminuir aqui, ó. 10, 10, 50 minutos. Olha aqui, meus amigos, eu fiz isso em quê? 5 minutos, sei lá, 5 minutos eu fiz as atualizações que eu fiz. Não, né, eu pedi o Cláudio para fazer. E aqui agora, ó, ele já tá pegando as informações a cada quantos segundos? Deixa eu ver aqui. A cada 30 segundos, se eu não me engano, no storefront aqui, ó. Isso, refresh data every 30 seconds to get updated real time. Isso aqui, cara, seria a forma mais fácil ainda da gente fazer, forma mais simples da gente fazer essa parte de real time. Isso é verdade, é uma forma simples da gente conseguir sempre pegar os dados atualizados. Então eu posso Vim aqui e abrir uma nova página, só que aqui eu quero essa página de status aqui. E aí eu vou adicionar, eu vou diminuir aqui, né, 35 minutos, 20 minutos. E deixa eu vir aqui na nossa outra página. Ele tá em 49, 41. Vamos ver daqui a 30 segundos se ele vai atualizar, né, para o tempo que eu coloquei lá, porque o ideal é que a gente atualiza em tempo real. Por isso que é legal botar 30 segundos, é Mas olha lá, ele não vai pegar isso em tempo real das alterações, né? Isso aí é outra coisa importante. Só que uma coisa que eu percebi, o Superbase criou um tempo de espera que é fixo. Então ele vai depender com que o usuário diminua e aumente o tempo. O tempo aqui da minha, que tá aqui, né, esse tempo de 20 minutos, ele não tá diminuindo sozinho. O ideal é que ele diminuísse sozinho aqui também, porque o usuário, né, o cara tá na barbearia, ele bota lá, tá 20 minutos, o tempo vai ficar rodando, né, um cronômetro para ele, um tempo, diminuindo esse tempo. E aí, se ele vê que ele precisa, precisa de mais 5 minutos, precisa mais tantos minutos, eu só aumento. Então eu posso diminuir? Posso, se eu acabar mais rápido. Mas o ideal é que ele não altere isso, ele não precisa ficar alterando isso. Então eu vou falar para o Cloud Code automatizar, fazer essa automação, né? Então vou falar: we need to automatically update Então a gente precisa atualizar automaticamente tempo. Eu não consigo falar em português e escrever em inglês, então eu vou falar em português aqui mesmo. A gente precisa que o tempo seja atualizado automaticamente até no dashboard, senão o usuário vai precisar ficar diminuindo o tempo e isso não é o ideal. Esse é um app de barbearia e o barbeiro não pode ficar diminuindo o tempo, ele precisa adicionar. Não, não vou ficar aqui, ele não pode ficar diminuindo o tempo, lembre-se disso. Então eu vou ativar o play mode dele novamente para ele não já não sair editando as coisas, tá? Isso aqui é bem importante. Uma barbearia real, o tempo de espera deveria diminuir automaticamente conforme o tempo passa. For criar um plano para mim implementar isso corretamente, porque a forma que ele fez é que o tempo de espera é fixo. Então isso não ficou legal. Vamos ver aqui, ó. Então ao invés de armazenar apenas waiting time, tempo de espera em minutos, vamos armazenar estimated finish time, timestamp de quando o próximo cliente será atendido, e o is_open mantém como tá. Então atualizar interface, remover o waiting time e adicionar o estimated finish time. Aí, que é um timestamp, que é uma data, né? Então, modificar para aceitar, beleza. Dá uma hora que vai trabalhar com horário estimado de finalização. Quando o usuário ajustar o tempo mais 5, mais 10, o timestamp atual, mostrar o countdown em tempo real no dashboard, minutos restantes até o horário estimado. Esse código aqui eu vou fazer, eu vou dar um yes, accept aqui. Show! Então dá uma olhada aqui que que o Cláudio fez. Ele fez essa mudança, né, para agora ser uma data. E olha que legal também, cara, ele gerou um SQL de migrations. Olha que legal, eu já tinha copiado lá do plano que ele tinha feito, ele gerou esse SQL de migrations aqui. Eu fiz aqui, né, drop column, já tinha colocado esse SQL aqui, não tem problema. Então beleza, vamos dar uma olhada aqui o que que ele fez, cara. Eu acho que ele mudou bastante coisa aqui, tá? Deixa eu ver aqui, ó. Beleza, loja tá aberta, o tempo de espera tá 10 minutos, eu vou adicionar mais 10. E ele já deu um erro aqui no fez. Por quê? Porque ele tá com um erro aqui, ó, ele não atualizou. Mas vamos dar uma olhada aqui no Store Front Page, tá? Que que eu vou fazer? A única coisa que eu vou fazer é isso aqui, ó, copiar o erro e colocar no Cláudio, deixar ele resolver. Eu sei resolver esse erro, é simples. Que que ele fez? Ele criou uma função e eu não gosto disso, cara. A gente sabe, quem é desenvolvedor do Angular sabe. Can you create a pipe or use signal. Vamos ver. Use computed signal. Yes, manda brasa aí, quero ver o que que você vai fazer. Então, a única coisa que ele fez, ó, foi dar um computed aqui. E é para isso que o signal serve. Signal é muito bom para esse tipo de coisa e a gente pode usar assim à vontade. Beleza, então deixa eu voltar aqui. Ele adicionou esse botão de atender novo cliente aqui, que eu não entendi. 10 minutos, 20 minutos. Eu não entendi esse botão de atender novo cliente, cara. Ajustes do tempo. Acho que ele tá entendendo que esse tempo aqui é para o cliente atual, cara. Deixa eu só falar com ele uma coisa. O tempo de espera não é sobre o cliente atual. A ideia é o barbeiro somente ir adicionando o barbeiro gerenciar isso por conta. E por exemplo, se ele está atendendo um cliente que demora cerca de 30 minutos e chega outro cliente, ele vai adicionar mais 40 minutos no tempo, que é o tempo do novo cliente. Dessa forma, quem verificar o status da loja, sabe que o tempo de espera seria de 30 minutos mais 40 minutos, 70 minutos. Vou botar o play mode aqui. Entendi perfeitamente, deve funcionar como uma fila de barbearia real onde o barbeiro gerencia manualmente o tempo total de espera baseado em quantos clientes estão na fila. Beleza. Por que, cara, por que que ele errou? Aí isso aí já fica de aprendizado. Para gente, né? E é uma coisa que eu tenho realmente percebido. Essas IAs, cara, você tem que dar um contexto muito bom para elas. Então aqui o Claudio, que que eu fiz? Eu só cheguei para ele e falei: faz isso. Então ele, cara, ele não vai entender todo o contexto, ele não vai entender toda a sua aplicação. Aqui é uma aplicação pequena, para aplicações maiores é até mais difícil, né, a gente gerenciar tudo isso. Então o ideal aqui seria eu ter pego, por exemplo, a descrição, né, do nosso, que a gente tem aqui, né, que eu tenho aqui, ó, essa descrição aqui, ó, essa ideia, mandar isso aqui para ele, mandar até uma foto do diagrama, né, e colocar essas coisas aqui para ele. Porque eu mandando isso aqui para ele, ele vai conseguir ter já um entendimento do que que é aplicação, ele vai já conseguir ser certeiro no que ele tem que fazer. Beleza, eu acho que agora ele já fechou aqui e a gente pode dar um F5 aqui, ó, já tá no, já tá em 17 minutos. Eu vou adicionar aqui mais 30, ele já foi para 47. Se eu vier aqui na página pública lá, ele já tá em 46 minutos. 46, 2, 1, 0, 59, 58, 57, 56, 55. Vou adicionar aqui, beleza, tava 46, adicionei mais 10 minutos. Isso aqui tá funcionando, cara. E aí, por exemplo, se eu vier aqui adicionar, tirar 15 minutos, 5 minutos, ele foi lá por 16. Beleza. E aí aqui, aqui já tá com tempo de espera estimado funcionando. A nossa fila aqui, ó, tempo total da fila tá 16 minutos. Aqui ele continua fazendo lá um select para o Supabase, o status da loja. Beleza. Eu quero saber se ele vai atualizar esse tempo total da fila aqui, ó. Já temos algo, entre aspas, em tempo real funcionando. Para o usuário aqui, ele ainda, né, tá buscando em 30 segundos. E aí que agora eu vou dar um play mode para ele e vou virar para ele falar: utilize o Supabase Realtime ao invés de ficar fazendo pooling a cada 30 segundos. E aí o que que ele vai fazer, né? O que que eu espero que ele faça? Ele vai implementar uma forma da gente usar o Supabase real-time nas tabelas, né, na tabela do próprio Supabase, para quando o barbeiro vier aqui e fizer uma alteração, a pessoa que tá com a página aqui já pegar essa alteração em tempo real. Então aqui, ó, substituiu por 30 segundos, adicionar método para escrever mudança na tabela StoreFront, e a tabela No Supabase de real-time é isso aqui, ó. Subscribe to change, frontend change, product, storefront, company ID igual esse carinha aqui, e emitir um novo valor. Lembre-se que a inscrição deve ser feita para o company ID e o storefront, storefront ID. Aquele tá só usando o company ID, não quero só para o company ID. Uma empresa pode ter mais de uma loja. Então o fluxo, né, dashboard obtém storefront ID inicialmente. Após obter storefront, se inscreve usando storefront ID. Storefront page também se inscreve usando o mesmo storefront ID. Ambas as páginas recebem atualizações em tempo real. Na verdade, quem precisa receber atualizações em tempo real é só o storefront. O dashboard é quem vai mandar as atualizações. Então aqui, cara, ao invés de ter que codar tudo isso aqui na mão e fazer tudo isso aqui na mão, eu tô só usando o cloud para fazer esse código para mim, para transformar isso. A gente sabe, né, que a gente como desenvolvedor muitas vezes a gente tem alguns problemas, né, de criar esses negócios aqui, fazer isso aqui. A gente precisa procurar, e aí é muito boa para isso, é muito boa para isso. Então aqui, ó, Cliente acessa a página pública, a página busca dados iniciais e obtém o storefront ID, se inscreve para receber atualizações desse storefront específico, barbeiro atualiza o tempo status no dashboard e os clientes veem mudanças simultaneamente. Simplicidade e praticidade. Vai nessa, Claudião! Mete bala aí no código, meu amigo, não tenha medo. Olha, ele já adicionou aqui, ó, e cara, deixa eu mostrar para vocês isso aqui, pelo amor de Deus, entendam isso aqui de uma vez por todas. É só isso aqui que a gente precisa para ter atualizações em tempo real no Supabase. Você consegue ter noção da simplicidade que é isso aqui, cara? Você consegue ter noção? É simplesmente você falar: eu quero receber as atualizações de mudanças no Postgres na tabela storefronts que o ID tem o storefront_id. É só isso, cara. E aí, ele quer— eu tenho callback, eu dou um subscribe. Com isso aqui, toda vez que eu alterar alguma coisa na tabela para esse ID Então dessa forma quem se inscrever aqui vai receber essas atualizações, cara. É simplesmente isso. Então aqui, ó, o que que o, o que que o Cloud está fazendo? Então no onInit aqui, iniciar lá StoreFront, então ele vai dar o getCompanyId aqui, vai dar um updateStoreFrontData para ele já dar, setar deadline e fazer as outras coisas. E depois ele vai vir aqui, ó, subscribe to real-time updates. Agora deixa eu mostrar uma coisa para vocês. Deixa eu mostrar uma coisa para vocês. A gente tá aqui na nossa página do Barbeiro. Já tá, tem 9 minutos, ó, já tá passando tempo. Deixa eu adicionar um tempinho aqui, ó, mais 10, 20, 30 minutos. Beleza, a gente tá com 39 minutos de espera aqui. Eu vou entrar aqui e o que que eu vou fazer? Eu vou pegar esse local host aqui, eu vou abrir Beleza, acho que agora que vocês estão vendo, né? Beleza, beleza, beleza. Então aqui, ó, dividir a minha tela aqui porque essa aqui é a parte da barbearia. E aí que quando eu vier aqui adicionar mais 10, tá no 37, foi 48, não atualizou. Porque se você tá nesse vídeo, você vai perceber isso agora. E se você tentar fazer isso aqui sem pulando essa parte, pulando o vídeo, você vai ter esse mesmo problema. Qual que é a questão? No Supabase, quando a gente vem aqui no Supabase, a gente precisa, na tabela, a gente precisa informar aqui, ó, no caso do Storefront, a gente precisa informar. Dá uma olhadinha aqui, ó, deixa eu dar uma olhadinha aqui, ó. A gente precisa informar esse real-time aqui, ó. A gente precisa habilitar o real-time para tabela. Ele não habilita esse real-time para todas as tabelas. Então a única coisa que eu fiz aqui, ó, enable real-time. Agora eu vou voltar aqui para minha tela dividida, beleza? Deixa eu atualizar aqui. Agora eu vou vir aqui, dá um F5, vou dar um F5, já tá 46. Então a ideia aqui, deixa eu só confirmar no código aqui, ó, beleza. Eu vou, tô me inscrevendo para as novas atualizações e pelo que tudo indica vai funcionar. Então quando eu adicionar aqui, eu vou tirar 10 minutos, Tá 47 aqui, 46. Eita, atualizei aqui sem querer, mas ó, já atualizou em tempo real, cara. Olha isso aqui, ó. Deixa eu tirar 15 minutos. 1, 2, 3, ó, já foi para 30 minutos. Tá pronto, meus amigos, real time funcionando com praticamente duas funções que eu fiz no Super Basic, cara. Olha isso, eu posso vir aqui, ó, dar um slider, pum, 75, ó. Ó, já atualizou aqui a hora. Eu posso vir aqui, ó, 5, beleza, 5 minutinhos, e tá funcionando, cara. A gente já tá aqui com um real-time funcionando. Eu posso vir adicionando aqui, ó, o máximo de tempo que eu puder, e eu posso só diminuir e já tá atualizando em tempo real. Então o cliente já fica sabendo dessas atualizações. Se eu fechar a loja também, fechei a loja, pronto, tá fechada. Tudo em tempo real. A gente fez isso em quê? 5 minutos. Que coisa mais simples! Tem coisa mais simples que isso? Não tem, cara. Abrir a loja de novo, ó, já tá com tempo aqui carregado. Eu posso zerar a fila, sem fila no momento. Pode vir para babearia que já tá tudo funcionando. Eu venho aqui, ó, já tá com o Bragantino, com os nossos serviços, e a gente já tem a nossa página e o nosso SaaS já quase pronto para produção. A gente falta agora então colocar essa imagem aqui do usuário. E vamos dar só uma revisada agora no código que o Cláudio criou. Deixa eu remover alguns comentários aqui. Ele coloca bastante comentário, cara. Eu não acho ruim não, tá? Ele coloca bastante comentário, eu acho legal. Então aqui, ó, ele fez isso aqui. Então subscribe to Story Front Page. Então, pessoal, só para vocês entenderem, cara, foi isso aqui, ó. A gente só fez isso aqui, se inscreveu nas alterações, a gente colocou o payload. Então toda vez que a gente se inscrever e toda vez que tem uma alteração, ele vai chamar essa função aqui, ó. Ele não chama o subscribe, tá? Ele chama essa função. Quando ele chama essa função, ele cai aqui dentro do callback. Você quer, é normal da gente usar isso aqui no callback. E aí aqui aqui no nosso front-end, né, na parte que a gente chama, a gente lá, ó, dá o subscribe to storefront, passa o ID e faz o callback aqui, ó, uma função. Então toda vez que ele chegar aqui, eu tô retornando a nova alteração. E aí que com essa nova alteração eu dou um update storefront data. É simples assim. E no nosso dashboard page, que que a gente tem? A gente tem aqui, né, tá update waiting time display. Aqui ele ainda tá fazendo esse update aqui. Eu vou pedir para o Cloud remover essas coisas. Ações manuais na dashboard, se há algum código não utilizado e se tem algo para refatorar ou faltando. Deixa eu habilitar o play mode aqui só para ele dar uma analisada nesse código aqui da dashboard. Então, gente, olha, não foi um código muito complexo, mas eu realmente demoraria muito mais tempo se eu fosse fazer isso do zero aqui com vocês. Vocês sabem muito bem disso. Deu, deu para a gente perceber, né, como que foi fácil conversar com o Cláudio, como que foi fácil pedir as coisas para ele, como que ele entendeu, né, o contexto do projeto bem rápido, por sinal, porque eu criei uma sessão completamente nova com ele e já pedi ele para fazer algumas coisas, sempre dando uma referência, né? Eu dei referência de 2 arquivos, mas não é muito para o contexto da aplicação como um todo. Eu poderia ter dado um cloud init aqui para ele também criar um cloud.md aqui no projeto com a estrutura e as outras coisas que eu gostaria que ele soubesse. Beleza, a gente já tá aqui com o nosso projeto funcional, ele tá fazendo algumas alterações aqui. Que eu não tô entendendo. Deixa eu só ver o que que ele tá aprontando aqui. Ele tá tentando o tempo total na fila. Ele tirou o slider. Não é possível que tirou o slider, que abençoado! É, tirou o slider. Beleza, eu não vejo problema não, cara. Ele slide, cara, pode aumentar ou diminuir, não vejo problema. Acabei de atingir o limite do Opus, agora ele tá usando o Sony A4. Não é ruim, mas o Opus, cara, o Opus é uma diferença bem absurda na questão de código. Então aqui agora é já mais tomar um pouco de cuidado com código e as coisas que ele tá fazendo, mas continua sendo um modelo muito, muito bom para código, melhor modelo para código de IA que a gente tem hoje, melhor agente de IA, né? Show! Então a gente já tem nossa página do tempo de espera aqui. Eu, cara, Eu preciso desse tempo de espera aqui também na dashboard. Então, o que que eu falei? Você pode adicionar o tempo estimado na dashboard. O Barbeiro precisa ver isso também. Então, cara, não acho legal a gente não ter um tempo estimado aqui, o mesmo tempo que a gente vê lá, né? Então vamos só pedir para ele adicionar esse tempo estimado aqui na dashboard também. Ficou estranho. Adiciona o tempo igual é no storefront com minutos e segundos e melhore muito o texto. Então, isso aqui ficou bem estranho, não tá legal. Eu tô só pedindo para ele usar e fazer, né, o tempo igual é no storefront, na página de storefront. Caramba, ele tá dando um NZStatisticModule. Beleza, até porque a gente usou o statistic, né, aqui a gente usa o statistic com esse countdown aqui. A gente não fez countdown do zero porque o NG-ZUR tem isso, cara. Eu amo NG-ZUR. Beleza, tempo total da fila, fila de espera status, tempo total da fila. Eu vou vir aqui adicionar mais 20, mais 30. Beleza, tá legal agora. Mas eu não gostei desse adicionar cliente aqui não, cara. Eu prefiro aumentar aqui, diminuir tempo, aumentar tempo. Então aqui eu tenho aumentar tempo, diminuir tempo, o tempo total na fila. Show, meus amigos, tá funcionando! Eu espero no último vídeo, né, a gente melhorar um pouco essa interface, melhorar, fazer alguns ajustes. Tem alguma coisa, algumas coisas me incomodando. Mas cara, finalizamos essa parte, já tá funcionando. A gente já tem aqui a barbearia aqui funcionando, né, com esse view aqui. Uma coisa que a gente vai precisar fazer nos ajustes, né, quando a gente lançar, é que essa página precisa ser com ID da barbearia, o ID da Storefront, né. Então a gente vai precisar usar esse ID do Storefront aqui para a gente pegar, para não pegar do usuário logado. E a gente vai precisar adicionar um botãozinho de compartilhar alguma coisa assim e também adicionar um header aqui para pessoa sair, tá bom? Mas no vídeo de hoje a gente já finalizou essa toda essa lógica, a gente conseguiu já usar IA para ajudar a gente nessa parte também. Ficou um vídeo, acho que ficou um vídeo bem legal para vocês entenderem como que eu tenho utilizado aí no meu dia a dia, como que eu tenho usado o Cloud Code, né, também para fazer algumas coisas. E é isso, meus amigos, você gostou Deixa o seu like se você tá aqui, cara, e você não deu like ainda, pelo amor de Deus, dê o seu like. E se você ainda não é inscrito no canal, se inscreve no canal. E eu vejo você no próximo vídeo, fechou? Valeu, tamo junto!










