From f4b185ae179b47341df69e407b318b8e0e1d5fd9 Mon Sep 17 00:00:00 2001 From: Leonardo Date: Thu, 12 Mar 2026 08:58:36 -0300 Subject: [PATCH] =?UTF-8?q?Agenda,=20Agendador,=20Configura=C3=A7=C3=B5es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/settings.local.json | 17 + AUDITORIA.md | 274 ++ .../Nova-Dev-Doc/supervisor_fase1.sql | 414 +++ .../Novo-DB/fix_missing_subscriptions.sql | 220 ++ .../fix_subscriptions_validate_scope.sql | 50 + DBS/2026-03-11/Novo-DB/migration_001.sql | 296 ++ .../Novo-DB/migration_002_layout_variant.sql | 13 + DBS/2026-03-11/Novo-DB/seed_001.sql | 334 ++ DBS/2026-03-11/Novo-DB/seed_002.sql | 199 + DBS/2026-03-11/Novo-DB/seed_003.sql | 283 ++ .../migrations/agendador_check_email.sql | 36 + .../migrations/agendador_features.sql | 62 + .../migrations/agendador_fix_slots.sql | 221 ++ .../migrations/agendador_online.sql | 170 + .../migrations/agendador_publico.sql | 219 ++ .../agendador_status_convertido.sql | 19 + .../migrations/agendador_storage.sql | 56 + .../remove_session_start_offset.sql | 6 + DBS/2026-03-11/root/backup.sql | Bin 0 -> 3112544 bytes DBS/2026-03-11/root/data_dump.sql | 3195 +++++++++++++++++ .../2026-03-11/root/full_dump.sql | 1776 +++++++-- DBS/2026-03-11/root/schema.sql | Bin 0 -> 1473968 bytes .../src-sql-arquivos/01_profiles.sql | 110 + .../supabase_cadastro_externo.sql | 212 ++ .../supabase_cadastro_pacientes.sql | 266 ++ .../supabase_cadastros_recebidos(intakes).sql | 105 + .../supabase_patient_groups.sql | 174 + .../supabase_patient_index_page.sql | 147 + .../supabase_patients_populate.sql | 0 .../src-sql-arquivos/supabase_tags.sql | 134 + .../supabase-snippets/Untitled query 116.sql | 2 + .../supabase-snippets/Untitled query 130.sql | 1 + .../supabase-snippets/Untitled query 132.sql | 45 + .../supabase-snippets/Untitled query 157.sql | 20 + .../supabase-snippets/Untitled query 159.sql | 5 + .../supabase-snippets/Untitled query 174.sql | 12 + .../supabase-snippets/Untitled query 209.sql | 23 + .../supabase-snippets/Untitled query 216.sql | 2 + .../supabase-snippets/Untitled query 219.sql | 6 + .../supabase-snippets/Untitled query 221.sql | 12 + .../supabase-snippets/Untitled query 235.sql | 46 + .../supabase-snippets/Untitled query 271.sql | 10 + .../supabase-snippets/Untitled query 277.sql | 4 + .../supabase-snippets/Untitled query 319.sql | 6 + .../supabase-snippets/Untitled query 323.sql | 4 + .../supabase-snippets/Untitled query 324.sql | 8 + .../supabase-snippets/Untitled query 330.sql | 6 + .../supabase-snippets/Untitled query 361.sql | 3 + .../supabase-snippets/Untitled query 376.sql | 1 + .../supabase-snippets/Untitled query 431.sql | 5 + .../supabase-snippets/Untitled query 437.sql | 12 + .../supabase-snippets/Untitled query 439.sql | 9 + .../supabase-snippets/Untitled query 449.sql | 5 + .../supabase-snippets/Untitled query 457.sql | 9 + .../supabase-snippets/Untitled query 468.sql | 5 + .../supabase-snippets/Untitled query 476.sql | 5 + .../supabase-snippets/Untitled query 508.sql | 18 + .../supabase-snippets/Untitled query 521.sql | 4 + .../supabase-snippets/Untitled query 566.sql | 2 + .../supabase-snippets/Untitled query 633.sql | 6 + .../supabase-snippets/Untitled query 641.sql | 15 + .../supabase-snippets/Untitled query 649.sql | 4 + .../supabase-snippets/Untitled query 677.sql | 5 + .../supabase-snippets/Untitled query 744.sql | 2 + .../supabase-snippets/Untitled query 781.sql | 4 + .../supabase-snippets/Untitled query 790.sql | 17 + .../supabase-snippets/Untitled query 830.sql | 13 + .../supabase-snippets/Untitled query 843.sql | 3 + .../supabase-snippets/Untitled query 856.sql | 8 + .../supabase-snippets/Untitled query 869.sql | 7 + .../supabase-snippets/Untitled query 880.sql | 8 + .../supabase-snippets/Untitled query 886.sql | 266 ++ .../supabase-snippets/Untitled query 899.sql | 42 + .../supabase-snippets/Untitled query 934.sql | 3 + .../supabase-snippets/Untitled query 938.sql | 14 + .../supabase-snippets/Untitled query 975.sql | 17 + .../supabase-snippets/saas_docs.sql | 123 + Debugs/agenda-terapeuta-debug.txt | 87 + TESTES.md | 232 ++ comandos.txt | 15 + estrutura_src.txt | Bin 0 -> 19640 bytes logs/simulation-cleanup.sql | 29 + logs/simulation-log.txt | 15 + logs/simulation-report.txt | 63 + logs/simulation-seed.sql | 237 ++ migrations/agenda_eventos_price.sql | 8 + migrations/agendador_check_email.sql | 36 + migrations/agendador_features.sql | 62 + migrations/agendador_fix_slots.sql | 221 ++ migrations/agendador_online.sql | 170 + migrations/agendador_pagamento_modo.sql | 20 + migrations/agendador_publico.sql | 219 ++ migrations/agendador_status_convertido.sql | 19 + migrations/agendador_storage.sql | 56 + migrations/payment_settings.sql | 71 + migrations/professional_pricing.sql | 61 + migrations/recurrence_rules_price.sql | 6 + migrations/remove_session_start_offset.sql | 6 + migrations/support_sessions.sql | 235 ++ migrations/unify_patient_id.sql | 34 + package-lock.json | 1562 +++++++- package.json | 14 +- scripts/simulation/simulateUsage.js | 555 +++ scripts/simulation/simulation.config.js | 43 + scripts/simulation/simulationLogger.js | 33 + src/App.vue | 12 + src/assets/demo/code.scss | 17 - src/assets/demo/demo.scss | 2 - src/assets/demo/flags/flags.css | 1 - src/assets/styles.scss | 1 - src/components/AjudaDrawer.vue | 716 ++++ src/components/BlockViewer.vue | 156 - src/components/FloatingConfigurator.vue | 21 - src/components/agenda/PausasChipsEditor.vue | 4 +- src/composables/Usedocshealth.js | 94 + src/composables/useAjuda.js | 354 ++ src/composables/useDocsAdmin.js | 21 + src/composables/useFeriados.js | 119 + .../agenda/components/AgendaClinicMosaic.vue | 269 +- .../agenda/components/AgendaEventDialog.vue | 2712 +++++++++++--- .../agenda/components/BloqueioDialog.vue | 603 ++++ .../components/ProximosFeriadosCard.vue | 442 +++ .../__tests__/useRecurrence.spec.js | 277 ++ .../agenda/composables/useAgendaEvents.js | 240 +- .../agenda/composables/useAgendaSettings.js | 15 +- .../composables/useProfessionalPricing.js | 57 + .../agenda/composables/useRecurrence.js | 653 ++++ src/features/agenda/domain/agenda.types.js | 0 .../agenda/pages/AgendaClinicaPage.vue | 2038 +++++++++-- .../agenda/pages/AgendaRecorrenciasPage.vue | 605 ++++ .../agenda/pages/AgendaTerapeutaPage.vue | 1587 ++++++-- .../pages/AgendamentosRecebidosPage.vue | 849 +++++ .../services/__tests__/agendaMappers.spec.js | 288 ++ .../agenda/services/agendaClinicRepository.js | 2 +- src/features/agenda/services/agendaMappers.js | 326 +- .../agenda/services/agendaRepository.js | 40 +- src/features/patients/PatientsListPage.vue | 135 +- .../patients/prontuario/PatientProntuario.vue | 125 +- src/layout/AppLayout.vue | 33 +- src/layout/AppRailTopbar.vue | 14 +- src/layout/AppTopbar.vue | 19 + src/layout/ConfiguracoesPage - Copia.vue | 172 - src/layout/ConfiguracoesPage.vue | 36 +- src/layout/configuracoes/BloqueiosPage.vue | 617 ++++ .../configuracoes/ConfiguracoesAgendaPage.vue | 167 +- .../ConfiguracoesAgendadorPage.vue | 1316 +++++++ .../ConfiguracoesPagamentoPage.vue | 553 +++ .../ConfiguracoesPrecificacaoPage.vue | 332 ++ src/navigation/index.js | 10 +- src/navigation/menus/clinic.menu.js | 7 + src/navigation/menus/saas.menu.js | 27 +- src/navigation/menus/sakai.demo.menu.js | 59 - src/navigation/menus/therapist.menu.js | 14 +- src/router/guards.js | 142 +- src/router/index.js | 2 - src/router/routes.clinic.js | 20 + src/router/routes.configs.js | 20 + src/router/routes.demo.js | 34 - src/router/routes.public.js | 9 +- src/router/routes.saas.js | 21 + src/router/routes.therapist.js | 30 + src/support/components/SupportDebugBanner.vue | 335 ++ src/support/supportDebugStore.js | 144 + src/support/supportLogger.js | 116 + src/support/supportSessionService.js | 83 + src/utils/feriadosBR.js | 82 + src/utils/menuPageOptions.js | 69 + src/views/pages/Documentation.vue | 149 - src/views/pages/HomeCards.vue | 2 +- src/views/pages/NotFound.vue | 6 - src/views/pages/auth/Access.vue | 5 - src/views/pages/auth/Error.vue | 5 - src/views/pages/auth/Login.vue | 3 - src/views/pages/auth/ResetPasswordPage.vue | 3 - .../pages/public/AgendadorPublicoPage.vue | 1619 +++++++++ src/views/pages/saas/SaasDocsPage.vue | 1200 +++++++ src/views/pages/saas/SaasFaqPage.vue | 550 +++ src/views/pages/saas/SaasFeriadosPage.vue | 425 +++ src/views/pages/saas/SaasSupportPage.vue | 364 ++ src/views/pages/therapist/RelatoriosPage.vue | 360 ++ src/views/uikit/ButtonDoc.vue | 198 - src/views/uikit/ChartDoc.vue | 269 -- src/views/uikit/FileDoc.vue | 36 - src/views/uikit/FormLayout.vue | 121 - src/views/uikit/InputDoc.vue | 248 -- src/views/uikit/ListDoc.vue | 163 - src/views/uikit/MediaDoc.vue | 109 - src/views/uikit/MenuDoc.vue | 514 --- src/views/uikit/MessagesDoc.vue | 68 - src/views/uikit/MiscDoc.vue | 197 - src/views/uikit/OverlayDoc.vue | 186 - src/views/uikit/PanelsDoc.vue | 216 -- src/views/uikit/TableDoc.vue | 391 -- src/views/uikit/TimelineDoc.vue | 159 - src/views/uikit/TreeDoc.vue | 30 - src/views/utilities/Blocks.vue | 1079 ------ vite.config.mjs | 9 +- 197 files changed, 33405 insertions(+), 6507 deletions(-) create mode 100644 .claude/settings.local.json create mode 100644 AUDITORIA.md create mode 100644 DBS/2026-03-11/Nova-Dev-Doc/supervisor_fase1.sql create mode 100644 DBS/2026-03-11/Novo-DB/fix_missing_subscriptions.sql create mode 100644 DBS/2026-03-11/Novo-DB/fix_subscriptions_validate_scope.sql create mode 100644 DBS/2026-03-11/Novo-DB/migration_001.sql create mode 100644 DBS/2026-03-11/Novo-DB/migration_002_layout_variant.sql create mode 100644 DBS/2026-03-11/Novo-DB/seed_001.sql create mode 100644 DBS/2026-03-11/Novo-DB/seed_002.sql create mode 100644 DBS/2026-03-11/Novo-DB/seed_003.sql create mode 100644 DBS/2026-03-11/migrations/agendador_check_email.sql create mode 100644 DBS/2026-03-11/migrations/agendador_features.sql create mode 100644 DBS/2026-03-11/migrations/agendador_fix_slots.sql create mode 100644 DBS/2026-03-11/migrations/agendador_online.sql create mode 100644 DBS/2026-03-11/migrations/agendador_publico.sql create mode 100644 DBS/2026-03-11/migrations/agendador_status_convertido.sql create mode 100644 DBS/2026-03-11/migrations/agendador_storage.sql create mode 100644 DBS/2026-03-11/migrations/remove_session_start_offset.sql create mode 100644 DBS/2026-03-11/root/backup.sql create mode 100644 DBS/2026-03-11/root/data_dump.sql rename schema.sql => DBS/2026-03-11/root/full_dump.sql (86%) create mode 100644 DBS/2026-03-11/root/schema.sql create mode 100644 DBS/2026-03-11/src-sql-arquivos/01_profiles.sql create mode 100644 DBS/2026-03-11/src-sql-arquivos/supabase_cadastro_externo.sql create mode 100644 DBS/2026-03-11/src-sql-arquivos/supabase_cadastro_pacientes.sql create mode 100644 DBS/2026-03-11/src-sql-arquivos/supabase_cadastros_recebidos(intakes).sql create mode 100644 DBS/2026-03-11/src-sql-arquivos/supabase_patient_groups.sql create mode 100644 DBS/2026-03-11/src-sql-arquivos/supabase_patient_index_page.sql rename src/features/agenda/domain/agenda.mappers.js => DBS/2026-03-11/src-sql-arquivos/supabase_patients_populate.sql (100%) create mode 100644 DBS/2026-03-11/src-sql-arquivos/supabase_tags.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 116.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 130.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 132.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 157.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 159.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 174.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 209.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 216.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 219.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 221.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 235.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 271.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 277.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 319.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 323.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 324.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 330.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 361.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 376.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 431.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 437.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 439.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 449.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 457.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 468.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 476.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 508.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 521.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 566.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 633.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 641.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 649.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 677.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 744.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 781.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 790.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 830.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 843.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 856.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 869.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 880.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 886.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 899.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 934.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 938.sql create mode 100644 DBS/2026-03-11/supabase-snippets/Untitled query 975.sql create mode 100644 DBS/2026-03-11/supabase-snippets/saas_docs.sql create mode 100644 Debugs/agenda-terapeuta-debug.txt create mode 100644 TESTES.md create mode 100644 comandos.txt create mode 100644 estrutura_src.txt create mode 100644 logs/simulation-cleanup.sql create mode 100644 logs/simulation-log.txt create mode 100644 logs/simulation-report.txt create mode 100644 logs/simulation-seed.sql create mode 100644 migrations/agenda_eventos_price.sql create mode 100644 migrations/agendador_check_email.sql create mode 100644 migrations/agendador_features.sql create mode 100644 migrations/agendador_fix_slots.sql create mode 100644 migrations/agendador_online.sql create mode 100644 migrations/agendador_pagamento_modo.sql create mode 100644 migrations/agendador_publico.sql create mode 100644 migrations/agendador_status_convertido.sql create mode 100644 migrations/agendador_storage.sql create mode 100644 migrations/payment_settings.sql create mode 100644 migrations/professional_pricing.sql create mode 100644 migrations/recurrence_rules_price.sql create mode 100644 migrations/remove_session_start_offset.sql create mode 100644 migrations/support_sessions.sql create mode 100644 migrations/unify_patient_id.sql create mode 100644 scripts/simulation/simulateUsage.js create mode 100644 scripts/simulation/simulation.config.js create mode 100644 scripts/simulation/simulationLogger.js delete mode 100644 src/assets/demo/code.scss delete mode 100644 src/assets/demo/demo.scss delete mode 100644 src/assets/demo/flags/flags.css create mode 100644 src/components/AjudaDrawer.vue delete mode 100644 src/components/BlockViewer.vue delete mode 100644 src/components/FloatingConfigurator.vue create mode 100644 src/composables/Usedocshealth.js create mode 100644 src/composables/useAjuda.js create mode 100644 src/composables/useDocsAdmin.js create mode 100644 src/composables/useFeriados.js create mode 100644 src/features/agenda/components/BloqueioDialog.vue create mode 100644 src/features/agenda/components/ProximosFeriadosCard.vue create mode 100644 src/features/agenda/composables/__tests__/useRecurrence.spec.js create mode 100644 src/features/agenda/composables/useProfessionalPricing.js create mode 100644 src/features/agenda/composables/useRecurrence.js delete mode 100644 src/features/agenda/domain/agenda.types.js create mode 100644 src/features/agenda/pages/AgendaRecorrenciasPage.vue create mode 100644 src/features/agenda/pages/AgendamentosRecebidosPage.vue create mode 100644 src/features/agenda/services/__tests__/agendaMappers.spec.js delete mode 100644 src/layout/ConfiguracoesPage - Copia.vue create mode 100644 src/layout/configuracoes/BloqueiosPage.vue create mode 100644 src/layout/configuracoes/ConfiguracoesAgendadorPage.vue create mode 100644 src/layout/configuracoes/ConfiguracoesPagamentoPage.vue create mode 100644 src/layout/configuracoes/ConfiguracoesPrecificacaoPage.vue delete mode 100644 src/navigation/menus/sakai.demo.menu.js delete mode 100644 src/router/routes.demo.js create mode 100644 src/support/components/SupportDebugBanner.vue create mode 100644 src/support/supportDebugStore.js create mode 100644 src/support/supportLogger.js create mode 100644 src/support/supportSessionService.js create mode 100644 src/utils/feriadosBR.js create mode 100644 src/utils/menuPageOptions.js delete mode 100644 src/views/pages/Documentation.vue create mode 100644 src/views/pages/public/AgendadorPublicoPage.vue create mode 100644 src/views/pages/saas/SaasDocsPage.vue create mode 100644 src/views/pages/saas/SaasFaqPage.vue create mode 100644 src/views/pages/saas/SaasFeriadosPage.vue create mode 100644 src/views/pages/saas/SaasSupportPage.vue create mode 100644 src/views/pages/therapist/RelatoriosPage.vue delete mode 100644 src/views/uikit/ButtonDoc.vue delete mode 100644 src/views/uikit/ChartDoc.vue delete mode 100644 src/views/uikit/FileDoc.vue delete mode 100644 src/views/uikit/FormLayout.vue delete mode 100644 src/views/uikit/InputDoc.vue delete mode 100644 src/views/uikit/ListDoc.vue delete mode 100644 src/views/uikit/MediaDoc.vue delete mode 100644 src/views/uikit/MenuDoc.vue delete mode 100644 src/views/uikit/MessagesDoc.vue delete mode 100644 src/views/uikit/MiscDoc.vue delete mode 100644 src/views/uikit/OverlayDoc.vue delete mode 100644 src/views/uikit/PanelsDoc.vue delete mode 100644 src/views/uikit/TableDoc.vue delete mode 100644 src/views/uikit/TimelineDoc.vue delete mode 100644 src/views/uikit/TreeDoc.vue delete mode 100644 src/views/utilities/Blocks.vue diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..566e886 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,17 @@ +{ + "permissions": { + "allow": [ + "Bash(node:*)", + "Bash(powershell:*)", + "Bash(grep:*)", + "Bash(cd \"D:/leonohama/AgenciaPsi.com.br/Sistema/agenciapsi-primesakai\" && sed -i \\\\\n 's/console\\\\.time\\(tlabel\\)/const _perfEnd = logPerf\\('\\\\''router.guard'\\\\'', tlabel\\)/g' \\\\\n src/router/guards.js && echo \"console.time substituído\")", + "Bash(cd \"D:/leonohama/AgenciaPsi.com.br/Sistema/agenciapsi-primesakai\" && sed -i \\\\\n 's/console\\\\.timeEnd\\(tlabel\\)/_perfEnd\\(\\)/g' \\\\\n src/router/guards.js && echo \"console.timeEnd substituído\")", + "Bash(cd \"D:/leonohama/AgenciaPsi.com.br/Sistema/agenciapsi-primesakai\" && npm install --save-dev vitest @vitest/ui 2>&1 | tail -5)", + "Bash(find \"D:\\\\leonohama\\\\AgenciaPsi.com.br\\\\Sistema\\\\agenciapsi-primesakai/DBS\" -name \"*.sql\" -type f 2>/dev/null | head -10)", + "Bash(find \"D:\\\\leonohama\\\\AgenciaPsi.com.br\\\\Sistema\\\\agenciapsi-primesakai/DBS\" -name \"*.sql\" -type f 2>/dev/null | xargs grep -l \"agenda_eventos\" | head -3)", + "Bash(find \"D:\\\\leonohama\\\\AgenciaPsi.com.br\\\\Sistema\\\\agenciapsi-primesakai/DBS/2026-03-11\" -name \"*.sql\" -type f 2>/dev/null | head -3)", + "Bash(find \"D:\\\\leonohama\\\\AgenciaPsi.com.br\\\\Sistema\\\\agenciapsi-primesakai\" -type f -name \"*.sql\" 2>/dev/null | xargs grep -l \"agenda_eventos\" 2>/dev/null | head -5)", + "Bash(find /d/leonohama/AgenciaPsi.com.br/Sistema/agenciapsi-primesakai/src -name \"*[Pp]ricing*\" -o -name \"*[Pp]reco*\" -o -name \"*[Vv]alor*\" 2>/dev/null | head -20)" + ] + } +} diff --git a/AUDITORIA.md b/AUDITORIA.md new file mode 100644 index 0000000..bde1865 --- /dev/null +++ b/AUDITORIA.md @@ -0,0 +1,274 @@ +# Auditoria Técnica — AgenciaPsi MVP +**Data:** 2026-03-11 +**Stack:** Vue 3 · PrimeVue · Supabase · PostgreSQL · FullCalendar +**Modelo:** claude-sonnet-4-6 + +--- + +## 1. Visão Geral Arquitetural + +**Pontos fortes:** +- Estrutura feature-based bem definida (`features/agenda`, `features/patients`) +- Separação correta: repository → composable → page +- Multi-tenancy é first-class: `tenant_id` em todos os queries críticos +- Sistema de guards robusto: RBAC + entitlements + tenantFeatures + session race-condition handling +- `useRecurrence` é bem arquitetado: virtual occurrences no frontend + exceções no banco (sem N linhas futuras) + +--- + +## 2. Bugs Críticos + +### ✅ [RESOLVIDO] `useRecurrence.js` — variável `occurrenceCount` não declarada + +**Bug original:** branches `custom_weekdays`, `monthly` e `yearly` usavam `occurrenceCount` sem declará-la → `ReferenceError` em runtime. Nenhum dos três contava ocorrências anteriores ao range, então `max_occurrences` nunca funcionava corretamente. + +**Correção (Sessão 2):** Cada branch ganhou `let occurrenceCount = 0` + fase de pré-contagem de `ruleStart` até `effStart`. + +**Resolvido em:** Sessão 2 — 2026-03-11 + +--- + +### ✅ [RESOLVIDO] Exceção de remarcação fora do range não aparece + +**Bug original:** `loadExceptions` só buscava `original_date` no range. Se `original_date` estivesse fora mas `new_date` caísse dentro, a sessão remarcada não aparecia. + +**Correção (Sessão 3):** +- `loadExceptions`: duas queries paralelas — `q1` (original_date no range) + `q2` (reschedule com new_date no range). Mescladas e deduplicadas por `id`. +- `expandRules` post-pass: itera exceções não consumidas (`handledExIds`), injeta inbound reschedules com `buildOccurrence(rule, newDate, ex.original_date, ex)`. + +**Resolvido em:** Sessão 3 — 2026-03-11 + +--- + +## 3. Segurança + +### ✅ [RESOLVIDO] SQL dumps no repositório + +**Arquivos:** `schema.sql`, `backup.sql`, `data_dump.sql`, `full_dump.sql` + +Verificado via `git log --all --full-history` — arquivos **nunca foram commitados**. Movidos para pasta externa ao repositório. Nenhuma purga de histórico necessária. + +**Resolvido em:** Sessão 3 — 2026-03-11 + +--- + +### ✅ [RESOLVIDO] `useAgendaEvents` — sem `tenant_id` em nenhuma operação + +**Correção (Sessão 2):** `tenant_id` injetado em `create()`, `loadMyRange()`, `update()`, `remove()`, `removeSeriesFrom()`, `removeAllSeries()`. Helpers `assertTenantId()` e `getUid()` adicionados. + +**Resolvido em:** Sessão 2 — 2026-03-11 + +--- + +### ✅ [RESOLVIDO] `loadRules` em `useRecurrence` sem filtro `tenant_id` + +**Correção (Sessão 2):** `loadRules` e `loadAndExpand` aceitam `tenantId` opcional e aplicam `.eq('tenant_id', tenantId)`. Call site em `AgendaTerapeutaPage._reloadRange` passa `tenantStore.activeTenantId`. + +**Resolvido em:** Sessão 2 — 2026-03-11 + +--- + +### ✅ [RESOLVIDO] `console.log` expõe dados de pacientes no browser + +**Correção (Sessão 2):** Todos os `console.*` substituídos pelo `supportLogger`. Logs só aparecem quando modo suporte está ativo (token válido no banco). + +**Resolvido em:** Sessão 2 — 2026-03-11 +**Arquivos criados:** `src/support/supportLogger.js`, `src/support/supportDebugStore.js` + +--- + +### 🟡 [ABERTO] `window.__guardsBound` / `window.__supabaseAuthListenerBound` + +Usar `window.*` para controle de listeners é frágil em hot-reload. +**Solução:** Gerenciar via módulo singleton ou `app.config.globalProperties`. + +--- + +### ✅ [RESOLVIDO] `globalRole` do `profiles` sem cache no guard + +Adicionados `globalRoleCacheUid` + `globalRoleCache` no `guards.js`. +Cache invalida em: uid change, SIGNED_OUT, SIGNED_IN com user diferente. +Query ao banco ocorre apenas na primeira navegação por sessão. + +**Resolvido em:** Sessão 4 — 2026-03-11 + +--- + +## 4. Duplicações e Inconsistências + +### ✅ [RESOLVIDO] Dois composables para a mesma entidade + +`src/composables/useAgendaEvents.js` era código morto (sem imports). Deletado. +O autoritativo `src/features/agenda/composables/useAgendaEvents.js` permanece. + +**Resolvido em:** Sessão 3 — 2026-03-11 + +--- + +### ✅ [RESOLVIDO] Dois mappers para agenda + +`src/features/agenda/domain/agenda.mappers.js` estava vazio e sem imports. Deletado. +`src/features/agenda/domain/agenda.types.js` também sem imports. Deletado. Diretório `domain/` removido. +O autoritativo `src/features/agenda/services/agendaMappers.js` permanece. + +**Resolvido em:** Sessão 4 — 2026-03-11 + +--- + +### ✅ [RESOLVIDO] N+1 Query — migração `paciente_id` → `patient_id` + +**Resolvido em:** Sessão 3 — 2026-03-11 + +**Migration executada:** `migrations/unify_patient_id.sql` +- UPDATE copiou `paciente_id` → `patient_id` onde null (resultado: 0 órfãos — todos já tinham `patient_id`) +- `ALTER TABLE agenda_eventos DROP COLUMN paciente_id` executado com sucesso + +**Código atualizado:** +- `useAgendaEvents.js`: `paciente_id` removido do `BASE_SELECT`; `create()`/`update()` stripam `paciente_id` do payload +- `agendaRepository.js`: workaround N+1 de orphan ids removido +- `agendaMappers.js`: `paciente_id` agora é alias de `patient_id` (UI only) +- `AgendaTerapeutaPage.vue` + `AgendaClinicaPage.vue`: `pickDbFields` usa `patient_id` +- `AgendamentosRecebidosPage.vue`: `dbFields` removeu `paciente_id` +- `PatientsListPage.vue` + `AgendaEventDialog.vue`: `.or()` → `.eq('patient_id', id)` + +--- + +## 5. Limpeza Necessária + +### ✅ [RESOLVIDO] Template Sakai removido — bundle de produção + +**Resolvido em:** Sessão 3 — 2026-03-11 + +**Removidos:** `src/views/uikit/` (15 arquivos), `src/views/utilities/Blocks.vue`, `src/components/BlockViewer.vue`, `src/components/FloatingConfigurator.vue`, `src/views/pages/Documentation.vue`, `src/assets/demo/`, `src/navigation/menus/sakai.demo.menu.js`, `src/router/routes.demo.js`, `src/assets/styles.scss` (@use demo removido) + +**Referências limpas:** `package.json` renomeado para `agenciapsi`, demoRoutes e sakaiDemoMenu removidos dos index files, `FloatingConfigurator` removido de Login, NotFound, Access, Error, ResetPasswordPage. + +--- + +### 🟡 [PARCIAL] Arquivos obsoletos no projeto + +**Deletados (Sessão 4):** +- `src/layout/ConfiguracoesPage-old.vue` +- `src/features/agenda/domain/` (diretório inteiro — 2 arquivos não usados) + +**Ainda presentes:** +- `src/layout/ConfiguracoesPage - Copia.vue` — verificar se está no git (staged como D) +- `src/views/pages/public/Landingpage-v1 - bkp.vue` +- `comandos.txt` (na raiz) + +--- + +### ✅ [RESOLVIDO] Logs excessivos em produção + +`console.time/timeLog/timeEnd/warn/error` em `guards.js` substituídos por `logGuard()`, `logError()`, `logPerf()`. + +**Resolvido em:** Sessão 2 — 2026-03-11 + +--- + +## 6. Status das Features do MVP + +| Feature | Status | Observação | +|---|---|---| +| Agenda de sessões | ✅ Implementado | FullCalendar + composables | +| Cadastro de pacientes | ✅ Implementado | CRUD completo | +| Recorrência de sessões | ✅ Corrigido | Bugs de occurrenceCount e cross-range resolvidos | +| Sessões presenciais/online | ✅ Implementado | campo `modalidade` | +| Controle de faltas | ✅ Implementado | `exception_type = 'patient_missed'` | +| Remarcação | ✅ Corrigido | Bug cross-range resolvido (Sessão 3) | +| Bloqueio de agenda | ✅ Implementado | `BloqueioDialog.vue` | +| Agendamento online | ✅ Implementado | `AgendadorPublicoPage.vue` | +| Prontuário | ✅ Integrado | Seção "Sessões" adicionada ao `PatientProntuario.vue` | +| Notificações/lembretes | ❌ Não implementado | Sem trigger/edge function | +| Financeiro/faturamento | ⚠️ Parcial | Páginas de plano mas sem sessão→pagamento | +| Relatórios | ✅ Implementado | `RelatoriosPage.vue` — terapeuta — sessões, faltas, taxa, gráfico | + +--- + +## 7. Backlog Técnico + +- [ ] Cache de `globalRole` no guard (reduzir queries por navegação) +- [ ] Implementar notificações: WhatsApp/Email via Supabase Edge Functions +- [ ] Integração prontuário ↔ sessões +- [ ] Integração sessão ↔ pagamento (financeiro) +- [ ] Relatórios básicos: sessões realizadas, faltas, receita +- [ ] Migrar domínio de recorrência para TypeScript +- [ ] Consolidar dois mappers de agenda (`agendaMappers.js` vs `domain/agenda.mappers.js`) +- [ ] Remover arquivos obsoletos (ConfiguracoesPage-old, Landingpage-v1 bkp, etc.) + +--- + +## 8. Prioridades de Ação + +### ✅ Fazer AGORA — todos concluídos +1. `[x]` ~~Remover dumps SQL~~ → nunca commitados, movidos para fora do repo +2. `[x]` ~~Corrigir bug `occurrenceCount`~~ → pré-contagem em todos os branches +3. `[x]` ~~Adicionar `tenant_id` ao `useAgendaEvents` e `loadRules`~~ → injetado em todas as operações +4. `[x]` ~~Remover `console.log` com dados de pacientes~~ → `supportLogger` + +### ✅ Fazer em seguida — todos concluídos +5. `[x]` ~~Corrigir bug remarcação cross-range~~ → 2 queries + post-pass em `expandRules` +6. `[x]` ~~Consolidar dois `useAgendaEvents`~~ → legado deletado +7. `[x]` ~~Unificar `paciente_id` + `patient_id`~~ → migration executada + código limpo +8. `[x]` ~~Remover Sakai de demo~~ → removido + menu SaaS limpo + +### Backlog +9. `[x]` Cache de `globalRole` no guard — `globalRoleCacheUid/globalRoleCache` em guards.js +10. `[ ]` Notificações (WhatsApp/Email via Edge Functions) ← próximo +11. `[x]` Integração prontuário ↔ sessões — seção "Sessões" em `PatientProntuario.vue` +12. `[x]` Relatórios básicos — `RelatoriosPage.vue` em /therapist/relatorios +13. `[x]` Consolidar mappers de agenda — `domain/` deletado, `agendaMappers.js` é único + +--- + +## 9. Sistema de Suporte Técnico SaaS + +Sistema seguro para admins SaaS acessarem a agenda de terapeutas em modo debug. + +| Arquivo | Responsabilidade | +|---|---| +| `migrations/support_sessions.sql` | Tabela, índices, RLS, RPCs (token gerado via `gen_random_uuid()` duplo — sem pgcrypto) | +| `src/support/supportLogger.js` | Logger centralizado — silencioso fora do modo suporte | +| `src/support/supportDebugStore.js` | Store Pinia — valida token via RPC `validate_support_session` | +| `src/support/supportSessionService.js` | CRUD de sessões de suporte (criar/listar/revogar) | +| `src/support/components/SupportDebugBanner.vue` | Banner fixo na agenda com painel de logs filtráveis | +| `src/views/pages/saas/SaasSupportPage.vue` | Painel SaaS para gerenciar sessões de suporte | + +**RPCs no banco:** +- `create_support_session(p_tenant_id, p_ttl_minutes)` → `{ token, expires_at, session_id }` +- `validate_support_session(p_token)` → `{ valid, tenant_id }` +- `revoke_support_session(p_token)` → `boolean` + +--- + +## 10. Histórico de Sessões + +### Sessão 1 — 2026-03-11 +- Auditoria técnica completa gerada +- Nenhum item resolvido + +### Sessão 2 — 2026-03-11 +- Sistema de suporte técnico SaaS implementado (migration + 5 arquivos criados) +- Bug `occurrenceCount` corrigido (itens 2 e 4) +- `tenant_id` adicionado ao `useAgendaEvents` e `loadRules` (item 3) +- `console.*` substituídos por `supportLogger` + +### Sessão 4 — 2026-03-11 +- Cache `globalRole` adicionado ao guard (item 9) — sem query ao banco por navegação +- Integração prontuário ↔ sessões (item 11) — painel "Sessões" em `PatientProntuario.vue` +- `RelatoriosPage.vue` criada em `/therapist/relatorios` (item 12) — cards, gráfico Chart.js, tabela DataTable +- Consolidação mappers (item 13) — `domain/agenda.mappers.js` vazio deletado + `agenda.types.js` + dir `domain/` +- `ConfiguracoesPage-old.vue` deletado (limpeza) + +### Sessão 3 — 2026-03-11 +- Bug remarcação cross-range resolvido (item 5) +- `logPerf is not defined` em guards.js corrigido +- `pgcrypto` → substituído por `gen_random_uuid()` duplo no support_sessions +- Sakai demo removido completamente (item 8) + `styles.scss` corrigido +- `useAgendaEvents` legado deletado (item 6) +- `paciente_id` unificado em `patient_id` — migration executada (item 7) +- SQL dumps confirmados como nunca commitados (item 1 encerrado) + +--- + +*Para retomar: devolva este arquivo ao início da conversa e indique qual item quer atacar.* diff --git a/DBS/2026-03-11/Nova-Dev-Doc/supervisor_fase1.sql b/DBS/2026-03-11/Nova-Dev-Doc/supervisor_fase1.sql new file mode 100644 index 0000000..87ecaa1 --- /dev/null +++ b/DBS/2026-03-11/Nova-Dev-Doc/supervisor_fase1.sql @@ -0,0 +1,414 @@ +-- ============================================================ +-- SUPERVISOR — Fase 1 +-- Aplicar no Supabase SQL Editor (em ordem) +-- ============================================================ + + +-- ──────────────────────────────────────────────────────────── +-- 1. tenants.kind → adiciona 'supervisor' +-- ──────────────────────────────────────────────────────────── +ALTER TABLE public.tenants + DROP CONSTRAINT IF EXISTS tenants_kind_check; + +ALTER TABLE public.tenants + ADD CONSTRAINT tenants_kind_check + CHECK (kind = ANY (ARRAY[ + 'therapist', + 'clinic_coworking', + 'clinic_reception', + 'clinic_full', + 'clinic', + 'saas', + 'supervisor' -- ← novo + ])); + + +-- ──────────────────────────────────────────────────────────── +-- 2. plans.target → adiciona 'supervisor' +-- ──────────────────────────────────────────────────────────── +ALTER TABLE public.plans + DROP CONSTRAINT IF EXISTS plans_target_check; + +ALTER TABLE public.plans + ADD CONSTRAINT plans_target_check + CHECK (target = ANY (ARRAY[ + 'patient', + 'therapist', + 'clinic', + 'supervisor' -- ← novo + ])); + + +-- ──────────────────────────────────────────────────────────── +-- 3. plans.max_supervisees — limite de supervisionados +-- ──────────────────────────────────────────────────────────── +ALTER TABLE public.plans + ADD COLUMN IF NOT EXISTS max_supervisees integer DEFAULT NULL; + +COMMENT ON COLUMN public.plans.max_supervisees IS + 'Limite de terapeutas que podem ser supervisionados. Apenas para planos target=supervisor. NULL = sem limite.'; + + +-- ──────────────────────────────────────────────────────────── +-- 4. Planos supervisor_free e supervisor_pro +-- ──────────────────────────────────────────────────────────── +INSERT INTO public.plans (key, name, description, target, is_active, max_supervisees) +VALUES + ( + 'supervisor_free', + 'Supervisor Free', + 'Plano gratuito de supervisão. Até 3 terapeutas supervisionados.', + 'supervisor', + true, + 3 + ), + ( + 'supervisor_pro', + 'Supervisor PRO', + 'Plano profissional de supervisão. Até 20 terapeutas supervisionados.', + 'supervisor', + true, + 20 + ) +ON CONFLICT (key) DO UPDATE + SET + name = EXCLUDED.name, + description = EXCLUDED.description, + target = EXCLUDED.target, + is_active = EXCLUDED.is_active, + max_supervisees = EXCLUDED.max_supervisees; + + +-- ──────────────────────────────────────────────────────────── +-- 5. Features de supervisor +-- ──────────────────────────────────────────────────────────── +INSERT INTO public.features (key, name, descricao) +VALUES + ( + 'supervisor.access', + 'Acesso à Supervisão', + 'Acesso básico ao espaço de supervisão (sala, lista de supervisionados).' + ), + ( + 'supervisor.invite', + 'Convidar Supervisionados', + 'Permite convidar terapeutas para participar da sala de supervisão.' + ), + ( + 'supervisor.sessions', + 'Sessões de Supervisão', + 'Agendamento e registro de sessões de supervisão.' + ), + ( + 'supervisor.reports', + 'Relatórios de Supervisão', + 'Relatórios avançados de progresso e evolução dos supervisionados.' + ) +ON CONFLICT (key) DO UPDATE + SET + name = EXCLUDED.name, + descricao = EXCLUDED.descricao; + + +-- ──────────────────────────────────────────────────────────── +-- 6. plan_features — vincula features aos planos supervisor +-- ──────────────────────────────────────────────────────────── +DO $$ +DECLARE + v_free_id uuid; + v_pro_id uuid; + v_f_access uuid; + v_f_invite uuid; + v_f_sessions uuid; + v_f_reports uuid; +BEGIN + SELECT id INTO v_free_id FROM public.plans WHERE key = 'supervisor_free'; + SELECT id INTO v_pro_id FROM public.plans WHERE key = 'supervisor_pro'; + + SELECT id INTO v_f_access FROM public.features WHERE key = 'supervisor.access'; + SELECT id INTO v_f_invite FROM public.features WHERE key = 'supervisor.invite'; + SELECT id INTO v_f_sessions FROM public.features WHERE key = 'supervisor.sessions'; + SELECT id INTO v_f_reports FROM public.features WHERE key = 'supervisor.reports'; + + -- supervisor_free: access + invite (limitado por max_supervisees=3) + INSERT INTO public.plan_features (plan_id, feature_id) + VALUES + (v_free_id, v_f_access), + (v_free_id, v_f_invite) + ON CONFLICT DO NOTHING; + + -- supervisor_pro: tudo + INSERT INTO public.plan_features (plan_id, feature_id) + VALUES + (v_pro_id, v_f_access), + (v_pro_id, v_f_invite), + (v_pro_id, v_f_sessions), + (v_pro_id, v_f_reports) + ON CONFLICT DO NOTHING; +END; +$$; + + +-- ──────────────────────────────────────────────────────────── +-- 7. activate_subscription_from_intent — suporte a supervisor +-- Supervisor = pessoal (user_id), sem tenant_id (igual therapist) +-- ──────────────────────────────────────────────────────────── +CREATE OR REPLACE FUNCTION public.activate_subscription_from_intent(p_intent_id uuid) +RETURNS public.subscriptions +LANGUAGE plpgsql SECURITY DEFINER +AS $$ +declare + v_intent record; + v_sub public.subscriptions; + v_days int; + v_user_id uuid; + v_plan_id uuid; + v_target text; +begin + -- lê pela VIEW unificada + select * into v_intent + from public.subscription_intents + where id = p_intent_id; + + if not found then + raise exception 'Intent não encontrado: %', p_intent_id; + end if; + + if v_intent.status <> 'paid' then + raise exception 'Intent precisa estar paid para ativar assinatura'; + end if; + + -- resolve target e plan_id via plans.key + select p.id, p.target + into v_plan_id, v_target + from public.plans p + where p.key = v_intent.plan_key + limit 1; + + if v_plan_id is null then + raise exception 'Plano não encontrado em plans.key = %', v_intent.plan_key; + end if; + + v_target := lower(coalesce(v_target, '')); + + -- ✅ supervisor adicionado + if v_target not in ('clinic', 'therapist', 'supervisor') then + raise exception 'Target inválido em plans.target: %', v_target; + end if; + + -- regra por target + if v_target = 'clinic' then + if v_intent.tenant_id is null then + raise exception 'Intent sem tenant_id'; + end if; + else + -- therapist ou supervisor: vinculado ao user + v_user_id := v_intent.user_id; + if v_user_id is null then + v_user_id := v_intent.created_by_user_id; + end if; + end if; + + if v_target in ('therapist', 'supervisor') and v_user_id is null then + raise exception 'Não foi possível determinar user_id para assinatura %.', v_target; + end if; + + -- cancela assinatura ativa anterior + if v_target = 'clinic' then + update public.subscriptions + set status = 'cancelled', + cancelled_at = now() + where tenant_id = v_intent.tenant_id + and plan_id = v_plan_id + and status = 'active'; + else + -- therapist ou supervisor + update public.subscriptions + set status = 'cancelled', + cancelled_at = now() + where user_id = v_user_id + and plan_id = v_plan_id + and status = 'active' + and tenant_id is null; + end if; + + -- duração do plano (30 dias para mensal) + v_days := case + when lower(coalesce(v_intent.interval, 'month')) = 'year' then 365 + else 30 + end; + + -- cria nova assinatura + insert into public.subscriptions ( + user_id, + plan_id, + status, + started_at, + expires_at, + cancelled_at, + activated_at, + tenant_id, + plan_key, + interval, + source, + created_at, + updated_at + ) + values ( + case when v_target = 'clinic' then null else v_user_id end, + v_plan_id, + 'active', + now(), + now() + make_interval(days => v_days), + null, + now(), + case when v_target = 'clinic' then v_intent.tenant_id else null end, + v_intent.plan_key, + v_intent.interval, + 'manual', + now(), + now() + ) + returning * into v_sub; + + -- grava vínculo intent → subscription + if v_target = 'clinic' then + update public.subscription_intents_tenant + set subscription_id = v_sub.id + where id = p_intent_id; + else + update public.subscription_intents_personal + set subscription_id = v_sub.id + where id = p_intent_id; + end if; + + return v_sub; +end; +$$; + + +-- ──────────────────────────────────────────────────────────── +-- 8. subscriptions_validate_scope — suporte a supervisor +-- ──────────────────────────────────────────────────────────── +CREATE OR REPLACE FUNCTION public.subscriptions_validate_scope() +RETURNS trigger +LANGUAGE plpgsql +AS $$ +DECLARE + v_target text; +BEGIN + SELECT lower(p.target) INTO v_target + FROM public.plans p + WHERE p.id = NEW.plan_id; + + IF v_target IS NULL THEN + RAISE EXCEPTION 'Plano inválido (target nulo).'; + END IF; + + IF v_target = 'clinic' THEN + IF NEW.tenant_id IS NULL THEN + RAISE EXCEPTION 'Assinatura clinic exige tenant_id.'; + END IF; + IF NEW.user_id IS NOT NULL THEN + RAISE EXCEPTION 'Assinatura clinic não pode ter user_id (XOR).'; + END IF; + + ELSIF v_target IN ('therapist', 'supervisor') THEN + -- supervisor é pessoal como therapist + IF NEW.tenant_id IS NOT NULL THEN + RAISE EXCEPTION 'Assinatura % não deve ter tenant_id.', v_target; + END IF; + IF NEW.user_id IS NULL THEN + RAISE EXCEPTION 'Assinatura % exige user_id.', v_target; + END IF; + + ELSIF v_target = 'patient' THEN + IF NEW.tenant_id IS NOT NULL THEN + RAISE EXCEPTION 'Assinatura patient não deve ter tenant_id.'; + END IF; + IF NEW.user_id IS NULL THEN + RAISE EXCEPTION 'Assinatura patient exige user_id.'; + END IF; + + ELSE + RAISE EXCEPTION 'Target de plano inválido: %', v_target; + END IF; + + RETURN NEW; +END; +$$; + + +-- ──────────────────────────────────────────────────────────── +-- 9. subscription_intents_view_insert — suporte a supervisor +-- supervisor é roteado como therapist (tabela personal) +-- ──────────────────────────────────────────────────────────── +CREATE OR REPLACE FUNCTION public.subscription_intents_view_insert() +RETURNS trigger +LANGUAGE plpgsql SECURITY DEFINER +AS $$ +declare + v_target text; + v_plan_id uuid; +begin + select p.id, p.target into v_plan_id, v_target + from public.plans p + where p.key = new.plan_key; + + if v_plan_id is null then + raise exception 'Plano inválido: plan_key=%', new.plan_key; + end if; + + if lower(v_target) = 'clinic' then + if new.tenant_id is null then + raise exception 'Intenção clinic exige tenant_id.'; + end if; + + insert into public.subscription_intents_tenant ( + id, tenant_id, created_by_user_id, email, + plan_id, plan_key, interval, amount_cents, currency, + status, source, notes, created_at, paid_at + ) values ( + coalesce(new.id, gen_random_uuid()), + new.tenant_id, new.created_by_user_id, new.email, + v_plan_id, new.plan_key, coalesce(new.interval,'month'), + new.amount_cents, coalesce(new.currency,'BRL'), + coalesce(new.status,'pending'), coalesce(new.source,'manual'), + new.notes, coalesce(new.created_at, now()), new.paid_at + ); + + new.plan_target := 'clinic'; + return new; + end if; + + -- therapist ou supervisor → tabela personal + if lower(v_target) in ('therapist', 'supervisor') then + insert into public.subscription_intents_personal ( + id, user_id, created_by_user_id, email, + plan_id, plan_key, interval, amount_cents, currency, + status, source, notes, created_at, paid_at + ) values ( + coalesce(new.id, gen_random_uuid()), + new.user_id, new.created_by_user_id, new.email, + v_plan_id, new.plan_key, coalesce(new.interval,'month'), + new.amount_cents, coalesce(new.currency,'BRL'), + coalesce(new.status,'pending'), coalesce(new.source,'manual'), + new.notes, coalesce(new.created_at, now()), new.paid_at + ); + + new.plan_target := lower(v_target); -- 'therapist' ou 'supervisor' + return new; + end if; + + raise exception 'Target de plano não suportado: %', v_target; +end; +$$; + + +-- ──────────────────────────────────────────────────────────── +-- FIM — verificação rápida +-- ──────────────────────────────────────────────────────────── +SELECT key, name, target, max_supervisees +FROM public.plans +WHERE target = 'supervisor' +ORDER BY key; diff --git a/DBS/2026-03-11/Novo-DB/fix_missing_subscriptions.sql b/DBS/2026-03-11/Novo-DB/fix_missing_subscriptions.sql new file mode 100644 index 0000000..898766d --- /dev/null +++ b/DBS/2026-03-11/Novo-DB/fix_missing_subscriptions.sql @@ -0,0 +1,220 @@ +-- ============================================================================= +-- FIX: Atribuir plano free a usuários/tenants sem assinatura ativa +-- ============================================================================= +-- Execute no SQL Editor do Supabase (service_role) +-- Idempotente: só insere onde não existe assinatura ativa. +-- +-- Regras: +-- • tenant kind = 'therapist' → therapist_free (por user_id do admin) +-- • tenant kind IN (clinic_*) → clinic_free (por tenant_id) +-- • profiles.account_type = 'patient' / portal_user → patient_free (por user_id) +-- ============================================================================= + +BEGIN; + +-- ────────────────────────────────────────────────────────────────────────────── +-- DIAGNÓSTICO — mostra o estado atual antes de corrigir +-- ────────────────────────────────────────────────────────────────────────────── + +DO $$ +DECLARE + r RECORD; +BEGIN + RAISE NOTICE '=== DIAGNÓSTICO DE ASSINATURAS ==='; + RAISE NOTICE ''; + + -- Terapeutas sem plano + RAISE NOTICE '--- Terapeutas SEM assinatura ativa ---'; + FOR r IN + SELECT + tm.user_id, + p.full_name, + t.id AS tenant_id, + t.name AS tenant_name + FROM public.tenant_members tm + JOIN public.tenants t ON t.id = tm.tenant_id + JOIN public.profiles p ON p.id = tm.user_id + WHERE t.kind = 'therapist' + AND tm.role = 'tenant_admin' + AND tm.status = 'active' + AND NOT EXISTS ( + SELECT 1 FROM public.subscriptions s + WHERE s.user_id = tm.user_id + AND s.status = 'active' + ) + LOOP + RAISE NOTICE ' FALTANDO: % (%) — tenant %', r.full_name, r.user_id, r.tenant_id; + END LOOP; + + -- Clínicas sem plano + RAISE NOTICE ''; + RAISE NOTICE '--- Clínicas SEM assinatura ativa ---'; + FOR r IN + SELECT t.id, t.name, t.kind + FROM public.tenants t + WHERE t.kind IN ('clinic_coworking', 'clinic_reception', 'clinic_full', 'clinic') + AND NOT EXISTS ( + SELECT 1 FROM public.subscriptions s + WHERE s.tenant_id = t.id + AND s.status = 'active' + ) + LOOP + RAISE NOTICE ' FALTANDO: % (%) — kind %', r.name, r.id, r.kind; + END LOOP; + + -- Pacientes sem plano + RAISE NOTICE ''; + RAISE NOTICE '--- Pacientes SEM assinatura ativa ---'; + FOR r IN + SELECT p.id, p.full_name + FROM public.profiles p + WHERE p.account_type = 'patient' + AND NOT EXISTS ( + SELECT 1 FROM public.subscriptions s + WHERE s.user_id = p.id + AND s.status = 'active' + ) + LOOP + RAISE NOTICE ' FALTANDO: % (%)', r.full_name, r.id; + END LOOP; + + RAISE NOTICE ''; + RAISE NOTICE '=== FIM DO DIAGNÓSTICO — aplicando correções... ==='; +END; +$$; + + +-- ────────────────────────────────────────────────────────────────────────────── +-- CORREÇÃO 1: Terapeutas sem assinatura → therapist_free +-- Escopo: user_id do tenant_admin do tenant kind='therapist' +-- ────────────────────────────────────────────────────────────────────────────── + +INSERT INTO public.subscriptions ( + user_id, plan_id, plan_key, status, interval, + current_period_start, current_period_end, + source, started_at, activated_at +) +SELECT + tm.user_id, + p.id, + p.key, + 'active', + 'month', + now(), + now() + interval '30 days', + 'fix_seed', + now(), + now() +FROM public.tenant_members tm +JOIN public.tenants t ON t.id = tm.tenant_id +JOIN public.plans p ON p.key = 'therapist_free' +WHERE t.kind = 'therapist' + AND tm.role = 'tenant_admin' + AND tm.status = 'active' + AND NOT EXISTS ( + SELECT 1 FROM public.subscriptions s + WHERE s.user_id = tm.user_id + AND s.status = 'active' + ); + + +-- ────────────────────────────────────────────────────────────────────────────── +-- CORREÇÃO 2: Clínicas sem assinatura → clinic_free +-- Escopo: tenant_id +-- ────────────────────────────────────────────────────────────────────────────── + +INSERT INTO public.subscriptions ( + tenant_id, plan_id, plan_key, status, interval, + current_period_start, current_period_end, + source, started_at, activated_at +) +SELECT + t.id, + p.id, + p.key, + 'active', + 'month', + now(), + now() + interval '30 days', + 'fix_seed', + now(), + now() +FROM public.tenants t +JOIN public.plans p ON p.key = 'clinic_free' +WHERE t.kind IN ('clinic_coworking', 'clinic_reception', 'clinic_full', 'clinic') + AND NOT EXISTS ( + SELECT 1 FROM public.subscriptions s + WHERE s.tenant_id = t.id + AND s.status = 'active' + ); + + +-- ────────────────────────────────────────────────────────────────────────────── +-- CORREÇÃO 3: Pacientes sem assinatura → patient_free +-- Escopo: user_id +-- ────────────────────────────────────────────────────────────────────────────── + +INSERT INTO public.subscriptions ( + user_id, plan_id, plan_key, status, interval, + current_period_start, current_period_end, + source, started_at, activated_at +) +SELECT + pr.id, + p.id, + p.key, + 'active', + 'month', + now(), + now() + interval '30 days', + 'fix_seed', + now(), + now() +FROM public.profiles pr +JOIN public.plans p ON p.key = 'patient_free' +WHERE pr.account_type = 'patient' + AND NOT EXISTS ( + SELECT 1 FROM public.subscriptions s + WHERE s.user_id = pr.id + AND s.status = 'active' + ); + + +-- ────────────────────────────────────────────────────────────────────────────── +-- CONFIRMAÇÃO — mostra o que foi inserido (source = 'fix_seed') +-- ────────────────────────────────────────────────────────────────────────────── + +DO $$ +DECLARE + r RECORD; + total INT := 0; +BEGIN + RAISE NOTICE ''; + RAISE NOTICE '=== ASSINATURAS CRIADAS NESTA EXECUÇÃO ==='; + + FOR r IN + SELECT + s.plan_key, + COALESCE(pr.full_name, t.name) AS nome, + COALESCE(s.user_id::text, s.tenant_id::text) AS owner_id + FROM public.subscriptions s + LEFT JOIN public.profiles pr ON pr.id = s.user_id + LEFT JOIN public.tenants t ON t.id = s.tenant_id + WHERE s.source = 'fix_seed' + AND s.started_at >= now() - interval '5 seconds' + ORDER BY s.plan_key, nome + LOOP + RAISE NOTICE ' ✅ % → % (%)', r.plan_key, r.nome, r.owner_id; + total := total + 1; + END LOOP; + + IF total = 0 THEN + RAISE NOTICE ' (nenhuma nova assinatura criada — todos já tinham plano ativo)'; + ELSE + RAISE NOTICE ''; + RAISE NOTICE ' Total: % assinatura(s) criada(s).', total; + END IF; +END; +$$; + +COMMIT; diff --git a/DBS/2026-03-11/Novo-DB/fix_subscriptions_validate_scope.sql b/DBS/2026-03-11/Novo-DB/fix_subscriptions_validate_scope.sql new file mode 100644 index 0000000..8aa8b69 --- /dev/null +++ b/DBS/2026-03-11/Novo-DB/fix_subscriptions_validate_scope.sql @@ -0,0 +1,50 @@ +-- Fix: subscriptions_validate_scope — adiciona suporte a target='patient' + +CREATE OR REPLACE FUNCTION public.subscriptions_validate_scope() +RETURNS trigger +LANGUAGE plpgsql +AS $$ +DECLARE + v_target text; +BEGIN + SELECT lower(p.target) INTO v_target + FROM public.plans p + WHERE p.id = NEW.plan_id; + + IF v_target IS NULL THEN + RAISE EXCEPTION 'Plano inválido (target nulo).'; + END IF; + + IF v_target = 'clinic' THEN + IF NEW.tenant_id IS NULL THEN + RAISE EXCEPTION 'Assinatura clinic exige tenant_id.'; + END IF; + IF NEW.user_id IS NOT NULL THEN + RAISE EXCEPTION 'Assinatura clinic não pode ter user_id (XOR).'; + END IF; + + ELSIF v_target = 'therapist' THEN + IF NEW.tenant_id IS NOT NULL THEN + RAISE EXCEPTION 'Assinatura therapist não deve ter tenant_id.'; + END IF; + IF NEW.user_id IS NULL THEN + RAISE EXCEPTION 'Assinatura therapist exige user_id.'; + END IF; + + ELSIF v_target = 'patient' THEN + IF NEW.tenant_id IS NOT NULL THEN + RAISE EXCEPTION 'Assinatura patient não deve ter tenant_id.'; + END IF; + IF NEW.user_id IS NULL THEN + RAISE EXCEPTION 'Assinatura patient exige user_id.'; + END IF; + + ELSE + RAISE EXCEPTION 'Target de plano inválido: %', v_target; + END IF; + + RETURN NEW; +END; +$$; + +ALTER FUNCTION public.subscriptions_validate_scope() OWNER TO supabase_admin; diff --git a/DBS/2026-03-11/Novo-DB/migration_001.sql b/DBS/2026-03-11/Novo-DB/migration_001.sql new file mode 100644 index 0000000..74c6764 --- /dev/null +++ b/DBS/2026-03-11/Novo-DB/migration_001.sql @@ -0,0 +1,296 @@ +-- ============================================================================= +-- SEED 001 — Usuários fictícios para teste +-- ============================================================================= +-- Execute APÓS migration_001.sql +-- +-- Usuários criados: +-- paciente@agenciapsi.com.br senha: Teste@123 → patient +-- terapeuta@agenciapsi.com.br senha: Teste@123 → therapist +-- clinica1@agenciapsi.com.br senha: Teste@123 → clinic_coworking +-- clinica2@agenciapsi.com.br senha: Teste@123 → clinic_reception +-- clinica3@agenciapsi.com.br senha: Teste@123 → clinic_full +-- saas@agenciapsi.com.br senha: Teste@123 → saas_admin +-- ============================================================================= + + +-- ============================================================ +-- Limpeza de seeds anteriores +-- ============================================================ + +ALTER TABLE public.patient_groups DISABLE TRIGGER ALL; + +DELETE FROM public.tenant_members +WHERE user_id IN ( + SELECT id FROM auth.users + WHERE email IN ( + 'paciente@agenciapsi.com.br', + 'terapeuta@agenciapsi.com.br', + 'clinica1@agenciapsi.com.br', + 'clinica2@agenciapsi.com.br', + 'clinica3@agenciapsi.com.br', + 'saas@agenciapsi.com.br' + ) +); + +DELETE FROM public.tenants WHERE id IN ( + 'bbbbbbbb-0002-0002-0002-000000000002', + 'bbbbbbbb-0003-0003-0003-000000000003', + 'bbbbbbbb-0004-0004-0004-000000000004', + 'bbbbbbbb-0005-0005-0005-000000000005' +); + +DELETE FROM auth.users WHERE email IN ( + 'paciente@agenciapsi.com.br', + 'terapeuta@agenciapsi.com.br', + 'clinica1@agenciapsi.com.br', + 'clinica2@agenciapsi.com.br', + 'clinica3@agenciapsi.com.br', + 'saas@agenciapsi.com.br' +); + +ALTER TABLE public.patient_groups ENABLE TRIGGER ALL; + + +-- ============================================================ +-- 1. Usuários no auth.users +-- ============================================================ + +INSERT INTO auth.users ( + id, email, encrypted_password, email_confirmed_at, + created_at, updated_at, raw_user_meta_data, role, aud +) +VALUES + ( + 'aaaaaaaa-0001-0001-0001-000000000001', + 'paciente@agenciapsi.com.br', + crypt('Teste@123', gen_salt('bf')), + now(), now(), now(), + '{"name": "Ana Paciente"}'::jsonb, + 'authenticated', 'authenticated' + ), + ( + 'aaaaaaaa-0002-0002-0002-000000000002', + 'terapeuta@agenciapsi.com.br', + crypt('Teste@123', gen_salt('bf')), + now(), now(), now(), + '{"name": "Bruno Terapeuta"}'::jsonb, + 'authenticated', 'authenticated' + ), + ( + 'aaaaaaaa-0003-0003-0003-000000000003', + 'clinica1@agenciapsi.com.br', + crypt('Teste@123', gen_salt('bf')), + now(), now(), now(), + '{"name": "Clinica Espaco Psi"}'::jsonb, + 'authenticated', 'authenticated' + ), + ( + 'aaaaaaaa-0004-0004-0004-000000000004', + 'clinica2@agenciapsi.com.br', + crypt('Teste@123', gen_salt('bf')), + now(), now(), now(), + '{"name": "Clinica Mente Sa"}'::jsonb, + 'authenticated', 'authenticated' + ), + ( + 'aaaaaaaa-0005-0005-0005-000000000005', + 'clinica3@agenciapsi.com.br', + crypt('Teste@123', gen_salt('bf')), + now(), now(), now(), + '{"name": "Clinica Bem Estar"}'::jsonb, + 'authenticated', 'authenticated' + ), + ( + 'aaaaaaaa-0006-0006-0006-000000000006', + 'saas@agenciapsi.com.br', + crypt('Teste@123', gen_salt('bf')), + now(), now(), now(), + '{"name": "Admin Plataforma"}'::jsonb, + 'authenticated', 'authenticated' + ); + + +-- ============================================================ +-- 2. Profiles +-- ============================================================ + +INSERT INTO public.profiles (id, role, account_type, full_name) +VALUES + ('aaaaaaaa-0001-0001-0001-000000000001', 'portal_user', 'patient', 'Ana Paciente'), + ('aaaaaaaa-0002-0002-0002-000000000002', 'portal_user', 'therapist', 'Bruno Terapeuta'), + ('aaaaaaaa-0003-0003-0003-000000000003', 'portal_user', 'clinic', 'Clinica Espaco Psi'), + ('aaaaaaaa-0004-0004-0004-000000000004', 'portal_user', 'clinic', 'Clinica Mente Sa'), + ('aaaaaaaa-0005-0005-0005-000000000005', 'portal_user', 'clinic', 'Clinica Bem Estar'), + ('aaaaaaaa-0006-0006-0006-000000000006', 'saas_admin', 'free', 'Admin Plataforma') +ON CONFLICT (id) DO UPDATE SET + role = EXCLUDED.role, + account_type = EXCLUDED.account_type, + full_name = EXCLUDED.full_name; + + +-- ============================================================ +-- 3. SaaS Admin +-- ============================================================ + +INSERT INTO public.saas_admins (user_id, created_at) +VALUES ('aaaaaaaa-0006-0006-0006-000000000006', now()) +ON CONFLICT (user_id) DO NOTHING; + + +-- ============================================================ +-- 4. Tenant do terapeuta +-- ============================================================ + +INSERT INTO public.tenants (id, name, kind, created_at) +VALUES ('bbbbbbbb-0002-0002-0002-000000000002', 'Bruno Terapeuta', 'therapist', now()) +ON CONFLICT (id) DO NOTHING; + +INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at) +VALUES ('bbbbbbbb-0002-0002-0002-000000000002', 'aaaaaaaa-0002-0002-0002-000000000002', 'tenant_admin', 'active', now()) +ON CONFLICT (tenant_id, user_id) DO NOTHING; + +DO $$ BEGIN + PERFORM public.seed_determined_commitments('bbbbbbbb-0002-0002-0002-000000000002'); +END; $$; + + +-- ============================================================ +-- 5. Tenant Clinica 1 — Coworking +-- ============================================================ + +INSERT INTO public.tenants (id, name, kind, created_at) +VALUES ('bbbbbbbb-0003-0003-0003-000000000003', 'Clinica Espaco Psi', 'clinic_coworking', now()) +ON CONFLICT (id) DO NOTHING; + +INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at) +VALUES ('bbbbbbbb-0003-0003-0003-000000000003', 'aaaaaaaa-0003-0003-0003-000000000003', 'tenant_admin', 'active', now()) +ON CONFLICT (tenant_id, user_id) DO NOTHING; + +DO $$ BEGIN + PERFORM public.seed_determined_commitments('bbbbbbbb-0003-0003-0003-000000000003'); +END; $$; + + +-- ============================================================ +-- 6. Tenant Clinica 2 — Recepcao +-- ============================================================ + +INSERT INTO public.tenants (id, name, kind, created_at) +VALUES ('bbbbbbbb-0004-0004-0004-000000000004', 'Clinica Mente Sa', 'clinic_reception', now()) +ON CONFLICT (id) DO NOTHING; + +INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at) +VALUES ('bbbbbbbb-0004-0004-0004-000000000004', 'aaaaaaaa-0004-0004-0004-000000000004', 'tenant_admin', 'active', now()) +ON CONFLICT (tenant_id, user_id) DO NOTHING; + +DO $$ BEGIN + PERFORM public.seed_determined_commitments('bbbbbbbb-0004-0004-0004-000000000004'); +END; $$; + + +-- ============================================================ +-- 7. Tenant Clinica 3 — Full +-- ============================================================ + +INSERT INTO public.tenants (id, name, kind, created_at) +VALUES ('bbbbbbbb-0005-0005-0005-000000000005', 'Clinica Bem Estar', 'clinic_full', now()) +ON CONFLICT (id) DO NOTHING; + +INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at) +VALUES ('bbbbbbbb-0005-0005-0005-000000000005', 'aaaaaaaa-0005-0005-0005-000000000005', 'tenant_admin', 'active', now()) +ON CONFLICT (tenant_id, user_id) DO NOTHING; + +DO $$ BEGIN + PERFORM public.seed_determined_commitments('bbbbbbbb-0005-0005-0005-000000000005'); +END; $$; + + +-- ============================================================ +-- 8. Subscriptions ativas +-- ============================================================ + +-- Paciente → patient_free +INSERT INTO public.subscriptions ( + user_id, plan_id, plan_key, status, interval, + current_period_start, current_period_end, source, started_at, activated_at +) +SELECT + 'aaaaaaaa-0001-0001-0001-000000000001', + p.id, p.key, 'active', 'month', + now(), now() + interval '30 days', 'seed', now(), now() +FROM public.plans p WHERE p.key = 'patient_free'; + +-- Terapeuta → therapist_free +INSERT INTO public.subscriptions ( + user_id, plan_id, plan_key, status, interval, + current_period_start, current_period_end, source, started_at, activated_at +) +SELECT + 'aaaaaaaa-0002-0002-0002-000000000002', + p.id, p.key, 'active', 'month', + now(), now() + interval '30 days', 'seed', now(), now() +FROM public.plans p WHERE p.key = 'therapist_free'; + +-- Clinica 1 → clinic_free +INSERT INTO public.subscriptions ( + tenant_id, plan_id, plan_key, status, interval, + current_period_start, current_period_end, source, started_at, activated_at +) +SELECT + 'bbbbbbbb-0003-0003-0003-000000000003', + p.id, p.key, 'active', 'month', + now(), now() + interval '30 days', 'seed', now(), now() +FROM public.plans p WHERE p.key = 'clinic_free'; + +-- Clinica 2 → clinic_free +INSERT INTO public.subscriptions ( + tenant_id, plan_id, plan_key, status, interval, + current_period_start, current_period_end, source, started_at, activated_at +) +SELECT + 'bbbbbbbb-0004-0004-0004-000000000004', + p.id, p.key, 'active', 'month', + now(), now() + interval '30 days', 'seed', now(), now() +FROM public.plans p WHERE p.key = 'clinic_free'; + +-- Clinica 3 → clinic_free +INSERT INTO public.subscriptions ( + tenant_id, plan_id, plan_key, status, interval, + current_period_start, current_period_end, source, started_at, activated_at +) +SELECT + 'bbbbbbbb-0005-0005-0005-000000000005', + p.id, p.key, 'active', 'month', + now(), now() + interval '30 days', 'seed', now(), now() +FROM public.plans p WHERE p.key = 'clinic_free'; + + +-- ============================================================ +-- 9. Vincula terapeuta à Clinica 3 (exemplo de associacao) +-- ============================================================ + +INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at) +VALUES ( + 'bbbbbbbb-0005-0005-0005-000000000005', + 'aaaaaaaa-0002-0002-0002-000000000002', + 'therapist', 'active', now() +) +ON CONFLICT (tenant_id, user_id) DO NOTHING; + + +-- ============================================================ +-- Confirmacao +-- ============================================================ + +DO $$ +BEGIN + RAISE NOTICE '✅ Seed aplicado com sucesso.'; + RAISE NOTICE ' paciente@agenciapsi.com.br → patient'; + RAISE NOTICE ' terapeuta@agenciapsi.com.br → therapist'; + RAISE NOTICE ' clinica1@agenciapsi.com.br → clinic_coworking'; + RAISE NOTICE ' clinica2@agenciapsi.com.br → clinic_reception'; + RAISE NOTICE ' clinica3@agenciapsi.com.br → clinic_full'; + RAISE NOTICE ' saas@agenciapsi.com.br → saas_admin'; + RAISE NOTICE ' Senha: Teste@123'; +END; +$$; diff --git a/DBS/2026-03-11/Novo-DB/migration_002_layout_variant.sql b/DBS/2026-03-11/Novo-DB/migration_002_layout_variant.sql new file mode 100644 index 0000000..6a74e0c --- /dev/null +++ b/DBS/2026-03-11/Novo-DB/migration_002_layout_variant.sql @@ -0,0 +1,13 @@ +-- ============================================================================= +-- Migration 002 — Adiciona layout_variant em user_settings +-- ============================================================================= +-- Execute no SQL Editor do Supabase (ou via Docker psql). +-- Tolerante: usa IF NOT EXISTS / DEFAULT para não quebrar dados existentes. +-- ============================================================================= + +ALTER TABLE public.user_settings + ADD COLUMN IF NOT EXISTS layout_variant TEXT NOT NULL DEFAULT 'classic'; + +-- ============================================================================= +RAISE NOTICE '✅ Coluna layout_variant adicionada a user_settings.'; +-- ============================================================================= diff --git a/DBS/2026-03-11/Novo-DB/seed_001.sql b/DBS/2026-03-11/Novo-DB/seed_001.sql new file mode 100644 index 0000000..c240a7e --- /dev/null +++ b/DBS/2026-03-11/Novo-DB/seed_001.sql @@ -0,0 +1,334 @@ +-- ============================================================================= +-- SEED — Usuários fictícios para teste +-- ============================================================================= +-- IMPORTANTE: Execute APÓS a migration_001.sql +-- IMPORTANTE: Requer extensão pgcrypto (já ativa no Supabase) +-- +-- Cria os seguintes usuários de teste: +-- +-- paciente@agenciapsi.com.br senha: Teste@123 → paciente +-- terapeuta@agenciapsi.com.br senha: Teste@123 → terapeuta solo +-- clinica1@agenciapsi.com.br senha: Teste@123 → clínica coworking +-- clinica2@agenciapsi.com.br senha: Teste@123 → clínica com secretaria +-- clinica3@agenciapsi.com.br senha: Teste@123 → clínica full +-- saas@agenciapsi.com.br senha: Teste@123 → admin da plataforma +-- +-- ============================================================================= + +BEGIN; + +-- ============================================================ +-- Helper: cria usuário no auth.users + profile +-- (Supabase não expõe auth.users diretamente, mas em SQL Editor +-- com acesso de service_role podemos inserir diretamente) +-- ============================================================ + +-- Limpa seeds anteriores se existirem +DELETE FROM auth.users +WHERE email IN ( + 'paciente@agenciapsi.com.br', + 'terapeuta@agenciapsi.com.br', + 'clinica1@agenciapsi.com.br', + 'clinica2@agenciapsi.com.br', + 'clinica3@agenciapsi.com.br', + 'saas@agenciapsi.com.br' +); + +-- ============================================================ +-- 1. Cria usuários no auth.users +-- ============================================================ + +INSERT INTO auth.users ( + instance_id, + id, + email, + encrypted_password, + email_confirmed_at, + confirmed_at, + created_at, + updated_at, + raw_user_meta_data, + raw_app_meta_data, + role, + aud, + is_sso_user, + is_anonymous, + confirmation_token, + recovery_token, + email_change_token_new, + email_change_token_current, + email_change +) +VALUES + -- Paciente + ( + '00000000-0000-0000-0000-000000000000', + 'aaaaaaaa-0001-0001-0001-000000000001', + 'paciente@agenciapsi.com.br', + crypt('Teste@123', gen_salt('bf')), + now(), now(), now(), now(), + '{"name": "Ana Paciente"}'::jsonb, + '{"provider": "email", "providers": ["email"]}'::jsonb, + 'authenticated', 'authenticated', false, false, '', '', '', '', '' + ), + -- Terapeuta + ( + '00000000-0000-0000-0000-000000000000', + 'aaaaaaaa-0002-0002-0002-000000000002', + 'terapeuta@agenciapsi.com.br', + crypt('Teste@123', gen_salt('bf')), + now(), now(), now(), now(), + '{"name": "Bruno Terapeuta"}'::jsonb, + '{"provider": "email", "providers": ["email"]}'::jsonb, + 'authenticated', 'authenticated', false, false, '', '', '', '', '' + ), + -- Clínica 1 — Coworking + ( + '00000000-0000-0000-0000-000000000000', + 'aaaaaaaa-0003-0003-0003-000000000003', + 'clinica1@agenciapsi.com.br', + crypt('Teste@123', gen_salt('bf')), + now(), now(), now(), now(), + '{"name": "Clínica Espaço Psi"}'::jsonb, + '{"provider": "email", "providers": ["email"]}'::jsonb, + 'authenticated', 'authenticated', false, false, '', '', '', '', '' + ), + -- Clínica 2 — Recepção + ( + '00000000-0000-0000-0000-000000000000', + 'aaaaaaaa-0004-0004-0004-000000000004', + 'clinica2@agenciapsi.com.br', + crypt('Teste@123', gen_salt('bf')), + now(), now(), now(), now(), + '{"name": "Clínica Mente Sã"}'::jsonb, + '{"provider": "email", "providers": ["email"]}'::jsonb, + 'authenticated', 'authenticated', false, false, '', '', '', '', '' + ), + -- Clínica 3 — Full + ( + '00000000-0000-0000-0000-000000000000', + 'aaaaaaaa-0005-0005-0005-000000000005', + 'clinica3@agenciapsi.com.br', + crypt('Teste@123', gen_salt('bf')), + now(), now(), now(), now(), + '{"name": "Clínica Bem Estar"}'::jsonb, + '{"provider": "email", "providers": ["email"]}'::jsonb, + 'authenticated', 'authenticated', false, false, '', '', '', '', '' + ), + -- SaaS Admin + ( + '00000000-0000-0000-0000-000000000000', + 'aaaaaaaa-0006-0006-0006-000000000006', + 'saas@agenciapsi.com.br', + crypt('Teste@123', gen_salt('bf')), + now(), now(), now(), now(), + '{"name": "Admin Plataforma"}'::jsonb, + '{"provider": "email", "providers": ["email"]}'::jsonb, + 'authenticated', 'authenticated', false, false, '', '', '', '', '' + ); + +-- auth.identities (obrigatório para GoTrue reconhecer login email/senha) +INSERT INTO auth.identities (id, user_id, provider_id, provider, identity_data, created_at, updated_at, last_sign_in_at) +VALUES + (gen_random_uuid(), 'aaaaaaaa-0001-0001-0001-000000000001', 'paciente@agenciapsi.com.br', 'email', '{"sub": "aaaaaaaa-0001-0001-0001-000000000001", "email": "paciente@agenciapsi.com.br", "email_verified": true}'::jsonb, now(), now(), now()), + (gen_random_uuid(), 'aaaaaaaa-0002-0002-0002-000000000002', 'terapeuta@agenciapsi.com.br', 'email', '{"sub": "aaaaaaaa-0002-0002-0002-000000000002", "email": "terapeuta@agenciapsi.com.br", "email_verified": true}'::jsonb, now(), now(), now()), + (gen_random_uuid(), 'aaaaaaaa-0003-0003-0003-000000000003', 'clinica1@agenciapsi.com.br', 'email', '{"sub": "aaaaaaaa-0003-0003-0003-000000000003", "email": "clinica1@agenciapsi.com.br", "email_verified": true}'::jsonb, now(), now(), now()), + (gen_random_uuid(), 'aaaaaaaa-0004-0004-0004-000000000004', 'clinica2@agenciapsi.com.br', 'email', '{"sub": "aaaaaaaa-0004-0004-0004-000000000004", "email": "clinica2@agenciapsi.com.br", "email_verified": true}'::jsonb, now(), now(), now()), + (gen_random_uuid(), 'aaaaaaaa-0005-0005-0005-000000000005', 'clinica3@agenciapsi.com.br', 'email', '{"sub": "aaaaaaaa-0005-0005-0005-000000000005", "email": "clinica3@agenciapsi.com.br", "email_verified": true}'::jsonb, now(), now(), now()), + (gen_random_uuid(), 'aaaaaaaa-0006-0006-0006-000000000006', 'saas@agenciapsi.com.br', 'email', '{"sub": "aaaaaaaa-0006-0006-0006-000000000006", "email": "saas@agenciapsi.com.br", "email_verified": true}'::jsonb, now(), now(), now()) +ON CONFLICT (provider, provider_id) DO NOTHING; + + +-- ============================================================ +-- 2. Profiles (o trigger handle_new_user não dispara em inserts +-- diretos no auth.users via SQL, então criamos manualmente) +-- ============================================================ + +INSERT INTO public.profiles (id, role, account_type, full_name) +VALUES + ('aaaaaaaa-0001-0001-0001-000000000001', 'portal_user', 'patient', 'Ana Paciente'), + ('aaaaaaaa-0002-0002-0002-000000000002', 'tenant_member', 'therapist', 'Bruno Terapeuta'), + ('aaaaaaaa-0003-0003-0003-000000000003', 'tenant_member', 'clinic', 'Clínica Espaço Psi'), + ('aaaaaaaa-0004-0004-0004-000000000004', 'tenant_member', 'clinic', 'Clínica Mente Sã'), + ('aaaaaaaa-0005-0005-0005-000000000005', 'tenant_member', 'clinic', 'Clínica Bem Estar'), + ('aaaaaaaa-0006-0006-0006-000000000006', 'saas_admin', 'free', 'Admin Plataforma') +ON CONFLICT (id) DO UPDATE SET + role = EXCLUDED.role, + account_type = EXCLUDED.account_type, + full_name = EXCLUDED.full_name; + + +-- ============================================================ +-- 3. SaaS Admin na tabela saas_admins +-- ============================================================ + +INSERT INTO public.saas_admins (user_id, created_at) +VALUES ('aaaaaaaa-0006-0006-0006-000000000006', now()) +ON CONFLICT (user_id) DO NOTHING; + + +-- ============================================================ +-- 4. Tenant do terapeuta +-- ============================================================ + +INSERT INTO public.tenants (id, name, kind, created_at) +VALUES ('bbbbbbbb-0002-0002-0002-000000000002', 'Bruno Terapeuta', 'therapist', now()) +ON CONFLICT (id) DO NOTHING; + +INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at) +VALUES ('bbbbbbbb-0002-0002-0002-000000000002', 'aaaaaaaa-0002-0002-0002-000000000002', 'tenant_admin', 'active', now()) +ON CONFLICT (tenant_id, user_id) DO NOTHING; + +DO $$ BEGIN PERFORM public.seed_determined_commitments('bbbbbbbb-0002-0002-0002-000000000002'); END $$; + + +-- ============================================================ +-- 5. Tenant da Clínica 1 — Coworking +-- ============================================================ + +INSERT INTO public.tenants (id, name, kind, created_at) +VALUES ('bbbbbbbb-0003-0003-0003-000000000003', 'Clínica Espaço Psi', 'clinic_coworking', now()) +ON CONFLICT (id) DO NOTHING; + +INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at) +VALUES ('bbbbbbbb-0003-0003-0003-000000000003', 'aaaaaaaa-0003-0003-0003-000000000003', 'tenant_admin', 'active', now()) +ON CONFLICT (tenant_id, user_id) DO NOTHING; + +DO $$ BEGIN PERFORM public.seed_determined_commitments('bbbbbbbb-0003-0003-0003-000000000003'); END $$; + + +-- ============================================================ +-- 6. Tenant da Clínica 2 — Recepção +-- ============================================================ + +INSERT INTO public.tenants (id, name, kind, created_at) +VALUES ('bbbbbbbb-0004-0004-0004-000000000004', 'Clínica Mente Sã', 'clinic_reception', now()) +ON CONFLICT (id) DO NOTHING; + +INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at) +VALUES ('bbbbbbbb-0004-0004-0004-000000000004', 'aaaaaaaa-0004-0004-0004-000000000004', 'tenant_admin', 'active', now()) +ON CONFLICT (tenant_id, user_id) DO NOTHING; + +DO $$ BEGIN PERFORM public.seed_determined_commitments('bbbbbbbb-0004-0004-0004-000000000004'); END $$; + + +-- ============================================================ +-- 7. Tenant da Clínica 3 — Full +-- ============================================================ + +INSERT INTO public.tenants (id, name, kind, created_at) +VALUES ('bbbbbbbb-0005-0005-0005-000000000005', 'Clínica Bem Estar', 'clinic_full', now()) +ON CONFLICT (id) DO NOTHING; + +INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at) +VALUES ('bbbbbbbb-0005-0005-0005-000000000005', 'aaaaaaaa-0005-0005-0005-000000000005', 'tenant_admin', 'active', now()) +ON CONFLICT (tenant_id, user_id) DO NOTHING; + +DO $$ BEGIN PERFORM public.seed_determined_commitments('bbbbbbbb-0005-0005-0005-000000000005'); END $$; + + +-- ============================================================ +-- 8. Subscriptions ativas para cada conta +-- ============================================================ + +-- Terapeuta → plano therapist_free +INSERT INTO public.subscriptions ( + user_id, plan_id, plan_key, status, interval, + current_period_start, current_period_end, + source, started_at, activated_at +) +SELECT + 'aaaaaaaa-0002-0002-0002-000000000002', + p.id, p.key, 'active', 'month', + now(), now() + interval '30 days', + 'seed', now(), now() +FROM public.plans p WHERE p.key = 'therapist_free'; + +-- Clínica 1 → plano clinic_free +INSERT INTO public.subscriptions ( + tenant_id, plan_id, plan_key, status, interval, + current_period_start, current_period_end, + source, started_at, activated_at +) +SELECT + 'bbbbbbbb-0003-0003-0003-000000000003', + p.id, p.key, 'active', 'month', + now(), now() + interval '30 days', + 'seed', now(), now() +FROM public.plans p WHERE p.key = 'clinic_free'; + +-- Clínica 2 → plano clinic_free +INSERT INTO public.subscriptions ( + tenant_id, plan_id, plan_key, status, interval, + current_period_start, current_period_end, + source, started_at, activated_at +) +SELECT + 'bbbbbbbb-0004-0004-0004-000000000004', + p.id, p.key, 'active', 'month', + now(), now() + interval '30 days', + 'seed', now(), now() +FROM public.plans p WHERE p.key = 'clinic_free'; + +-- Clínica 3 → plano clinic_free +INSERT INTO public.subscriptions ( + tenant_id, plan_id, plan_key, status, interval, + current_period_start, current_period_end, + source, started_at, activated_at +) +SELECT + 'bbbbbbbb-0005-0005-0005-000000000005', + p.id, p.key, 'active', 'month', + now(), now() + interval '30 days', + 'seed', now(), now() +FROM public.plans p WHERE p.key = 'clinic_free'; + +-- Paciente → plano patient_free +INSERT INTO public.subscriptions ( + user_id, plan_id, plan_key, status, interval, + current_period_start, current_period_end, + source, started_at, activated_at +) +SELECT + 'aaaaaaaa-0001-0001-0001-000000000001', + p.id, p.key, 'active', 'month', + now(), now() + interval '30 days', + 'seed', now(), now() +FROM public.plans p WHERE p.key = 'patient_free'; + + +-- ============================================================ +-- 9. Vincula terapeuta à Clínica 3 (full) como exemplo +-- ============================================================ + +INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at) +VALUES ( + 'bbbbbbbb-0005-0005-0005-000000000005', + 'aaaaaaaa-0002-0002-0002-000000000002', + 'therapist', + 'active', + now() +) +ON CONFLICT (tenant_id, user_id) DO NOTHING; + + +-- ============================================================ +-- 10. Confirma +-- ============================================================ + +DO $$ +BEGIN + RAISE NOTICE '✅ Seed aplicado com sucesso.'; + RAISE NOTICE ''; + RAISE NOTICE ' Usuários criados:'; + RAISE NOTICE ' paciente@agenciapsi.com.br → patient'; + RAISE NOTICE ' terapeuta@agenciapsi.com.br → therapist (tenant próprio + vinculado à Clínica 3)'; + RAISE NOTICE ' clinica1@agenciapsi.com.br → clinic_coworking'; + RAISE NOTICE ' clinica2@agenciapsi.com.br → clinic_reception'; + RAISE NOTICE ' clinica3@agenciapsi.com.br → clinic_full'; + RAISE NOTICE ' saas@agenciapsi.com.br → saas_admin'; + RAISE NOTICE ' Senha de todos: Teste@123'; +END; +$$; + +COMMIT; diff --git a/DBS/2026-03-11/Novo-DB/seed_002.sql b/DBS/2026-03-11/Novo-DB/seed_002.sql new file mode 100644 index 0000000..a9fc80f --- /dev/null +++ b/DBS/2026-03-11/Novo-DB/seed_002.sql @@ -0,0 +1,199 @@ +-- ============================================================================= +-- SEED 002 — Supervisor e Editor +-- ============================================================================= +-- Execute APÓS seed_001.sql +-- Requer: pgcrypto (já ativo no Supabase) +-- +-- Cria os seguintes usuários de teste: +-- +-- supervisor@agenciapsi.com.br senha: Teste@123 → supervisor da Clínica 3 +-- editor@agenciapsi.com.br senha: Teste@123 → editor de conteúdo (plataforma) +-- +-- UUIDs reservados: +-- Supervisor → aaaaaaaa-0007-0007-0007-000000000007 +-- Editor → aaaaaaaa-0008-0008-0008-000000000008 +-- +-- ============================================================================= + +BEGIN; + +-- ============================================================ +-- 0. Migration: adiciona platform_roles em profiles (se não existir) +-- ============================================================ + +ALTER TABLE public.profiles + ADD COLUMN IF NOT EXISTS platform_roles text[] NOT NULL DEFAULT '{}'; + +COMMENT ON COLUMN public.profiles.platform_roles IS + 'Papéis globais de plataforma, independentes de tenant. Ex: editor de microlearning. Atribuído pelo saas_admin.'; + + +-- ============================================================ +-- 1. Remove seeds anteriores (idempotente) +-- ============================================================ + +DELETE FROM auth.users +WHERE email IN ( + 'supervisor@agenciapsi.com.br', + 'editor@agenciapsi.com.br' +); + + +-- ============================================================ +-- 2. Cria usuários no auth.users +-- ============================================================ + +INSERT INTO auth.users ( + instance_id, + id, + email, + encrypted_password, + email_confirmed_at, + created_at, + updated_at, + raw_user_meta_data, + raw_app_meta_data, + role, + aud, + is_sso_user, + is_anonymous, + confirmation_token, + recovery_token, + email_change_token_new, + email_change_token_current, + email_change +) +VALUES + -- Supervisor + ( + '00000000-0000-0000-0000-000000000000', + 'aaaaaaaa-0007-0007-0007-000000000007', + 'supervisor@agenciapsi.com.br', + crypt('Teste@123', gen_salt('bf')), + now(), now(), now(), + '{"name": "Carlos Supervisor"}'::jsonb, + '{"provider": "email", "providers": ["email"]}'::jsonb, + 'authenticated', 'authenticated', false, false, '', '', '', '', '' + ), + -- Editor de Conteúdo + ( + '00000000-0000-0000-0000-000000000000', + 'aaaaaaaa-0008-0008-0008-000000000008', + 'editor@agenciapsi.com.br', + crypt('Teste@123', gen_salt('bf')), + now(), now(), now(), + '{"name": "Diana Editora"}'::jsonb, + '{"provider": "email", "providers": ["email"]}'::jsonb, + 'authenticated', 'authenticated', false, false, '', '', '', '', '' + ); + + +-- ============================================================ +-- 3. auth.identities (obrigatório para GoTrue reconhecer login) +-- ============================================================ + +INSERT INTO auth.identities (id, user_id, provider_id, provider, identity_data, created_at, updated_at, last_sign_in_at) +VALUES + ( + gen_random_uuid(), + 'aaaaaaaa-0007-0007-0007-000000000007', + 'supervisor@agenciapsi.com.br', + 'email', + '{"sub": "aaaaaaaa-0007-0007-0007-000000000007", "email": "supervisor@agenciapsi.com.br", "email_verified": true}'::jsonb, + now(), now(), now() + ), + ( + gen_random_uuid(), + 'aaaaaaaa-0008-0008-0008-000000000008', + 'editor@agenciapsi.com.br', + 'email', + '{"sub": "aaaaaaaa-0008-0008-0008-000000000008", "email": "editor@agenciapsi.com.br", "email_verified": true}'::jsonb, + now(), now(), now() + ) +ON CONFLICT (provider, provider_id) DO NOTHING; + + +-- ============================================================ +-- 4. Profiles +-- Supervisor → tenant_member (papel no tenant via tenant_members.role) +-- Editor → tenant_member + platform_roles = '{editor}' +-- ============================================================ + +INSERT INTO public.profiles (id, role, account_type, full_name, platform_roles) +VALUES + ( + 'aaaaaaaa-0007-0007-0007-000000000007', + 'tenant_member', + 'therapist', + 'Carlos Supervisor', + '{}' + ), + ( + 'aaaaaaaa-0008-0008-0008-000000000008', + 'tenant_member', + 'therapist', + 'Diana Editora', + '{editor}' -- permissão de plataforma: acesso à área do editor + ) +ON CONFLICT (id) DO UPDATE SET + role = EXCLUDED.role, + account_type = EXCLUDED.account_type, + full_name = EXCLUDED.full_name, + platform_roles = EXCLUDED.platform_roles; + + +-- ============================================================ +-- 5. Vincula Supervisor à Clínica 3 (Full) com role 'supervisor' +-- ============================================================ + +INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at) +VALUES ( + 'bbbbbbbb-0005-0005-0005-000000000005', -- Clínica Bem Estar (Full) + 'aaaaaaaa-0007-0007-0007-000000000007', -- Carlos Supervisor + 'supervisor', + 'active', + now() +) +ON CONFLICT (tenant_id, user_id) DO UPDATE SET + role = EXCLUDED.role, + status = EXCLUDED.status; + + +-- ============================================================ +-- 6. Vincula Editor à Clínica 3 como terapeuta +-- (contexto de tenant para o editor poder usar /therapist também, +-- se necessário. O papel de editor vem de platform_roles.) +-- ============================================================ + +INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at) +VALUES ( + 'bbbbbbbb-0005-0005-0005-000000000005', -- Clínica Bem Estar (Full) + 'aaaaaaaa-0008-0008-0008-000000000008', -- Diana Editora + 'therapist', + 'active', + now() +) +ON CONFLICT (tenant_id, user_id) DO UPDATE SET + role = EXCLUDED.role, + status = EXCLUDED.status; + + +-- ============================================================ +-- 7. Confirma +-- ============================================================ + +DO $$ +BEGIN + RAISE NOTICE '✅ Seed 002 aplicado com sucesso.'; + RAISE NOTICE ''; + RAISE NOTICE ' Migration aplicada:'; + RAISE NOTICE ' → profiles.platform_roles text[] adicionada (se não existia)'; + RAISE NOTICE ''; + RAISE NOTICE ' Usuários criados:'; + RAISE NOTICE ' supervisor@agenciapsi.com.br → supervisor da Clínica Bem Estar (Full)'; + RAISE NOTICE ' editor@agenciapsi.com.br → editor de conteúdo (platform_roles = {editor})'; + RAISE NOTICE ' Senha de todos: Teste@123'; +END; +$$; + +COMMIT; diff --git a/DBS/2026-03-11/Novo-DB/seed_003.sql b/DBS/2026-03-11/Novo-DB/seed_003.sql new file mode 100644 index 0000000..e849895 --- /dev/null +++ b/DBS/2026-03-11/Novo-DB/seed_003.sql @@ -0,0 +1,283 @@ +-- ============================================================================= +-- SEED 003 — Terapeuta 2, Terapeuta 3 e Secretária +-- ============================================================================= +-- Execute APÓS seed_001.sql (e seed_002.sql se quiser todos os seeds) +-- Requer: pgcrypto (já ativo no Supabase) +-- +-- Cria os seguintes usuários de teste: +-- +-- therapist2@agenciapsi.com.br senha: Teste@123 → terapeuta 2 (tenant próprio + Clínica 3) +-- therapist3@agenciapsi.com.br senha: Teste@123 → terapeuta 3 (tenant próprio + Clínica 3) +-- secretary@agenciapsi.com.br senha: Teste@123 → clinic_admin na Clínica 2 (Mente Sã) +-- +-- UUIDs reservados: +-- Terapeuta 2 → aaaaaaaa-0009-0009-0009-000000000009 +-- Terapeuta 3 → aaaaaaaa-0010-0010-0010-000000000010 +-- Secretária → aaaaaaaa-0011-0011-0011-000000000011 +-- Tenant Terapeuta 2 → bbbbbbbb-0009-0009-0009-000000000009 +-- Tenant Terapeuta 3 → bbbbbbbb-0010-0010-0010-000000000010 +-- ============================================================================= + +BEGIN; + +-- ============================================================ +-- 1. Remove seeds anteriores (idempotente) +-- ============================================================ + +DELETE FROM auth.users +WHERE email IN ( + 'therapist2@agenciapsi.com.br', + 'therapist3@agenciapsi.com.br', + 'secretary@agenciapsi.com.br' +); + + +-- ============================================================ +-- 2. Cria usuários no auth.users +-- ⚠️ confirmed_at é coluna gerada — NÃO incluir na lista +-- ============================================================ + +INSERT INTO auth.users ( + instance_id, + id, + email, + encrypted_password, + email_confirmed_at, + created_at, + updated_at, + raw_user_meta_data, + raw_app_meta_data, + role, + aud, + is_sso_user, + is_anonymous, + confirmation_token, + recovery_token, + email_change_token_new, + email_change_token_current, + email_change +) +VALUES + -- Terapeuta 2 + ( + '00000000-0000-0000-0000-000000000000', + 'aaaaaaaa-0009-0009-0009-000000000009', + 'therapist2@agenciapsi.com.br', + crypt('Teste@123', gen_salt('bf')), + now(), now(), now(), + '{"name": "Eva Terapeuta"}'::jsonb, + '{"provider": "email", "providers": ["email"]}'::jsonb, + 'authenticated', 'authenticated', false, false, '', '', '', '', '' + ), + -- Terapeuta 3 + ( + '00000000-0000-0000-0000-000000000000', + 'aaaaaaaa-0010-0010-0010-000000000010', + 'therapist3@agenciapsi.com.br', + crypt('Teste@123', gen_salt('bf')), + now(), now(), now(), + '{"name": "Felipe Terapeuta"}'::jsonb, + '{"provider": "email", "providers": ["email"]}'::jsonb, + 'authenticated', 'authenticated', false, false, '', '', '', '', '' + ), + -- Secretária + ( + '00000000-0000-0000-0000-000000000000', + 'aaaaaaaa-0011-0011-0011-000000000011', + 'secretary@agenciapsi.com.br', + crypt('Teste@123', gen_salt('bf')), + now(), now(), now(), + '{"name": "Gabriela Secretária"}'::jsonb, + '{"provider": "email", "providers": ["email"]}'::jsonb, + 'authenticated', 'authenticated', false, false, '', '', '', '', '' + ); + + +-- ============================================================ +-- 3. auth.identities (obrigatório para GoTrue reconhecer login) +-- ============================================================ + +INSERT INTO auth.identities (id, user_id, provider_id, provider, identity_data, created_at, updated_at, last_sign_in_at) +VALUES + ( + gen_random_uuid(), + 'aaaaaaaa-0009-0009-0009-000000000009', + 'therapist2@agenciapsi.com.br', + 'email', + '{"sub": "aaaaaaaa-0009-0009-0009-000000000009", "email": "therapist2@agenciapsi.com.br", "email_verified": true}'::jsonb, + now(), now(), now() + ), + ( + gen_random_uuid(), + 'aaaaaaaa-0010-0010-0010-000000000010', + 'therapist3@agenciapsi.com.br', + 'email', + '{"sub": "aaaaaaaa-0010-0010-0010-000000000010", "email": "therapist3@agenciapsi.com.br", "email_verified": true}'::jsonb, + now(), now(), now() + ), + ( + gen_random_uuid(), + 'aaaaaaaa-0011-0011-0011-000000000011', + 'secretary@agenciapsi.com.br', + 'email', + '{"sub": "aaaaaaaa-0011-0011-0011-000000000011", "email": "secretary@agenciapsi.com.br", "email_verified": true}'::jsonb, + now(), now(), now() + ) +ON CONFLICT (provider, provider_id) DO NOTHING; + + +-- ============================================================ +-- 4. Profiles +-- ============================================================ + +INSERT INTO public.profiles (id, role, account_type, full_name) +VALUES + ( + 'aaaaaaaa-0009-0009-0009-000000000009', + 'tenant_member', + 'therapist', + 'Eva Terapeuta' + ), + ( + 'aaaaaaaa-0010-0010-0010-000000000010', + 'tenant_member', + 'therapist', + 'Felipe Terapeuta' + ), + ( + 'aaaaaaaa-0011-0011-0011-000000000011', + 'tenant_member', + 'therapist', + 'Gabriela Secretária' + ) +ON CONFLICT (id) DO UPDATE SET + role = EXCLUDED.role, + account_type = EXCLUDED.account_type, + full_name = EXCLUDED.full_name; + + +-- ============================================================ +-- 5. Tenants pessoais dos Terapeutas 2 e 3 +-- ============================================================ + +INSERT INTO public.tenants (id, name, kind, created_at) +VALUES + ('bbbbbbbb-0009-0009-0009-000000000009', 'Eva Terapeuta', 'therapist', now()), + ('bbbbbbbb-0010-0010-0010-000000000010', 'Felipe Terapeuta', 'therapist', now()) +ON CONFLICT (id) DO NOTHING; + +-- Terapeuta 2 → tenant_admin do próprio tenant +INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at) +VALUES ( + 'bbbbbbbb-0009-0009-0009-000000000009', + 'aaaaaaaa-0009-0009-0009-000000000009', + 'tenant_admin', 'active', now() +) +ON CONFLICT (tenant_id, user_id) DO NOTHING; + +-- Terapeuta 3 → tenant_admin do próprio tenant +INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at) +VALUES ( + 'bbbbbbbb-0010-0010-0010-000000000010', + 'aaaaaaaa-0010-0010-0010-000000000010', + 'tenant_admin', 'active', now() +) +ON CONFLICT (tenant_id, user_id) DO NOTHING; + + +-- ============================================================ +-- 6. Vincula Terapeutas 2 e 3 à Clínica 3 — Full +-- (mesmo padrão de terapeuta@agenciapsi.com.br no seed_001) +-- ============================================================ + +INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at) +VALUES + ( + 'bbbbbbbb-0005-0005-0005-000000000005', -- Clínica Bem Estar (Full) + 'aaaaaaaa-0009-0009-0009-000000000009', -- Eva Terapeuta + 'therapist', 'active', now() + ), + ( + 'bbbbbbbb-0005-0005-0005-000000000005', -- Clínica Bem Estar (Full) + 'aaaaaaaa-0010-0010-0010-000000000010', -- Felipe Terapeuta + 'therapist', 'active', now() + ) +ON CONFLICT (tenant_id, user_id) DO NOTHING; + + +-- ============================================================ +-- 7. Vincula Secretária à Clínica 2 (Recepção) como clinic_admin +-- A secretária gerencia a recepção/agenda da clínica. +-- Acessa a área /admin com o mesmo contexto de clinic_admin. +-- ============================================================ + +INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at) +VALUES ( + 'bbbbbbbb-0004-0004-0004-000000000004', -- Clínica Mente Sã (Recepção) + 'aaaaaaaa-0011-0011-0011-000000000011', -- Gabriela Secretária + 'clinic_admin', 'active', now() +) +ON CONFLICT (tenant_id, user_id) DO NOTHING; + + +-- ============================================================ +-- 8. Subscriptions +-- Terapeutas 2 e 3 → therapist_free (escopo: user_id) +-- Secretária → sem assinatura própria (usa o plano da Clínica 2) +-- ============================================================ + +-- Terapeuta 2 → therapist_free +INSERT INTO public.subscriptions ( + user_id, plan_id, plan_key, status, interval, + current_period_start, current_period_end, + source, started_at, activated_at +) +SELECT + 'aaaaaaaa-0009-0009-0009-000000000009', + p.id, p.key, 'active', 'month', + now(), now() + interval '30 days', + 'seed', now(), now() +FROM public.plans p WHERE p.key = 'therapist_free' +AND NOT EXISTS ( + SELECT 1 FROM public.subscriptions s + WHERE s.user_id = 'aaaaaaaa-0009-0009-0009-000000000009' AND s.status = 'active' +); + +-- Terapeuta 3 → therapist_free +INSERT INTO public.subscriptions ( + user_id, plan_id, plan_key, status, interval, + current_period_start, current_period_end, + source, started_at, activated_at +) +SELECT + 'aaaaaaaa-0010-0010-0010-000000000010', + p.id, p.key, 'active', 'month', + now(), now() + interval '30 days', + 'seed', now(), now() +FROM public.plans p WHERE p.key = 'therapist_free' +AND NOT EXISTS ( + SELECT 1 FROM public.subscriptions s + WHERE s.user_id = 'aaaaaaaa-0010-0010-0010-000000000010' AND s.status = 'active' +); + +-- Nota: a Secretária não tem assinatura própria. +-- O acesso vem do plano da Clínica 2 (tenant_id = bbbbbbbb-0004-0004-0004-000000000004). + + +-- ============================================================ +-- 9. Confirma +-- ============================================================ + +DO $$ +BEGIN + RAISE NOTICE '✅ Seed 003 aplicado com sucesso.'; + RAISE NOTICE ''; + RAISE NOTICE ' Usuários criados:'; + RAISE NOTICE ' therapist2@agenciapsi.com.br → tenant próprio (bbbbbbbb-0009) + Clínica 3 como therapist'; + RAISE NOTICE ' therapist3@agenciapsi.com.br → tenant próprio (bbbbbbbb-0010) + Clínica 3 como therapist'; + RAISE NOTICE ' secretary@agenciapsi.com.br → clinic_admin na Clínica 2 Mente Sã (bbbbbbbb-0004)'; + RAISE NOTICE ' Senha de todos: Teste@123'; +END; +$$; + +COMMIT; diff --git a/DBS/2026-03-11/migrations/agendador_check_email.sql b/DBS/2026-03-11/migrations/agendador_check_email.sql new file mode 100644 index 0000000..0de3715 --- /dev/null +++ b/DBS/2026-03-11/migrations/agendador_check_email.sql @@ -0,0 +1,36 @@ +-- ═══════════════════════════════════════════════════════════════════════════ +-- agendador_check_email +-- Verifica se um e-mail já possui solicitação anterior para este agendador +-- SECURITY DEFINER → anon pode chamar sem burlar RLS diretamente +-- Execute no Supabase SQL Editor +-- ═══════════════════════════════════════════════════════════════════════════ + +CREATE OR REPLACE FUNCTION public.agendador_check_email( + p_slug text, + p_email text +) +RETURNS boolean +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_owner_id uuid; +BEGIN + SELECT c.owner_id INTO v_owner_id + FROM public.agendador_configuracoes c + WHERE c.link_slug = p_slug AND c.ativo = true + LIMIT 1; + + IF v_owner_id IS NULL THEN RETURN false; END IF; + + RETURN EXISTS ( + SELECT 1 FROM public.agendador_solicitacoes s + WHERE s.owner_id = v_owner_id + AND lower(s.paciente_email) = lower(trim(p_email)) + LIMIT 1 + ); +END; +$$; + +GRANT EXECUTE ON FUNCTION public.agendador_check_email(text, text) TO anon, authenticated; diff --git a/DBS/2026-03-11/migrations/agendador_features.sql b/DBS/2026-03-11/migrations/agendador_features.sql new file mode 100644 index 0000000..6e1701b --- /dev/null +++ b/DBS/2026-03-11/migrations/agendador_features.sql @@ -0,0 +1,62 @@ +-- ═══════════════════════════════════════════════════════════════════════════ +-- Feature keys do Agendador Online +-- Execute no Supabase SQL Editor +-- ═══════════════════════════════════════════════════════════════════════════ + +-- ── 1. Inserir as features ────────────────────────────────────────────────── +INSERT INTO public.features (key, name, descricao) +VALUES + ( + 'agendador.online', + 'Agendador Online', + 'Permite que pacientes solicitem agendamentos via link público. Inclui aprovação manual ou automática, controle de horários e notificações.' + ), + ( + 'agendador.link_personalizado', + 'Link Personalizado do Agendador', + 'Permite que o profissional escolha um slug de URL próprio para o agendador (ex: /agendar/dra-ana-silva) em vez de um link gerado automaticamente.' + ) +ON CONFLICT (key) DO UPDATE + SET name = EXCLUDED.name, + descricao = EXCLUDED.descricao; + +-- ── 2. Vincular aos planos ────────────────────────────────────────────────── +-- ATENÇÃO: ajuste os filtros de plan key/name conforme seus planos reais. +-- Exemplo: agendador.online disponível para planos PRO e acima. +-- agendador.link_personalizado apenas para planos Elite/Superior. + +-- agendador.online → todos os planos com target 'therapist' ou 'clinic' +-- (Adapte o WHERE conforme necessário) +INSERT INTO public.plan_features (plan_id, feature_id, enabled) +SELECT + p.id, + f.id, + true +FROM public.plans p +CROSS JOIN public.features f +WHERE f.key = 'agendador.online' + AND p.is_active = true + -- Comente a linha abaixo para liberar para TODOS os planos: + -- AND p.key IN ('pro', 'elite', 'clinic_pro', 'clinic_elite') +ON CONFLICT DO NOTHING; + +-- agendador.link_personalizado → apenas planos superiores +-- Deixe comentado e adicione manualmente quando definir os planos: +-- INSERT INTO public.plan_features (plan_id, feature_id, enabled) +-- SELECT p.id, f.id, true +-- FROM public.plans p +-- CROSS JOIN public.features f +-- WHERE f.key = 'agendador.link_personalizado' +-- AND p.key IN ('elite', 'clinic_elite', 'pro_plus') +-- ON CONFLICT DO NOTHING; + +-- ── 3. Verificação ───────────────────────────────────────────────────────── +SELECT + f.key, + f.name, + COUNT(pf.plan_id) AS planos_vinculados +FROM public.features f +LEFT JOIN public.plan_features pf ON pf.feature_id = f.id AND pf.enabled = true +WHERE f.key IN ('agendador.online', 'agendador.link_personalizado') +GROUP BY f.key, f.name +ORDER BY f.key; diff --git a/DBS/2026-03-11/migrations/agendador_fix_slots.sql b/DBS/2026-03-11/migrations/agendador_fix_slots.sql new file mode 100644 index 0000000..e2d4e6e --- /dev/null +++ b/DBS/2026-03-11/migrations/agendador_fix_slots.sql @@ -0,0 +1,221 @@ +-- ═══════════════════════════════════════════════════════════════════════════ +-- FIX: agendador_slots_disponiveis + agendador_dias_disponiveis +-- Usa agenda_online_slots como fonte de slots +-- Cruzamento com: agenda_eventos, recurrence_rules/exceptions, agendador_solicitacoes +-- Execute no Supabase SQL Editor +-- ═══════════════════════════════════════════════════════════════════════════ + +CREATE OR REPLACE FUNCTION public.agendador_slots_disponiveis( + p_slug text, + p_data date +) +RETURNS TABLE (hora time, disponivel boolean) +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_owner_id uuid; + v_duracao int; + v_antecedencia int; + v_agora timestamptz; + v_db_dow int; + v_slot time; + v_slot_fim time; + v_slot_ts timestamptz; + v_ocupado boolean; + -- loop de recorrências + v_rule RECORD; + v_rule_start_dow int; + v_first_occ date; + v_day_diff int; + v_ex_type text; +BEGIN + SELECT c.owner_id, c.duracao_sessao_min, c.antecedencia_minima_horas + INTO v_owner_id, v_duracao, v_antecedencia + FROM public.agendador_configuracoes c + WHERE c.link_slug = p_slug AND c.ativo = true + LIMIT 1; + + IF v_owner_id IS NULL THEN RETURN; END IF; + + v_agora := now(); + v_db_dow := extract(dow from p_data::timestamp)::int; + + FOR v_slot IN + SELECT s.time + FROM public.agenda_online_slots s + WHERE s.owner_id = v_owner_id + AND s.weekday = v_db_dow + AND s.enabled = true + ORDER BY s.time + LOOP + v_slot_fim := v_slot + (v_duracao || ' minutes')::interval; + v_ocupado := false; + + -- ── Antecedência mínima ────────────────────────────────────────────────── + v_slot_ts := (p_data::text || ' ' || v_slot::text)::timestamp + AT TIME ZONE 'America/Sao_Paulo'; + IF v_slot_ts < v_agora + (v_antecedencia || ' hours')::interval THEN + v_ocupado := true; + END IF; + + -- ── Eventos avulsos internos (agenda_eventos) ──────────────────────────── + IF NOT v_ocupado THEN + SELECT EXISTS ( + SELECT 1 FROM public.agenda_eventos e + WHERE e.owner_id = v_owner_id + AND e.status::text NOT IN ('cancelado', 'faltou') + AND (e.inicio_em AT TIME ZONE 'America/Sao_Paulo')::date = p_data + AND (e.inicio_em AT TIME ZONE 'America/Sao_Paulo')::time < v_slot_fim + AND (e.fim_em AT TIME ZONE 'America/Sao_Paulo')::time > v_slot + ) INTO v_ocupado; + END IF; + + -- ── Recorrências ativas (recurrence_rules) ─────────────────────────────── + -- Loop explícito para evitar erros de tipo no cálculo do ciclo semanal + IF NOT v_ocupado THEN + FOR v_rule IN + SELECT + r.id, + r.start_date::date AS start_date, + r.end_date::date AS end_date, + r.start_time::time AS start_time, + r.end_time::time AS end_time, + COALESCE(r.interval, 1)::int AS interval + FROM public.recurrence_rules r + WHERE r.owner_id = v_owner_id + AND r.status = 'ativo' + AND p_data >= r.start_date::date + AND (r.end_date IS NULL OR p_data <= r.end_date::date) + AND v_db_dow = ANY(r.weekdays) + AND r.start_time::time < v_slot_fim + AND r.end_time::time > v_slot + LOOP + -- Calcula a primeira ocorrência do dia-da-semana a partir do start_date + v_rule_start_dow := extract(dow from v_rule.start_date)::int; + v_first_occ := v_rule.start_date + + (((v_db_dow - v_rule_start_dow + 7) % 7))::int; + v_day_diff := (p_data - v_first_occ)::int; + + -- Ocorrência válida: diff >= 0 e divisível pelo ciclo semanal + IF v_day_diff >= 0 AND v_day_diff % (7 * v_rule.interval) = 0 THEN + + -- Verifica se há exceção para esta data + v_ex_type := NULL; + SELECT ex.type INTO v_ex_type + FROM public.recurrence_exceptions ex + WHERE ex.recurrence_id = v_rule.id + AND ex.original_date = p_data + LIMIT 1; + + -- Sem exceção, ou exceção que não cancela → bloqueia o slot + IF v_ex_type IS NULL OR v_ex_type NOT IN ( + 'cancel_session', 'patient_missed', + 'therapist_canceled', 'holiday_block', + 'reschedule_session' + ) THEN + v_ocupado := true; + EXIT; -- já basta uma regra que conflite + END IF; + + END IF; + END LOOP; + END IF; + + -- ── Recorrências remarcadas para este dia (reschedule → new_date = p_data) ─ + IF NOT v_ocupado THEN + SELECT EXISTS ( + SELECT 1 + FROM public.recurrence_exceptions ex + JOIN public.recurrence_rules r ON r.id = ex.recurrence_id + WHERE r.owner_id = v_owner_id + AND r.status = 'ativo' + AND ex.type = 'reschedule_session' + AND ex.new_date = p_data + AND COALESCE(ex.new_start_time, r.start_time)::time < v_slot_fim + AND COALESCE(ex.new_end_time, r.end_time)::time > v_slot + ) INTO v_ocupado; + END IF; + + -- ── Solicitações públicas pendentes ────────────────────────────────────── + IF NOT v_ocupado THEN + SELECT EXISTS ( + SELECT 1 FROM public.agendador_solicitacoes sol + WHERE sol.owner_id = v_owner_id + AND sol.status = 'pendente' + AND sol.data_solicitada = p_data + AND sol.hora_solicitada = v_slot + AND (sol.reservado_ate IS NULL OR sol.reservado_ate > v_agora) + ) INTO v_ocupado; + END IF; + + hora := v_slot; + disponivel := NOT v_ocupado; + RETURN NEXT; + END LOOP; +END; +$$; + +GRANT EXECUTE ON FUNCTION public.agendador_slots_disponiveis(text, date) TO anon, authenticated; + + +-- ── agendador_dias_disponiveis ─────────────────────────────────────────────── +CREATE OR REPLACE FUNCTION public.agendador_dias_disponiveis( + p_slug text, + p_ano int, + p_mes int +) +RETURNS TABLE (data date, tem_slots boolean) +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_owner_id uuid; + v_antecedencia int; + v_agora timestamptz; + v_data date; + v_data_inicio date; + v_data_fim date; + v_db_dow int; + v_tem_slot boolean; +BEGIN + SELECT c.owner_id, c.antecedencia_minima_horas + INTO v_owner_id, v_antecedencia + FROM public.agendador_configuracoes c + WHERE c.link_slug = p_slug AND c.ativo = true + LIMIT 1; + + IF v_owner_id IS NULL THEN RETURN; END IF; + + v_agora := now(); + v_data_inicio := make_date(p_ano, p_mes, 1); + v_data_fim := (v_data_inicio + interval '1 month' - interval '1 day')::date; + + v_data := v_data_inicio; + WHILE v_data <= v_data_fim LOOP + v_db_dow := extract(dow from v_data::timestamp)::int; + + SELECT EXISTS ( + SELECT 1 FROM public.agenda_online_slots s + WHERE s.owner_id = v_owner_id + AND s.weekday = v_db_dow + AND s.enabled = true + AND (v_data::text || ' ' || s.time::text)::timestamp + AT TIME ZONE 'America/Sao_Paulo' + >= v_agora + (v_antecedencia || ' hours')::interval + ) INTO v_tem_slot; + + IF v_tem_slot THEN + data := v_data; + tem_slots := true; + RETURN NEXT; + END IF; + + v_data := v_data + 1; + END LOOP; +END; +$$; + +GRANT EXECUTE ON FUNCTION public.agendador_dias_disponiveis(text, int, int) TO anon, authenticated; diff --git a/DBS/2026-03-11/migrations/agendador_online.sql b/DBS/2026-03-11/migrations/agendador_online.sql new file mode 100644 index 0000000..bc9390e --- /dev/null +++ b/DBS/2026-03-11/migrations/agendador_online.sql @@ -0,0 +1,170 @@ +-- ═══════════════════════════════════════════════════════════════════════════ +-- Agendador Online — tabelas de configuração e solicitações +-- ═══════════════════════════════════════════════════════════════════════════ + +-- ── 1. agendador_configuracoes ────────────────────────────────────────────── +CREATE TABLE IF NOT EXISTS "public"."agendador_configuracoes" ( + "owner_id" "uuid" NOT NULL, + "tenant_id" "uuid", + + -- PRO / Ativação + "ativo" boolean DEFAULT false NOT NULL, + "link_slug" "text", + + -- Identidade Visual + "imagem_fundo_url" "text", + "imagem_header_url" "text", + "logomarca_url" "text", + "cor_primaria" "text" DEFAULT '#4b6bff', + + -- Perfil Público + "nome_exibicao" "text", + "endereco" "text", + "botao_como_chegar_ativo" boolean DEFAULT true NOT NULL, + "maps_url" "text", + + -- Fluxo de Agendamento + "modo_aprovacao" "text" DEFAULT 'aprovacao' NOT NULL, + "modalidade" "text" DEFAULT 'presencial' NOT NULL, + "tipos_habilitados" "jsonb" DEFAULT '["primeira","retorno"]'::jsonb NOT NULL, + "duracao_sessao_min" integer DEFAULT 50 NOT NULL, + "antecedencia_minima_horas" integer DEFAULT 24 NOT NULL, + "prazo_resposta_horas" integer DEFAULT 2 NOT NULL, + "reserva_horas" integer DEFAULT 2 NOT NULL, + + -- Pagamento + "pagamento_obrigatorio" boolean DEFAULT false NOT NULL, + "pix_chave" "text", + "pix_countdown_minutos" integer DEFAULT 20 NOT NULL, + + -- Triagem & Conformidade + "triagem_motivo" boolean DEFAULT true NOT NULL, + "triagem_como_conheceu" boolean DEFAULT false NOT NULL, + "verificacao_email" boolean DEFAULT false NOT NULL, + "exigir_aceite_lgpd" boolean DEFAULT true NOT NULL, + + -- Textos + "mensagem_boas_vindas" "text", + "texto_como_se_preparar" "text", + "texto_termos_lgpd" "text", + + -- Timestamps + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + "updated_at" timestamp with time zone DEFAULT now() NOT NULL, + + CONSTRAINT "agendador_configuracoes_pkey" PRIMARY KEY ("owner_id"), + CONSTRAINT "agendador_configuracoes_owner_fk" + FOREIGN KEY ("owner_id") REFERENCES "auth"."users"("id") ON DELETE CASCADE, + CONSTRAINT "agendador_configuracoes_tenant_fk" + FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE CASCADE, + CONSTRAINT "agendador_configuracoes_modo_check" + CHECK ("modo_aprovacao" = ANY (ARRAY['automatico','aprovacao'])), + CONSTRAINT "agendador_configuracoes_modalidade_check" + CHECK ("modalidade" = ANY (ARRAY['presencial','online','ambos'])), + CONSTRAINT "agendador_configuracoes_duracao_check" + CHECK ("duracao_sessao_min" >= 10 AND "duracao_sessao_min" <= 240), + CONSTRAINT "agendador_configuracoes_antecedencia_check" + CHECK ("antecedencia_minima_horas" >= 0 AND "antecedencia_minima_horas" <= 720), + CONSTRAINT "agendador_configuracoes_reserva_check" + CHECK ("reserva_horas" >= 1 AND "reserva_horas" <= 48), + CONSTRAINT "agendador_configuracoes_pix_countdown_check" + CHECK ("pix_countdown_minutos" >= 5 AND "pix_countdown_minutos" <= 120), + CONSTRAINT "agendador_configuracoes_prazo_check" + CHECK ("prazo_resposta_horas" >= 1 AND "prazo_resposta_horas" <= 72) +); + +ALTER TABLE "public"."agendador_configuracoes" ENABLE ROW LEVEL SECURITY; + +DROP POLICY IF EXISTS "agendador_cfg_select" ON "public"."agendador_configuracoes"; +CREATE POLICY "agendador_cfg_select" ON "public"."agendador_configuracoes" + FOR SELECT USING (auth.uid() = owner_id); + +DROP POLICY IF EXISTS "agendador_cfg_write" ON "public"."agendador_configuracoes"; +CREATE POLICY "agendador_cfg_write" ON "public"."agendador_configuracoes" + USING (auth.uid() = owner_id) + WITH CHECK (auth.uid() = owner_id); + +CREATE INDEX IF NOT EXISTS "agendador_cfg_tenant_idx" + ON "public"."agendador_configuracoes" ("tenant_id"); + +-- ── 2. agendador_solicitacoes ─────────────────────────────────────────────── +CREATE TABLE IF NOT EXISTS "public"."agendador_solicitacoes" ( + "id" "uuid" DEFAULT gen_random_uuid() NOT NULL, + "owner_id" "uuid" NOT NULL, + "tenant_id" "uuid", + + -- Dados do paciente + "paciente_nome" "text" NOT NULL, + "paciente_sobrenome" "text", + "paciente_email" "text" NOT NULL, + "paciente_celular" "text", + "paciente_cpf" "text", + + -- Agendamento solicitado + "tipo" "text" NOT NULL, + "modalidade" "text" NOT NULL, + "data_solicitada" date NOT NULL, + "hora_solicitada" time NOT NULL, + + -- Reserva temporária + "reservado_ate" timestamp with time zone, + + -- Triagem + "motivo" "text", + "como_conheceu" "text", + + -- Pagamento + "pix_status" "text" DEFAULT 'pendente', + "pix_pago_em" timestamp with time zone, + + -- Status geral + "status" "text" DEFAULT 'pendente' NOT NULL, + "recusado_motivo" "text", + + -- Autorização + "autorizado_em" timestamp with time zone, + "autorizado_por" "uuid", + + -- Vínculos internos + "user_id" "uuid", + "patient_id" "uuid", + "evento_id" "uuid", + + -- Timestamps + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + "updated_at" timestamp with time zone DEFAULT now() NOT NULL, + + CONSTRAINT "agendador_solicitacoes_pkey" PRIMARY KEY ("id"), + CONSTRAINT "agendador_sol_owner_fk" + FOREIGN KEY ("owner_id") REFERENCES "auth"."users"("id") ON DELETE CASCADE, + CONSTRAINT "agendador_sol_tenant_fk" + FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE CASCADE, + CONSTRAINT "agendador_sol_status_check" + CHECK ("status" = ANY (ARRAY['pendente','autorizado','recusado','expirado'])), + CONSTRAINT "agendador_sol_tipo_check" + CHECK ("tipo" = ANY (ARRAY['primeira','retorno','reagendar'])), + CONSTRAINT "agendador_sol_modalidade_check" + CHECK ("modalidade" = ANY (ARRAY['presencial','online'])), + CONSTRAINT "agendador_sol_pix_check" + CHECK ("pix_status" IS NULL OR "pix_status" = ANY (ARRAY['pendente','pago','expirado'])) +); + +ALTER TABLE "public"."agendador_solicitacoes" ENABLE ROW LEVEL SECURITY; + +DROP POLICY IF EXISTS "agendador_sol_owner_select" ON "public"."agendador_solicitacoes"; +CREATE POLICY "agendador_sol_owner_select" ON "public"."agendador_solicitacoes" + FOR SELECT USING (auth.uid() = owner_id); + +DROP POLICY IF EXISTS "agendador_sol_owner_write" ON "public"."agendador_solicitacoes"; +CREATE POLICY "agendador_sol_owner_write" ON "public"."agendador_solicitacoes" + USING (auth.uid() = owner_id) + WITH CHECK (auth.uid() = owner_id); + +CREATE INDEX IF NOT EXISTS "agendador_sol_owner_idx" + ON "public"."agendador_solicitacoes" ("owner_id", "status"); + +CREATE INDEX IF NOT EXISTS "agendador_sol_tenant_idx" + ON "public"."agendador_solicitacoes" ("tenant_id"); + +CREATE INDEX IF NOT EXISTS "agendador_sol_data_idx" + ON "public"."agendador_solicitacoes" ("data_solicitada", "hora_solicitada"); diff --git a/DBS/2026-03-11/migrations/agendador_publico.sql b/DBS/2026-03-11/migrations/agendador_publico.sql new file mode 100644 index 0000000..4ca29d4 --- /dev/null +++ b/DBS/2026-03-11/migrations/agendador_publico.sql @@ -0,0 +1,219 @@ +-- ═══════════════════════════════════════════════════════════════════════════ +-- Agendador Online — acesso público (anon) + função de slots disponíveis +-- ═══════════════════════════════════════════════════════════════════════════ + +-- ── 1. Geração automática de slug ────────────────────────────────────────── +-- Cria slug único de 8 chars quando o profissional ativa sem link_personalizado +CREATE OR REPLACE FUNCTION public.agendador_gerar_slug() +RETURNS trigger LANGUAGE plpgsql AS $$ +DECLARE + v_slug text; + v_exists boolean; +BEGIN + -- só gera se ativou e não tem slug ainda + IF NEW.ativo = true AND (NEW.link_slug IS NULL OR NEW.link_slug = '') THEN + LOOP + v_slug := lower(substring(replace(gen_random_uuid()::text, '-', ''), 1, 8)); + SELECT EXISTS ( + SELECT 1 FROM public.agendador_configuracoes + WHERE link_slug = v_slug AND owner_id <> NEW.owner_id + ) INTO v_exists; + EXIT WHEN NOT v_exists; + END LOOP; + NEW.link_slug := v_slug; + END IF; + RETURN NEW; +END; +$$; + +DROP TRIGGER IF EXISTS agendador_slug_trigger ON public.agendador_configuracoes; +CREATE TRIGGER agendador_slug_trigger + BEFORE INSERT OR UPDATE ON public.agendador_configuracoes + FOR EACH ROW EXECUTE FUNCTION public.agendador_gerar_slug(); + +-- ── 2. Políticas públicas (anon) ──────────────────────────────────────────── + +-- Leitura pública da config pelo slug (só ativo) +DROP POLICY IF EXISTS "agendador_cfg_public_read" ON public.agendador_configuracoes; +CREATE POLICY "agendador_cfg_public_read" ON public.agendador_configuracoes + FOR SELECT TO anon + USING (ativo = true AND link_slug IS NOT NULL); + +-- Inserção pública de solicitações (qualquer pessoa pode solicitar) +DROP POLICY IF EXISTS "agendador_sol_public_insert" ON public.agendador_solicitacoes; +CREATE POLICY "agendador_sol_public_insert" ON public.agendador_solicitacoes + FOR INSERT TO anon + WITH CHECK (true); + +-- Leitura da própria solicitação (pelo paciente logado) +DROP POLICY IF EXISTS "agendador_sol_patient_read" ON public.agendador_solicitacoes; +CREATE POLICY "agendador_sol_patient_read" ON public.agendador_solicitacoes + FOR SELECT TO authenticated + USING (auth.uid() = user_id OR auth.uid() = owner_id); + +-- ── 3. Função: retorna slots disponíveis para uma data ────────────────────── +-- Roda como SECURITY DEFINER (acessa agenda_regras e agenda_eventos sem RLS) +CREATE OR REPLACE FUNCTION public.agendador_slots_disponiveis( + p_slug text, + p_data date +) +RETURNS TABLE (hora time, disponivel boolean) +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_owner_id uuid; + v_duracao int; + v_reserva int; + v_antecedencia int; + v_dia_semana int; -- 0=dom..6=sab (JS) → convertemos + v_db_dow int; -- 0=dom..6=sab no Postgres (extract dow) + v_inicio time; + v_fim time; + v_slot time; + v_slot_fim time; + v_agora timestamptz; +BEGIN + -- carrega config do agendador + SELECT + c.owner_id, + c.duracao_sessao_min, + c.reserva_horas, + c.antecedencia_minima_horas + INTO v_owner_id, v_duracao, v_reserva, v_antecedencia + FROM public.agendador_configuracoes c + WHERE c.link_slug = p_slug AND c.ativo = true + LIMIT 1; + + IF v_owner_id IS NULL THEN + RETURN; + END IF; + + v_agora := now(); + v_db_dow := extract(dow from p_data::timestamp)::int; -- 0=dom..6=sab + + -- regra semanal para o dia da semana + SELECT hora_inicio, hora_fim + INTO v_inicio, v_fim + FROM public.agenda_regras_semanais + WHERE owner_id = v_owner_id + AND dia_semana = v_db_dow + AND ativo = true + LIMIT 1; + + IF v_inicio IS NULL THEN + RETURN; -- profissional não atende nesse dia + END IF; + + -- itera slots de v_duracao em v_duracao dentro da jornada + v_slot := v_inicio; + WHILE v_slot + (v_duracao || ' minutes')::interval <= v_fim LOOP + v_slot_fim := v_slot + (v_duracao || ' minutes')::interval; + + -- bloco temporário para verificar conflitos + DECLARE + v_ocupado boolean := false; + v_slot_ts timestamptz; + BEGIN + -- antecedência mínima (compara em horário de Brasília) + v_slot_ts := (p_data::text || ' ' || v_slot::text)::timestamp AT TIME ZONE 'America/Sao_Paulo'; + + IF v_slot_ts < v_agora + (v_antecedencia || ' hours')::interval THEN + v_ocupado := true; + END IF; + + -- conflito com eventos existentes na agenda + IF NOT v_ocupado THEN + SELECT EXISTS ( + SELECT 1 FROM public.agenda_eventos + WHERE owner_id = v_owner_id + AND status::text NOT IN ('cancelado', 'faltou') + AND inicio_em AT TIME ZONE 'America/Sao_Paulo' >= p_data::timestamp + AND inicio_em AT TIME ZONE 'America/Sao_Paulo' < p_data::timestamp + interval '1 day' + AND (inicio_em AT TIME ZONE 'America/Sao_Paulo')::time < v_slot_fim + AND (fim_em AT TIME ZONE 'America/Sao_Paulo')::time > v_slot + ) INTO v_ocupado; + END IF; + + -- conflito com solicitações pendentes (reservadas) + IF NOT v_ocupado THEN + SELECT EXISTS ( + SELECT 1 FROM public.agendador_solicitacoes + WHERE owner_id = v_owner_id + AND status = 'pendente' + AND data_solicitada = p_data + AND hora_solicitada = v_slot + AND (reservado_ate IS NULL OR reservado_ate > v_agora) + ) INTO v_ocupado; + END IF; + + hora := v_slot; + disponivel := NOT v_ocupado; + RETURN NEXT; + END; + + v_slot := v_slot + (v_duracao || ' minutes')::interval; + END LOOP; +END; +$$; + +GRANT EXECUTE ON FUNCTION public.agendador_slots_disponiveis(text, date) TO anon, authenticated; + +-- ── 4. Função: retorna dias com disponibilidade no mês ───────────────────── +CREATE OR REPLACE FUNCTION public.agendador_dias_disponiveis( + p_slug text, + p_ano int, + p_mes int -- 1-12 +) +RETURNS TABLE (data date, tem_slots boolean) +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_owner_id uuid; + v_antecedencia int; + v_data date; + v_data_inicio date; + v_data_fim date; + v_agora timestamptz; + v_db_dow int; + v_tem_regra boolean; +BEGIN + SELECT c.owner_id, c.antecedencia_minima_horas + INTO v_owner_id, v_antecedencia + FROM public.agendador_configuracoes c + WHERE c.link_slug = p_slug AND c.ativo = true + LIMIT 1; + + IF v_owner_id IS NULL THEN RETURN; END IF; + + v_agora := now(); + v_data_inicio := make_date(p_ano, p_mes, 1); + v_data_fim := (v_data_inicio + interval '1 month' - interval '1 day')::date; + + v_data := v_data_inicio; + WHILE v_data <= v_data_fim LOOP + -- não oferece dias no passado ou dentro da antecedência mínima + IF v_data::timestamptz + '23:59:59'::interval > v_agora + (v_antecedencia || ' hours')::interval THEN + v_db_dow := extract(dow from v_data::timestamp)::int; + + SELECT EXISTS ( + SELECT 1 FROM public.agenda_regras_semanais + WHERE owner_id = v_owner_id AND dia_semana = v_db_dow AND ativo = true + ) INTO v_tem_regra; + + IF v_tem_regra THEN + data := v_data; + tem_slots := true; + RETURN NEXT; + END IF; + END IF; + + v_data := v_data + 1; + END LOOP; +END; +$$; + +GRANT EXECUTE ON FUNCTION public.agendador_dias_disponiveis(text, int, int) TO anon, authenticated; diff --git a/DBS/2026-03-11/migrations/agendador_status_convertido.sql b/DBS/2026-03-11/migrations/agendador_status_convertido.sql new file mode 100644 index 0000000..cddb978 --- /dev/null +++ b/DBS/2026-03-11/migrations/agendador_status_convertido.sql @@ -0,0 +1,19 @@ +-- ═══════════════════════════════════════════════════════════════════════════ +-- FIX: adiciona status 'convertido' na constraint de agendador_solicitacoes +-- e adiciona coluna motivo_recusa (alias amigável de recusado_motivo) +-- Execute no Supabase SQL Editor +-- ═══════════════════════════════════════════════════════════════════════════ + +-- 1. Remove o CHECK existente e recria com os novos valores +ALTER TABLE public.agendador_solicitacoes + DROP CONSTRAINT IF EXISTS "agendador_sol_status_check"; + +ALTER TABLE public.agendador_solicitacoes + ADD CONSTRAINT "agendador_sol_status_check" + CHECK (status = ANY (ARRAY[ + 'pendente', + 'autorizado', + 'recusado', + 'expirado', + 'convertido' + ])); diff --git a/DBS/2026-03-11/migrations/agendador_storage.sql b/DBS/2026-03-11/migrations/agendador_storage.sql new file mode 100644 index 0000000..6d82893 --- /dev/null +++ b/DBS/2026-03-11/migrations/agendador_storage.sql @@ -0,0 +1,56 @@ +-- ═══════════════════════════════════════════════════════════════════════════ +-- Storage bucket para imagens do Agendador Online +-- Execute no Supabase SQL Editor +-- ═══════════════════════════════════════════════════════════════════════════ + +-- ── 1. Criar o bucket ────────────────────────────────────────────────────── +INSERT INTO storage.buckets (id, name, public, file_size_limit, allowed_mime_types) +VALUES ( + 'agendador', + 'agendador', + true, -- público (URLs diretas sem assinar) + 5242880, -- 5 MB + ARRAY['image/jpeg','image/png','image/webp','image/gif'] +) +ON CONFLICT (id) DO UPDATE + SET public = true, + file_size_limit = 5242880, + allowed_mime_types = ARRAY['image/jpeg','image/png','image/webp','image/gif']; + +-- ── 2. Políticas ─────────────────────────────────────────────────────────── + +-- Leitura pública (anon e authenticated) +DROP POLICY IF EXISTS "agendador_storage_public_read" ON storage.objects; +CREATE POLICY "agendador_storage_public_read" + ON storage.objects FOR SELECT + USING (bucket_id = 'agendador'); + +-- Upload: apenas o dono da pasta (owner_id é o primeiro segmento do path) +DROP POLICY IF EXISTS "agendador_storage_owner_insert" ON storage.objects; +CREATE POLICY "agendador_storage_owner_insert" + ON storage.objects FOR INSERT + TO authenticated + WITH CHECK ( + bucket_id = 'agendador' + AND (storage.foldername(name))[1] = auth.uid()::text + ); + +-- Update/upsert pelo dono +DROP POLICY IF EXISTS "agendador_storage_owner_update" ON storage.objects; +CREATE POLICY "agendador_storage_owner_update" + ON storage.objects FOR UPDATE + TO authenticated + USING ( + bucket_id = 'agendador' + AND (storage.foldername(name))[1] = auth.uid()::text + ); + +-- Delete pelo dono +DROP POLICY IF EXISTS "agendador_storage_owner_delete" ON storage.objects; +CREATE POLICY "agendador_storage_owner_delete" + ON storage.objects FOR DELETE + TO authenticated + USING ( + bucket_id = 'agendador' + AND (storage.foldername(name))[1] = auth.uid()::text + ); diff --git a/DBS/2026-03-11/migrations/remove_session_start_offset.sql b/DBS/2026-03-11/migrations/remove_session_start_offset.sql new file mode 100644 index 0000000..1ddddef --- /dev/null +++ b/DBS/2026-03-11/migrations/remove_session_start_offset.sql @@ -0,0 +1,6 @@ +-- Migration: remove session_start_offset_min from agenda_configuracoes +-- This field is replaced by hora_inicio in agenda_regras_semanais (work schedule per day) +-- The first session slot is now derived directly from hora_inicio of the work rule. + +ALTER TABLE public.agenda_configuracoes + DROP COLUMN IF EXISTS session_start_offset_min; diff --git a/DBS/2026-03-11/root/backup.sql b/DBS/2026-03-11/root/backup.sql new file mode 100644 index 0000000000000000000000000000000000000000..90052773934b41f8958b206a5651b587aef3c6d5 GIT binary patch literal 3112544 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 z zjL?S9hTHsJ8>~_?rSOG|FZq3DO@^tc!d`<9BL4n%{Jb7{40oeyDqPBM5Ore&EK9c^ zuVi@zwmOxuK<``m+f}EkHS)Y(L&;;-@K$7wtbTmhy1g%H!noR=D!BgqbJul`Io&bx z8~RZlc`j;SlIMhbQq{R!WD1d%^di~wqPcR411{LEi0_uxT-$xJ1?k<<58KUXB7Hkj@9d@})f9L; z#@LOf)@f7qXxr(Xdpnq+Gxt(=dJ(94ygE}xYCk<2(mIf36c{tM9@pk4jc*rLHa40o zzA%r5Ct5h?yfJo0x<|HBi&_WzXVFg?zXdDsTS0$R+`w0mULvv$)GO3<7WWsBRUmyp znnXE2jn|G)w)lsl?^ZUH?f!@1tQdJc%*-RnXO=7Vc+zqHr=i^^14pUp)xJZWX~FAA zPN6bqrP%;ibW}7e{9&&RI>$eYHYMHjm#Ykrx4|hDog2)#>rRle)p&<&YngL#F3vjJ z;dGL5u5IpS;>cQCY(MVN?%a#SJH~4>&D2nCy-%j)=fycLpD)zZlr-}+B5TQW*6;;U z{^4k4?H(RquSTb)ay43y@#w{(mfrfj(sdMr^t+)NsD`SxTPWw{c*B~*A*pBmo*tiq z$f;DNCr*HU5%h$=i@ZzS9l-g1^Io)?-tX66qg?|9?qKpgx+N6&zJyl|Bc8&a(0o*F zOkO|tu)CJLHO2xD;0%_tIZuaESbS4*hrAKK&B^AJT7NBg35nn+ikBL)-Z0GGjEK^E zk=fANnJxT)$iIw#((`0zzf#T7C;HSARr1P_#+K~V2v=i;bw0Y!6`lr6KOB5}?2fpP zwriBF*6W{dY{L7vw9c_FEpPY4Dif4AoslDwP?i)Pw`-%s+ZEK&C$9En-t(RXJ|J<>q^-Xz1>-f}++=S|=KuvUo z7@PeOoL9%Epp&Sa9&ttKo}60NW7u=yLs_ZYlA5Rf{rYP>hlJ}KrvPfDc4RviKUu<) zR%0z`x~=kdt&c%T^}da(OUV1pIC#GCU;1tN@z7GpW%Le@dm!3h#`^2NN=)3f$DS@& z@@i{Ro+C3DN1Ullh<}b&)Ue<;)}?G>XbISpd2DLQr>7w?u>h#iU2>&eIJ|G3>ht*0 zzjJ!>x1sBB!^7Xjtm--fr+YW)LTPMH}p`>DdFLNH)Md}b@w7l>Z*0OqLm`a z^?986GZ3Zj+?$nW=TB-JwA!_wO?}R3-?}+!TG#e!Qx4VfoR@jzw>j^5dR}9V{P3%;F}qz&`?vM+T_7VUta(%V{po-)b)6Jt*!F08u3y_) zb8WoRTBp4o()K5-r0rba!eeNBu9audlOLQ=cQ$*>UH)mgYUXeO8Fa3LA3`gp*URo#8GtnKUR4 z(ejUdc!V^@`Q7{ZDp*`L>~p*&*uNLLB-sJn8TNW;m1}l(39r%S?hd&#J!vf2eK+)G zdlJa&8=n+e8U@MqPW(fQeJLby|IGb|F&8vJY8FjdSIagPEm}*ewrVun(w^b@SYFp} zP1!=FpTfS(t@pjP+RBS<$JTHi??&3Ib<3$8$oAmrWqNOF|JUVtYJiLF zyYv+;d3MGTeV{E#z4m+nZ$S61%C)=iho1T}ZmSoGo}5R9Cn|I0FV8ondjEGq512YT zWKY#NpU@h|pTZ*MtnsITMdf)pDqa4^kkyiAW$XI1kzz3DT<9ge)>F}Ud^6=3r6!|H zzPp3Rj+~si>YS_qPdd8*exet>H&`6^1`B&Ur;;PIvnW@Zv^v)c%+zUZcoDb4Q?GFD z4QCnA9v>!o&YaqEybArtkRL5$)m-ab}vK8=1PcTs=_I7SQoE>J?cvCgDZ?}2n zVn@sVwKs1>)Jn9?S!XcuZvzX{6P7DGy*Q;!oD042%b=S&;>C=!{llvL7)SbESIz3* zhR5M5{fyxTe9?j53fx2^{`>g!oxkJOS7|NGrJUiI?o?ZtsMWWDbKD*}K9$~+I`Go7 z3+g3$iA<5_$P#CXhBfkdw35=xn2SbatZ~mJ)vI6Ixu+*-y^hC9noF6S9m`N8qX5dqfaNM%k%$ih*2>YLW8 zI*t4O$dhJ#MWU3|tlz0iA_$k5WA0A90;GxRJ7HBOFU1y1UTXh(xu5WwtSv&6OeaTt z(=ah0xF0jiQ)g4&sM>d~>f2y=J)-@Yxr61pN?7MgYN;R?I|HW1KJB{3CKvxv$OSTh z+Ia}prjjMi)ws6XOo?bH52-f`@(7uSywJ!os9se2d92`kL9garXGHa2(f6`5lX>{= zJL@&jpPM^g9AxR6li2@ytN`pqQ%KoY%Sxcvm$EO%Tb$s196zcu0{#;pQ$;20fp6m3 z_XGA56_u_p4MXP}bT*-^<--|DZkC>+g<8v+!>gp9seK}@Nha8P!CNvTY@V)4`bwD9 z`hw`IjiY`Qr^alFKt2484dUOKWoupdSoM8y} z&(q0NU&&MK%Db_Yf^%!7W3QIvD{<3|*px7u;*$96;em=>Zd-%mQks$XVtSmv9!B{| z{NH*!*Y+T@-?S1lr3}Tb_C9IgL!08T_?=DJPd02{ud5I`ac@^%xeEqObIbNgDU+{@r-ux= zdy%UnpW2kqhx$ZsggliMubXMHgwx8mW!q+uT`!oVl*^Ub%L9$AvnJMCAeOvnZ0VUv zZ>a2q)~4NEGqhLKeAF4J_%QIR%4;s~7kiHHLVn`$sdVa1a?g`;f2q<#ttPata?ia& zeP2l?I-v$ zef0Ne&6*F(pc02=Z{9_JzBs#i758CI z7xE7HGi5+e=I!Hi^9WO%J>_X{Wci2ZJ=J~L>v7k3XWX_tfw9zU3tji&PiI8}*}AW} z89Bm1T~5h-<)M5PydS?KK3lW^erq*9Rp~+pP}OhMi^jKy=Z_pbMOj@P0?9|UMLfa8 zgL*hDydc`H^Cb79{rWQ@M0QR$`5=39Fhuu}*>nBU|2B!9x%6Olsh6(7S4TaRc|SL^ z(gXQwcYlZ_%xS=eT@SBR&wv=**8E_udw?b`EN<_crz9x__wdH8dVHr>XbyUcw* zPPWW*6#bpswJn%n&H$&#Xu(|X&kHB^gX=QXcG>fq>$?YkPRobo7UOrzJ<$$dfc--hiwhQx=# z-*n4}DrS>4b2mn9GmktL67ILrCvuc?)$|LW#g--l`bK2WzZ-KWC%xBC#(BnbxyrlZ zT_|UrxQGTo#5FTn;D2P9I0H;}Zky*JD(LkoEMQOW#onVUpxM0t%==a5Ui5d48Ye_j z$zdg`jbuPWA|jwDHJM}F%!CxFqtjm5J{&9G?OWw|@X(lci&lGv>#ZbXaG8(!Vt7t^ zw!t=??fLmndhz6S-jhRH(LW^o=y4oVls|X%i0!tchtS?`I8LwHi{b%?@YR}2?9Xrd zUf*M4Wj~U(j?*Mw)p?7@_tU;;Jn4suK{v9BT)p|cw7$pSD)NM7S=F}atwMgovDMI{ zd27n5@VDM-cx|v6?hcy2ZYYr-6srxt6tPhL$NTwaSeb8!{iajU@_xP&k3mWVoK_C{O6wmxZUjN`4wlKW_AU!IZExd&`K{`D<7uRU``6=UGcB7Op@ z;mz;tdYF5x_EX*qjoZ)JZ{O%;5*x$T_0Y>V-qyoXR`Ryq#<|N|;8Dh6u%OEme=Y3% zw|CVZiHt3kehQr%nC39+alexohPgjIUr9h&v&?$RizNwaET>lBZ^G{;{~R+d-z1*sy3Tk~(TCX`e5Xi+ z&xhaVId?rj+cnIvwodAKkr&m@E6)_R^OAkGb!NypDyWFll(#1;Td%Fvru24&YjR$XKaa23c_e>| zDt|dpvGnOu-a(yk25EhX@vIsNq-cs|C--x~5qN@z{!JCP@rYBOKz2+M-b?LxNt?MZ z^U|Ol&-Tl@x8|dAZQuS|P)&W=R56GDez(9f6_d+pbaG^h9W zM(VX+H_}@DxHsz3yX$5!rBnAtY}>9IVHdsI_^4TAL~uX-+r5fH*6QKX3ARvCa?-wB zTtkVTD-hU?GdU}0UP7$fL(AaHnfcl|t??Kcj{Y$sKKH_J8Mdzxfjv#Qie z&{4Pn=(yF#(E?bXZp|y}Pt-F@+9|7Akm*Q$a`l4MqIy952|)_SO$>?Pe$?|UDVFZ?3l>C*ao7^}J*c;=r} zmc|m^mN<@|gbD_8n5x|vMi0fis^CnO2X3&wm=f!--v^H)lMbtz6y+kL14_vhw|qn3j-d;XU{~ zRxix9H4Svch4Hn4`<#HQA&!*!C^84JH!~(gqyfn0iis-Rj&GDRn4aDH(Jo^=SzqSzHx0{%mJeb--W#H4p7T$me$&rRUWv@Twl;?K zqp{{x^YS{faY+8V%q5PmCqM~kJotX6@7lp{2?mKfK}l=Au@t6#@AvCp*|mnAr~`Lk#bS6cJdD;HXAVoL7k zc#PhSJFbj}FB`A?7lBXneHco0MOJ3-zTh5k8_owAlD*lu&fYO9yY@Un%x2rIJ*=wd z@!74XB`?lyy|$j3)05u~JMm>mtU6M%q^~UN+1IJEt0fR#m9bw$@rrjtE8|8e$x>JS zv@cjU&P%&5Wu5gj;!^OGr8=?6K@{h4mDO^FHHY#{YQF(1Dcf;ZwX0sD8}*{xyi|d_2LU42Y$L|Q~bl2N7DRs`+hWNZUp<{n2V#L>#Np2zk0FWTj9$6;D)M)i@wJ? z>Z%G;p1)~G!mpjFU|moiQ&-RR4CveWGk6}*=K62+?PsmvDxW>k3|Z4uy^}HZUgh<$ zV=80c&WrX>2c4jX};D?*3|`G;!@)s9M`yQcYW6i zx4#-N1A9+=CiODqQdr9?X(D6&CB&zp#S`}dpygos8#lU8EwX2j2}pug;v_3wpaB z-+T}{9rE%QL;kbbf`D{?h2)g}JP=DzUk5d-{w(Dm@lJ_?M$(^to9ZwKXpE8NwQQBCW3=wLc! z#onx04|>OY;i2ZtG&i}`c(bO5@wvwm6HWuNPiJS+*A9#&=fR(lB=^E!jDNfCTR45| z*&g58;Dye5-}sw+3y|pqeQCW%yY6f3Rr)6GeRj`1UE(++^|XiMjI^X9>^f?Ct_;1g zcPsfwi5qSGc;k~l$(L{>h#1$~vpCvfVV?$Dj<_pc3ip%;ZLQt6O`%=)_m#+v&JYme z?cD^$yDj|YDLi3YN5I;;+w;9#7I!`jUv@8tm_Fzc`Jx=+_W#`s$Z@(w| zTk}xHO8*|8a!yc??$TjyjNFTq*kayow$OY3E}wQL%jd`XGlauj?tMPnXTEhu=GHWq z3oDNBdSKAaJwLluP6Ef06V^FZ_C?kpbggBA=3@UZ zdLMsJSN(aOI6Bt0zp||Gr0IsohLzCa%D7bFeV5B` zb(Z>&9M@;QZ+PyD$#Zwb(!+4vU9fAK=eAEu?kipXt+3Kn`v42pw{??Yp^T!r8+wv& z_hX>tXy#eyzj=}>$C2*K(vA2|2wy_m0HseL>~)z#V$JFNxvylolv+C`4^>lc<*^M3uq0f1hA?|N8m z>^>$Bn5vdodS>S6$FaO+ACXscgJuzi_;mqfV>JRkdLYsu^N%vp49GaVaoi*bx(`boL(lJQqL&sHr!-rSyhhTv?F}Z~J-HR~JZ+>gCiOU#;pflix!bKaqn(eC%!U$3IAK_`=Wq+xb4ctizg>sfYvhK<6(?C+8<$$!<%yfC zbVr4&pil>)%r>6p!BCX)jnlWzdDbUE%{mqQc~H5k4)i3zRK~Gk>(4E`20Sq5Rb@&= z_=OLxOq*WY5_g#P=x>>|<g6dw$9=llat4tcWc;4wi^{i5O=bG+=gsVY+eNvLa3J#uXN6>)ld`4j5qQ<}bw}pl zI~Qd!?EPu^G^NdoKeZ)skmt~ng{7>4nbg_QQs*Fo=`#9z~E;!10S>}&CO-q2m!cj|`ilQsIG zdp5UOvrfMwDDHOGi2GP)O^M(1Ie|IfSSRDjE;f?qR@zFv8Ss1^mb%9|8>%-#ul=?W z=WMOsh`sjPMqF!?^+sQMciT*+?6}^@ZQE@l?PKd1H#Dn5*nIABAKtju29&;Otz!-M zNG{peq}KG|6#}y@_EDdMq`gOfV?MGD7k1&GhnoM|8E)|f7{->ztsY!@A~NQeR?qyL zjGNXv`>ovyoT*#*N&UXQRm=TvOet#?o>w{USXg<7NY4tXTO?Gl&d?}$KPz;XQmXg7 z^_Gr%DCb&_?Wzpymn-!3TV!2_d=70~Ze?>-`J=W`TbX&kn&;(?E&Yza1fTTxvFo}8 zqrG2;=l8?5#?Gd87bg~KdxsY9MJ)yR)02zm$aC%uz@PN#pv#r_0F*a#zy;B-_~hT+ zsM2&VEK=&fuDR`}#D_VEejT$YEvVdiv?rdH*zFouCH!cU_}#-^wQ%k8sTM#_-t+1E zeCWyeTvizw&pKO8<9*#**{(kWXrYw!jcKxc#^j*It%MQG(EBk`CWlQi!^>@{OsXUW=x?dJerKsH}NvCPKkjpEV#S!RQJ1dW>~z}9&#=}DYLRq@;l->vVV&xz_Ddu`T_(C1L~ z2)#DzM_A@u^=M1&*N;5rZuLm*^L0Jfn#Juwb0ppjZ|M7AsT!G;FX0eWHV~)yaZnbr zOf#GAV-9<_R9~3uXKmg#)jH?;fts9aU9Nn(mPlC%l)5C#l|b=1_vRo!*qzvwN5N~* z>p5{sbhLzRecQP1jXJO5r&ARR)&J|UqpHf)qYZAI(rMWqZK7YG5uTpB6FIc+MikS$ zq1P9yoA6{ETv!>hXK@VvVkk3tpQ)onx_Ih0(RUCP?)#VBKuDjnl)Ob>oy!u@)=+ z|BKlFvR3M0ICDAPaz)W~Yj_a0z=wl1CaBAsRbp?CR~RpnfA)2axpzyRIgPthQK`9} z$F+c``|tHL#Ub%;d=$LyvNS5{Kd1I&Nwb9L!dnYdf%O4Rvr$XKj@r1Dl-d3wUF zBFT-`$>iP~&DplqRW7Zib}my~qc{2#=TT$=Z4Aw9R|xe+^m-F^?QYDyRr2t8&Bo(U z!`C-uuB%kf85%rR_;1&Z;jx_Oi5HgJVaXyo537NkVQ!j*hPX8quhS>-yY6qLTJh9A zxaaoMJb6k_pM#@ zej6~EZo3sqOZA%*5_9nC*S+a~ThirRpZ)A-?`rDL{6aW?67ng5X-Cpm4d zsn>_&ZPPuK(q_IdLve0iWp5=XobS2r5o#>u!%g&i?73Wy&bNBrF{9tQCyo=zcf$vA zXV|?`QX`!ccZDN~5#yM4wiTYwwM{B^zQ$}ESW7(gg!iT##w}huwF}`ipk(n=J-ik#tqd&)-^Cs3Zo2Bft z-Xp_Zt0*(@*}XbTpxrGzAn@S4>s`*=%=Yc9xn=NKwf&k1Yt?6?&X z-5<`2@2T9a9`1U^%5us1&f}-B$#RXwW{RW3^J=QHZ>djK4z8m}3=TOPx!1X5s z-kpX927gwD^EbiWWcAU*(}Di*kCT1D6L5oDZ_(apL3Z?`m@9PO#rI58b(mmLCCM_;cQHW0QrY73*O8(vjCwmx2U-kErgBnB7SMHeoG^I`0TWzZ+ zj z8ovb(_#`+6(vjUkI`hfD<uFdV61yd(?*{gN5E%mxhCAo+QoT9krXnR+ zlO-$?{XzUyO9f!8Y}g0E1MzA|yO@W3oi|Za7UNC(%4+QJIVdu3q_2F_XmiZ(`=Dub zU$Raz>#(+!Ig$D}o?8aE*3^UG3l9gM-7ijlb@C4%)(`g(P? zFS2}@Gdv3&Eoa{IWdEm={~WN#kDcx6xd91e`xgi4&6=#d2M;fLg(g_FIPG|ziW0n1 z>`|YO%7@@RaZNtuWg%rTV+c%uLY)O9&Ejj{kH2@ z-O`EP{7+HI`)<&o@R9#tj-A#y(py0#r}12N8n(c1;&;o1A3vj@TZ=R`Wh?gP)LZ8q zy^eMJk{b(~+CG1>0nTc>9?muYFqD_L&J={kz4g{|X!!he1ANqWJ$(8ck@v@34;eQF zndyF72r)w-RCC>$>(676YipI5#oV&eR?RU44K(Ekvz(SbY7ao_G{^>g4EWEbGxTM8 zdeq3N{U)^PwvTBanPkJXkEq1H=~gurPq*vsSPM}g((3%nkbXa89XFuNNi}+5J*Aez zKBXR@JRjXUUVG1{A$S(Nlk-K=$K@aTB<6wr{9bqw-k9;goeesC{f;b}X&9cx4vRZ$ z4B`5FA)n{p@kyuhtvn0yyqc$twV)qGFVgqmtbYouKu0k4mv8rZt+}e6 zmKXug0~=~KjrU_X`P^{m~vp9U)sNv8 zZx5%d?svu%jpDf=yAzIp?v1^aR5vxs7&d(mh*v5(#$R|~@@>9Z@@npHbFcA#%zFxQ z#`YK3tB*yd+9t|m!s5WfKzEgo!g?!OYx1^U7-^^9MJ*hhQpngzfgni{BhgcdmcUeJm5wmad=Ui@;YRd#tvS>z0}q86ZTEJ<})g zH*2sT!4`Y{F1<4n(Gt$C-~obb8^-cV6CFPf{{Y_LZ(~MyMPwak%d8NRc^v(fmwviq zjmW-OC*k*&mUi3kHMEi#w}viC`HZIlUk{!P;D7z7WO+3$&HQP=J@W+Oc_I0oh~jd>YdyAM@W^#X2B1IAQKd-7~w zfHzWi39j-}EUnS@hH7ju+Ha!w-^3@r>d#`A@x+#RF!lqV#SE2kHSPsJJSQ3PY=8ym z6#X@S92O%j_FXa9w2V)Qztq$CGJZZCW}48Z!n?D^4h3zG`n!OaFgnK*)veuK=jhH; z4VDOJ3871H=HnO_PXMt9V&sYs-3gn3Oad}b(4Uw|y+`H@d}6Vb{)oCI5m6-hXR(_) zrS$n=bFs5%TEt_4`0jI29wT;~`UGN+W3(+jE>T5KD?u9<)Rrjkl?Hkr$D4{+;h9Fi zRMZiVHESTF0iT5;I>a>f9c!c_8sj|*ZS=Ls%>LP+k+%DGHgMN3qu(dd=Wj0PZMn~S z?~I+wz5xs1?Cjg&_)!a+9JBO!A%m35jV{l+ejm8IOocxgXulnUbC_7_)D|ITgr^b= z9!opri$8q!%=j)#j2d;H2ZVLvT^^*nC;uV(Iv;*|J!YJwzRz4)CPco@N25)@;~dp} z^n9=jy+P7tU9QVE4Ii2DNk9rbSAH!R#CT*N!{OUZmb6WJb};>6f335A)pmVcKgTB5 zPjBBIew$yzSaZX!#9w2osdc%U*6L?V{HXN^+Z$Z>*~_R+Yc=iKv}p5b+Ol<@p9en? zEI%1ApLppyZuRq%pHA>9X#>mLX$+Muw#v4>TxX$-achmm+hW)}UbVCV_j+gWdc(Ia zhd#;?;SiinX;%S7uA>vh#m|EG3VwLL_+4-S2a&8qG&1+q76dd|X8GI>*_JQ|AErHU zpAFoHij%^9IA06hT-D`37Qd*^f#%pH=jqLQ%xkvz-3&|n#q6)EDc$rUn-1-N%BsZX z<2fzSTFBIZzhmLy(ZP%7tQq%uJKC;&tDe`~ds8z+gZXNxlBbLt{OF2D5gt*iwbP5WTm_0aNr zvuAS@J>bc=f$sM)+|8eZrya%YAeafn(H}j+&w)msK40sOzPsPi& zaNX-7*OHT#kRxY`92oowoWOY__JO$dujBu}3yShdOYTX{J5$dCekGOEd-`%zdjFev z^DJlwuL#_`_M2k;<2S&QLDnqe)_h->Y5i{O-$O%_mk2BMlbG8Vv7c^FcK#SEcH{W< zO2rS>`Wh@Xw|N~(ZMrx5_2T%w6(q+u|HhK4xqtsXypGfc;2gC4rq~ZYA?`ZXPr{yC z&+(C%WRtuzSckoF$ssT%UsdSWtFXqVlh3U@E7#NCi+j)3i?0%CjQkbVp(`frv1)uy zke$GeLL*M?lF?;t=sEV-SeHu(lQ*by{)~jZBY$bWUGGuJeb(m*(jiao z#~PfC2eul*JX<=g-#;7?RnAO2~5M64~K! z&HHo{*Z(50_@hAw{33eCGDlD39Q<|g>d(!-UfSoMo*4`fLNi`2R3^gx}au`p} z(kSM`mWSo}nq7T6OB{DMo-@C{m*sDmo5l6wLvt%h4aoR`d`CCnq`vr(pVXMcbNeam zCm!oPM46Jeq!%MO8Q&>7pdS09iGJ5>I9~JEw|$*BTyOR*hg+h-nxmDlzM9-nnU&<8 zU~eAIKirFeBBAlKE%8pWVR+wBj4AE!+vx4%L9WXB#Y%4_P|yFfAD`@F$z}7&-Yl*s zpX{w<4WAtQY&rGeeDiUy?Kuo-c=$^`-C)6+)0LEcop@Y5@BO%&HRr9Ijc6X+25%Z! zXn7`QiqgwjmvKo;uiKSWD_hKadS#V=GuQxWXSco8t>$}tk#tyisn!F}?pxqwCSs>g zN50c1KBmb-$(x=e(9F|!tT*1rpO7uA$dob$va&_v#7>O(zueTqM*iRmn zv;j}MY)Mp)e?4VTy@vgzPu<^oJ-YU+_GJzA6rB;f4d<@v-qfo$1yOYpI6ka+JD!(a z*Pr`(zp}XSB*VYx7cK|Crvd=l<(-fXJSWCGrsu3ND8Dh*mvXeo>_MV%HcvhByX>kT z5Bmpq#pkT=(pKYK2s0qgq+E$oM=$*d>+!10t1x`A|Hv24d0huRX6;J$(`=?;WL?M7 zaLJabvskuSk5l?pErIX?kQK-$S%1VP+1ZrXOLOEj8c~u`hA+QEo&-?HamMo^e#UHw z$xOAgmDiJ(yS&qS*SwdzXVb|u!+9M%c%<8ugxfFjr1dz{xuYwfk) zyT2Xtgv`7G8^_Uc&M`@o$GU%X5q)=mw*zMWorsip>GCM^E1K)au$;ym_C}byyY@MT zLsm6hq8#E_UtiEGIg!kT*^cYt`V4hG&5ZN$49)}ouB>=^@-L&$v*BdNU&a4FiIZfU z@DhfxQ&8@ci^>kY42GJPvz{-qXm_~Py)s`#M5lHO&0u^AWgSilw$m7AOyRr*82l(; z!tK)S85K!=;x=Ww^I2?m-$3@SPpC!Xb4YD<>3vt|k$T*-p7HvX&GnfpdNtPcuZQfK zdRO;dQI9^*0oh4p36iAUqux8GLuOFV9w#H{uyamK-WBHALqhmiI0FoO8pE!0pX#q% z$t!WP>=m-)8O;}W84&acr3Rjfd*9a!ZAHg@yzU@ zKi}OvA#3HqaeX7@ENZPkSAE?qtm$>^XJ54$wx!2*y=CRIF{OPhi`jkDT)rm@Qn%7B zQNw0FCwHvh?T@u{aK0>m-fsAdw7RlFEbmX^M4f8G zDTlDd?~E`?&Y3?;{8urr`F4lm_^rZq73{)%!es;9u8CRMlDdB>1fA z%Yf}(N9#*8oiFYBvJG6$8c#*}cgDka)wBD(rOr*Aqt}L71KTa(vhVTCMURJ>xBALi zQ}t?BE3%z+%RzRXaof*vX1fcv$|FQffP4E|kI61Q>i!n)i}|}js&bDjr@8(vZiRq$ zv-VRfDW$(~!nr=3MZMJdH(e#G_nv$vWbc%fvi@|TH`B&#uij~qx!Lche@(@}mN;;^caGUPgJbF4^r~#pc2Zl~N6wD@`s;NKbiO}b z$hAXB`ZbcQ##YsRs^{_9pnc#&uc0*NOXq{-Q@>4oq`oHvE~`6GrrQ6_;B~J@Q>;ZN zLTi0;msOTnva9qc`#6;3Xm_I=1I>c$T67*f9kNzi*)Zk3qZZg(VeOyC-CtDZ`ep1w z-ceAFqcgXh%%vLeVR&)9u48j!GTN|u6qVyQ>xt=7J}=MFmh+V2n%h!O*ZaD}`j>$3Fj zxmmRFmaDCI&#lCM^SX|BTLI~Q=uz)PT{>E4++Dum_k&xORiUxs(6I4<>{??yXN(?- zzYX4Ty|N^i*KjqYFA(Mq4xK^VDt{#z6fJPIdCTsa4>L}kZ-gzEa=LDPT_mNe`j*&f z7&@9*uWU+A_V-~wF5T<%upF8Zdi0q#2Dh>34(ss^u8yh`cl#t{75Y&aC)3ELNO70F^mot|@5${NH?GK*qk}8`jPgN(9OWiKBO;!7eb8u(?yrt7%WN6@x z8FPI`MawH|p(^)cyL+OF_+iSa)0HhyE5K3U+CDv+Ew#f zg8XID_0n9f8(lB0XPquqdf}CQA}OjYZ{s@o=-&?-6E@a1>O&JS9$pU*M?K?~vg%mC zm{w}}+{SAx#h2c@J{pT6PjL8oO@-<aqH#Hrtu6xhDR<&0=6;m21cXml)V)fVkAa$o}5ZAeHWe#MGnRTD_%FDn7Ri+4tpG#`3_T8Z*i&ImfT6Uyn__pfTUN zsyhIk<^2H3nb)kTzc23wZNv3So}E?pzYHG1O=O%fXglysPSE#L|js)&4y4Xg2 zE%sJ$G-~Y$gHA8Bg*3uIevRk8A4f#PDeL)| z6ZS3X>%zf^un`fFwl017tKbai?qJv&tNqrX>-J!?E*hm1SH1W5$&2XkSIt3pJx65v z@8Q^G^U?7ft|u=YuOoHFJE7^JE0W_n#ZU2#m6<-iiH%!@d4kW1$kI4|1-!7|uvRlV z*qe{uh3hK6VGB=f?S?5XCChP44Oewn>vfeLhOH~?@ArqXXP;kW98lYzUCf=7W}er`Z~zyoaPTx>8~-|HxdjS8LZkO1*FQnSh_@7*q{L1L1TwXJe2| z-(KMPJ}b>xa#D``EGX?s=%Q<5D(TCcIv)f*_|Er3oi4BEO5Q?NNU}$0AGl2SFCL&; zFNz9ntH0Y~8rg8<$$_6_v!zFCpZUXO>V6M9?;3BQ5qPamJ{$g=8UHk}bf0xhjdP4X zbs~qzm(KeqW|v;-x!TJ0-r9>rzlXom8@|T9r?MGcZ-`qDdN)_qGxNLV&)eR{l3-0_ z9DucDmez}M`fz+V&A7fsnaRD(;p-j9+i#A?ck3~dMoa(PxRRD?;_SDc9BX%eHiq}v zMZKQG&F!!}v6dP8$j{T0^>^OC9jE2)gr)Kzw3(V)_N6)cYKA>_YAJ4+bQ6TSc&-Lh;yRDAnjXvd8L60^{SNP zj;5m+hkSp%i067)0t9Vy+4?PSbh!$2wmiqf(wpUw>`%+GRsxOpjJtsz$KGOx&DR9M zHam0$M9ms3f$qK!3?qgOws8kxdgS(*cRyZX2qC?9qlo!x8ZG}RdBQxMspb+De@=s! zy?bGM?>0y0{k%5R58Bo9m$16Lh)IrlReeDHxMa?|@7cLO*feklu-vV=HS4Re8RRWV zoz*;1-;*r>rAm&-bB7EOZfx;r27QPOoTccXYF^DpIpU z&}x~Kx8e2T!QS;$26 zITn7OKCxYnL8dKMHus#JWI=EepbAJw-p|<{w;GMVt#m|e-rk^2!<5)+`dj!^IEN71%dH25H)bN1R+gbVHv=cn@tQ`)3ehm(cb?q8r zU&Z*e*UeM#fpTBlw%lR|X0rp1+m7|Avy0LH7`;7iYQZk;^kL$@<2j)fuB#8;*YTG4 z19pOFX@;nQPz%J%HUj&t!*6?ii--64QoO=Jt zy<7R}x_Gbo`l?>u6=u?vewIKoEit zC?Y~$jsDVkQ6kAmbVcIe0&oPP!>tVbS=1U`qIcQ<=0D)#zN0RWX%7D97!3(K&&%!v zHxp&S9e*5nA!xiGpOS+$%`B}L4VmZ}r%EKPpjy_QXL9A=!Dk{J?{G4r9HW%Q4~Iw+ zzGpavZlO(S;5v1-A=XOIax}@$dwgI@d~e{aWn($qMWRf8@g=LZfII zm68uB)$1`tgN%iChdzNn6nzi*fb=(3t)WnE99Y8FcKnZ`;t#P9M#JNg_W-hP)AJNh z`1xk2f`zIdN8CqI5mvr!rQD6UZKd+MNsmX{yu6XYDE3*aETtKoh<%6u){tMb+plhf z03I~-k9qzmOIf+Fa8~5hHjY?h7*(D=yU=D5&sncP?K&RIp&yxt#~ci z#i&bg{$j8do^FKh^Vg`$6V$usDU9`t^*VjZT-TpRazoQt$AbRxWbWLUeVnfCF6=XG z?yrLeqy=)9f;%929MU9a*wRl$ZHw6T@BOS(&zSYx`)Omd|by)9By0R9YwN z`kV9G{A|cr1>f<K8%yqZ#S{YvfpKk@$fxz6G1tLbvCkYuvu3lvXu~U zELPfjr?9csdt>G?{d`kj+{eJ)gUfZ~c*~43UQDG3LFlj;zpPg+L1noI$M#BWH5IIR z8#wmwXIsZFetN-2kk>8$I5fW5c2_K5*%!A2-L3r@?^>+e-j6DjVDldb^XBYFduGyl zT!PcK-lm|mwU_4!qn?eu50rZS?E>;4P31-riY@u5}h3H)Yple5D^n z=N@%z;?_5N980gaYT}1;7GVFKIeYdjAgO2>)YkXx3rd`nQB87U>qJLu|Nmt`VO_Ll z9!BRCKIqoe(psB}0Ii|Bb@SVm;+8#iT6yo@>GQza+N;>}^Yz!b=1uWp{2uFVz_wr8 zovoj9%c`dONQu+h9cyRdUBe^oRc@(>SZ0>o4*JQMBkO~5d;Wp7`P25(Y|otG?&6F$ zUaxGKdhTt8Oq~-s_9|-!o=^5B-f&|1f;@5VdbYI>1&UAxXN^Vv9uIQvBAP^E*LdA$ z&v-#{@m>0z&*rSp0@eMO&$iCJTpONhNugc)pI-y;9p}N;d(-AtD(fucTXkzRJ!i)5 z>i1uYwAiES49;zFyrtf6BF)-c^5r_A z=#S-@Pb|TCSoGh(J_15h8T36HELYLTBSu13at_+qMnW6%ot10iT!~G}begklYMw^? zX3R;^JP)Oj)pNTHE$qA4d7T`%ep$<4dO7>+q=|`EI75+CGp`jm_Y%rXX%7ADnn9aA z3eWfHi&-q`iry{dIF}mLvQ(h1HPxHSjKP|V-Dn7$$0<+3ms0q4^$eLhw;OG?J^mWQ ze~sol*Y`Y@Q^if$$Mcc_zY!VNc;vQe80b&PV7y6KFXW%pl6Y+f$`aPj<;E<%yH1iB z&eHznv6#w8IgeTsN%1ugajruzYa-tdxadjT@*>2t^I*rrvg|?@#9tGZV8k=edH4UgexqNU0<-FA`>^D7}=2GM0@pYGy zX36X$r{J6Tyk5Sfsa5oKnetwjB@VLtNv&@KV?K>cOf(bKbQDL%yTe(mc@BPSkQCTL zx1#M9?PRHES+i5saL4w8GXN%H$ohu@VS_48-hl854gQ>%P_+)#GBGN1o2;*IyCM%3R%uH?O->AUg&Wu8rK z$ELznR%U2p6;qI{*H`)isDgDTs$h{1`s=6-`yg&DA@8tk^VYC#DrLPhz<{=|pZwjZ z9UPD9#@3-qWq<%pxNu%!eKyM2{cDD93=yb-}-!=NlJ0 zaa@eNJh*#3yJ7k5(BwX8aK@EL_=H1~C-CV|g}bz@6=_yBY3~HY_0pE`22QV~uQRzW z%2+>mo{_k9^)!|wZ{Nl_tk#ud*d{xqPPg4BJe3c#1grF5tUqJ2)aQ-nczn%qp62KE z#WC*Adj@Kc;u^hnX?8t2pPw`5DRkPNxQBcK_=)>jGX1vBi&>u)vqfh3JY}5?x3sE0 zr9b}+I&=>7uJeF(FUN1}?K)h%XC8Y}8)AOcbj8EVSzYdgp+bTxL+qY~lU|d$t{SJ5 z6dfyZ5O31;(igU`??#7k{j@_%dB+bVF~+g@8~IF@h3-yuL@%odwGo;1^$Ct0h1gDG zuJBTy$6k^jeMz^wR6LZ=XZ!jum#>#H=K6B)auq*39*xBJy=KZjnyxi9@0};3>a#&} zpo-N}UoF>JuD5U*6?W<|`seD1`N8=dv)H~8!Dj9GnEl7Qk$=};{*_z`je5S?)RM$o zdVk6$Tz*gXVR@!tyX9NTy}5Pw=yTi3dp)dMd;iVjuD++IEUmZq&eRI~ZTGeKr+0G; zA6#1JmcFLezpW3!WxrE~)3BM7rc1Dxdv|K>^Y3V_KilJ6>hwydHISusPQU3@a*npV zLt^fYG3_2hk1zSzv9)zPE#$gSpT@dQTKn>9TJ3%JJe4`iww7mGbgQgNwB-HIOn&I* zkD+T$`8KfUgWvEZJ zBVUueSDjO4lsvKgXjng5eEOdbmEQ?$zYbe!39|Als|s^_nmO0hgYMGl=Oqm7d$ge& z{BOMxmrtcHjR~B|1P3nMCX^?L>{VW_x_9dt7JeGNahB!Qkhi1T%&AdJCAqKS+wJxF zd{$SuCm$5HweUyU#d00kH8l=ht!G?WL8FMuw$&P5Q&pKg{OAPVp`!m!FZM$x#vBt{ zQ`Psiz>#@>0+Ny#f$BPKUCUDMXaZ2MPgb!aPCmk!_+FTx`#zSadOctNI(nxf2`7V; zBc4=RbEs@d)p9%z$Up8@+3s7Rp41XN$Y>-sh*twi0(~EzueGD-jGK5Wd047?$Qi`t zNcwuHlZ(&l$TEO7O`nQ^>OQ{1?J*n>9D=(b9iUPC56Gv-@%`7algq1Hn_(*ag~xd3 zScz(!bJ9|G13{7I%{89+TknA+oZ^4t*iZ^o|72Ak^v5|yap_#I$EioZ$#OW2%)R%5 z6OvQ-L1gQZ2S~1<_EWpJtohFQ66a1KQV~<$%q^0n9~s%Dr~Pf{HLz*r@;pS^*3iOO ziVFtIwI=&-k8RDGE)IheJsoY{rtZBlmkYhV)=-&c+v@VvESk!_@@bOe!AG2Ly56o} zLaVXPJP(`aU5RK7ZOrKz^K>%zrnJzEB#Bza-WY2`%Q}uIW}n)a>!6YP?b7PAr8HGp zCSy(5oTBwat$jav93txU)xyww(A_=XQ?TSC%aTX z==XyajFq+KR*j{-sQDmNCI6wS-e?@1wErStog=bGo`o~F>fHjCX|EfGb(=YByZ?q| ze0}=gZO3$tK4{;n?21;`gS)$?ihGwY23UaKxz^nvaj3bj*-KT;k@vCnnHWm-9#|*D zAMxkFQ{liN*4^(Jtpv;6XI1LiQ1eGV|C(dht=J!Mi=8F6XRd8oXJ)?TjqSh1_7`sw zj=|s1DEK6barJDveXTaH)*ND9A9bsm^4sis^gXiO&x1$F?x@?(oflZ*YO1=6&&Kup zlKOduPmod3`JwolD;iqcZ$_x~G9)1yCKdjOk<3A@Y&mbmu33AJ_ta}t-3a7g$uoOx z=3%9NkYryDHCDL!3QCxQY0b&j`&EpA^bQZ5ho)OCK@zTyE+I_ltsV$v6l$tP=^cDB zflY_Cqgvg_R?IQ1DCsHq5X#DTz!=!!MJED%^-qkfUB~5HPjIIx8)!-I>94BR36}dn zf=N>(var4qBX~$=12#;1;<-OFVT-JUe6!8k?cM%fR}I+G`+Q_mycf=;N{?{t?ON{= zjID?7b9d$ZI?~IBhkP8_o`1X5|2`fn!u0jjw(YJEYj+(B{M*n7@XfWe-JO5-F=foZ zj>9{_aioZJ^)aQlIbXkunA5$eW5M^Ab$h(W98>Vp?8)Z4e^DQUdKPcTzq>=ktgJJN zm4apSP5cl8eH43qHbCVM!9Bp%Z%%HX{4VyMPwplCXpkb zJzbGwA2_@hd-m={Wsk$0;KY_-{cGyb5=(de*A}Cwj`I4jGna`|IckelyRPepCzpR8 zdrDm{ut0fSEmy4dY3SzT0T0%{lbFNpoZk-~qjfvhf3xN3XU}FY%B`h%9~b&P&#xUG z3pYWRM~*M&bga)j3FL9qWlTezz1hr`1yR;Nf70p{0KQx_URlrJjbeMK$p z?tc1>xDnaBXj1!l4_nRbINr8hAa!^Qq=Guwh5rgI)_z-hTkdmrZa>DK!_ySeTIwOc6MoLq$ULhl?Dinft zE!EM(JI^XG^YoY=?s6;>2Y6E*zP&Ca&{$8turO!w#fZ@z#%ucm5*$sG6rr}r8%Z8qtW zz9>F=_&Z(5yi{%yKBuXhFRz#FUhh&3_v3ih$`P-=UQo}r#qk!aTRr^pZKY%T#uYC( zj$i-!QqFNGg*ye&?ysMun4Wn{LD{mUr5gz`e+p=uzPGzxlsj}8(xJA3YVLd0^`p7D zw|L)T`{5gnYH z=ltinQ9BM$<6Y|MXs6v%ZFdo)5X2r2Ho;~2-0N99k7)Dm{0K;j%p5w zrLI_T8+~dym9srB(~k3)trfS+ddl3}y!X!ch3IL^;e6Ipx6fs^?$huiwy|F_dr!m0 zr^*#{DypfmH2c$UpG7~8Br z9k)7iZzA3h;K8bExyFj9T$9;NH8#{x>0!LjD7JS{>mHzXXFrTRed}V6xL@$?2|TFt z;yFWg`?*ln7n`Z7YwXuMSA{2NHuYK!eYnEZ z{X{ChNE+EBA@8m|kJBzCKQ3F(LCbujY|jZ&JXqfpb4pok zea7?s#UQ0WJb6Fnq#Jz4aBU;5&bO`Oq~)Ekht4WU6&kcM+Fa|617y{EZ>{k8t&+YXP2jEIcPDzEBBhqZNAb!L3JA3x_k z@A>d!w3Rg+Bf`^K`UeqzWvj=$|0OUtz%7yJh8q|4OJ<*N)e z`E-R%ne23k`Bm{7R7^fB^9$oWeRgd;H+R8_j-SB3owzW)XMK?HeiQ)-x;b4T zcupO4>xZ?Dy)n+eJ2MBnKc?9>a@pU2eiu2K+SRdU9*?|Qg*2cIV<0PFyWXSn|hpNjGoFIPL|gCyA898$%v}$>>n~OPgap}_2k(R zBf4(5&&m9mW(2BCk0te3vhvB;8kU@9HrE{G`FnUK`mxr@Im+%wK3SUGp}ZT{c1|k1 zmuJzDLz&0?opXMo>$)t|-58dik&Iwm@R#(T(OX_+-q>8W?BY{r*t;j$>!OruzSh^e zJIo=n@oJyXzgCU+&*d&dj9|vbtn&{K?C1}#{<6$mqE$o7x7OQo&hpK5S!5r^yi|^w z+K}-v*U!j4wr56i3HjXyk7OpSdlLO@V$JsS-*jv_j+&kFeQQMR6z+l@($AFyq=z?c z6uXp_d431)`{k;&*8mNi6<>E6AM1)Rr^iPfXEdGO`|Iv;td+E+BX7<}9k1Kl&=gbM zMQ?rd)Yk@2pL+WLyv0;=T<$YYuRr!!POZf}&1tSV`&&m($MSX2SYMER_k%y^Bj8IO&5%> z-hcIt@3*Yg#>buGWskjKD{rad;GF|b|84R1$DZo=-nawT47Sfo#vxpun?JsO^eN06 z-UK_bU7wDxm8)POwlQ7d%g*J~)>+l$57%)YKOZ|8Zolop>#gxE^Bv>H=l5XdhAZk^ z9%{G65KrO|c8p`JaL*}QF*xQ&Vt$sX?FZ`qN2yFD510l($^L~YJJYszWE zp66bJblGzc3yW0`AHRH+OEvNIS#O?yzZsl*tg*;Mc0w5Ir(@ZMIZm%6=PfZhr_jz= zDnBkWXLZ^8iq_U|yw(P7&%msihEtwk{I*lyIO|^bk+$}a$L^&fQ!P-Aed+4| zx%zL#!u|WztL4w{ul|n-CQF6RmUkY{98R|0|NOT-{Z=nr^?v&C`-t|?VI*;V#+J`p z-+d%_a{Y~#aXz{G$w52SnC19g^2YC!HO-Tr`|ih2 z?8rDeJ3jJyBXT_6QyG97;7cPy*FHGx+%Sy;rjjpSM$pgjIvK$={grx-T8%XKRCC&@ z*0oiwFw_gGu}(eD@qNZ)d%dSRuC}XnH8+t1jAOWY-euZHa5#c03+H_0X;!;yJiXlz z$5OHMPE|L*RQf{xyx1I>^56c>-+l*1__(Zr+D}gOjD_Pns>4hCe>h6|9>xm(+hP4+ zHk}O#saA%x>~6w~WB-3q))~8*Yi{p>*eYei-0=9G1>UT7of$s$?XzcX^rme4dLH6% zN2X{-T5^dK`qP6fjdjc^hSA`m7bX~GP^D$y>-o~j>9zR3P#Jf(MeOQ+`oUdv0<|aFVwEK+lQJ4(b81xgb zrmeQ>sZ@y?pV^oe8dFU#x&+D{Y??QvLH=2%pd-JEIuCYl>d+I65Xzz9&1{jV+a)Y1>uDPZT^buI<0sz3FlXHjDQeZtisKYHMa4>%8xL zC%5!h2T2XmdEx5c4t9j}PI1Z_mbw`WGF+LrXF=Lsr&{dp{n(~Qk1Mt3HCpZB|HH#P z%3}Yh=xN^MupfWC)MV!-%5TOoCg1+f|1M`hD}2>di6IgJJxFN zm*-4hI{wLYF4{;u%@*aoqNj#$F|{yLyE0v4*U#i?qdUFVx_?*Ef7AD;aCt8c`m2M? z{_4Q9d{nfPJUHCIMtsRf0?B=y)m7`~8CDKW^opV(?0=Ct&zRGCTDK=a` z;}q7LLuErQy*gx_o59BnpJ1Ky7#_JE zaT_!EV@_jR6fsAgibYOGgvT(x+s!d3wAamRar4u5wrV>4-T~jyL{pq~_n3G3%nhHn zZlDln)1?*j{&iU;(XMTECCUP`LbDaIvJ^br#8ojM`nSFCb%)n)f9F5S|L`yWQ8Z2R zE$$cQgqQT2!{`6IaPhLS&OyG@H_Ov_m!a%GyE8I;i^gUBtc+rdn?1VvZW;Mc%IJmB z8qW)^YP`Cw)Z-|v?!CV$-wapq&CJBQHhgyHX8pa|Z2j~g{L9?x<-9Il&C*Gx+;C_T7O+)w7S&B zYIp|E!q#U0oDa@grBKGB!k@C&&qf4w{Jf`7@H*afE$`jX!Z8!{Qkj>`oruFYUv6w4 zPvMgfi#$O^bFAqYrQALG?4J>NYP5z~1*f_Jd|o_fm~l9h;}L~OY2WI*jK9q)#2qCM zp&d6T4_N5$mR$6oPw>&HH>#D)jdiR~Gk2GF%6g_>l7I0>B~v0fx<4yF$u;~5<70|S)y#q~ z%NWw=>vAHt&#yR7O9Z!ld5CGrq>*tNEfpJ)e2ag&`tRlL$G+3QmweCh{c_~G9)#8Y zx=7f&MW)|5^dNq>TzzUAWZ=(_!@94tbk@4xGe3IqWyYv!{JuHj7)8w;HAGb7@2jsf z))QODsm|E?xYVQ8$3X=F++g%8h95s`edBFbs*YeHLeOdLjxhE2>XE~&xbdCqC|!s1 zGYSoV+=gE`zT>?`seab*@7DKf`1jqS^RtU>VkC4NlymBsYw z-$zo$Yx0i||5s@h<|+}FV~EfGXIZ^)ob1V+QLPCB1`(nkr>C4 zL_SG9)BpHTKIaMjxG;HqX!WCfI2x@U3u{2pv7G!ZvVe_@KL*8!v;U?%@Bb?2$1}%q z_-#(-o+B&l{y0}sg#pW*%0xKKN_+a_4cp)3lqWXDD%X$x%|F}uk-#cbH8*f;-+J;U z;!Lh$M^gh#*R|i)kyk^K!}##Ma^-CjgmbP~bp1}j#qSNCtUluybcO= zG_W`PUHOgPhKj?t*KewSGk@Kz?(BD+D_wp~kpgdl{qQpyrg~N5`=3`u=$Z66qz|At zm2NalGIfK&$JfticpX{2?A|Bkd1$Y;FUR-{a}3$h1kIBe9}|BxR+a|A!_t4AYAosF z^X`H{xEuv;m3E_f^KpauyMJ+*{bzv_JN5jxubGFIdMc-EdkJrc; zv92FWvv?~WIenj=74Y(>hfnM{l$E)Dou;j~==*l`)Ox;D^e=AVpNp3H>WRmH-WAua z#e7coshu_SFcvG zTGwVVj%VSe!s6U4d-$+uL$=LRuvd6+>)?3yj-Td@Qc-Z~?S`{camjWRRY(5#%<+n^ zaiK@WqEGQTN%TfmIc)mHr1Np=guQw0Mg!a&hq;bqj>ptqne;x-JY9>d%P~7Me)sbc z&3TCFeEgF+hq8=)MQwBM8o4{}E_6z&?g9mkNB!>ODD#}&t!CrLnkq|Fqr7+I>*uo+ZQqJWCRD z{OnV?8S@#(INVSR?_oz^{vOXV3aHXl=8zu)tTT5e(`*7OnJy6N6E@-EbX!8dFcu#5$|ev-1@V7W6{;* zP4Lxlz3Xp4*T_N=S(xIqQ}z>|RihE+=x8jwJFWgSC3?<0EkaqN{eSs$C&v zTm4Hp<5bqy_N=U?(Bd4Q6zqy~3Nb-n7ikV`yXEYD134`d-m>Q|W%TvNpE8Q_I$Pr`QTHE>;86%Cj)` zsUb<94W9NV<+DF4eDdFxpE#W4T%_XK_t*p1inpHs%LLJPqsBzojz1`p^nYEEllu3& zC5zVYezI*jUPj01*;>{x&;G0}zgwHVUzG8tea)af`eb9(S(FijCxMyFDBNXs{9b2L zrVf-L%OEy#Zr&45&pF#?uSsHb{&Ys3w(9oj^WHu-PF|h-bMc3vT|I^Qj(=hnY+M(CkI#p|^<}1k>l2UPueS%2 z^$Us66uU>jTD|b(&-3XK7=g?BxgKlTn@4%md&tG8w(nW9Lc?djeTx)4IL&1_t^dT$ zFR^3vOZH4id}m4H-Kfnk;V+M4a*2@aoR?cP&; z!6&)fKF`A^KW7YU#{gbg)|ojNuhc(!@(sVQu0WkJM1*C*CL+v(fKKgKUcHU%U7nm& zpYc8Jmz-C8tv>HteLlSB`{mx&&#=?qFzfYMVA{95#qI0!<4j6d=)4WyX|n9-fffrHUu`HQEr+$<`Se`>uIL^5DSpR?gRwYu?h?1U zWmUdcMs|8Y22hLo~cbWEAr{{M1-~xH+3>dF8eh#X}q3p^o|TQ@%WV zeC3yFkBQ+96LZ&J&qx~9x{Ny!OL_)P7vJ zT$pVgu`P}1sW-cQyLV~s#+*iOb<*qBCv%g`kF7dy$x@xtckR4scfPSkp3iKoPd7dm z58rwnurra=DZ4j5Yn)Hbe$8J!=yFTeZ>;!OC!89O?bgxy`K+vtDW}rWduGg>#|kRwQn!&N<5woYo7J7-Y>cL_-bpqOcs2N^^eb5vc=I7$9m7I zB55rDZx8db9_f7fYF?_BGmz(xUyF<`^&%8;d8y!lwVejG?V+IGx3``fkKtNbAB*9U z>sEPgRpo7T$j6s?9$g#B&{to_@W$&fXH+Sh`)-&|EYD_qOttOT;S(>nLOqzrtxrR~ zYsK+5$I=hqYPa$%NV>F*HDa^YWAF8p#cAj5R$lyNxAKWXRsDN2R(`mKrwI3yg!VxQ z(xLAC&8}$cLmk`q+Iu}%XP&ze>yAepU+CW zPuHZ~_tW_}E$z-)l6K#Wig(qRepAP_~BbUJ>L0vg)}`z-^ziWTB9cEQ!n_GcQU8N+Feeay`z3ofA?XeZQc`H9&N8{aE=ew`ISNw=aMMFL9mj3cLyM1dvepY@*(?6%Q z*>uj%we#`WvU~1acdm7rX#jljEbGt`#%IrQ55s??U>=>+ddluk~4fGEI8hOISU7B+G1hwk+cK z*{ADkx}v5sef_>d*IB`He(xzeS^L^I59!nyx<#?3I(9bh>gGpcI1^a5wM^!_*AT4Q z=f!tp`Ps9Zvd}Ldn8@l&{$UyOm#)5F{*^hc=WRSy8h?! zRo74QSaO6$xs)N1w$uCqVIqt3e9YRvI-k2$fWx2W|sFO|HA zw)0l)30Jd1@0B(AlcGKJoci{6>fXz$D($ZHpT1)r=ntLizWts5xBUJ8%G^8acood= zqeWKu?#>y@_wkzeqsbA+D`0v=mG|R)xXkGIjlb+iQIotYW5&yBWIOZKd0{YxE#f& zICl?F^P@Ip>m1eigc`8(-t6vi$g{=Lv~@StEj=*zZ;J%j?boVpd2gv16s2obfA5x6 z01K%3s~H%y-Cbu7ZhM2|vLt_NoI4opCbJN4Va!zp`*e(_8;dgjd``Z{M_8fO&wJ%x zySb&d+`m?Co=H|&%PFff(lWYO(HLn4tvD-|tu&Up{m&BmqAzlKaE*@5^O0b;@|TjO)Gf6C$y$ z@lM$T_2sfl&L5QZ`-8Hs>#l-d9;(EBR=J|u!8R+R%~joxr(SbTZeK1MqG^qLWesiJ z(<+FwUDJB-Zhv;j@BNE{#eZ_hiX2~meza)DqyQ`m-BmVU2AD$dHH_Pn`m#y0Q=WFxft@^B5xhKXDLZG#D@stz!d6A^| zia)D@kG1fG=_h!Md!M#-e91d4uk6pun9OCI=W_@Uz8YJBd}qw2`#$BHVfTaM^^*quY|DegEZWa;{z>>*!H$(>ojYz0J&li>(?v}-=!B2T-(W$ky>uMd^)TwS7pFfsz`KKQZEb}&Pw0y->y0&-E^;Ks#owPJcZS}=|gr%zT zUTC zuYQ`eRuK%xgf!q*czVx*<~;olYnrm2eXP^6SKgR6C&T{y@KEdXGMIBpMA}Ojv0bB^)@{nF9H=UBg!96L;7vXtGY?&8o!K6jZOx#b>- z0^!_WOe_h6s&;D{*FV^-;hjD$sj8j&+l~iqX`>uWx zS^rfz_M^hi;O+hVa&VR7?{d!EY_;ppeM^q)xhuO*@8vLIo^3QyfMs9C7qcjkoWoiUu-y{*05`2J(r zvkr!JwRH`(`wqWtW75We_cPR_?U}vn=aY9m&8oIL53d^SH)bq6dpml5e9~L9&EM(! ziyXA8u3-%8cKAeD$L-uxPjoE9$Ll&ee@U(}>LkEO#KK;RsfO}ev0QLXFD$iOEk3qY zVg4T%ZH+C|8}w;MT9?1s5QqJJi8=89Wsu0?jdqrkTG!}2cQLgCa#F^T#d`iR%huL+ zTQT*w55JbNdj52tB7w`-SkoCxV@8KOp6HPJMD^!Ve5S3$@sma`>AKwbPddySwsYF* zHG<>Mqg%t=)HC4$eQ4?Vs;L|D8S|v|$;UsJ-sAY`$ItG$+tcPf#^;2)U4MqL?Geu# z_o|5Pd8xc(WA^8;Z5*XVC9V2B*@bh6c$PG5TU|}oplaUJmghJ=f2|9DW%S_fhL`V^ zY9Uc^pB!^Q?;Y8OsdU^vzSdn|{*ye4XBSHk-y$n7>t<~4ppf8>@Qcgy6iYW;d(NGr zkz8fn%1x2e*yi|lj3&q5H(##mlXi5qh0~`TMh#l0Z9A;Xtw{Fl7iGT3ck(3bXR;vE zOvH@J=jHRY?2St;>+$FuuhFp$m|DF$T9?^5qrZexTQn9!rUK6@a&%)1F1zc^pzSSl z*+z3}TZdM9t7N=z^?w&#``H08>nn7ONn$%vfohy^Q6x0l`QtK%)7GZDcT|FbF^^@}6duvY+4Ya z^B(osA(LpWZ=kd4W zH9!7-N2%k{X}GF+qC@Mpqf|aQncGn+o2m;qUR*9^A_iluvZK^gc?>mFL%2IaQUL>_ z^ukG^{&kP6Ryi=Na(Mc4$G5!0GA>%))nSO;k69z<@raLWaC}oM9hxl5kHR^q4^Tbu zuy}^|%lTt_n{!Xq%s6VUmSKFY(-kwiAj16PN-Xbsy^5I!N3 z*;>{-)6t6b@vWvg&09RP@yO3#J2^4>4~*m3nY}9gVYAqr$eB4Day>Fkd^45muqkuj zOxgS6Jl}dJUhv!%>gR2pa!lNiF(}JO2~I}@_(79T1Rj?`b}!hZl5a1F^@82 z%a&sePdk@?$vZ9U=O2~)m|v8f0F}Afho`QB@qMDT$Og?b%taXMoH3qX`fiSapR4^D zpFcz~<8Ri{aLzks?$^(nW9{d%ALq2%C4AE~bL4oWn|E}~0k+uiaFi;SJCyu2g#7ZE zens=rYP@jEn7(jz%mTM4=5apX@kr2ob90f-F>2{A)m2039*)|wzPKIT6?=c2xAJUh ztEIPC)=&3~O`V(nw(4Zy*SyVK$0wMp#ienMG6cupAFrqJ z_otcNroo2Z&~Y8W)1_mU^Lvj+BpyzC&ow=Fv-)D&J*z%E6}ek_vz}UMxQ^~tKh>I^ zZ;F1Z@3X9*#ul9o9k1|`mQ5)JO0CT7GxBOnhbYpdA3&gmN!~k;}Gbnl|I(|^InAO zOrK@$NU^GP(v!7>!?hmgcAOe}=oPIT&sd9nSE(NNN}75r+-SK3;j- z{hlGuYJA5})jXCj4}RV8w{xiCG#7mQ#HV$|3nex*eA<`G|1Wu7GgveCU12=(Rl8TF zcv+sNjPWsJd)o%ar(URvo@VruU&uMB%Yun=I)dT z-=p#^Z7)kTy(!Kc!6hBIJ{CD^D#vp+sg6kfnKQ>4WbW;9{L(nCt?YR_lj~IucwBp+ z|NQuh$B5i9=e+N^Ik_(v%Y8k~iVqmeCnP=8qjQ>doTEQqr!|$aF?v{@y`|1(#(KSj zRF&bWE;)rqrcX*19!*xyyd`hFiiRAm$nDrZ8|7nJ$;i&j(Ub*UlB0Hwc{w{}o9{+` zZo-3^zVCF_Z^wU;2l8pDd!S9nJs|a2cvM!B+JI-F7voqyx4+lWQjay{mt|yXy-g~s zmhX|w^RfNN`Qvkrb!?6rXX4LYr|yq6_uViyIrsfsOmBRg64l%F~p8A@Eu`CXsd|3;qTyHvZi~_2~p3jvhcjG%Aul{4% z9IwmqiW`6D+y@6!WzsD03_ z?|l2h)xQ-f`K%mQ#|#>p?*2HhQO4}#ctnSD1NTg|NsFV-ujTPdHrj0+AJ0wG8-G`r zho3yjY}4`Yr%$xl*n-qb%#7zbvh(o<*%{8lbRNh0ZajOg-L&}eck?neeit3s$dB28 zYU`{nOI_Zm?Sp!byyc0v$;+Cw45gd2eEhZTnQ}hvhB$X+2; z`die++WB3%!m+0RrlY~J9$C{(!&Nx6G4tAgoo%1$|K|%&8nJDbD19^6B%9{CRI;5r zw#&!zza|lD)(V1H!a3KqNxAlE?`Zh!bdFI~r{14VHD5Oo}!F$NENQKr~IY+*4kEP7mEwj(mHvtunIb#}65vQ{8AU zLmX{ZmgVi{u}3&KJJ#EM;kf>JeYfpYEb6)!zRsHdo8rl0?7k>Gk3KtU7xfUfV=H!W zdX7BHhs8sNU17}cmOp;_`@@6Pd8bsw=^o#n<%OfG*!jTow>RN=SIjCx04-w<9~^$K z{L{3D>DV95QRYJjQcPrO?!sNIpX;r^D)Ej-hxZ%iicaq#E8(;9eC^ufBhtHEXEv5s zul+~mkNBF(zvKP6TO50Qow+K~#TeEdIOYDO$(0Q~QjY z>Ff&Zed|g~6Fh0hvqg#Lvp;{QOYO zsiHHLoY~jm=Lc`*zdYF!VSYT;n7(sY!WO-;wl14StE$ z#(UOqgtyss#Ev75J&9*uM?|*oMn}B*jnWaX?mD9Q;^P&u`x@T_U*pv)vVAu?;WwS+c&Qx?2%}vA2p8I+xw$K%vfH8tbyCet7wrJ(V!ZG@%uSh6sO;0>SLs* zLd%bMzr6ED??PT85QnE)>rmQ=L8)`%@B^~<8OBxDC9UODeO07LUcpCY&FW+zXXq3jN8f>bn`S%=^9WC0d3_A>zA|~dL+yC>{>ir=o+lS3xkq&r z+yCXW{B`*&yG6#DWIH)`IPI*>_PK`>&yiYDteZyMEs-i|t)q_d3n0(-tLA9J$ zbh%!e*D!so;rzX_X7%p=;ObwF5VIQCzb)BhWax+G-~MsD?HLnGS}5{O*6q)%gV#^X z8~jyy1688(KHe!3NCvmAjh~dGjev}?cgw1oYS8H@k?wcO9py(J>yD-89?t{|nVvsc zImueHgSBV)^YY!RqfE-|PGEJpuV;PXDtT?=fXJcqUYQ;XO%;rM>% zM|`e#zhRBs<$1UFOI`QJ1qYA`y5A1gAC#XT6zQxU!sS=5y>{r;k4wJK1uH%=_#_+7^LAIpM072CVjim{hUzPY`&J~>!cyNkVWSV{8Zt);qmJ1iAEKHif! z`ZC$pB$dbfQn3ppqW)c;iSgK*M;i5$lH+d;Klnyin7Ox_TAlOlNL$%!bKZ_RUjNoU zwDu1NT=c`D4}$x*U2m!Z#@gw_gPq6Rd|BkCYOpyk?I#CZ`lkhp{Jh|~vFCBhmiD)l zr=Fm{?L74aS%0;9;&_BFskRu;CA+FF#w>2DE1AOwH)kQ{*HeG1G1XN#I#>gu{U#t` z`-BePXsV;mL&i<>Y||&l`stTNC)lqI=WuhH>G{+dH@W(zQqq6rK>{BX%#A6u*KD`3RhyHXim7!ROPDK>+ih3< z-ll7cSn%Jl;affR<&2MGCgF!A3itE!C()_*4y=(_mAJ5I+0PDq-!zi66b~FrjZP!S za(EkD@Njp!XVb=y-(X(m8)}5pY(@4j=iQFi@lqUc&8HYYr7k>Q7VS0c7(0z>ZI8~sTr{CBT+yMqruVm} zkZwOOf9>y!LA-SJM-!GkC?|AWQ>?k z$!*O?y1pK(GmYc_P4T}HUy);}%3!O1{PgOuFytSdp^vv}uS>P#U1+`QAkj;-#%=iQ z!w4ihql;wNk7rYBt-a5@c4}zo=Kc9&Fa202T?boSM`P4@SIef{js*1aDoc%TF1wSK;k!OKL(fb-$M?$FD%xb7esn;Q{OcM)Xc4{n%$?YecomNL@Ae$RF~A%j&)a>c*-I&*ctOZ4$sc$V|~M5}-}^*r|q zKUCj#UWW~HsE_A)ENS&xb5Wu5)^NMh7Ckq9io0KN{L6nSqtC0w3Isb2NAkS&aqc{B zStILG)-r>avx0|lo;qL0Yi3I}_UZTA60cf+BO_kl#qZbCLaIzdkB|#I$hDFAUc1y~4J(IUByK zceZX@x9T=mk<9BmMA z+PV&JPBz=~sW?=TN9v|M)wjsS%}eX;%u9XmxqT;&=Vd7U+25nh&bs!PivSz5cS{V& z-kNk-)1pt$EG&0|*di56k?(QOxl0)b*y!9{Ay|a#?Mz{wx90(jEt=Z?sYP2FquW6v zytUyTDD$1&mnD@2e)k}`YHsJ`men0r?mOlbmS4v0L#@!(OK^y4pSham={t^}`Gu0( zalGrs^r??`iwPZ1TXJ7sFG%B+tGCKAvTJ@Y`1hql z>{pEdA7kz;{j}%K+OCyO&;D9>{qaaX@3U_}!9^+RtoU zGW*N(xIX)O;P#&VwT{^P+Hd<5r6ciWv%fTt>$CsbEzJH}uj768hqG@sE}Q+Od0e0U z*Kc9=U*9!qV;XSMW5QUmeH!TZ{F$1x|G%5Eb*>>W5|50-ho^pcVRpi8JIsy;oQ4f`x( zQlF}H4m*F=hP{fMeR}4WqG`iXp7+X!_qtc!CV57u-fMW>>&@OJ_rKY>Z1ICj=W7e& zwq+iVIjHNc#VyY@WKP)+JHRgYz}vnm&%O8c=k!NKdSywp7}GFH6scqe*NZ9?sN;diX-m*o##^ila= zzIU$d5wY7k4qqHT`=oqQuQSiux&p2=IWVmzMD;`C&cua9`#vkBn%kh6&M&lpLy&sl)iJbnpT;bi)Y4exmia#k& z{aX3*!^G_$wRxM@g_fW5R ztUb)|kgd*2QJo+Qs%0)U`#T+h^auXkVI&@YJrb9W>(FksyKjH~`gAyctI&KTHZI4j zKHqTvZ<1>sKRFz4t;xsxqV&%(F0#TNKY1(6)hkbAy`7;i*1wkHQc+4jSWkK4^)rmU zT(ML;zh7kEormXsugv)yMZVv>`h8iE)4BR?d7lr;bAIcHUk^X?N?9d8D3bD4`Pa(d zdK^vj--<8jXZ<_IZ0k1RbcgUMc6&N4#Oe27FUHY4ns8p@uWR<~1WsPQU;e&X*0nm} zH_D$^C-e5&LFZ!89Q}iGgnwTvvuv(%9sj;wet)|h<64oT@%(SS&i4-Yd9D2W+TogS zUidto)3ey|{O$5~Z(V$y*UA`q9#JH#9Tn@D!I=0%WRRQ%ihbFc$-%bW9>SxUo<{OmfUzM+VhQz<~`@vcXOTZ6T}zTTbhnXE4o^gh}D}(gBU7qWbb>VreFMo_R`*q2@yN+idL(v|d z>XP^J994d@#xB23);p#t!O_!nZO$sjE(YR6O)~9Jb_n`@CKqs?Ife#`4v^`1)DgHw?kD4-J>| zF;e+GymCYN%h#<>Q9TO$C!f5XVb2eJp1t+(>U{0IbvrgA*q)jXsAre6^B#4q{Z!B3 ziuy|6J3cI4iEGI!<`J1!?Aa&fGktFyJN-7i?N?8p?6?yQ9}{ol-1p1xse|Wj;tj&h z-7i;luP>flB|cXASbL*dv$Jic>WHdy_^Ld6?nt_7KX{|2O^NtqWs3J?6Zg&X*7;S0VxZ~`Beclvet#yI|cVI_3p#u>a{c!{?PL-DKf z{J$~zbIGypj`daa{bTCxcy~e zRvwol-!4afR9K0>DBt{T;Y~g-&+*f8t*|B0kW-6|tzscW^)B;Jzg5nrhqv%pInvRN zujkdDAC}KBU8%sYzV|;JKKs`vUi^z?9Ns7+@ar-TpOxSKt-Re2%ai|Q8BzSpFU!3C zUHS80%Gmt2eExo!iN7sJ|FC@Wu*}jM<>y;vv>ukvKQC<4kIU@+Y5BZz6<>XQpP!X6 z|4A9mzbe;x=P)z>Q2zIe!W#Xe%-mlU&gW0d@2{0>KQ7PkUbz?T_iyF;UzIz&UFP)H zWez?pS9w&9e_XEhujNVVeXQD#zP^`UPw>l|Uw==}{`Twde^zE`{C%`_m<@FXDp#yw zqlfLREY17nS=ik-%M*QAesi5y%lB`U-@aEqd99ommh#ndgf+s-!+Q72F@8QQpTF|; zbNzFX;5J732-i0XV^;5LHG9AMOdpi9M3KmAj`^qZGyZxs+lyt#hTk8Kj||i+VN`!v zM))7g=>MeL-4p(@jO~LW<-aUXX2+(_%P|kjvyi0s%lBWF(N()6K90HkdAYOW{_M%| z|60B`n}2=y|GQ;2v7Xl6qr>NaQP$%>lyiSxj(bq#?61ld-!C)!b{Xe?EYH&3Yd9J@ z6yhI$e|VE`mC?=LH_Oa^tBeLsN#A~6j;qpd9YBo!T$k%%<5G`ePYqol5&NY4A3lS>eDfz|tm_f?%3D1u|C?T;>gN~B zI|Q44SdKITqyRE`dax4k>e);)&`JOJH-T@wj{1RJvv3&pg18W_x z{g}&m^}t&Cm!EjAT>I_AUD?Y&Jjlei4%%rt&rJf>f1957tuj*lb{_Kg%TorYu}^Fe zKJv}OXYZH$KPamKMtQyb{IDGTVfjpS%sBC9=jA{007+(SvO=cvezW60yhoLovAl1W zmf^K7lYLhpe`-EhC9CAJ6|hxyXry~(rf^^33i`;-+vPs56&VPtk;p5_38uMUB*kaq ztoiL>c^){7j{x!W2JRR6*=1)*Z{Du#yjJuM4M%n`UpTneJLw%ZQ>5a}A_x3Gn#FI? zxZ>TUNYq}WPgIZ8K*?{EGfDQ_n-jfXGfP8x6#d{jmH=CeW+pH&42Z_jkN=yL#u%gUx#LV6)yTdMDBSKC<&x zkq@|q-g)&PC#)q_C%)n<<@@iJ&)GDx^JbA1aTfn4Q9(Xp{PQ-eV%2c4yRUdTQg&t= z&8e@5@y6pPR&buDC?d_Mk%WqDkrYcHRm|?yT(7_;T0~`3U6R3h<5D&!6v>8Gl&*h;4}f1o1omCb$yUOSQZe zAU@Bte6`aGzy(5`uO0MxJQd7Ia3_@c;gdHP@yGD{iAmz?%8Gzd>g?-qF=k>S$JSyl!P*|(8Zer+<*vr3kI+WOw_mGg%?maZ{tQ^s$d zA8g-F&pW2N5hmRGf$-&kB!_zF}tUB z*D>u@#rY>?#*(-4p!jS&H+elZu6?h}oQV0D^=K+<{MGixDnrsRj5#x2RS+Os<@jct!*_Y}Ul&T4=zlIcYw^27LQxT#=S{(9sj%r2ji zH-ufdU;fgqxQ3fq4c{-TAu(4B3XZs6u7{_FTC6y}0`4*y0^Z!W#=!Toq4=kATHu|B zWyGu+QQ0m0#l9M9w$Wvo9_y=N&X2v$iojm84CI}3^WSL3tcX|2H&%pry$HSBD3N!( zv+55Tm1p?<8(a~|V6jT&2w;)>ASF>8Zz^6RJ5;QgwWyX6Z=V$*>&b8V-kQL+v!deM zOZH(~H1KBa^N?SwsCCTIT!JfxSG|n2bA{W=gQBt3|H?-YdBZo;Z+)Z)vq5{O8V|Mz zf=CW2B#slYQbb8`Y|t1+1lo?i#Ufu%if-1f4d;7ail$Mttr}=}Ktzy;0o%{~zx@Wu}To;u0R*|_xZ2cdnMJvgAN#)6MJYu(Q zDh89`P7ZI^xk0kr_4(t5owLSVG-+*k75P{D&PQ zZK;#EEh&=e3%l3skwmGX+g?)S&9IPqaEV&UySraxCN-k8O|@*i2_6W|s&h%0h}+7yvKnunH%B#{(o38oeiVdq%e z56ZEgN#xKG*Vjuo$djlAFi!X4p$>B;MQ|GQ=DW!WI#8nF^jf@^t6eb6=;ky8NA$5X?$`aiUdGlGs- zx?m?di`8ZGAZ-~sx}WY`(zeRv+eF-$qnfR1*37Vf`$&@LElH*M63-F)<P5Pwr+F&MLcduRpazoj&^v-~kzF&T?l>;yo zUoHJh^Q~+=2uU9fwRiq5*H49yRB2!9?1xCWS3b<}9#1pcUdxpy1<@yFU!;R%#CG(t zPOuEj44J1367-UcOH!EL8xRn`ELEBqBlw1=Pfl62>uQvnjC`M#gy$pDL7HTMlPM8c zwuujq+3O=sdTOyZWJ+}fT*J?595t&1H3#d6=HD+*$1bI!hoqhI!M13Y=UJXkX_zV# zI6~Scc%hdk6>kYwBR7R4kixKq^bF>QOu)ImRdX)FD#n2iO1_J}VDr^lTccmkvqZ>a z>VbcwVS-)4IERa^jPitM8b`3M` z8^)pzqpGJhOk^Sz(R7R)n_f`}`8>&xHt)&DP~(cBpA z)n?Z)H=$vyWVsi-CAB=gFbvDVcF+_&VHIlTovx8pK?A|MkWG!LC))xq6h9l1*)`1e zUX@du(-*_&;DL=5>r9?azn*LK1~1zi`d8FkbpyTP8F*omW zUeYB!an~8%cu8VTxICHgau`IZd&Qh!U(Ac#M6wfmMd#2kxif}WwMldh+>(6*NE&Gr zGv77LIo*|~7VET^L?*CbwK{@s?^PXPeq%>;PlHn6nbe;p&ls8!Z%pT9mBM!-n#wBBWX&C4@{TZ^O8fmJQD^;7Y zRqR``+HWF;^gLUv(;6l+frm*IpBd{FSH$bXE^_E-ipT^{I=Gfc#OmN(Fuhp9Kl34*Ug#Pd6*tN3@nW2sIeqg3mWc~>5z(N^`Q6^K9cOgDog6FuzP%RT(E3Wc^4|L z=p}WlTeA6fAL()*X($nxIqOb+Uccxf9RZuhs<1R_e?Co=qF8LknwsjbU`roL4b@&Q?0hoZV77kBH{8n)loU0 z#O*%Pb>wLc!3Z*1q8R44ASYI|_4+nl}{hD_nhbUpG@eOoUKgTYPCL$Z6}VYnnbuk5MhJCLV* zmQ1YZJ~|1iS?+7MJiA9BdzHBGZ^;Sq!NO zmp6s!BTaHPQl-MrP9+_=;~{ybn$f#QlFr*j?;M_YC=)OYERjrsJ`#~ie|Mli;x|LJ zu`k(+hu_S9j`d-qM3v}1RR!5g@4EVBucJI?PsR24QIjFDzVw<9qsH*|ks@(t_9j2$ zU(+$EeiJj07n6Dbx`w=A@BCq*{GVo8m!d7~%kwBlr+lK=7`aJMZ0ZfI+g`FDYGhYR za|)e6&Z5sjEch0(5T*`d!2t7+F?M8uZ?xC1UB^rA=@YR7d?K0!ib(g7ULLj#UFe!7 zqhVliRs6}MN*xku61|4kp(iXaDZ=Z?@PyE>uUU4VXxS&KGLfo%-U_VPN54QHu&OL> zd6wxp!|S16#0mLEJoQw{M&FSGzLZ%Mm)J93o^Jhu$w&;6?daD@G}op(ctJraA^?#l zF(ML%nSqq$K&T5~+r%z$y82G<9#LwR>E0cuD~pOJ%Ubbs(=WP@G^stJC&&lOm>58Er&J60jx^zR zSuQ!_>=|vulM<68Y3tIoYnb&YKHRR~_;A;kiJgxdM-c12r!}`<)--NR?5B@@z_Y@nq>cZZ`o!#uke$D!+8&J4xN(1N@ca3Ua~Dks_6hES4;9$I~zLlz0+7wIoG#?O4&Dmvirzd{tR_ z@0I`EFKhhq)$dA1?-%8h>^wMJtVaAtHO?~h8if(^Yj{LYt;>U+`cA2PSbG}T_|JHFInFu?} z_KOnG5!QAxB*lAFcaVu-UATZIQw^;X5T;fpS z62^kW(~)1GRt(CZAFyRIQ!plBSV&EJKtZ=PWAc>uyK^W%C^qtTkq9Xgh10VI-lWTW zF>w!zbjZIGLC%g7B#P~bmBF#lBVvN|O)_lh6dWN2Pju)ME4xe4?Msp9A=!ad_{}}} z7d5KMGQh9VIwC)85yVOl`YdRP4=oQW5g)sF`6JT2quC)2@9#A?3Bj?j=>6)*M3!+R zeCBX;DuzTM$%sGvW^%)d%3$He^P9y3;FfgLJuM?Unw?fBo`Yt`GQk6eB>JFPwTn1< z+5itL4h*@F1QJmzfAn3(w4@tU<$CeG^v0>I>@88^9nFp-f??G}hs}nZN4Y?dX0M#; z#BH#c`W|5JgIno>)VRimurCk^E}zWkm5ae=ef)1pKkU5P?RRvF6lG@_S(5QZNl`Bj zpGLrz$TZ1bX>-k`s^yiPpNOTzbU~zahdSRraKXyJA37h7d<#^7nQSMTs;9uD#Iwd`O`bZJ` zq5@2WP24!KWoVZ6;1wtH8iJr@(w{#OIv%p#V06*CM%n%2+xL%?oglUh`>+W()jm=L zr-sd!;Yecev8t3w5&tHnE5l9pY&d@VPVtIp4LJoc3@PO&vsU;Mm0+iOIqi7%I(Rmnn2aZk4;WVykSB&)yB5wN7gtA#}Ihy|xF*9}Gu?-osydJZzeBjQDq6FQOnlB6YjRo{EZv)941Q<)Iu z@5j%|n64GX?t_aZ5tuj;Kstoph<)-c8NklwJRLRUXfMgcp1-tKUwSHkDYAe~(?uuo zdMmdN62Y^}SQN(-yOCRxN@KE+9lFT^_AHXZui^EQ0!Wzb?9AHJiA3N6+4!;{>GfWC z7Qe5WNBoACh#pbjTz~VKBjmuO1Hb2iM|e_X3&XaqQFeazw)xrUA~Tb?p}YXn)JGTb zr?Wed?p$Hq*rP~Ms>A4_)*Auik{$@@IH{Z9vRBlw%ASvZ%4@1)wH42%rvbiP&9W+r zJ~9H2vOg>kMuj}^f}(SHL!yXsY}30|95H#7B$p&7qkl=$)c4-;?Dg?%lL@-Mmxlwb zK&KE%vX;bcRPwMr*nC`ynp8QE7<(~kQj^Tto#tL|t1hTX5k5WL5csqF+&;QUC=%OOGjhd<_*eANx)kmC3+LxAM5E}NAuBffF|Y%;_dXgWeK17* zFqSM&YJ5^9#zMh4{AXC_yJhAfcK;&>cwqd`at_>%Zte=*M2b>r2y-M)u8$N!G$ID_ z5J)cV;f}annNMsGbVGXJ93Ho9f9y+kOOz3{M-85)s6o?3SUh|$`{egt-nu*qUX<99 zEIPVKhwb!wVzqomCwU4{12qCc$Fdh{KHj=r+M@=y88v89L~d9#8F_3*FLc9}K`HPI z>5$>TBaamEzxZ4-H+kwb6={p)=^5p7&$=Wf-1uA?f`!2n zhGU8BkSkgTMv+^9^6MJRfZXA*ni85y=@ZNhoz%t?h7+?M~E>4z2 zBqm;SxZU{FeCg;dlEi=ZbGJ*EXrr}?f%r=Lg|QX7D2N2}PJ3}FsUH$2sx|N|6-^P1 z5+)aSOYcPA;8E0_(K~!6(WG@**jd}#XKf=zDhA>!S--t{aflHmCX}piHYha;k)miB zJRA#_PGe$DYLk3Nr^x!EYsLTeD8#uIA??N&o+mrsm(27^XFNs6es1nvU z{a$doESICnl58tJ`nnYD{?euXQe?qyhjaNtAE1n?_#LUu>QzsOjy$0{k3K@};Y zMZ^T)8myo1@%i2GYaix@G~jpHBKcOZ4GR@r#9CFp##6vH z&@sfEE_WmlrrxFKX_O+qExHhdtSqJ@*2i6As?!jUoBSspy+@^56rokW8Kp?mPJ%ad_kSu=%9_fQaU{U%*^+=-5$;ZXExN|y4K_Rg~>6QtX@Ui*c z$=cne=xIZOSB*bP2zzc{1XGss2Nq8I{y z2ZtN$g}X~fhOjiS58Wfvfq#@N;I$m8#@p`P{!MWE$1)-oZPkkb_0cq#9X3mriYiq( zm)JS1Et>@61OdxxV6S+(JZ0#Jt#jb=E>K_(Jjfu&dA+9BNr(W9Wblvr0JC~r+siR zhDD@Xr7FH9Y>S*YngyF8#zdFUDR40KD>g~eJXv}IElJUCeI6aWp)KB49joNI^6cfLz#-5FzaAqK)SBJp#Sa}5|C!Gd{x;c`BH2rNW4AtcWqrcsrS2>} zlGO_Ku|ANg_;>Oe=ni(Ja(QZ`P9*!IZco<&cvx^f3!-zSOA~GYx0dgT_+0`B&BgVMJJK86^S zcstmCRx35}GODsOmY>-LHkF8EB(X<%c5)s_3Iw;@y<^8PVgs?-*YTjoG9hNe2kK*e zNSpapL7)C&;t|;iz&FXjl@r0^p+O*=WZufj6I~SVShqfVRPp?%VzVLq1~!B~_qP|r zW*#wk>;P7k7X$Y|wsNe(rjP^7THQSYqE&60&S7g+r#qg#D?F?649X-$RyR(rU&gM8 z5cWjh4^l)+*o!Eha(evZRFb>P?xb#!mmDu!Ey%7>w(uqF@q-d~{!OWV`SK8BUXC!+ zC{SqpWSqSWCahM!JSI5^nb&9(u|Bg+7NAc^H5@FawsvDyFN9x7UzbxodiL1hZN~<& z9cqQtvcd+|IZ5h+QRJ@hgVT>PF+qHP?2^xU$fQa?ACkpCPE9kvDEXDA_AS~m%4Ha( z%7R_-MB!K#y1$Ps#IDdN{9KulqQ;Sc=#%)lv<)9dY&dcgZwAMYrCYZyyGFTvjWWb2 zB0kAl=_5t*n8=LG6<#;XLvF+7r-F#D1I_xDjHQ+cvf%@fs%1}jN4j@|bX5uJj2pYe zOJ$pSAzd|!{3ZFg&`R>K-H#38xBHEpsrraF#d{Jhf^cb0zpv|}-7Z~fmm&*%XFf9y zmNn?3QN)3gWectFde|tEK^A0Ll7+DRzQw>{;@C61i|RK>YF!p~yL2~pDHUd7EiwS0 z-9A#p7O^gTI?~GW$k|U`xBMlZla2`_Mh2AHGQAa?BZJPF`~KsXc+S1@y5n`zMaiX1 zZGhSBRqe{hPq#QWh@6P@q$4+;pLawTiI&F`C)2W698ca-Td=N+cDr<$U83jlFm`L@ zqp$@1a{Ohx+515zN;+)toXG>b#B+*W(&sdl&*UTf5vA^#r0)LG)22}(MXFVCy6i^! zF!ZrY>BqxI!m_|Lx$LILhQYZwAyomG8M=jbN8^Yn{H@bsr_2!>340hoUzu%W(jjH$pp^99Q4u_*o`{JII(2bvmT@(olLXe3$Fu9h7*eh zljSCdimutUg>D7+OV`xL<sM*GM@_6|&MSu<>B zWtpq+Wvl{3ft95%_#e0{zpL@&eb5-EVzzsn?snpI$5IqKV@>z$#Dxt`#{oKnPx98%#RU7cocr9~e8(Tt3Y#`I=Sqcji6ifov*^ld zt8k(02Yq4Q^BeDk<}mN9pDdzuEx~cXDY!46E$NFLe+;$5wv2d|L!}en#Eu7MLoPG6 zTIbDP86K&lW1Y-(BCevbkp(eW%(z*HI8$RoE^u9}$SXyH^b}Z^g&lv~9{w0hk*Ge) z6I;_uis%Y*t~XzJ5An6?(WtB;S$HwlMYb6~2UjA7o4&GSa7l`qF5TlRm&aE`Le<)& zk`Ds0hUpg^NFV>k9IGOh6-HO^Z)z?XoDoka984Hf_JzkqukeUOXSYkn&VZcDfXqt; zy^o>nCl#tXX{Kaoc#8BV!KTV*4+FwCflIL=vRGKJ!P$$NeZwrUY6;$I*9`I)so3b;B)JD^Y{MhlEFtz7Du{p((&f1 zmnG3J1kV8_uo`v{O=lv}9jKHgp}(LHImM&`iz;_szee)2RWf#cahblDN(DclAL^tJ zvfpPaGu2(P7^%jEN%^vT*mTFExp4jILqk_YgKU+GU0+Nf-)w!ZOP-8mVHc-Mr=Y#PS4r@}Wg+cYV<>ucy{nkEOyo?uR<@-#k${eUJ@a zy!j(oEuV?0Bx|_tB|vg;pCkucy5ozU`~^%$Q}9as8+`%uvnG8k33iITAbqK8Hz<*&`Oe0gEj6hS~AObu&cgrGlQvg!hpOz9t3}!Dqik$(6ho!qTavH3^^W?aOgSB9vl96h08O{D==i|3K7K%NGv zAeX#l-(pB%RGDD32d`zjRP6r9CH@E>B+LaCgFk|age}^lUVCkOS1D9=kgcxQbDU*(|x1@U#0J{wU52TclsTc;A^B$ zi=+IdIn*uDBXWI2VEH3EfAQX7zsw#LD6b#tTa#ao-%5VD+93A4Uu{x&b{s1oBv>L` z70I9t*c6r~**g5y#Mn~P1e@&mq8I91mI~UU7rMZKvlDcHnGfF$`0hSl7|I{DR38T3Mt?tlM#_rpVzK& zY>hYx%)w*XUdgzli*wKgZ80wunVDWbDr~?~up42%^LxCJR5y|eoCWmB6Tw$NsXP%# zL+o`c=G?uJbG?yB2DX!i;Em`w3R_r>stNk&3)Vw*BKBJh4esQ3guUQ#upjseXo6($ zRd8I`a{59&?w+mHhrL*q3S%xh(Mu}CM|9U=PZ9|c*N+vEtCt>c=AI5o7P4njPXKN3 zY?o^arX2XLFD}y;$p)u2qAzewIHg`*DprIZ5Dm-TEv$l^59p$HrzI17Q86|8L41#f zk>M#0zr454R4#UOaXz}3$^^V&9{OgGI{D0RMef33h z!9~q@Ac>7&!TAb(Bm?Fod2nP91T>j^zWhv$yJ$NsNWMDs)y#WvY9@mE=H#G+rv1fhznACXE!OGZWv0hqBxqW9p^u?8PPQMY3{u2JnSm zT_ghT@5f(YGqIPXPn49tuv-p!V8iHw_#@F5PzC=L%Fy*s4_Uh}?fRmZzL=8=dYl#S zqb+1v(GBJqkI6@s6`o2nc#@8QG15te{ct?4LmwuXgKTV-iCtTqt1Z6wb!YK(zF9!fGiw_1@MUtEGOl9fXac&jqO?M`8K@E3jbMfzgN z1?O*)2ea*e^o4#YeoHPV-V?j2&npiVJMSlLvsE&7d~q(mn3D>21j6Xm4+UF>Z^u9+ zQii>%s8ckJzVJzU0b|)%HBZHR5>0i+R;k$a#bx>ezKFgs=D`;-V2pnseZd2bZz{^3 z_y-9MzQC&a4c1KePso$U6ugQfP4};@lCkTH^Yz8CRA98sK`*w`tg{g~v{a_zwt_17 zAdv;p5txEy!KGw>U${gTz`l3M7iG_qUeQ#@lMK)orDiWr<#lmy|b{QVae5^$=&1I!auUQc74%Zf<{h$(ml}M* zA4%*4;}!l3QY9<=nC&sM9ba6AFXD-$leo@Wbi48IRU?qPAUzKF71%5`B(Zfmihmk5 zOAaWhfjH!K`b~x*CcWXdZCLsso)K;A-yWAXR2zGvbrt&0z~Ns~^{PE3#vY zbFoG8F09$?F9B~_o9ss~3qliND)46_=CFnQ;^cKg6u}ml&~RM%itN!0Ti9Jfp4V0j zvU?(zcp|kMO7ld*Gs(*7B^jP9d|uxP)Y;A&9une0LO`HGN0qQMv0FA?70k0eW+j!9R(*c7&Bt7Po>;v9Uj zEES^IG<_e`Da%64Lwz#ew07l8rdA>*Jk(@dB+|~3s4e5Mz^c11(las=$>57%qW!Bb z74D=f=#4&-0n?^Fq{i6uN#bL*LNzt(@P+8Qd<-!WsFYmsWp;hhgS%Lk3O3w~^^pp* zYTeTtu_EGPJXKZ%&z)RyRaL937mnj-txtl^97s=Du_c{@94PNfK94Hm(5^vd3$ zRn(Kn*MU8g6`ooX@+AW`7&STLVku%S^qst&^dDXJX?GcF$RqtRA6@a(jauU@>; zSNzMXFUlx?Tz)<-|NFt!zn6bMFP}X+MECJfUmQMvvHbSw;mA+Q|9@ZpeCuF$aA5Eu z|A94n;qZI4PxuksdSYJv_%eGQ$qObC><(W>O$wHbe@j;2mF(Z^TW63RN2M}>6fW7P zU5f5fiV~sWlk#QzbsCmm;_AGdNKASwgkKYZ;V;86{3enm^OfyO9~V-^-tJO#|LT*X zPd+$kn5>=YUh%i9i*%vQex9)xY)!9-4k?u}B4;d}p5y|A#fO&oZ>e`7D^L*~B(DjB z3=i?4mh%F3U36Evh!mOKbOPcd%MI*l2?YE)p;~sCBx9rI&@JaMy6VJ{FHwH z8}YsPV@tYdugPB5Pi=glon@>e!=(D+I#9|vf`izPK9Yg4XP4YnmI-vs?~2z&M&KXP zAYzE?hiq6V_DLqbJ=~TNb9?jbJil{yP2aS!IbSMd1L_XhM=E3#scc|%NCH5 zApW;3XE7k3@V;3*I&G_D?E2z-eK98$Y)HTCRh%t-0bQh4O7?mfI~qcs0epdNfj%Ie zAXL2@$OzA8djx3DB{(;i0GEO*ZTjNvf-f+rm^plWA4_8G(-78tl?Mnkd5S@$@P&K> zo(#Ofas+qEOT)tKJ>~l35-dwaY8rc?&eX!ek@z%NGaacCF@_yj5ngNPpu^MZ#SHw^3Hyy0u$6(7~QIg@iS~rz^R-He@ zk$eto@JU1gwo1mXFV5E&b5enA>erdnoT`*!CsaeR6BsM9KmzCj{)ku}CPUSoZ&R0@ z_#bS#RVsFUahblrcd{Go3BFT~AS+^3_Q4k-ChDYMNxFlr@EQAo1rGgb7VOpf-#^WFk0SA7yM*1_d^tXO!?A0p43_!ZM_)G zfnIUsL)1g=syr2MV`hBgxxC*pW3fkEn?{&QLZ2L>Dn+TT;>WV}{MdeRdz=>pAx7ga z)@poHQiMAX!$I%(O&p(pL#wE!v8LB5w|9;5RnbvRkDaSgA`3cG()z(2y>d9{WtzdB zj(B+Sbxe7zOYlfEeT}QB$mQvZtg?JM3@z7F?HXlS5^h7I=syN6>Yt9K?1NE~DHeYw zJ`JhGZO|xuU^yHjw#o2d#q1Ord_el(h~>!JE=6}KMYxN5WxmJ|KB5=%E*it5Nj7wl zZYpj_kzVRN zQ#AR!;ov$}YuO(|>=GFA?^;A>T^9CAt=p^A8e18eWXa!xFMBbutQjog-t>kXfJE(BnN+OfS;!0j8S;f% z#PirCTpbU7Ns6i_O$GqI>9T9R43l*)0#P zdrFr~V?n2)f>jo16v#2%AbQn3n05ZIe8bc@=xRhBXcYK0TpHiVZz}2htitb;Fn~O@RjL_CCW!63;P4d(m&ZZ zAimQYVwp&{Sq6}< z3`5x}dO9v4koM+#<<+B-Q912Y)5d3AGT0E+F1R(76ub)a1|#&*7qA6;rQQ-Ei6s%u zWl2~M>`Ag+#eC8q8Y9oUBOTbc?KOG3zBpfB%t-|{1P9+oD%9b@2!8TK=mxkmRzxlc z7M3Rrvt|!fehlrA$gil)GUM9T!>%tb*B2tKGzE^8W>1DIev`)TBN};*BNK27FEvaGjvd;dG1w4Ui+*D* zfF^XQOCWH6-ftO`<}`GqZ?A6OLHV{(>fTE6p?(M3tWQl z6642yF6oOs7wEEFAS+H34WA{WLN1UzRMOB#5_qHO{Sx1l<%m9t<&Yr{MaTdmCo)1r zOeT2f`!lr=HM3@1 zulwcIugV*IQLgxT$(WbBc$am%eQK+QvJ_vIB*k;-Wo;fFY>Q4pIs-tW^ahk+9wF7_ z3)Nlm%$%rf_6*3`&fBHw(V?>Zl6;TbkS4wk?}Igf5BlgPnIYD9qV{CS|Kr!Bil1(h za~4ksYoY@QbVDy?&-YWc61#3%vsL}2Db*Hc5tl*l_mL)bow!uK@dpPh!XtB6x+xW& zq)9F`znUzOw(u?Vl;4(pr0tmJdA4=S*=R$1We(&KnTfFEePklKLv8`v6ILF#8oyZ_ zH*89}tC9{`BZ&lO$8hZIaujdRZ*AfReW)aV^C$!8AXu6kXAp^-nfTfc$0wX6& z8ft}ERoOsB(Ke!lbdlIG)`q58M?HHs+PT?iRins8Q@a4OU{8}<+DD_nxGWkSpLxg4 zr~22YczrlV7GiQqFtzZCcn-!t4DY%uoWd+}R^mB|E74);$rR}m%L+FPIe7{mXZ15h zl+=0PiH@te=KU!(>0cgdkL_Xg&Gn^7k`6|(P00Z3g?{s4W+UV; z)*VB|GqHVg`{f#V#$Ae@HfDw$uQ{>V?MSUvuPAh)hBy`&C)v_)OGUhF7jKEb3}3u{ zKsay^yOfG9QKog2bJ{kMdVMsu{0S&zJ; zFunPWT*+(@g$y?*-c!4Vl0Nl;qUtQ$DQViGS)ONkI)!{=ZN!7qt$>#2S@)3%*%2^@ z8RzBbM_{hw%|g7SgD#QL!V{8BO~;5Jz%-bbQ_<>E8s_=+gL*P`>6k-)YW7@mPWnia z`$TqDJEC16U49j;n{1ePSnw~;S_c&w5ZA9ne|}}@v}Q>LgzPA?fn({{fy-Q) zS$qj^Io?n*=%5MA3u_~5l8iW#Hen6Zqrmg+-q6$L4W*|+GHA?Dc24PqSulcZlYdj~ zg|&m8XqD(Q-cZfMj33RWg{6g``7ygUbcr0D(kNCg{vTE$3o2}QuDvV_cFwHR4^;xN z`ecEOgn9QJ<}TIfvZ_drc%v~m?0F0^~D+FIq``|0^FJ`-rDbi zPoz^$awW5u2H#ljE+6`owK=U}o=4`brzaH6Vg-vX(%_=iy;wUL3$hjH4RJ-5NQQ5+ z7ou zg`G==xD5Yvj1)JZTXqK59uJpifuF)GW~lBK7*EA+8NGVwKq91$tx10a=z-S*y{Km; z6PR4wKj~nLM5cWQ^YW0dt6`pB)~%;@sgfif|!d{`^9uB#7kpQTzyz*~5h=TVMMYZM(e%zw?`PIvr1vLI(kz7lrN z?2-i>TKE;8laK7#!dn&{lFdzG`Nn)C*mhkOc5mpes?O;As##zJ+*vf^!0=yMHpPWa)<=TyzFDA zQuR!Jf?imn)PBG$V#}$H4i5tZ%T%bjn(z*ve6Kp&wnNLgF(Jsc=3_$=sg&uQwe*~awOENlb>EK;M^s8_xvZ$})H z4oePh`bW_x!>lNoxnXc0lp`T2*$k<%hl7`-sddXbzgOw=Bw=lwmb!|)S#tj2MR-={ zQga}BC_>zmbx8~v@4}+Mt#nAdB^fUF4?0Lkm2$*dfWN84A21ysc;>*_EN7B1p^`dmMX(&D-^db?`;$ zecr1pAqiniM1u54HwP>X^pGA+eXy&@4osqxhA1)_fRbWipjYuA`XwFooWjgVi zJoR!$|E@ny?-SO>XwACJOGh$@dgV~cv4$f^qr6RMHd)~CNBSx7c4#p8gEsSdSU4RG z@pY%7g*#_*N!Hu3#t`S>dBPj=Yx`&nnT+Ne&k9XMJ5(Nx#i2W3R$K~+5#`|nlOueZ z^OyUW?$z(NS^YkhBKgwkhRg1lr(RMdKOX{tQb`O8RJ-9~hLeW?nPB5!+loq3AtD!Q zkMrClXVPRLoQWB+ZyXPXo#|y|u&`lO#dm^1*p}3SrGH9t-Jnyy*@pwBB|q>BE_NBE zZq+Eylg~0`(QckI8A=mG8;=;DFE0%r+efp=aKg!8KWYvNX{wyQ=rH?)wULKF3yA^H zcAic46(4@d=h>Q<@_bi*%*T1AGQq~MHl%_~^wKc!Q1*&Twsooto0o$DArr7FIl;B1 zHy57>@`Y^QIw2E#oac6Sri>KX@dK*#Z#wpf9p_IU%_8#v;jT?DDljmomgg~ExTaCE`-?b_kx6b!c=KM_Zpp?^Hv<+#J{z8fMM>7uVUPg4GWKnUji|6W>QF!o=c2 zNCv4;D`u|gi*!a2&k?!tEiK`Ha#LVi=ba-J``*}NX11-Gb$uZYEOyem9q=J&_+EHK zexm$&`Hl1dTfwV|WWcHHM;H^5!E%rXTz$H$+vR0ByRp6bt}o8t0Xh2OSSt9IqHX=~ zg&qa0Li|`h3Fd`&LO$cMM1$~q@uag0ltX;V#eaZ z^syx3xG)5-)IFmclBt*)3Z4uO3l1SIYI@X!dMfogyxi@XMO*Vmc6`zB#hg^I`fN!b zso=q4Pe}(&K`QttEC#7aR|2s;aT)S~otGivFXmNLX4$LV^~K{dPW;!f$d_6Y6~h%@ z$P>X$@>2U%PsmsmX^~CnUKovG<9vf3Y=k_dHmQ z+ltshA$&v{M%R;MpBdqPz67+ znl8CrDZ;425vp+L0RC^UxUU#4X`og3FQh0w3@M_YWEOaTk|sA-W&?D?O5xbZ&`rdB zpGR%97M+Pk!Iq^n8xJ)7e0$YR@MFw5Jw{WI05wJw3D_Ds&e zu2D{Buimaki4^gXRc`uguKS=H*XG^m2Z|-bsX;FBhD3sWrdkxr@@@EdSXgef_>te& zrD#j`>#k9Tl@vw;MrpEuV8rr&n!6BZ#*J8BN~M*qET=u=`5>%EZ&XBB!VM%O;!4? zQ7)0A(-@`6f_b6Ut?)h?B^?JaW-JAdS(L7_t?4h|Gr6wGDv{HeO0D2rahpAl{t`*( zl|j-pO6s@NLZkw;j|{Oj>5#*}l4k^Qus5ty-SaD0R<${%1{0@`AKXOadA?nrTp~r= z^hqQE4)9wq4kf)MQpraGWVqti61#y!NC&?Qs^$IS?&K`8L%d`8BB!wGp5c0%8LmTZ zBEz-jNRy*J`o!)k`ZT8J5si^fH?cpm&|;^^F)5;ZFu6LQ=)s2XB~?rMq%qlhKH8(J zk4io9W%1%~g3VA{&i5sVLi9SfO&`1Sb8m6BX@fm%`(qL=JOZExd zDj9qHr*XDz)vU*V=A;6GHEVtJ1^nsy<~DiGi3#$6X_CZ{c`o7EU|#%5^4PNTB>rft zRP6aBm+6ai!@`${;od8AgXvD5M<2;Zg+yjLc$7Yo=FH#<6RM<7)ebc#rSdA?A&^KBs{+TW;jQbO)#;^Cc&wNXb#`E+^IG?zDIq=&&si%mMhoQ|FHazMg5cV z`A6mR&&u^aF28?Xp7-N2JKpBg^7H-jq{mmitb1#HmNoXh$_f0En2aprRB88$$>8;6 z1Ic?%Wmfje(Rn1*;K_0|L*_=2a8=Ew_icWV_oia(5R=a18ESlGRLMBiS|Sg2#ENVKjOI(c}Q)iCOG z0Q@03n;0(4iXnq#aqPHx)`S-0AJOZMUCxT%^~Ft8cN*imi-4Tr)XvZxR%;)9p;s@& zp>{^pjjdo&YIZYhL0|A}Xbv_6M!}VZ-DTIe$8q=Q{<+cpIjO)uq&rX_sSt&QFYIIk z!I28+E#6G65Qq3!650gjfhxkg(i`My313uP^JsQakYd$bD@&m*09qA(9 z{PF*!icK;zi!AOYyKAG-?CN5XELN_HSg~S7>^J}4^6@{G-|3s>?|n|W{ub|lHQ(;* zW2(QqIftTC2HHl_HY=5}d5Tfno|}WoBNpSJ@#4w&2$ulP%3;Jwq!XCx3JYn7CULg4 z`1Kl0B;Cj7n40G{l5~w#dY!dqURY%}CMMyia8%5pr}=3y7n&_3Q`_nyv{k$MXTTZH0gGmH885+T+} z&QTQ;J>TXMb#Y3DJg4I$LaB{pz4mA2MxX=HUoa;fXc_vb7x0oQ?)z8&<44kYy`|f6 zs&jQPYG+H!ca*bHamo&ZrjON4DsX7Y-D0{&oPsLRORc4^#1+R4#Vx5$-_Ce1z0=@R zN7M692;E0wo_CnjPh*6lm>5SmMS-@McS6rxy&>0b z?(zOa)D&G$;{@B96I-C)y)UB~I~RVvDmr`$W40rqY8>~_2Ie>B@QzR&05J?S(KM@cTa zbd`bLF@21uNR4TOGrY9{bX&nV{pPR3mpYNPA`7PKyN`)m_`OU>dtRq&PTK(FR{UOc zOL?`aarJ9(En#K8dW-2#M)us!lJhl;HBybQ}3QUTg-#jD7t(?-4KJTWqC zAD-y;DI9b#4tt6iwWBWLKAt8cyRXfm8~HhR^1lv_x=n=@a7)9G6CCcmXkZumYW1GaJ{jq=gy zR;7PY^r;r792v5){JPnzTgtnDZr4UY+U>S$_b$3#+Wjz*bwXB~hDUWPF@5u@GAX@6 z7r>-IaSNhCn~Vu#o|jo9lkhP)NZe**cab&Y*7Li6Pp|QQCD}GgJJ_kN&A!T5{x^p2 zi&k>3ex)9zxMfZ)pZGepL?MGK*sGT0DVHH>`>Ne@v*L_f&+99{1X-9rpXL~3$%u9# zV^Ma7apX{Ap@>e)8J5eUIVW69T|lSvdH!OKz;lr`7{#|b z4Of1{*Y$=>DCDr| zx@vV|=P}BSl>4T;?LzEKO^?U7e2xQ%+M%bkg{-v~o3hHo`}Y4$Nqu?az52`I#`@bb zi*&!D{}3}%pBk@UU+rGapO%TPw~Igcr{$G44fa3F$M2W>zI#J0;c_tXW!CuX8>jBO z<%}haZM(}Ur-^;-#cGcptrmht#XcGZ|Di6YXomCKnb-_Q9z{H^t|rGdO|2;}{epH< zZ13qjaf&cHGwaJ`R_MZ`WY&MV$*kBE#dee@gDX}gfT8ionhjN3=3=DG=JlbN@&DMG zBa_Owv^CQlW(v0A-(7Ug%=$8!^**w&CCq4)J0rJ_xTLP6_RFT~NSReE6TxyignY-_Banf1d?G>_^LoDd2fb}vv;O{9+6=E60k#|d?!EQGF|0aZok0EJ*t zP@N$z!?CZVQWY6BQSPpfS~nEUV7YbI(mgC0VB|x!6Qb zGx|9{!ZPkB=F(O4DYj4lm{U7g}w{W31h%U$N5B3?d}|L8ty^1+D=W1^0_ zKyRx(DAbguJ?pf_;zXTlVwH#M>;KLQRQcqR+lo4Ob(P1ccAp}WPOry)&wX_XVe%9< ztXhoq{vLw_44fw0ys)UQcgC$Dez=vw#t)}&Di6?QxFtO+xqv6&TqK;UuuT+D972J) z4J>5b?)ubH9z;49PF&ZrStV|M+N<}xtIfl&rn3dZWRuRgzUS-RUH?AY_+ok1ANSUQ z50#m2pTJ|91f!raiArPQ5vN6G{?WH+u#ko4rpu;;Q6AE2>9n+e-BIW?fvIP(6_2Lp z|0O;DxAEl6YZ(S39j8%=n>s;y=(w`2PIj*3ShT4}euJla={~2{Qoq=i;Sv7b!qZyM zOr8JJ(D_dYZ5BYRQy+;-VNZAa91q%O&$Y62=H zcaPZi-2MxiXES;9QT2%D=T-2ma0!~Ev-z4rrb$xr)v7*QJ@f0c)ycPuHuRFyUG0P3pDJQLqzZ5wH~26=r}}&hZkkfmPttqye)jH_ z>Ac5bNiO0Y@GN|`3_#VU9;B6xaFu?lSUOjsZeCv&N}H5Ry<7bqgN3>fB8gf|wyzt} z><%Vf3^9A5S4x{y)vMj@C27ayb5Dg$9LOc_<3Q}jzsBG|u9rRPS9t%o>#r?FCgYnu zmDSuQ`->g*@S&pZ|Ho|Phvl(z7UDylK{LwBQKYJig01PM(olRHgHTMF4oyjlQAR492X_Dtckr+k3WFetMeCImgTKsZ~p(JsjbNhXc#81HAfS+?0c> zNTF#DxE`$TS{@sm2hUT{U^Y0kGfVKEb~fZ#la03`+j%Vc)56Jz;>P#U0yW%(qx52Z z42p)ysnicS5h6sHVvw2&n(!ekh`KDYIEP-h45}_ei|;??q_p>|@7b&UX1TWK%>F^5 zSmh({BG(AUJdT-Td$DbbRPHk9jG1FzVj0alm!K0bRAwTbI!z^qooylUlc6QSO%y_@Xqjpyc5Wf`yv#ad zr8#Dt_^*qS{`JlIo4s;(&sqPFSvw?BKTRUQB0t-xc|#f6D_~v*e`^bbdO_BP!#XLV zquRFlEisZ`L1j=qyM@G4tbCl7PQ#=Brt(u@J(D81=SfxfKJYrF!eJHqJDv9^-v8>! zTDn~S?c(@0@BZ=W=_a971*W2_6ugQsG|C;tV@J`dR;VL`%T-~zPOzi@(lx|GRi3_v zVkP2XgIg#%FP^DGK2_9ws0ef)JMxZq|EOF@VGw831#vV}PCO?f5ZuFQ?Cp7J2S?`~LVya(D=r(4VbZWIMu-DV0+>OUSs*}!5J#w1ZRM`> z&l}+6c9kIRbB?z8^jhyzM#swU#(C9Fm}PCuZCnFkh&SMNuaqkY_;GHO12Mr!9?*wOnKrGlzH;8ZMvpsEyJHSs9k;=Xoa zxWyZwme0#Z?H0-Qu`@FgkJI07YP9{ywcF97lT-PoMgCEf)2_U_l&3ZCe$#6Cz|4in zO>L-h%e8NspI)vS;u+kI9&5zC#OeB}x&+qOW^^`!sC5J&Nn|dB5B8u-B1R`>}Z)A;+u2rNViy`mj4etuh8d=7sD`aLvRTRZs|V zt#s>LKZ+V1upX~m1V1vE30&823qj}A*Pkk4J|vU5jT?$y4x&+&mAKK)8NNpEXG(9k z;HkZbdI*rhgYDf7O(K-;KS#uN9-Fwi&0$9MwodVeBCPw$0Wi*Mgt@F5OdSJtT9F0+ zwPlNE#Aa!js)Ilw5^?k$_UHCP%`yMImUwfd#uPKU_S7$bcyh+%8np{InU54*8OGd0 zY7Ew?a>ffVa1lk#Ooii4kpua;x6j<0G2_F<3|qzNcIGj>n_Qbw9EIMmukEMM>T;FI zZxEDU+I{A@s4!v$W~`%xom4yj>42lmsBvz^tn-SY>Op&F*0&o~6OVR`9Y>98LC!JP=;{|W=puFh#$0`Vfx7+bR9QhDXmU?< z&=qv`Qz_h1nfOabp`p-Jw(HteiFlkcB8tgdauzh^idH|1Wu{cyJ&WzQkCMX;K{LjE z+!p&DuZ;Y1nFOYjeEi-O?2t-=d&og~Ge_0AG6>&LUKH6!)!P0Q?6tn39W4;!vto^| zp~w?=rQlwsk9^v=`LH?YHhS7pH%jZb;}U)#MrMJIrog@1;i`AL_jekJ$s0}uf73wa zqKO^)N7da+c`s8++IcC1sg!A3s**7oj53RxKtmkY>02rKoli;cUnhv&l20)l6UJDt ziHU9R!ns<>b;X_|7Q;W(#6p`0AOK?+g8>c#j09g03G7+M395Z`e%wb>bFFb$EWs2p zT)>OZZ9BoA#$vE)zcr@=y+|~p+N9%{Y1JucH)r*@ttNKt$7JME4x7ibnA>}ny$e6a z{*DN*dUn!P?x(zqV-SSPQrqO8Hp%g?K#8m7S-3(?G+@NkSPnUg3*Alq>}p+>gFaQn zd`RZNcZ*y5@#a`{xfbLc z^A%TLZQ33`)idroCTetIiTsbVP}T4wd(1=)JsqTodEDH{e9n|_amWrYH3}qB zvY>KQ^`u)M*16WW3#)PNKk2)N>rx=tOaG8?sS*GOO!RYj)jxyy@WSjFW zm!6|uETZVhjjBDkF>iorjp6%FVoF2e_0F4-D>&@Pk(f5+Pc^{3!<~^sloBP1ZFgDE z)u^utJx9@lUbDJ$XvOLs+-M8}R9JEfO+oGMx{C<8`$UbZK$@dC!lfgAc&sX|*t4xr z&x-GP&o=)sie<5AMIv6b`aMSV>E$2{ot}j2VBmTsA=2DAElPDS;>cn)is4ZdZtoL# z+;;n%HqAC!^_a8arW$eH9-Y%`yf?L{Vi(`mO_};|)M~HtC=X&?HQZVTgCrUkmyURs z-&CGc{ngXwU#BB+Ejv#DTi$k{o__Ptb?$j{6ItVtRh2&`dy11Hqo}MVQ@6o#+?$gq z?yY8nI$4x5)zlV*c{g0Hmd{#lL@jqaPEkFvB3FByHh^j4dwM8*M@?Sle#N=Nm^fvo zm{(d?PfU{w^<*G%I}4u2#;&FJGD=fA;U-N<1}Vpl>e^vWuqlI98Ci_?aNCBET=&3nqd>o=^tKq2IdK{ywI5`Tc^yeTj#fXbd9MYr3 zkz_BcOl!;roo9?h2DTY<$QKXtxghyV3ZQgwsSu<|ET-;jSbX-*?8RaDX zhjALaKCalL`lpyvnxH3*T|}Y{)JZ94Qm6D~_^asiw9xH2lDp`d>eI`_t^3GQuiJ$@ zDkC-k;bvb_0M%COjYBls>WVq<0N*qa4?&s)sECDulAV8#?@EU^0QQj zrWWG$bkOt&$XU65x@d0u6AJe6G$Y%`7TInik>^T34>y99F-Vj>=@I5?aD3HdTL;vd zxLP#;CB4X*gI>MHRD zx{n_M+iT{>^t-OowthBif#>ca-K|T{%a}MHz{$(S%gxuD#OQ#zz;ZP`u? zh-)hce&!ae#l)a%+YNZ0%Vx%~C8Jx!S81KZ|qYefHY=@QS3`TRYn_4Pd`W18x~arm88aq;#sxWedl zzUi}6j%v*2=J_x%FZJGfg4R04FS?oe(6vw#Zq)?q?>%ufrc1ECzQ?$tR;_1m*Cph4 z7}amWxn#bz?~QBeYwBOR-xLO1!A?#yjvk5!rB>|Xy5H6=*57;L>g92jvqv7JSJ9&M ze8$8pDzKkGhgi4y%5yTJc$F6#uF`IOw0{*x^ED>Ycv)w>^18Is^2YOD)meSOc3R~%yE z73NNt7}fQ*b4~r%+%-Ld4+D#r2f26Bx3Keim{6sX;8x`9Y3JcBd}!MwhlIG6-XQ#)mV8zjLg1vKYQp2Z(DLllOC}rf}sMgDioN=Uzobl@Q^7j>2bgU+b zC`>xTc+MDHaWAyTgd0%ygW^>mrI0q=;rWPWvZY6uc{CT&DK^`Aa5^Af&H-Vj;}6T# z>Lb0~J-Izcnc;aEk`>`)5^RG^kEfhz1n$sKiCj?&e z#BEG$MIueC`5n5!NH1zmE!b)<%_#-=S6ZB&HoWD=!P6-E5ZZ?7w(M+0wwWGgd)veL*#dAwkjYY^|^3&g@8s(eVRNF&4gF*6@&Vroi#$xt}8 z{LdDK@LD~oBF7rBsvw(*=JXn+y_zM%@J(Su3GG#Es#@&aRdGt!+h^+_=@ikxsQ)@i z+gl7L&w4F9t4xStb;2E|gg;|4A$3b0#F*q=5s81fc;&go>BAm`K_7jBcizOT|8FZ^ zr${|{)=TrOHs>_?(>^9w&zUHrvLPRY_`^Nutf-u+l!&UsoH+blWkbCpsH$@zm$tL@ zToyk)UeDV>I=y@MdDcV7qA!h!S$H}>m;N;tuG2$*&pAjh#jNODl+#@H)Cd0OPM{Ux zwmH`6x1KTUrDIm}WVt4aSz?B4G)mDDolO4dBjQXl;<^preeo+XtGyBRI{Cn87O52! zw;8iuhQXiSz56liA!O;&jGKey6cnAfCpxW+`^V%)sy)|@SVkR0i!I?<`l>n_}AZ{_mDsV%I1aA!lluX$}ZAAh(VPM(2_t^F(;m>dwK+#IDo_ z{?-|{UU%Gj2w6p~QGR-HhvS*6i!zJFw+$My+-?WSx~q#5MGE93ST^0{9Ks3TPa(V_@>O{MW3bJi=+IrawlfbNpUW^ zW{vm~HR40aQj3XPqtpk{$|Mk%gifNk<>%$Pf$NZk%aMrSCI!{Ox&VC(EA}pJt}T-&0|?i-Ja+k`3r`dk&zV49Pkk^#&bRSRC<^1uuobMvh zbdU*c*^K9EoVJRIQBmO#{+y@LK2)`39zyeH=F3z9q8wdSuH;)ab-S&t&dJB;)gFB(Mdf%PnBjb*$Jk*VJO4H}0KY->u&FHnQv)aplLvEoyzI3W?2PC|0*l);f6`vg~>0 zbmh6w4R2N(lWSYpb_PBD=F_wDa-N;gB_FB{R0{Z6*S_i3G3e^#7Hm*$Ldl@8nllr( z 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 z zMM>L}!b*IqV@#Yg%&J%~tyr`C1dIF5a7=&!X0XW7q|5y|RW^z9HYHR$vmKc~3W~$d z2~+X9m*L}d9@nw>r)`tllWl&t?Qws*q4%rpSAVs==U@JE7XtH1ZTN_9AHDU(_S_xcJ6~;Yeg2lua{n8Bv;FMX+usC+KKse9dY}8l z`)6~UcabILWx`cA&1HSD&Xj9_L1kBPU3=#=xqm417!1epneZMiQt|khx(50R&aQFX zCF%3AX7zsg*t&d;&(T#K#TI+^#nfa9UGx-(369(?Xj>R=pi9b%UoM>hB%IJN#jNVf;l~^!4qh6-^Mq8jV=AO>kvtd1gaR-c(4 zAAuW6+xr!LZtsGf9@(3^m0>8Mv}}I!48!0G`*(l4z1p}C!|*NJ+4D2?Z$3g5qxsEf zFiUrUee@Y7J{B+G)2mlgPQrzqN{gyG`m3n~ixi4Gteh#G9L?P>AZ}81d7pBj?vlIx zv+refsXSNfdZl|)k^g>k48GiY_kZ1fTwVecJ#|w4ytx;jZ;s0IE-hZZ#>f4h97{=L zKXOcEklm=B(oxh9m&(-GMlwgrd(!2Y&0DsQ+d}1_!o9mfTvP0Lbffz6H(&kU#LdOa z*Z29z@`{_;&eTuW4{Y?wsdNEYPseeufyL(g>8f=Uqb#jO0vtn?`TfP#v_NZ1UH2m!1>@hsO@WxgL9Dg+8UJ zo}x**MUCNG`*DVyQuP#$KSkZs0b(q;GCOYX#x9?qRSC@rIaJ+*!EI+5^))?y`SiG3 z(|JlJEA`=Ct*JzTSJo?B>Jx|beA@1{=?&loN#ZG2*yyzkFL)i33u*{4^prr7C% zL{5*}dSW?U1# zsaxomuko=iH#ye9`%&eyOTby8bY{?%H*R`YZ>hG?>Tm{K)j+katOBf4Rdxfr&q2dq zPvKqu=BwlTkR9L8k;PMx_?&Xl&1C2$8r`+L9CLF#$l{Qh@s&*AD(LRY@8K*ghEva; zwtkDIdO!KAPp^U=b$k~*(Z6YQT1*aohN)~N!-X`0JSjX;;cY{d4(1@3%fQ&a$t>F` zYelp3?yl9rHRJnmGrkL&q)Oa4Q-S1KrqD#c(^D#2$tVhI_oMh=oT-v6raiX5V2ifz zLY3+A^<>NK34}*>5Y8FqAO50jFw0$QGPGQ~2CdTJ`F;+xO(>TRv2#RUg-P)9-&HHnOB1z4~bN{S06uc24-sA zp6T>eFjdJJ=T1SQ3aI|k=5j2y8B$rMGMI`N@k@F>(b$wk*fcX2b%RX|goARTu(~c%L%+w=2y1ls>c52tu zq?bOzKQ`Chufk67(&iqtsiJyJ?vx2$ml;a~9xL%%I=e^4)0uYiwSf!_({&0R|CCF~ z1*MNvE?b?nlS)-`fS0afbrC~%CdJD|!Z4UmEmh5qF|oAMXRr0p{TUR$!_z$PEIWln zHxp=Qt|ms9VJEsra#Ov6tL8R3y4Z<}0DrU+oMI_n0cX?a2EV`Fe*PGVx3JUF@h{Wy z=gejXqn2ZV=>9Yot*Rg+3At-bQ{C? z-res$rBP-uQR*$%Y1c`ZBke@ndn<3M?#w*{IN(lk1)yqarw?_JZl0YmM%Q0y_&M#= zOmN?}qn%7x%4@2#cB~-LmV>#A%Pcg1&nwOi_4fVjw6xQdc5=VWWR>s4BcPt9s-1q5 z-nQ+TQy_VXt>`4T6KN-CQghoMw#8#A16SQTKEu<}P9Mq@r<0(mtO`}*wVcY3o9s$r z;+wY7+jl8ZU{kNDFr5xp6jo}e+uuK!@VbW+g&j`gjHN42Mz@gVS+37w6xQwshvWi4beSMFvU$K z#xy%*<$qpsDtu7f#fjoF`HnF=4u4py+_0?FHRbeXj&AMceY;%+`kU>m`0lQEUcSah zDNT-gzWVO2V>j~_mwRVAM2Qn=C!K#zCjXpknU0bVrOVrE@ji-*PN$&SQJ}wWMc1FV zOHu!}{dsHSQ*U>_+x}8y(Kk)%&yUw;@X(4`DMEQSzXTPW6}<<<3Tz@l62nCbi#OT34VG@#L(W2sl%*Z$;MP ztq;Ll|FGSO^eTBaZTDk24SGxb;I*7V7q!JLaD_TA!JoHZ04hliU23O^U|6EM^r1LT zcIx^Q*)DouZN+?;t(a@bQVn%zGq{qbE1@Z`DJ7)_?pLZM7U~W4gnm{cruiQ}lda)# zTvuDSr_PtZ{x1D>Xwr>ICB#$wb)L3vOljV9B&U|Y{-(cv!35pIdFl#+ZKP5wGYsRkEo}fDTmh`nc1(Y6b;@K#e^*aw zE5VG>7AIAHT?yUFFsoj@tX{qQY{HvJlo>EfhD+=;mBZr$G)t0ufjYaO7z#V}4AVM3 zm{axeQBH!qUOvS2%XdpVy=y=H&5ZHeQ&$%}c}A?A7|f>Xz|-9218xA10+!&T$>IJ) z26@jaU|9q+&azgjUOC}VcUD~2`ACww)Za2gelcR5xJ95 z_O5N2>YJZ8r?Gzw2WNME&U6!P2&4X{auM#m@K2j8>WX1mz3nqIxAxH#B{a+2_>6wO zPxsU3P5smM(O+y=o;~aQ$L+^oz52)P$>)Fd*Z+I_fA9AstAE<=6nyoT-)Vnl)K7oM z@3vp_-Y|x<^XDsWM++)U;-;>_=7E~}$zSoNXua;?nZuYALW4=S zpOvDqi<)oc%3~Yy_j24q<@2whzlq9owhLJ_9Av3#YTFFkxvr=Kl-29%hPSvKd7@nm z>Z#oJwIpZkM)WLhJ)}PKOxK^Wot%XHO}^;94a8&fSztB_Qa{Uu<&5YleCEDB>N?l% z*KgsdpK{ZucZcJBaGbhpj-tbya=&nujz!im_nqJ7ss{w9`cTnxOY`f!NB3bG%}vpj zE*1CrR=w5oYWH`qEBD`Q|M%|G4KL+2*YwH>dxhulgez1-Jpsh1&NA`vgey1~dQiTE z+?FcoDU$Nd^p#}S*{tV`*ZfJ?HK(>d!~_YOnT$8nEQPpNb=`>G*)<#99en>>#l2m7 z{jh!f=i6)kX{#0u=!WB(kPvG;aGx3V|yb1dm_o}W( zMA4Z_q8E7S~if$2d6S z626&ivOiaMR~ABoCPv%0!~9ursSm6x@s+7lM)mrAMYbBD~PGF-|vL!TWiK@I^_gQr=sppljBU=HsCZ3XiMQ`GoEfQFNwO zRBmd;g|K$IeJ@YxR%x85RZ5|HIL`|R?1?NFEstI8~!gdtf;uPz4;ie@U3D;B&#{i_tM^oVJ4dIhi0m^z>K&Z%SB5)KhZkWWno zUt^OuHw13qKY0XxxqNl5ZR(Z-xoqm1OyL$9qUrh!E_4-q*%BvRi{l69)4>OQVhTo| zP%6~5`zUZksbHn+3IEIA{5hK=3lk(907nm3MUa$s_$ zxA7y*QKnj_j4ST!Z&sWm+c;`#UFlQXw%^)YYLujg#iRsSv>`>w_FQ+L>LNYB^msYtvqJ|@+H%c?6>Dwoy! z;F3<&2iwt*k3U1g@?Aefg1OohnkZM@aIf{0iyuq4#DHID6ABeZASYGJAE8R136l76 zCO-15E5R%c_PcEo@WVDu*8iG@Jogzkw=&Fr)5=u?)nKaD$dBky%zr7@o~1^w#xSZ5 zwOXzjCOGkGkTh187_N7@w>c#%{qj;YP5CVsc9Nkq0ciRr12cof5N6VYm1JG;jVTc% z%C_JsHIKHor3j09D=6gs%KDut=X2Gwu=r9e-o|WLrn`~m#dCPVW1e-SmbpJ8 z6Tb7lG&VgYy~-hOm);~my*!&To@u9*7rnn?z7LM0z<9kpWq6t4IO@F=p{v`fEsW(8 zw5d_X53k`px7(gWY-iWCc@*ZG()MMNu^RsyisIJh zoF)?H7Q8Py-p|SrLwXlzWM(M+V`QDN-6Q&s^Xx?7U?<=G5H#gBsE8_~3{JChNsKni zC@>jh71MinKeLRLy2_#GNzBI>I#*zih@#ur#B|Y&iwDTpnW|G&LY2lGgWD)`haqSu z6*45qPo&i4n9a6mEa}~{f5%8TW0R%CU#i642PaYS5?d+`oid}Cx&oLR@9;3UMkC2Z>(~3A{|6Wv_o* zn{w>-Jf)ngP3qKrY_e+8OKa0CCxyh^PN?w8Pi3F&2TPFn(cXj(U$&&W##4`z^!(o9 zbGg-Ef{aHbROD8Uk+^iyyL%SN^K(r0y|9W7(5s7QrtlPR($2OpAx64Rl}jg8_c-j* zYi2b(0hP@Y0n|Wy8TTd+9dW~1SKPOFBD_t!sG{Yw5@=~!Tscnba1HD|~3>~~1E+Ab( zg~(`1Dsgh!M?bD9XKb?Or}xiKr`YK!CiPzY7CteCn!#jlGcQQTCDm^RLK~-*Ln0^J z{!bf07)p*w$L771^D!pR*=eEjepKGdcD6~(KIrGUIUF{Vy)?Hk5u$rH34yF`QF)u5G6%6Spw>(=UB9;qs6&MyUV?kC;Y)u=OG)E3>+>sk zRWiEr0q*Xdxt?cCx3W(kTlVRq!+4{YOXqW$UfO)$NvFoz4b~^dWhD;m&d~B|F4ofr zxI@lSg~aO@xo+L6TUdN47SCC&C(hV|(wpTzOzj-VJmDh7Mm;cCT^3|SUHmLpD16S0#Cco!_} zPQjH|y&LjSZXaHMcc!|}71MIlkKObz@#_r}zV5!C&0A&|##M>tC$w`OllPQPu)WmI zo$enxFbcO5!*DxIS={hDdT5@`C{J%98gssr@^H6@hn`4 zYRW^e=`P(4l65c#$C!)lK0GSV*$%#JXqwuXA=1}V$WlMU5)9FHoUc8LWm3qE$PXz! zZHtGV!*l%_ecv&%mbROJ?(wWc=86LMRHBP+s_&a&yY7WhlIk#K(`&S+th>a87;vx8 zl099-=8a)HZu0$;#HH=thqn7~uj?qbYm$fUruG(HC{sW61gfQp5B*kF(Dn|Wqo-Nw zBvenorZkxvPuuOQSB)tBobXplMIR z^67XavS3^iuATliu3Osf!}koc+72d7im)9|gU*|(z&v9A^h8f=XL9AwYrY_{LGN|1 z#Lwb5z6$*(jp6&{EU&oO?u%_J_Ur8x{pZ&^vGAjkc&g?1+p}}t%}oBhlXabhn%Bvy zQm{3}c4iZK9XbQr4%@*RWXXbgpV?^7F7FD3>3Vx0HU)IT$8~gdvh%o_WxFt$yV3?F z)|;uos;`_i{>rzb+|<^*WR+LH;q$SDW3xs%;7X%EG;l)8h58MgDg z+bc0;Rb6!y^|J8SQ@635nk?<+Vuw^4##6mb*HqzSOfGHrF=)FTS*HDNm0&yb{uyMM zUzxD-ex-|C&Xq_hi(+D7ChO<1n;S3ir;c(|Oi)zXv%9)y+HNH#Uz(VlRCFN`>u``u zBXMnKkZ3!AO5*}UAgtl7(!2T$Z>g_TotqghV$cC{#lA!MD`yV!Imaz5z7&hM={U3e zZnBoQp2Cw2I2#Fd1$tF@=5(l;`dIIiw#03aWd`9HPjCcTu(+7*58GGco9%05*WkPD zKG;{=tM@+Y+*l=Rb55!R{3MRN5!eU>MTu3$-(Qr z>TNOGG_&p3rm>ESIfEzH_IPbQCrS@WiD4|v22UkR^a{DZ<|48ra!uuyc)!PZI@4^A zxOq3vN%W46lAe*ooZ=+Dn4Z$}GRk7w@>Kz=j&xR@uJ=l6>LYtj6a?ujCDD&Dbgs4@ z5kVEy%+~|x=9(yb0 zeejCfME|NDs=-WcDq+SeXscJBMu%6M_@mz9sFo6f*m$~?Va#fv zp^V>@qwWrx@vcbhsY7#{FhRGp?^IQimXJ?$F97Ep*P1hiSt*?RQ#kWH1qhXJ>{A~8)08T! z`qE+2*{Us9v@LX#Ynv+A&eSk3G)KWKD3#BhT3b%PgtWwtEH1k)UWcu_o6-BRoj+mc zGs-?k)1S;K;H}F0zAK~_$_i;kb9F22tYoYRfRGxLRA**d+jv3{}gP1{<%#GXw z|Dxw%Q*0C*ugn~&PPWb!?#ykZ!}#uYPGM`Y-G|Q{PIj_8CUe}{AyS8DFe(4aH|zEk zKEtorE&rC+*K}L0?YY@zN9Nr+>~@kD+x>F1oiyOS!7h6^m7plsh)pqA*ilJwod4(A zN>KO=N{R9LIDDKHZ^>5N+sQt*lRM8-X2g6E423tQGOT8cyxzPK?6hzFRy$*-s;Sg< z8z#0jxp2G`vx571>ap>3uBZ0<=I#;fQ|Ku@Ro2Q}*=+$XY}Zw~2&6_e50DGQKc3g2Gx45c2 zR{1`Ty`1tfCeL|l`BU%1pK|epZnZ;E(t=w);{~W+*sZ*$nNFDsZ{b0cMrh-~>fM?Q zz`MOMX?ZirGmX7wkH7TUW0>?zQvJEfBgcFOlWzRTu=`W!b<8HMoGPQmQe|-KXKmi{ zS>rjn4I7`Ol^5H+kDZLO?omfZ+o_{|ge{%>46@*gLW2)m;nbT{8TUZiU5Yw9;WR(X zy@Er(u5BPpcw9#p+x@cHZpUO#!-?zE;TcTw(YT(NuDcYbjXF}8tkObanIPF9A1jw@ z=ZtgOb=hM~F1GtP*p9mq+tGGvDD6IjEVmV97V|W)UHP)+Jd_(>URS|;w?!t^gMoDx z={lzeJoh;3lw&SVLd;A``A6$nEX+8Sz z7?X?bJ_feKa}tZDMQ+T+I8${rZ4`FM+(GqW`LEe!DndEF2x6Q{*O?48-$U4(@ zk3F}VoP&m@cDr*cU~1~AV*VV{%r3FxsU}&uz*xx4%e1qb0eV(@m%593P!oo;PT^dY zJvN?hV;Cu^^b}W$2S20KrL^z}1#aKg>)*Uw?P}}D`>+qhbjeV{t3-}p%Qd-|Vf-%U zS=3r?FEr+k=xo(eJ#75~mV;OGvF_{1)BbwPI{0oio89m3ezX1G*W2$X1@YOd|GC|% z`C)s{uU`GtU;m%&M{j-c>W|y)ns2s$?H>I6clguxE56)r`2O^FditwA)h8~+PFSFM zfYgm#^9&NzDibJmi&tSooKq1yd8M1ud!1E1Gy3LQv=-&>veUbG4(7t*Z?~`g=iB!M zTq;6H$PWQkBFjM*`yv{m(N$6sZAV&o;Asz^h&qIT^~lXn=R6{ejclM#bla&*W)1< zE6;Fn)`zWJ&i%QZ`EJfDZOW}vUf&R!KSPu zydKxLb8cFwydRafah+GXrxmJ)9m}jZBdzuvM^QKsezNdie);XA_&@?Lj3&-hSwOfBjd#kqQf0UCskF@JC zn$B73vGH`oFQ#|C=AIkm?ya7TvNj=}QBx9FdLXH*-E-tR>Cq%&xRPlojsQ%wIq37# z&GE$fP{){940F`0Pch6>G|4vWq1(Kf+T>_H!Xfk)hEap|i>12hyhD7#Su7jKLG%m- zDoBTSwvD<{)tkx_e3~*=p6V`C0A( zR;#n~>y9yb&QlAO_oMPQJ=F|PAMRh(W`^x@m`zAL??eT3Im?rKAj^Mooaq`Y&-2Q<&imL>2eV_N?H8Wqe*sK{+ z+jCT{@#Qfl7u$X41n5(3$BA#IH|4|gnq&Z|dI@$jVu~#vUeB8Q&ZFm2Nk7RpO-&PeXC4fY0Q$AN>x!#`)wc`gLkf*R^GTnuv$o^E3p zGY|}8e#NJn;TJogVS@j~1&|5~2U1CH4%Pc(6`3U(hElilqE_+0&)mwhUhT0f&b)%r zbvH?o|1b@mK@(R9qqu`t#*Hd2p<=4nT?I9>4Jq?}T3GjI)7ZyKnJs>q=NDgTiEb{8 ztlw1U-MrQ7O*5%97)Br7bd3|`eQBKDqI$Y-1Q{}H_bZr{qJ3G4cAlL$k&vjn^7d2$ zSIzSKt8<tpQ5m9u`Cck-oNq|n`^YT(Cml^GB zTgb#guh%_cxS*6F0ZMp&SdBW8Lh5ND`~pY_MQ1lERwwr1Qb?gmC#IvHLsIkk=K7NU zJ=?U)V{MP%nYL)53#Oos|HC!p3HWz)VY6M>e}By`>I`maCO^e4W}K#wFI-qk5{Xs0$}sZ~9Z?uADPIcm|K zlchx9N^%;n*kFV?8mi1b$MEd=xJ#?p41dlpt2u)2EV*eL8JL77&9WiK*JuGuGv6=w5SgTgLW& zpb2hxHC}B9;@Uu+ZC4elCm(w*$8l{s=at9C(^)s9{^OZ_o6vVVo|$17%+X~SsZ(sC z3*TL1vq-GNk+UI>f1s4FBGHQd^isb*!NeKEEWPrsc_j?#ftozbrBJyj5M-*Z7lIbu z4L?PVGI8Se@_N11l}A59Hiy_pEVc5kFK<*|!a+|Sq!;o2)QnqQ@w%s}u!U}SM*{Bz zzxb$T+-@hh%m_bpD{qB{J+3cjT%zwd0^G@>wmCtlGH7^ljLv>A{KHskYxXt**rgA^u6z>n)fB$CtzxkWUx2Ysr zr5zrr2d~}?p7zW<9UNl(X=*Aw@p?GLRFc$tvvq1(o{Oi`M=a0y9-nWPo$?4xAiAMJ zw@me6dM;aE(qE9J592C94yOmAu#?Y0SFdhzbaDe^!OYk1zZ<*yur5i}>v|pJ?S8ef z2<>DNcnZ@pUfX&u z$(V>np4-fmKlZ&W|L`xb*~FjNMlyzJBbiDzo9fb;IfUJ1ZjWCrnSP9kGlp4C&%1Sc zb_}J1c|G`es!CBO?XtIxheP!8Whc}xdPS~}_U&iQKH=;Amyz+=BI_rpb zB$V+qEo?qD(-GN5;22|t-*11C?1NXh4!f%xs*WjT8BeYcWSBxwzOoPZZ)7g7=Vb}c z$!=;#BKO%;+V?y~IfF#bGAz0Uy|a#qY05c0O0(*?dY_)l&$pq0&s4a3IcfQhFMZF7E!({?qEUg~{(%x(fxaa?S3`C~kt>7>W*&F9&v z`KszAHBO_Db4O0V$gTNPLJH#-^MVihE$I} zjNdcmChNmZyv*ZDi|WdBUNCV{Omr0$4H@#Kn5pT!9OJzV<9E_~=26q_u3%w3p9Rh< z5zo_sQQe}CZu;+MU4;F+w|G52ePYHxZNI1aLC<*la`V^zahodq)nEVb|C}rQ>eWBJ zo-Ewz8hy9@jz9kA@AzpuMqYIr>s}A3(kY(O*Lgj?#+(8ez&v@<>KVr3Lgpg1Pindb zn^LRP{rwZOh06P{N!`kJ^ppv`Of)BGrULQ;+Qw?DPql-g@*xn-J)q#}_;v+tcj+5? znzsslmO5K{>O<{Ym|Jv7Scb6+;;O?8n$%3HjnklVsg7o{IZ!IMO6EOHQOsn!Hr=Fx z`(SJSSe>6cP>-$8&lv_L(%9|wb#Y(@6RsP$mmw>yF7cx5qsB10eH|O6ZGxq;$#-~$ z3-<^Y(K~1J)Wt9#mSI#V^@>I@t(uz7!v>vGCr|Y>CB`){#l_xdpz2k~!#paPZjYOE zmSS5BbMNddhOvR(bC=*^Y9mM2(;aD3TisB3#V}E4hGF1F{poHGm&&h_M*Doj#o5KU zGlqG@smH7n6ozaDdWChmQ#pH_q8>`ryX%BYWL@j|bx-P6o+Fo9pY_GYB-D#ZiJB#G zf3I$NL=4@gR%q8YhIz|V?lKf`b!1WfV@8Twnwxo^6NRGFH@$-hufA!8kFzsM!`weN zdt^6oo>L%5k}$_+ZuZ5oiM602m(E-w<*P2i5Vw(Hs`Hj3#5^Xrv@!SQURGJ%P#O_) zt0ZqG3Dudd<(SLsh`6aU-H?8Ub0X&h8*PPhc+?!ei_cQht0(VZ9F?Y@Q=M+nuV-3i z`FQvHc<+O!Xdm;hoc%f1##ID$ET%A1#a;Q#dOG#b&$VUfzorJ#^xQ-5^{emYsfEh> zQF)}M{@ccLkmSd%s-|4<&)#YlJw=l~-|IwExoa?kCThrQiLIbR?S!WKHC=)C!P36xBRvFBe#ZM#=*MVU z-p|XupD^)v8^chsO&q%EGu63cFuAfzPiAk`bgCY{w6yLlXOIgh8RXa4itv9l)-fg) z!+Z#L8JZ|#>b!KBK8f=?x|Kg}|M%r9b?A@Vd;jq2cUwN>2v27k#tgvxO7=pBO<&AS9He>lYbu++ zP0vi)XPSA*dUyUI4WpCv(P|V8?PpZ1`xs_v@+-0$5l#q=+HO}rS zM#N5(cDY5^#8?!M8V8eRuhdeP(bC?lW7~6YA2OwO&UT&xUHZ{$ZVDp*ID;&1H}}zh zO;bG&v+W=llX=Vm=XR@wm`#Vr2e&hwKealxd+OgTPlYDx91G~o?fuN4$vjpM53%hb z`9E79>8UPRVXnMT*j8=f8(XifEFAzuZ2`$KyCI{dGO{I&{`?o*EsTA=y}tka`VK60#r5;G`hNR< zbR+ipTzL6PKObXd;pQgH?ngAy^GrKwB@^UQ2mC4D32ofsw{F95wm78Rbo%SeuQ=CS ztHM4XRdDHk+n=^d@#BWmbN1qnrrdZAyfE|H88xpT)GfGnRsKn)(u4(5g&mA0QyK1f zwKnH;h&IyH*0b#GQf~A2`=&a~Dr%UN2Zu;V!7($KvK$w7a5?Om%AUvJ-+|FYGJ-@o2%{Fp21`|4N@DtgTGD-1cKAwtR%C8rd^w{5j1iyAqJQVM>(a zhOg93c|LxdIw^+=XLe_lZ)*>G~3Z=rJ22Q+*>uY?U^ZL$$Ck~OIW~@xm8{Vgz=8) zGu^1!xGvO`K+c&z!nyV9kCC<5?w8AUPcbQBzwZ;yWujfCf(#z#eb2MIaZZ8y3bbAsA z+tGt&RA%>l67JeDvKHI@ve|COq)wI-;Z>jOH=xhNG<>PR>S-Qa-wma*O}V_)9pjR0 zCa(TbzmGAw*zRLsJ4r_hPbvu)rS7JZYI;-&4t!VF&=j=U7B|jYI8WY@&#S9x5~lYx zuRllD8QbxK>QPFhlqPo*3+Lu3o86khahrM4Qo!bMRHi!byW>{B|1qBMk((Qu^q~0? zbkEe4BHppon(C-W!9-lOlG>2%6;&fWVce_iv#~LtcH%gjk!KmVbDnx^JRMEXVZtnM z-y`u#HJzT@vgS-sOEkOMW!I<_5YE{rl{`B$B|PH>G3Jrk&_B{+$F*xQ%+Y4i)ZF_i znry03LUzKa;TbPN-^P>2_t+nsz*0#vXvQ%5Pk8F)o;0=UAcyh!>(A{hr@t8HrO9f% zFPW1gkUGxygo+tVxJ_QVUMGfORGm^0)G=?2daw%=!>BnFhswjJGOs>M+n+HEor1Y~ z7Nhh9ZPn!n_^b-TpKh}IefH|`B2Si{r^Rm7Fh6V`|M`~E_>en1GraN?L%Qnyc^$Sk zrgSh5$!q7oU6uB_@Wji`s9#=D+Zkq-@2z7gp`fzRG<{rMn`xp9D6PQ!gxI5I3u9!Ee@~LT5k&7Yb(e`1Fb@MGsXCd)rPqRAX zHOiz}p5EMTX!(?>-kgI&m(d#SBw|#5YP@Ev2b=w7`&lYU&qiaLT*JBl*QX!j>5SJ_ zI{yB2{3OHenCz-G#U%qcm7~FE6mioyEJlIJp2Fnr66yZ28P(OKyPMXo>GyQMV@#fN z+(PC3sJxBssAoO_56F*GK7mXN+~7FqO0l=QpSx7Lw5RNKQOlDbX*zDVJtF*fjI70W zztkySokeV?bL-wD{e%lpco$-21xw!a3<;k4^)1Mi zNBv>jQTdzgyLKLxx3L{OTbzsZs$~&L6Mo_$yTM~I3@OSDLVZu-h;k9y^z8* z=~0(?CtTCxx_hqZ78YNM#WQB(ZP`DtiW^dBsQ-(#}uF8lJ+0q z!2TD##2YhdHk(tEs3acPF%A}&bZ3ML-|sn0amfWiUO!yIo5v(mJ)9n`?v1yAOC*=d zI;n{~R!SS6sZ8))KS%GVV4j|I=AtexaRW+f<0*=6;}R}9hskRoEk318Od(YXUV7O` zudI$LrArAzLYwrGC=i27s9}nQPC2V8XKeD=Nw@dGE0UAGv&))JU4`-oRm`+5@aoP)5nN7_IAO6c9p-ud0?R;=t_GC%d{!7kMzUKd?wY=l&%yRjAKj#|bLWFMNA71@x z`|)jv;Hb`dBzj{NM|MaJ!3wH}w_Ka@ulLC$r9^x_7y?t!EPjXEF>(7P*oBJ=E;#u* z+&wjv%dXB(U6pWkNpjh%K#AyRIQDS`EXZZp)RM%2mF`f$hM(0Bt2ftF$l{7?PlvgD zWsa-I+c4p~buKII_tv?(P)}Q^ANKKj{kf==sgLNc5+xyLVa9`DU`lLh50A$3)U@DuHI^&8IwVvTdMf$dRltF zahIa~Zu|A0Z-cCY;N?Q8tw z_LcTK{QLIfcia2EeSO1RYVZ5k@BeIj>+9Da`N!@5|Kn#@r1`OSuYR@tXiE)0Qc_)1 zRWH4NDv>DfXzJ7!BFDx|5l5z)+7Bx`L3P6}wrsX73v2##mW(*_a~1|~#o(Kj_g!-3 z+mR^2WfQPeU!ntSHCSRz7&gZ z`qbC(WU3yL)W0ca(*u^e@gxPcw_PMCG9QcMct_p&?XoI%E8ALMa9suN)u7sIBKYU+ zclv&NmS*qy|F+8eHhs|{`21RDb_d<`>wZ{NE<~ZdZu)qdMHQT zoI`g}Vz4UO{Ugj`GD8LGI3Z0X_3QK=*Z2STzxUF4-)vv0_jfsZs=8hfDv5DPh;XT9 z5K7}g8dfvEqvWLb>xoTbOz`ZOcj4T33neHyz_;O;sldn8^-SkIqBk;$A+O=?x~7(R zqEi!^lKCdMdIr-Nsn@-mwKt`+ZNDYkMA4yQ<@k)eN_|uf;v(zq;rL7u?pAJ9W;3rN)}q`1rILCgR6(VXmjoE`RfI zaocm$9)W8vUzz7(g42yF=A19SMcdl^Rc^c-h{{uLNxh+f)D;PNPJ-1)PGOqV0 zhaLe1Z+Zepeb|K^e5EB4)r&m&8Ft{t`wYFdvSD6plm2G7c!L{HY4}IZ-Nct?YDS={ zQP0==u-h(|JR%OJlt=y~H@%6DE}l>6b(_JE91vfq2_NR5C7R>;v(v0*f89oE0@Q>L zcIaE`WGRn#{dCPs->rhvqC3OboS;0^`l+s_%^B$*8I`z2Me!E>VX{Mc*pERimdGapt%iasV=dW!BrFDm_MbKmrXS zds=RQHwO!6NI3I6);!^*^Mo1w@>3*AJbU%kEe`Aq5^)hvgj*t$rV?>bu#?%A?*vSw zQo(6AvHDf=^FD$ezNTMp%_c1@z7&h+%w}WMoW6_ZvZr&*raOiSUDcj{EYS#0d#(v` z?3BWjd6$|f|AY%+?YbUbJ=Lyr-t4VsIVlYFWHwzDS7fTEqEF~^lQOADI?0S6PO4I> ziT;5h`-D1iw}0&an5z2hu5r>uAuc!f58F)mr?;ywU!5c8&RsH_UG>^8!JhcaECs@ZU z6)R=q^_OQXZ*Lw%znFQ`&bUGX7e>vs+Xpa7yoQNe^~>t1aQ2=T)aB}?u!A1f_9vgr zJY|L(IBfFKZVXTvIx5N4Tz#&JNsk>1^F9@&dtW9|ZSipG&RqS~QT;qE^yk;92dUm4 zwxrQZRqT{{x!@2JQNUh#NSR_J%ER{pMItYq?xlvkWzyvP1S7SPOi96@G`0#=`sS>+ zKX-XnNA*%H9(7dV$qd_EAw2cW%qcbO9)^xcMv%TWuk0!cJlRz#ALI3|SEq$M8))~Q z%gG#9xHD#Z#QHYNNnyxEFMH)po2RNH1lero?QoFkAk)h_DhX=u<3#Jkn~3{0a#r>| zVDRXfQkN9qzT2TAJKyhs*`80)XV4aR+Kr1Kr$L>ygQ6QWXY-ly4d^#q{_~o&e?H%A zpY_+<$6|udUgup)y}r+9z)0EpET(od(pr4NvZbDa2v4-n6er2P!vklBQ*LsuhV3=3 zC-y*29Xf=2rJCvU5>4Oky$r@*`t$jDLo>N&QwlVki&{mx{y3I5wnlT+rb>oM!o8GFw)QE zb4q1-U#Kxz$3K*_G{xETq?XG0Z2PMI^h(^M%F%ao2~)~VvN(h@d_v*uIKnMvS-F8J zWqu%kNN=W6Q9BUj@*LM#byBhJ<&#I$%4cliJGl)~$-bPRxjZ;k(B&PvgNk%@r3-^y z?nzmuBkf;te<)3Ofe-Vkd-cg9;$V_Z)O;GZX@d$tS5C1Bo|Fu>D^T^3MeT{0CD-*# zd>fp>Z|u2Wreoc>^cmi-P970OM{J^^?EC0#D0y{!$4_-TrcJsmQ-w4sx0!!jUFoKe zZaL@K#bnBslV`JudWDkXy0Wy%`_m?2s7(|O4Asd6F%6i}CN_=yDY{@P*93y%#Uc1& zcVH-{_Ebs-b3FVUCZSJ`F?8PREH?S+oa%xE+RyV+=>W5;DK_DXaL4#>`rUR-FbgE; zx|$DgySz_@^N(~ebz5HR*C$9=Z1TR@q=ZaQ`S4wAhiU49fa)Vl4yk-nY$6XDo9LWz zNcmFJPCBXkq+J&B_W2#D#U{60Rew75j!j%9rBF=0+j`}V&eRn(#TG;Lp;x^e&dw&y zy&=WIiSH>k;pFqup|x!UzDbvEZA99WDOW?O zs7U<#wykMh-Lt-EX_L=i{c%e{eECWjTyp5mblsco+j*x038pJ%&Af~H-WfJ2*@+Rj z?=I8S`!?5c|JYl$P?|OSY;<1w9QBB1b%W~|35!kMADifLnh=Je`eZno>U7LfC|mwn zoAze4*rINEpXJiI^h!Il61!Bl&yVkN9YgzU_i{(@mRU2s;|7;rJcaGPiTgG_s}krq zj?(7lm}R=|E~CRQPj&y-zf5s`7t2I`zolpQ&*$2#`R`tRTGM8T;=Ey{^5C>Zo$VAW z>45WZyS3)^+TGkQwzv8EUfH&#I5Uy~_F8O&lN*zN+ipSbp5BVm$yxM~oLnDCJzq!At}LFXbb3Oy%$bT=Hj6i;M$%)j zP3g4X+(v{Ns$NoxG`v3GIjOquw?FOEQaQPKmrNbk*6TRMMdkwb5bC1vj(sKdh&t_c z#5rwEN=`17IVJ|AgrgQFNqiE=b^-Nxw8prYL8SK-c(FO0-b2G>mC9Bs43}&ubUT z=R^BY-}dET1)A<-lcj9l)%AU^pw*-?zd!G;r>xt<;WK+!*M|MgzIjol&hEolqCR>yw-wVKDo(YeZj z1v*lWhJWr=n5j=#+$5~)F=ZUgveP)-cTVl6Rs#EYHMPv8K=Y@6nIN0TSO8jLShuf?!s(Yov zXmg)sUO;^uy@k>8t8t?KlJe)7O20o>e_HJ~L*X(Kx(1eXe?-R(b9iAF(H+=%nC-*H=;) zuh2zp>~sF$vP`PnmO4ZmcTbIT zV#eJhh(F8~xaI_2?t-mLdN04E_xGtExE&7xLa|tF6muvkbL{<-?p#nH=8~`sy1)KMDG05zGJma?t;5Zsp@oK z0avt}?|obp6-Y)@x{BLd8mrFe8YW)W4Vjq9cfn`(iFIE3d!JQ(Qr&%@RnBy`Pjq$E zlp6TlZs@;$V%<=9>PH)IJ;|BtI&}w)g0xrPB^tgA&S-v3v6^M;hSVSowVA1#L;<$f(VS>>xC06(S$#6z$6#$Iz(5+-Zj-kpVsz5dGdM+$ z%)z@>q1J8jU8TH#KG99{eE0p^sic)z5gltfQUAvPDLsT?}R_l?@8V#a9pX`om>2g^}j(uRCRpAlb}Ph|ex{>`l_=ZkGSN#*=%`?a5@ z((xp)x+z~H6G@Zh8D65xp{V^8uaE0?)Uj8OzuOKb_nDfeRK247BfO-V9d%Q;@zUd9 z=>4+OQzVs|otkdPOFEdcyJkChCmiY2>&m!*aO9)7(ff5y{;yQUaeX`APk3A;o#`DK zlmF|Iw9Rh3!hxURm99SMkJ?~|^y%IY1?JiCV4n`3^L^D0h>?Ce#=}_$wQ_v# zF2|Qz4nuN$v<1cEb(+DD-p3SD_MzQ5Gsg1d@S7{lxv5@J$R?C@HeI0ur-6gv;#}E+?$tyGdosh zSgMuJ0vfAuFe1N6=T_l(i*&f{;qrpi_pjgL=KXa0_J6*98o}qUe)a0F{`&uHKYHt_ z=DpnyeEO^2=Z4Gs)HvbL=8vkTa`08A7)g&MJENOV+ep!H2_caZh6c0Gz0$#^zMZ$w z4E#oq=*8R-t`nnKrzW2IVzUb0KkA$OgxAijhd;T)VAwuloC~Bp5ZwgB~Cdq zW>RXazAO(3tC?<;V&~ng=em6U>JQsj;hXKN<%!?lZI$|~jTye!u4#O|{r8`@n;JiN zvEI!yhK}@@XM^Jce5JcnZ+Od7XyWSO96luV4>`@$RYAI271ST}EHiyvUN?u*=LUP% zC-Ap?V^k15GJ^!KHSf>V98aiCRD3xv+bT`VnqTO!BzVkG>74Kk zJjT#+ik^E@^eGbTkL%5Sz3GM-Ht||>3@;85r>Lwbb;NsCS9I;1Bzi=ZQ&(u+W~|qH zsN1y3>X~lsnckOI6cSy2YXZ`=UPm;AM2c8d<2~k3LRa%tssr+Hk{xxu{+|2Mnd$kt zp1kgRIcZ_>rC2=ENnA&rSBkkgmkGoSvvGg)O_GJ>4=EwLG!%3FdCoW`B~4}q!Zo*- zl}Ari9pmXtCoMF+6it)8+m1xj7+BCZae8Ku2zRi><4#Yhu>2uN)b)4C0@^qM_^kdd z51f*>J$Ma?Z~BzK-+YxXH?QSiw;%uIEe^|9uis0XEOg$A&db;M$OZQl-u-%u8JvDl zk5)%GgD#08Q#1eV9-Yquo}mld<}UdxC^+xIjS>Xi2ZFcj?$YINzFhDL=koIPeJ--R z-cl-4(>t2al+I47SuXW&I=fd;SvdXzZHB>gjV3Je2Rw?{>-x>ZTRo@6Qn#|yo87^6 zMHW*%%{Xxa?4|QEXP62nL6AyVl3NneznDs&TOJqQ_z(PuJaM{A1uW%#tq!hUb9SaO zqsV@WL^ZS9yI%b%W^=JYT1qmvl(pxNbGINd$6RkP?AWSarZf7!CNwk5Mol%dQzy$GNcVH%F&pIU(;3Vr6~jx}ZyND3)Xif&o%NcJ zIGdT}r1rGUh$&=x%Re(1(vwPq>lL6u{Zsww5>0O4N|wcCGic%ttN5k`Y9<6;-&VO* zZ9O82&UI2qu(#yvFN;5StEzb(SHfIRUH~@yKQ>XjbaY$=6^ttPEBN?)EBh#+VX?_` zpU^bRCT-NlCX$zJ70j?ny&GKcl;~<{fTlUV!}sK+jt#@KIYnW2(-Et1-;XhLu5cEc z^aLVb=U;8#$34|LB=Es~XM0uV>WW&zKWs+A0pddTq;!AszF%baqUy-v(k%Tt@8v8l zAN)fl+1>{yc^Yn)H`I@*ysn;!Dz<~rvscO-wA0NgrI-C2)bYU~Rmw%OvKr{SkMXp+ zuJ@IMsygl%(z)w^^zBnQDEwl}sOPiCK9W#5-0tFYgnX2@A;|0mcj>|OVrF_PRms(T zuGT*5xpo}rx!M_mgQ?mic_)F=<{L*^C*Jm)|K{aj7jZCzaQTpUd5 zn=n+$Uni}%nY&*ECGg*EKSK{YqsvmQK2pF=uV@6>H+Q!EbgSqFd4 zE02w*+w_X>u%6jezdAL+)aiKT%VxlYs?#i!tJ6g*420)=Z>u?7n)Ur%*L3FZoiohZ z@&E1io%MY6JF9xSI^B+c{S$w8hMj0&^HmI`+F&Q{VeI5RZ9JCyP;b;aGj=~`k3jcz zcDd#jc3N0`85Yl&&1Um&U$cujC}o33raCdXF;8%}^-6u{wRC2CHpAR46|F0zWWIdO za;0qPCo1YUcWS5RX;4hRtEwuh&%~eD=Vt~hEg}Wyc2_E%Q|V*rtB?KZb8qIwCRu4m zk-a9f%977BoTS6@x|qH6bQXJ$&Aj}-N(e(DeZkQ)=7(BSqbXHH={|p!d34Ft$&|B$L#S1pvS)KRJus0L;Hl`nOEY&{4MKB({5rcoi%mWzpIG&wa9waP z(~-{f3eKn#?7)xF|LBIoOS?N}4Q2i?htET24?CDeR)@<2L1!2`S0{^2exA+Qk-){F z1bDIf+ZiOt0r&f>5GDOMNOc+d32#ASZlBpUy#fQd%l2&UonWs##7pxK^9o0ek)^Pk z(=PK266q(i0arNnMI1vFES22FndVvMRTxWuBvsE@G&{vnE1UB%UOa1NVM<{)we5S! z@~(f*;K?NheUmB|v%w2Y<=Et;n1$j%yMwq5aE=Y3j@@MU|BZ;RhTm_H(thu=r9eo^^oySn9o} z%5+ab$2EhewrolZnPaGwykE$|UY?P~3(yUQCp?JR${2OcVO`h$6!X*}(dGnZ(>vgf zDI}_y{tWlndS048tLKfU=AcuKq$F(DAp8o+S-%=?muCBTHJeuvvz0S3dutDDhS}&u zc>;Mf2?5RnUTg9O$@&7jBQ{z+gGAy@*U*M5JejNgC|q-lhBIDyM7ML2Q9_U@h>IPm zViU5N+Qj+hno~DC1v7hy&7YDEp}*rBj=HWAp12Pt|GWhb)iH+78RZdCbj~F?OS09z zK2YF$cLoU(jndJ)@e&rLsa?UA_i>2F`Mc>m^ zs5We-@E|GgwWWpXnDK>)V9rj=BK6TuhpM73>Av}gWrogb%o(#RpYWwV;XE_h9g`5~ zQXXYG!%VJ4lueXCODEfvZ*vDT@uXlrR$C^LhTJ-}`1@UePc%r^Bjt0`tPH=);g zjF^qWk)Y%H%`hA0$`_ZkrqA)4q%9<>sNQEr!ZYwz3N8OgccCU@@JQ}gFT3ovGZQ8 zdWkBi`}?arcln#ITi74w7WUhb)mFd0eg;>(C%i+KbsYp+_WEg0NlnF?-8D9Ilh*p; z^?&^upW(_7d~B08Xi|N0!mEY+aIcsd#uT2~B;$hH=}y(_Axn|dXzeFaWGQ`#6m<{k z@qtCA#jF^Qsc!IO(raeJ!|3vf zj!xEqwz@Zu^oSL1l9P4}NY^n zoPngJlb(O$=1eE46&xZuiDsfl=QelwQC?TG64{ZSSEc{LCNz}SpCi=1N~vwS$^Le^ zG{5o~3Cjcj<#^y1#U2v%Yjyuz9RJSLHB)A@x;9@V3u3A2nydjwK!5Lh!q1w;n0>oC z0I}{0ob5)P_ijtGzf`lIGaK*Q>nFFMFPCul{}e@w@E_tlz%+^L7Q(Gl;)`{r=Ckx4zz9g|D_t z$>t`vVu;o*_d?xHVaTjk-BXRLjyf^<78vSAw(3Yb>Ed9zstH}@%NXfQYoBw{BckXC z38l1isQHRvK-V=>o7~3Y5UEZ3EgRaXq=0;_w>XGisl2AVMTmePOmude;!GtyA_}H@ zuBQm1v}ql$t|~BtA-=Q?kGw|}$Lm?A)z5H*^zD#^RVeee((Szp+wWkf zbe|$Y_ucGZuH({am7R47%RHiM*k$(B59(G&R%cH6@|J9B%WundQ#HppIOCF~a$l-) zXBnv{VPPbBTMAhcV}_B`CA0XZr@AZC)UJzC&E+YvkdN`R6pu-3n8a9geumCI#?u+I zEtT}{Ixe*_43&iB5}R+#?J+fh)t#r9>&tag>818&aZ-MeZ8o=-n&9cT%z3XTA=mR> zzuUe#_~x_MIznFUPp`h&o=S0)S~MlNAOV}urFKB3Ixf#`@EY?3p^o1t=Tpa3<_tC{ zYWyPCXp#?~`Z7~|ld}7`WL2h@R;Edn6eGDv=^0q`GEZ?vBgvw1fw;~4Znl(TJNwW_ ztv4Ov3d!>N{7N~&A|&3QC|XE-DH6{$l4~MfM=pS`v;J&qn@+Fi*+TfLT#_!Zok}ia zR|aKfeJ*&-JfBjRBI&ckZujxp(n#-GBZZ-KHjhUhW2$fC0@?h4B)Z3Z-lk2Xrs|-ZCzr0pq}*@Ps>UAxd$-GNMQ&Ybh}%JFQq!wx$!4>L0!V(MyiNmh+b;W z(laQyOFiMhEgUtQQis4}3@w%P5+^An=x5X>mBRP(6cTiF_=A(gwW60xn)Rx;|B7+` z_BGc)s5BZCXFe-G#8)~-!Wo;a+Vs-eG|NdQZYKXyB&is@G{s4-wRMvO=G`d4Lv1*= zBeHKL(d%s_scv}8uaho1)9dG)w6OS6ES~8kP7XYAle!*RXFh``6TNncpkvQ7>i01l zE!3W@+qGr8d6Q}zthpk=CAjzM+avk_lbp0;NE(Gc@(SaC84N*$I_G*|ny9OiZAz+$ zZ2)+$w@hW4tQ~(BQYz%0aG&)d26~`4pM!hk|2^^;%J(u zmE5nJ^HF^8y1V=&yKTovJZGe(k|tDAdfNuJj!%-nWTJZjGt34_rfrO{Nj-?uYtq9>RC@Hc70zKz7# zgqK7enalBzcugu7C%g2l?2@U>eQdI7(@Sg9Bq!~cMRfmMN1U(X%pkF=?fw*bY?Z5L zF4z5c8gG5SO4O!^4!U4_7GXB*f{ zC%wO^o9eh@2q&4V!p~eH1u|el)~Fm3_o5sMboFcsid_0cB87{fVq+zaBs87f@H^+E zM^xKqIth31rnyNjIWz;E+6LhkO7Y91b*HFocKi2sj;JI0n0sW_0VQUyP#~$)g`?x@ zwAkc*vq?D+6^Yj749(5U?4otQ4=b3GNw1mS(mL`U?aZ2Qz>quH5V!9WsYvSAF@_eK zJa>j)T?q*$r`X$$jw$<$)~#aD)Y6W*)7+Z0E*#J+5=lLoq~2T4MH@qeEuniSU90PQ zsnVV7x~gk!IZ~k1sEpbS5_2l`O+6Pt4O6w+-_|3*B#cr*JRx&nUV%OhPEF13=cI+j zmtyfYouu2@r*1Yg=5$g#X3}O7Ti3PE-S~*=9$eAPJ=KQe1WDbJ=sMqVjXTpx<~gP* z)pS^vBA~>owDt#b#_d|lnPXMj&i9?~2Fdc@yronA)7Bxo_Vdm5E56>|@~VBd_0j+O z`n{iTSAo9TKH|q$|6}|4Pv_~^-Ilo2NppNXyj}-4O`(a><~%pE@aow=3q$&^UQxZ7 zu1v+Gm*k7u>*rbe*<&=FE2hWB(`^i6W+5eH{-yhw(oQ8TRjB`;y?g7CEIYEq9Iq6h zf1rm#0Ru>Yno#rJoR^knMo-d=AoYs?0g0@tB$*)VqRb*&)L{OSexuG8i<{fy__=r- z4~tBX*ho~?NspU{pXFxDmMybQ^;326kY%Ssv_nxxr!^cqr+vs@zS4BQxU}ca-;Xfd z0n|rvCYjN5^0T9qQZV^RY?s9JDedu}1f$se&le)h!^rXSaeKopUUn%10Hb;!df}RQW14U3?q~!lGSgHE?!qfh9;iE$!Z zc7EZ5I&iwdI5cm!if#>w^E0-_32vY21UDK~PLIerZWx?gMo+Jr8-S&piX?VLH@CSK z&hW;zF|f^pQ#~`|n{7E?szCI2@Aj6RC1l~l zb!wKKf+j7+q0|QE<*+QsQYE-j>xZvl@2W{EtapOEs^(ln)}{NF29_?xlKXY()}~WD zWv8IKhFw=hD!LW#ZX5)>yO=wU6-E{v$-H+I)9`t2DV`|58TaKLo(3a3kIVLIU++k% zVq`<)!9@cCKqwrGu$rWk}tC_w?8mpd+UL=K2ycON{H?0gD-ZBn#6>xLe zPF$=(BF6S^`tG_H;velTT^|`1-lFI0Ev1VHyIg)YRH;kl*gd8Z_h%Pl~GFhfam7bFcqI3%4 zMC5dYA#?mRHduo+yq?ykJH=hQ-c28I?P(d;yyIEbqv|-s|8pi}SW%VcAv$6CsV=Ex zwiZK|3`^BW_nk+`V>A+2RAsiWrGRW_*rB049s8eS@v^vvr)BzDru46x$cFWcQu>;9 zJEpc2P2tHl8hKK8KDvgeM!$tZ@lYHzBe0F9!Pst>u?2~ERQ7IF27&yJ*!sJ1fers+(tV#_bv+}%UnodlGPZb4k zlls)Z^#@>3PXSte-gb^1k?m7Pw&pKV1K`^tTNR$NL5VjgZZuIW+fPL{YMZ(=kxeyf zF3vfa{`Ps4x$CF%xI^@@G8yV8>Zgjjo<$;WP|f?B=>}ach?e6;U{%U_{8*l?`#636 z+o|XE66fmFk?x$oZO7ocp}6~3O?Ff%st2hObTaphQ!OrT@z9lSCSJy=;j?LCx{vN5 zFUH<>jQyDO8d0=Y0X8J40Nn}y)?=(e0+vLJb*HoIR-9#lg{JZ=dal}B;rY;I8@Z2kUj;0Dn9s2PU|}@Od-f7{9`@}fgaOm5|=Q0 zdwaG~xF3&3C$g#&87xt=64g}tG=&;G>0Q&VoG8ex0WrKcZT^j_0b|)Um@9l6Pgf(_ zI;b18ji(XSZZoQx1HjRp1`Y|bTa^w0i4cf!b4#f2u;B1y+9`Bm<_rBNGAktN8~Ibk*>r`}iL|VA zz$snkgJDv9O|q-&p9l+?G|NE|u#Q|DN22E8LX#m}cZTcwVr2ZZd>-ya%N9l|g&5Bp{{6HS%|6EYyumRg=F8L|Gxbmh#@k1)b%J4 zywIsDW!tD_{Pq|b#R3*^F@GraqS5@B|1iyRe1DIF{EnRBdpaSf5yd#pqimF^b5zRL zGCj9$PO*V?NEc((F4?Rt?_&TQz4iw>>CtOuUkC+hyeHn>qc)zuHxu6fI^n!;Ieq^3 z#LusMPq@SMJJas*KiUmS$Ab)yWah~finwW)arX4d$0{YY?pIIvp2&7WKLx+^GirDT z%%{?Vb-$(ef%m@O+;7FR;ytOJk1rHg@tP#F`23M4WEzqDQ@tnr{I93{@@{%JzMcO6 z*DK!<*>+^cS&bB2V8E%2=+;rQWfS=#h%h-}(o2+t+O`|H=b>X+g6}@+gxDNCph|b; zR7eLplR>IJzhjt_kEK)WUEtNwNu=9j;<}CeT)uKGOAM#B1V zVkXzjhNlA{+D3Qv4s@mWonAm3Ilf8{%HOiu&v%eGYQj%f6E-}V0MR8+Kd?%7rCH(h zVwjAs=HjP`#(;$GwaT zRy?PU4?FOrqoj6_E$h4&)C{@OEQbhXYRF!cbd+?(b(D0ExCdQvq>5+oXTN|tYcEso z^~wjHoN;nQ1G_{iio=k4Dle%n+~Jz|gg@#3Kt}pPnG=E{F;c%>e1f{TFkFdRvMXhc zmbHG$Y~QCawxLvYE&FS{y|coW9bDS39q7WzavnsLpMo~850D)?G{D+r+^ztUXWb9I^COF~A z(Z9;fhrGpu08Od`nT}eTJ;5TT{slElEb}il-!_^q(MDf0p0@h?J-&$A*_h<6RGqVi z8^ePt%zPK#j6a7}N7E8tD4uyt_VSFV6Z%}Rvc6;R()cn?Svz*hn(k?ZdT@$E^_}|M z9hXyTVw3LG@*K8`z(FQn_;!eSrQq|E5e3W)Y>(u+p& zRp)f4P+?3k5?`IQW&iwXK-bQK=9hF*PqsyN9y%$Y_w5RgdpLYFUx2r%M zr%G?97U0D3s8sdoq8YgZR7x&aOuH$Tv;)Y(al{$CTkeXk#62!EnJ~DP?YwqG?MIoQ z0tb$>4Lhjv2H2_>1zQe@7g#qf%A-8QEv=@fbwdSLUvt${ynXhy)!5TcEF6h4kD0kR z{r;b~cPUZE-wr%a^0OWw0%81+1mIEwW-(H@vH>h!$#2X9-v++^7qDK+v}yr_)g@PL)n-@09Rv;M5ymd-|c`TLvr_hZbc zmws~38}uJ3s$Odx_KWG=+xe}2xmgb#qI3>wVhkPw13LeyqGccvges$64!hwM(+xFw zjp@dlAGe0R=G**sFUH`=vftCpv!2#7%c{&Z^SGzq{Z^_a&MaFIZ4Pm_t9T5~B4Wr< znMPJ;Q}CcEii?betH6D{h|uIpUtPA_b9wB?nAeS`Jr+X?Z@xl$udJYMt%)%7T;49a zO!AJ(r*T_sH@!%Xdnz71PyOUsn*6cjLu42c=KINm^ZE6-gQoPjRoptxl>Qnti4Wq5 ztf(qWj~jxMuk4RWHSQV3{fx)pSeS<>1c%#b8WCoj6JHi#umg2cSd4$wV8Wd?QK5!b z2a6%tOnihK%9$#Zldu^X$$u0gDh|cYo|SD(3=VU;N9Z}Lq(qo7;@sglx@yp**2YJ~ z2{FdW63~>6bvhX0iW*zg5%XXzyjgVO7QFuCg27?L?6oSXVIteUVS^r1RXhJ|LPNIa z(D_9eTsE#3RZ_Sv^-Q#Zm`vSx_Lz))4*RFQ?nRifJO1>N+2HDQU$Sv5N?4pP233+bnfC9uzf_Plp$4^ zBAeXFF)8nPOvD@hlaJGh1D{jx<`hqAP29!=h^~tMaE)@2t(72IkA43NFzLb6U_uwVb$LvsZFNJ%!r#0xx{+sk} zaBqx;bKe!TQA6<^nKDj)d`C1?#kJiv>&(0V=8uU!16j|3EWUv{^@+NLH*;}EU(&lV zjRslCVU%~LgkaY+e>@4MJc32@G_1v~OErSmmdPGd>1VS-G)Y_1WDb=+-&#$);l@o4 z4~_fZO{Y6?P&iHS?bK!Xm+6^(oOYHiohR6SlZPh&e0}mA{(1Ty&$R`nJ)3<#glpI* z#LXQIGClvA_@oo3|IEXZxihHBCKx`-ponwZXJSk7ew%KDz)ak)@9t>7_v7$X7q1?o z0e)=D|6%(7pC=r_)Xx^WIqkQ2_|>2KG>P`C_A!N*=);*eQ6FVOph{B|Ei$2|V-h~y z-QXfudb?OpCLQ_1)%T*4`kvQwT?P8|Oz0sFZW~39=5z3Fp(?^MdcW@vh zI?i-DHi_3?+wD9_1J}#)cX}m>Y;}8Vs7xw;Y~5_GnTGg?#WsFq*)f%)$d}3@ssZjr zHR4de6jh&>U*&eW{56P@J>|2SIK?9`H|ow(HMrDin(5|dGnVKitLnsMUXRy~vp}|l zxpn5%fAh!o-=0h1eEFzy3RkwU(Hdkw6K|E%ovS>fmyoQ?qCeYDZYo@uh2} zhlj86Y~o?@wv0IS^&`%N#-^Sp^PM9Kr;+!nDn$Jkc}(4qX+EA3Q#3)8z1iZFnZ3+E zz&J!@id=--n!g%x>f@x5{d9V@zMpiwr}aYh*LIsvQL&;s&>NlV#!u((n%rkE4lRp1 zni+IeTiZ*ZzXDUdCO%UgneAaYts88cyYSW{E9rNkxJ(YmCgFShKhechNnonmZCkn#YHlFsU5nel@_M(g&(VVv;j2KhZ z7uMCaM^H6pOMwX$nx$%uJ{rdXMcn-tfmCNYE%py`pm_XRpTVf|KNpQ$R0{sM*M2(P zZPiniKCWAr7$mDfpXv_ZhdxzXrjB*^lC#5ON1o`fhq9-cPT@50mm=RlPly zDamAQQk^qF1y`jCh(d6aP7CcDg0dZi?nHy4hx4*T(S#=*KV80j2Bx*0*G8}J%jwm+ zR$H3msFGa;gK)>ON3F)5t74fhVon0g)&#Lkc8vdAZjGZM6P;pNb|IS3v&9Z8gW+uy z?z5}Wb3W2@-s5CqhYp{U1>`FCOub&CAlRV+u`~o34wk3{sr=NRDnH5;{YkebPAlpr zCyc2m9^q{)?M1Y~%04Gn)(~j-i~JT(LEXGVoW(f4ys9psD#)bJukRNG=JaoMqMmZL z?NLb0ysytYT&6vYSau|qRp!*7P-dmf%U$WO)Wkut%w`$cGcI_VTbsHuyCpW#G~g{$ zqm)*)M0R;n^7l^c895bVo}SxXmQz)8aw>jCQ>}_;7x4f z*@|1)qp2A7u(X#`U%U2I8=KnHsk5EM1RSkOIrF{cVN(>rlc?xFc(NY|igNM~?IM0G z7^mlnopSiK=lqNe`8j1sE7p{z;C&tyjC zFwACT13$+XrQZ&Z?Mh)}$mh?HnQm5fW=0I6vj3;5-$?JL{qq3o{m{{{sAy)C*Z8&6 zq_8AgQ_*;F#4}YV6=WMrdl_;>w9hS~H8+mRQ*6P}Xb?3KEjq2gdAsCL5fwiZ(Xwv{ zJJX2@` z{HKj2GpRAOs1&xaUXaZoET86Yt%cXyRR|pMx7wrLxU4n;2v!S*Ibv z`}p1TnI>A(7gFn~7_a3=LzVwrRQXc`s`lcEp#W5!W@FAqMiY~gv9R-Ojgik_Uwra^ z-Nr;EDwg>k5ekpmQ|0%$(ZJwiF?d-d)1S7zL8QQct0EbXm;N(`lSybE4H+hkM8v{K zuojvE)~)x6X~U0DlW`#Ub?N-JHv| z4F?bB?a%ivyj+GPFS@5~cc;5olNF%?gSC+=C--sIXX`7@+gzpYbK8tYnUbmfkyH0o zgG*u(1>&`$X+OUFazaGr-u!|6p z`#mqrUfng6q|Z%Bq7#ZsIoAOS)!S8BPW6=Tix2VHW=D%GPIyjCzY~_snb2GBAUzzM}AIf&ghpxVfwl1 z1fM6isYly+UYX8@$7?4y{N&Mb{_Wj=o@$C8rX7Ia-|qml0ThORJN@@=+HdoAnwI?2 zbp2nZKR=n?|2!=+PtLCL_ZQP$lodsk#`5W%FjZA)%670JH)3L*4-TK4=%d+jWcmni zi|56oX0$1Z{;x@pf+GV2`1X9?g$a%n&JloE$Y`$J50WSQ1IFBRNSItSYMH3`mTbN+uh@k_oM_ zqjsutrs^?mpT)i4IqA=Meot`{>FCld=NYbX{a;h_CStt)5K(vPo(`+|1V2xYm0l#i zWX4Z7FPgb6Fu02T4NYD5hW|--kNfGm2=f~AOjQNnF{GZscku>Qa~0p!Uy*9Cu{jUe`kM;Nz%Qks{IQ7HKJ&Xt(+nu6T{K$yy`VR00>am#5s$l z#P6C6Ba7fL@g~VXaAJOd&(;Jd9Z28!x@a<-Nso0VJx44`KFcmm6;%xaIllKQuhC;W(qpTQW>DC6z~o&nmeioo z1aoFXIDO?)junh59Xgp-G{dcUeN}2Y!E__qRdVZ|M{_@#4ICc9;eJHR_Vnzg;xodG ztF$DMN@j$L)OQ#cjT)Ay;p#ij0zc$l!OiqVqAvNG>o>^`EvZ6F3eyjoblTi!^OE>Z zO=J>-RDHold`~!+Oqn?tG0J2VyqRb7Z2a3Zl|Sqc{9ExHr#y_c=_IMeG!L@oCbVVch^?_pC&H4#Ro zn3F#2_LQ6aL{S8q^fr^P+E!xdl0D5i>FPrxzrppD+)%5x)aqcOojB|LTgQiG9I?U{ z&rA#XcU(hqk2{4A!;PxUq?{Z@Q_6gbT^3*MU}7)A3^sg(4Od1cE^Cn~{*H7$>rkk> z9)@MYk`6#cf-;ebl8IAOl``X^Q({^!ZZ*uu9@uM9IPzQ-lU5C>@hMF(W#f*lSCi+k zU{TZ0le4fUbzpk@*-ss%$?iHmeziWtiEZ?Ck#Df3kCVekZ~pU%P2!M#ZswhE@Mt%x z?kWc)?a@q~dW(n1J`)@}XF1?UsxcXi!Wmz!o<96R6E6z}KUmW>cv`Q^9%4d-Nw2~? zxJpILel9V^Pf?d)$UJQF71aq>GTG!`Q4v$Gi%0Zt=-6Y@d#vd-c4uoi&qEAl>jd{u z6rY+b70#0iKX`$NoX8RPDxZi+BiRy~(ua#vM6AJz2IsjZs#Ky0E45`%M2c@YI$aH# zIM6WX{0uc4wDcV&Dt;L9S#V|Y665xFb00z0T9%rhw|M!P=&vD4^;c)>6i%;iV=t+! za0gzZIt7v2S>IL19&5pN-TS!FqU=OL%z3Z2M!=111{n~7_gspL%T6^Pn1~<#i|I99 z!USB1`!%t`?ml;zmW-=fhqD3g%POTRfI? z*}G1RNY4pNq|a7u1vO9a&dN{zWH)V_eAZP^+hjA5D>bz3SDDy{2KwRHz4qMagjMmD zjzD~(orr>$)*(<<5>KK#tEBCAz+mX!elo3wDx)W=uGY24Zd&Y$%ClZc^~{`eqA%wy zuS*T=uhTYzNpzwO#|up{= ziE~S3#yv0M(0}z0beXtPaVC$5M4YK>_0eVX?Wfpry@i^NsZ;E@9{72PAN(OZ5@ad& zss=-9?54Y9L!(I49P-(SATPPIcnwCcW08~H)c*SGd(N#rHFym}Fdd{UUClA{v#H~Q zUCO$m{)f9acWZk;&3!u`_ucdvKTcOKYwzbg8U;<*PEJm!LKALF+tp#hj738Uqx z5T$CeoOqL6#84ua#DOY8K`~WPT!I=pGsa{~QTBh@pg?P?ic7kzLCn(C9814Eh^3#u z3M{F$;fbHT3QM*o!YcNolDDBOo>cSi)F8SeoTX>Mo0@Kgt~&qM_2=NOF(%I^h*`Rt zW9c6+#?lYdGyi(ZaPOu(_v7^UYshhWNBmyybPbm99$P!JaUtCd=yk%cy$~`|vb%ibC zJ&=IC$V-?^(}l7(Q}r&&#RGWlKI+$qgQxFkonpxTAFR~O76fr{R-N3T0$15lgv1FQ zEsw;@uHTP4>vDxf(-TAzeT(dK@s)dO(Ec3XYedn0G=T(nz%FR7vMRR<3E5FEHn@^a zO#kxzi6%6jRNuOvGK?-2%wRI&3uU@a$yutC`eXB~GAgF%UGu2IpP^39;HjCadj^t@c#$wHIn*Re-qo8=ylDjhjXS1$uimqi!RJg1Gtr%7gP%1-G}S*{@vrZc#L)AmM{>^BQF@ca8mZG~OSL`(gM{@5Hdx6+wtuiILu{4|1O%YbZ@8E?_PDjVr^ z>vS$fjsDmi3nLqyW}~p%ICEqp z^8$QRYSbFd1zVL@D1@R2UxhAcRN+)nG8An_#iWkUJ`~T(SK~M9by9l|)y1BUt);8m z#9MpSwj)nRi%P{jCRTyHR7D=h$fjI69mc|)#kCiOu1)-MczFzO!C5jt=VU0TsjG;V z5YQjHO)P{N;B&O*OArxHpBmY#tzM~OF7#GBmac-QLIL+mI^0ekk%_4MnX>db;ZnX* zjT9Ho$V8vdbZ%HpVvFfq`pQqIyX^niLzQAD*YVMOGoeD|oVh1^OQ6bhjUEn013@B> z=Yz{oVCc4Z&!~&8nWEdOi=wymEjKs!R&&yYCMltEW3>S-QG}$2>gQ`%)+1L+{q}dL%CAyjX;(1;`2C zjsL193UN_!H0TJ?Ww2T(iuMZ=9`kq315lOQzvK~pChDH4@a-t{DfPPB!^&ehvHZ}s z*1!!`Q59*T&B#}DUcDlnXv`_>IJ>#@h=L*PMJ%Mrh%(8~EGvKx3_Ae*J=li=qPXGFDNBKF&4#rBQtHKVQ zhvO5o7IhMFS{H(5?H$goXQF{}EZ)$BD28H_xV(1?z~Dty^?XMRU!1;`dRqlnb*46- z3{N@b1`bqNzn=ad?5MU}QFqKBi$$VNc9ZHf$W$=BmaRT@-|F^xbQLo?#TsTLDuo+W zZANikAH?JjZ6nU!Q-WWoqSWnrD;QI zF?E}IOvb`?;`YOt^+a{msf?nNnoW&It>!bPI#$gOFR|tR*vsV2&sDee=wt(duDd){ z*+=CsOI;|Z!4LX8s1#5TNJZ3l6p z-FkNGzxk-!o*O&qgy11Hd5%^d1T?o{>ak3J!bvnEkE;3OIuv~KA;6MK1XFr&vr znt7&M@53hAco);Nxqd_d4tTku1~FJMH!8OVwTLI#o&s?Pd&ZhX8(A%SQ8t*W+0vEI zw!yV*bzR*SriKA6UCo)%n9KWOx_dHKFoaX{3E{Hd*;UT5%wFL<=CCN$JVAP9Fhs$I zCMbp{%79b-;$ZbPn3=EK#?bMovxJ@g*lnX|Kbl~`P~mhm97c|)LPAb!v=2pQ!B}ix z;^Kh>H8>>bnCYLIw6W2GY6vmCuEcL(enw-lkKkxU9QK zBaY{SlU|%i%`B^^kkY@R<%lKjy}xZshJ>fsdb`%ITDtfBvD-#LZ7d0b#1eNgyRfRd z61b0ylHP)f2lue+O)SY=L?*?znS`%f4$!; zmu}`fBW*Dgdn3J9#gd$$N6+VNsOlMH3dYoBoDt%Mu0i~!xUu{~5w_PxR-wUAfH4#G zj|?=J$>VWQ6-_#Zut;t}@7cJqYM2TBs*1^u8r(x)6+%Q4%$jNsE2?+-iicgEk})ZE zaptT=lesc?y(6b*q@}Cd%2NH+*;Z_`k*3etWhzovx-QF@g_6xwJ1QIuMCO4DN*grj zduIyIJPj=1Fd~o`s0O|i7uPv$mXOdNdp(%I4ZQL-u|h0LWrBTpeY49d`NmHUd!@YM zB`RR?MGg%6kWcsW&CoZ9`URwB-fwbu~x_QKJ(JmJQ^%bbPs2YIZU27x~Ka~zo5j*LBSf` zg8nAnU?_D{RerY4pq~X{YUU_$nWONS9EH#7EaFZWi?8xWM!Gx`UC&UKP}d)OnfSYu z$z(!Pz3g@1U5JWbm$fhz3O;_4-Hdz-G7~1FBI0LI4^ii`%LMDC=2HAQ{Hct^pyOqYwbRU%~rAN>=n+|Y85$71$~*r^3!#kM6;YnWk$~|1Fj|eQGPgS z*5cH4eWs;o)E|49aq0Q7rgGwtaIdkis<@^evmH51UF4$p#3xGi!O=a2N2%^~qjCQ3y7S}v}s`Cv_FOl=XYK{>3+S02+}r(fXr zvM8IM%C!&G*ENMa6@;1lW3@})QMqYR4yNl zLkOqG%;Z6}NYy-H@0ToH&G9mPsnpQSQ2b`Xkb4V5{&>8qF9!u2h4NSGKzgUj4~BBy zDK$%MNxew7!0%LwdU#Z>^}Rr;5|2lnCG7OaZW~2=(S)uT)jt=FA?kn=ZYo^ zlD!!EA#GAde^$(Z1g=4jAlb(TR9D$ynX{}!7G3_TEl{3CV#dHmnNV-yuh>3#1DB%?^XtYC)ufT+lp#B7@_Jwj6Bu6i7IVe*9I{R z7@jzrRqmJzEnBRqtB#g%)E|2}h}w!Wr>IEHObfvw>uP2-O;~80h15qAHlmDN5>)ss z>^1x4_?zj0sJ{=g_;S^OmJ7tWa-Jv zM7CeVb>@87Fy44Y+(Ag=Rm~nb@rVyv#z$LZ8}{gx5XlR}Chd36e?h%x#J$rl`af$WWz%lJ!GEwqH9{@6>w(_Vz(K-X_hu2He*HCL&*xKPfO5o1)I)D@f5 zT&a3e5kZ9bmIs$No`RX32gMw&GSRL9r$^DOSVNj=UL5k}WJe8vB97}I*xeAx(Iu^5P|i7-p~r9U=D#NaEP zuXJ~1)D<;uRhHtZ%=QEE%>AJf^Etr~y&p@_C(>DVE&vBbRp$?!LDVWGcQJ=3?H;qy?wb>)b($$D2 zYGd*LbnCz=hHNbNDse*BRnU}K)v=m5Zfr3^WdlR81n zhEKU=?GyC-4Zfnq#c}FY+ljU~O?NJFqle~rL#v|o1`}#y6?iOAaer_`) zRV<}fI!jmc>~yQu^j`Ht>1s}X{t^GdNew2b@$i6$Whipey?xt76L%e)?m#kEF|@3U=TG18$)zjZKd56Lgug-zfS@B8o@x*tq%K z0nS^>n+}8iAol9{Z6jfDmQTf55?5&NHaMuJGrL+7SJX4Ijc!xeu84sZiz~b-=?Qoq z&?HldL-vv3Xp1*_@@HK4|WR9WiR`M3_F+tg7WDsEIHXj9b_QXgkqZ042mmF#tqb<{=lT)8F= z7tuuw(hq_MTHL;0a&VYW$6>M=sCAuX6#kN$2t%oZ3^OA7$Lb(VH-0&8PmIBAP#oM; zJL+%tf`%XS*KOyk!C{V{pOLJSNsr8^ivKFuI!vf}be$m~ogj5^c&&JX&0?}LpQ~(G zR5f$<%SxipHYP@d`Lq$nyI$9keyT@P6JKbvaX{$@MY+XJR7O~`%322F)N;kO3qh&3 zaUWRR>k^Fk@)Yq!htVV%tre@S(&NMjsvrH9x+cGFW9*2Ng@$XtYEyVsK4J^q4#&k;>`usTImpFxYhp_nbng1_xO_X^h4+&O!U<28 z;YZZxY~Xgp5UMzfxBw?{RpKmSOYjm`TzuVn2(COPlEmG>k*i-cCK8|8<06vqnAl87 zYl-(ZuXYW46-}bw;wN$nKa2m8T|AFe$2f_{)W!PF@F1?JtM}YaM=PP;BV4+gXP41| zb|-moPjRFJ9gm|PO;tpJT6tgXoZVsmmV<(sucnX7N~*EUqNPV6m&Fm2F7!6zJ<3wz z*$Q4>CX&|ki}xx=i>Tt&x24Cs+TE%0wNUcie^rnO(dL{JL7)^{k#kh$7%k0TJ*1BW zLv)#{xuGQl^v6b2ftYhI?n4}@qp4vkjXGyP21M6~rksZY8;z&fw*paeSfYx2Oli>} z5LJAH>N29rZ>M+EQ~Gfm8tg$Wq5jy*K+`^F(HZi)s)Q(7aUs=I zLh4_4Hd}h|6B-*8HT!ICL5II^n;m*U6esL31}-ivS2>{Q(}TMo?RDePE>$X9Gs1LR~|Sfa1i#237T`xj>Y6e_<=6tzWFh8?H(s6)WfjmdDmVCk7B zTJHh$GkxFO_w%kl8F>j;{jpm`Sbv>p{6Cpq+vUocw*{xvGfd^IT9JjS<^XUP_ut7v zescVB_)PRT5eL7e;>t=qSlN81lD55tUtzs#*njgNN`J9t19I-=WPBx)V80*h6FQRa#pSMBKB5*e+@YMHDBinIH95t!q39*2sEnzybYl8!yh#ckEb-L-*c=f81OY6G8QVo)PcXcuaUym@JlxT94|4bvo zmE&rK^{Mr^_Nt=E%&xP4ND^Oa*bAQ| z-b*V{fnmDxqdTU{=vqZ&Uc^U5o77J6$EoXOx@{~C_Odk_vL9Qb=Eu#C%eqrl-llfi zR5*;74jrvB@_!nBdduQWW>qtnN>S#`uG^{5BgxX$h%T35DV0%XHgp-Qq6@7*N^NvD zk))k@$6KkEmc4Wd!h}5=dM(w33)k1zO$#kys6X~H&~zCha0a!J_cfnDRcA;wp6&ZN z3*;Z}SqVp+e4|&CUZHFx&cuDIayA8@Ga!6qJKr3wjbymo^`)yh9>xaTFQ)7t?M{Zm z1vsPR3wNvvL$nrp91R6N+%w!Z{8u-b&JyiT^(~6Xn%UCg>r9>P@!#W|WeGd|vD-$` zWzmEtCYt0-Fd3kVy^0v_zKG>soAF4MEK0cNat`h)uFE%`4ZVd5hu3gM)I^h>NtUkW zI2e`Cc_oynLbXe`&fisCW*J9M8Ix6Yg_mF-G7}X>zsPwI&5^6a(YQ#+<56V^ zL;bOrfu{ZFl35SF1B!m8Dyn)!@|ju-J5Ar1lPP*&+>;PX#pO$I6@?BKAc_hLiVExJm|<}SAs5G zol>g?=3)^~a1b*N*NSN|b+qh*#i-C~qRCQL>5sjX{8AfNf+iai zWG3@n-qSUFMI8)J$%0~tpBR>+!q$nabou#Xnf~U(O z4E;+*CWg;zHnEv<$V)D)IQD-l7}FO3MX69QuLHzNykWR@tkP? z;X2z0Iv!P)kkcQ#Z4B+llK7a^KHjr9tL}bHe!)8B3Vyis|Kcz3YIm)cD;s9Kv(r(? zuI;#P2V1#ruX-(837Tki?kr6d3#~zu`i5gghDo=FLm^5^xUasV>=ieZI45I?JRX&~ z_BSRUk1I0E4QlFEk~GNPCLK+hAN@oOn-YPr$2}bROxM45NCdVhRPQ|!B@l= zOi84XXL9~(R{&)m99Hb9I%`#y%Uxf(n&aWu3!Q>L-+i2(=Z9(Q%GpEN_&D_y zY%ut6_m^oW%g3qD@Zp7RWSOJMUB+8@pxoDgDvB^Ur&(_Zw}mG)POGkY`Q1s8M29&Z zOxlb*hwHfB*XoW(m?a$b$6gMi_F|0wVAEVMN;AY&947S;2ONG%T}ic*4GEOL_?oC~ zFcF1CcZk0QQXpc_fiUW!=h(&4<4Qx2dWc#FKk`KlbD8}qEygWaUzhJGnF`ogRyL*=r~VVLQj9}_HnewPec$g#cU8wRCcMVf#RYy z?L}+BS^4kivvQ060nP#?@{g-zB6IGd3Y2)h+gLanQ93(ax|$L>5y?I*CpaN)_bF&rD>&gOjQB5_OI2hyNsOq5RQ{2=dRmyF;eg5_nAt0&?PU|OUdWb%&Yoto% z_m`n`3&U7wFWXG^Xq4%hW$Eg+vrTPeF@GqQaP&vH)fKAARM`m^53Muq_?>tZqTHHX zO?BN^aW)dFzadWj4dHw0|MAGOgq{A_ZKG(9vrw^cmTa>X=hY`wt|l%S6%cPyroy-< zGntdAW|@Vb2D8Cvbc|#^o&}yb3htl<=FO8nFUAnoYJSFuxumYC^zvFlRK8K=2_)dolLcHg$v5Nm9iqD$RAZK zMZC}%^z%%7aM$Vx;3l#nmBnKe7?1HhnLJbX_&<)Kr?iHq`KI-;i$4?I^LnViPHVgP z6K`@(b9ih!V^t24e`hHh# z*v0?lbl$T0|EEL;uQr6#paWO6-9WxcEzHe?nLq*@$OF7i@*{4mQuY;b;M&|Y;)l&M z-UlD1JI|TLKbFuT!h5``HkP?W3HWfI^==>rCd3cXAzL(5&$&uI z;zm*9#FH}k$MeLGDD>15T1B*2y%u+{CVudy$Qk~h^B8#V)v^!*Gp_g=>|+s0@Duf} z{!n%yL)WDU8D{|<4K+yAK^L<3JFHz4}Gm2s0I5 za8>@8OVKgvmuna*-!g>!V)|PRNr&eTqF>Zy7}FO#D7Z#qg`e5tN3QJO!8@`Q0h{%R z%7tPg?p%tH5kHQ{k0o^Ah*gd?o!__`c?hT<@v?1p8;}4^e)l@I^&&+lP1-v5kk01mug&LVA)k`+!ix{@edaf#%5kH7%8?twRs!majr`02(MjUYz5PJMjKc0hsoTDQyK=-Q( z9b9YJXh%oXQ8+Ozj;D$kIhTiyrnj5vER`{3WT>al6+ies(xs!DnzvCUn4+u7FedQC zgQk3OcZn6Eh8SVLXApvI(9d%If;lW)HeTk-5iKa>Nbz*6^bM}`n=5MW~itt99-m5b~@^p>*|;6SIgECGvPF-oJvxsutP*}@07+cZ%&lK?b&ic7NHloMz=&^(jeSNvVCVpfCjr?LRMjpvM5Bs2e zK@9anCW(t(y(Tm>APBTeI9X(=iXx#5<%CcCY1#nh3)y zrt=c6L0_eI#IcN_I4uXl#2`^8UPW0))r{Tv%2D4uk3N#KtJB|&zADn-lXyxELMZP# za(qE%@8qE9?cxnQB=a=ys<^}-px%j(mBu>in|gh92_0%*8Ka7!h!ps%KiMB*PB%V7 z=xDPKI8wCvIES*4QQZSe!(Ub(KYsQ1ZJb_jTOw>4aqa!B@~nv;CSAgk+g4wdOx%W) zv~0HWSuzhknXIF>QT1dy&iba2QQ_=w4d}1Y+U(RiI`ltiBsJ)uj$ovmgwfn(vvm3? z?`m&s)+5w+e25mS>X27p3Oib3v;8;E?9@<5jw&QUNai2-5MiS2Lz8)`6cTfD`ghzO zZ6=r2o*nbJ28D#@Fq_e28a*R_co88+bh#8ELm@e$kgTIawOKdaulq(%ckg8j{#0I& zbnnzpq6P$UwDYIx-pP3Jp2eT=_F{C5_;FqQ$oxa%2mayy&@$zLnhe7o#&asqU^~#j zUl=wjT2SNpQ?m&#nyYEQIIH!7X=x*VRL*WEew?Et?%+E8JsVWz2&_XUp>4<*s#}Vg z{;nED+{hk0@x?5a&K^CUhjk4dLt$Oo_7E=)-TAx8m$uDGVM4rCv2cWl7@4@NiWqve z?mHzz*Pr5%E^QPKn?ghky_@6|_{;=^Xhtcc(QaensKN?`(cG7==KF_U`#$F$R~m+* z(yKpp+NwIgrh=&-X1B!(yAfp+_e^vVL10MbjmgGU;v@dhRA6sUr9a-eS;9_#?6y&~ z+^;!D0)<_FH8`k>CL9J-a(iLY!rspPnkzc^vwQNv@Cb5C1UF6DMDw{S%3TX0^y^FI=lP(W=bd}^K z87*qMqI;O)Kw~7ojVn9(2;X- zqOWE1NZq+vP?-C^bTvoBFBeYwe0aj=mv_3a;wNoSO|pCv=-1PxF;VgT^qJ<^|9SfR z_tPuz-Slt!r+%3BPraYsvtLi&<=g51UrpcZ{CgkURW;|gPv0*-jX#+RHtm_om}~&4 z!5W{M2%_IebLt|m$6hA>`m4CDEpzX3nfP0*k|nb5rmB9Y9dkP9L#n*ec~ZfNRc#)X zav0~7dOm(#U*jv(ZtMMq{+mC=uGo%~rK^FRId){Cx=tqM!vzDQqDsy#&Kb5`F>y!e zSH`tVQ#Rd-+hapmxJb1Ydq(Z`_^s5BVMaaL$QabZRLtu28n!IoWIF*s8Y=u{bs;)&ZMEhUlt<2ZL%{C?m|M}ebPvTF*T6`YrGTw@+ z%HGU=PK|OE)+4H{$)Z^#N^LlMO-4(de|qdirC7|NNJ`^)5)_ zPeT)D5T0SK8lr0IFRC)#P}EC>uiMVm4oz?aP0*t*#MHzlO0}K|=AZ7#cCH)z=Q{o) z1KDr~6FLZ9^}3S{Wu0G5cbNAmdoXPk3KPPOvolrh31b$GytDaba$<=XIP{-ea|R{; z1Zy-vTBEEMy`?7pWNW63M%Tovxgeph)nDn1(ILg3Y%S3l6PYj}9gn>(?D6=s)WPVF z&GXsI^r7u#EZz;%7OJ!CeTbu@1~KYzDo%P6@p9PcoY@=EN$!fz44&wQ(83QyO`uTK z%~^D=vvf7b%g}$$^&eTM%?V@EYV5jAHrWIUQKF8%21exH;*aSZygKef>JSH!?hOx! zsAUq2dOi40jWZ}YDN{Ijk4Y|G2-%`)c3f2@M$nsZZyhct8f3ekIOi%lAe_*gv1c86 zo7Vha=WH7jM=PwJeU`4~5$0uPq?-O$!&W%oLS0S%q zKRG*Eta0+Vnhn-`u2Z(Qu{QWmRdll1A`?9-bi zJ{0MkN^csOrXZ@})wIL9>THSi^vCAWY4D$i{HLQSYGU$^j(3&*Llacl+id_96dr0b zuA{ogw4sTY9>Pqo>w%fn;1FsX&a2{2$IjB#OTp7tg%wQX42-4;Ccad4*r|H5ijG&j z&lF=F2bfTACnt$8aDtCvMX&*>c(jjfV`A{1&#(X0u@?PD<>ijodCk;Qsw}vHyY$-W zj)_0XaFm{GT*)jL)rVJKbcz#y8*79A)bgKfGXB}U{u6dW6ROdFOlYXHY>rHJ!kr-^ zj9Fe%lX1Pm69rqP9@WQ|FX*a@PD@#;KlW1cRaO1f;}7POb2ypOon}&X2Fi#$vl$Ng5)dJS>_M7x$@Dvth1b@tHFG>oj)B*;z680YMd%8>2Rr^_%)yc zZe*?aS*bxHjy{HSPsJV^gw$!cw8#Tbb-MEshWcYK1x1viyX*Q4IV)LgOD}?|OkEaVTK|)OUI)xJj`gkl*EtK9x?TOTIU+{i>&xlReLLN$ z_tSO;^URlG&5R+A0cWO~Yp@mraohxFocb4ob&W2Y|nhU^qqG<^`tbnfYx__QoG z*w67gy;AoPYxGj-J~S5hx~lS`9z=PT!_@WoF(w2{92}Xopa^;YQa zxe8aZ*y`P zUai-T{lvp6Hc_Tb$MbT~iS`_3$Ky{&*3#AMK-+$F%DM7w>MI+3>!!Z+tl+_Xdoos> z&=8{!(KTuJEG}nC5xm&Sff?;>aXA{Dmat;(%~zG|N4)9#r1Ur3d~efV_aW`CWwHjbqu zVLxWuvY}!&;h-Z{lc8`Q{=#hJg@Jg{!iGc?`k-ggTw~NB?{xhNY)R}{p8@N?`BQ8h z>#=6(>Q>`Ve~li84!tXwsmeu|M?9qABAHKb^MUrw$v}9G7$ZN$E00Z6aPsWdb;AC8 zkJI&;!o)c}-QxF&WzTIq}<1>{}#1ZN?T-ePc z|L~r!Z*`g@WSqWt^z=QfHO>m!OGAhIQRiTn7x-;Nk%kV6UQ_aN-boPJ+!s0v>BVQW zH{=ZUrOI;y6RKc*117>W;?k^%7&1jP9zFEr58jAu$c0ip0$E2~&@JFi&Pi%I6*=j1 z&xbYYn^X2V-$Gec-#}CJ6->+qgXm^_Ej4JuUa<|;udWgHYLAaxBQNDKm9$(#-_5z6 zcGqPuvn({u2kxh(96QmZ=jm+*YkpjpMz5Rx4;gA3?4brBbY1Q}`o5TguW~db2l@Fb z;G7+tzEXB#(1=wwvXh>`S`O;J`KWK!&IjnP(c{qpCsd3Ybf|h^L9WSE0)FB#@dGwh z#5x7$Lv;$wC77k6m%xVFXMHNX|K_8@d5Q{$cBYaLKV%r11jbNR-{?uX``Mb58E`+- zRX!%?(C;%VWw#`~UoTn(oO5d~uYgB=bG*J;!bY1?tBD?A7~+5~kL;mG$TbBWyiyn} zl`Ped+E+H>!_(#AilO$c<(6xGy-ONdf9zJ(vN@aG>fgYG>D4w<;N7X)rv|OTgwCBh zg@*;x;GTnx)?Lol8hj)(P0+%7CuZmjVy`0HHYSeNH!zy}zH~K5#5f(;uHsV+aevb| z<(#@%Nm!tp@EpLBx!o-x=L4G(KC$N4uKxaR2!y>neqZW%E|SC96_|0YX`H|DWb&6S&H zdgNHTdfCy$b}JQ)Nf7lW*TfdQB?@fo|G`L|w}h_7vCp$6_QWedsfUob{KXqR zNC*-8vf(qevAk$Pe~rEL-+XAV*J-ay=-^D#p{r8nF)n+hXlM9HqDJNsah7bKjxvvz z&{`>P)OdZJI8!c1$MB{db(j2lI5^!;`;Ds_mzYY>9}>f6a=nRBM5rOKtws%!Dm zXeH_$c*R2G9!fsudiiP0qkD6td$Wd)+$r~<1|67%E`R2_;tqkvbZ^>pDQwV4oUcQv zHv^VA3p_-WS<5b?d-MI>IUeRZ+p^x;F@b-Ecf`-?-*tXg*&;DRbjrMzy@SaqcxvWF zIZ84w!DG~73`QDH{5B?r-ufJR>p6yWZ>U*f3O-pASL6)n$@Vf@mZ%ZD(0O$r;~B^n zgfM723cedh15f=nhDP`1x6`(Z$3&C3M*Qtvn(j^B?KL=%DR7O<(8wU}y!epnC5{o* zla3A@M90P~ma2z-#sR&~PlwvNpIx55i<77lEM?L{EsQs)C^+7$&=j{Bv_OU(a+H(! z80~_`VD$cIeAr4mpCWa#Z9g0aYf)vcr46;@8nr~7fweSMp0i%98XcnsAz~TU3IXvg ziY>Y}QPzSQ`aEUCW4uUajk9q_{&9UNLPoW79)J3~XibY3KbFv8j!Jf@I_nrG!CG-y z5u~{m#R`2R^{^a7F{7$sEc6l%0(DO|r0&gK9A_mctS3AK3W|BT0rkc4I zYHL-*kSomS`P-|l?~+}&5P`wSDbdjAYtWNtT6?p5n? zrC|ui<&IWgxX(2h;#Q!$$|mtPQr(;1QO-$R;XILvJOX1fl-k+!GH$Ysq2qC-BWCI9 zwo$YkO@4FVt+7KOnyWh`n&7DTX;m~)y{Ktq7aT*qLtTrWrn2Q#lVReY=WoQA>1*m@ zdrx>#wvljDJL$P(>1vLH;VxLSMAE(!dIDcmn>b)aWMGGL%!0{ zq`tscqH%~WHE41!j2y$sm|bcjMw>GiPvOd>U^>jHeZ(Dq>_@Swe|^(h;`HDv5BI9g z^VD91p{3~m$Ti->7>mDaFp>FRS;gI_szpC(imaKQ$K#*QvEjETum-k0yh!ob#1qx$U7lTwlkLE$i6%=~r9U>u!C))rY$a%lYD-Hsk0rX)peZW9xj#6e zr0Db5fC5cA$?Bo(HwX*X7c$=?=7=g#wZ7+Zs4K_4`cd*##tjpk2l5V%Sr=hs86Fg> zE$(XmPi5?VOzp#OVZyr^Vr;{v@28IDW$_$`y7KtCxKdpShTNN+4i*Gex#HkKS5TK( zw-8FWQ6MK%VERI8q{JFpt$B}hqT`s{njyS4t}L;X{@6TE-4^S;jIY20f3<#4I)gPC zMu$Kikyo7mW)IG(-ymBHRAAJ##2RXhuc5}N)%UmLjOyonW}`lu@QXOPQf^QKRq6fe zU?>$AIGgO_qPLnu?X_@^YN81) zjIGA0LP6o7Zq*Nbgr(vzw3KXSidQ8Z27<;ZUe}y^P#;(HeJKCt%;~mOEG1`z(f6^B zOb@~qwFL0u8wv(==k zLujjCHkhlB-G8%-(Nwsrv+<8lC9H9w zAu~alS$5a-Yii;O4c~;1NddVhr`5Ji2vnD3DRGB>OOMl&2!65;)okiEhK|RTCG7Oa zZW~2gY{m4tyPm(f4a5>%x~dH0wKU)E3IWe1zHJCR7&Lh{{66 z)iq4FS)FeNP3%#v!O}K{jz^Ux?DWTO8%2AuMC5M1eLWbNMm<`?Td`KPi;j@m*!{;{ z;<=8G$^FM@==i*lX2e7p6CkuUpTCWSqtRq3r}W3>I2df@oUJr8i7V}H)p=L^G&PNk z!;PTM5l`H+APjGT=6G%4O1F`^hx4kEw)W&-+hgw7S-N^Dc-oIJnLVVgs8Lj+bz3uN zwlERaL2-+A4;}K5=p(M^3;L+KDSkLvhU&}Pw0?HNbzc6SRhF*ih!}jO@f9_+c@U~C z)ikW3CP!tqM-^{+8CrrMcT5KWgMuJY1#d~Gk#38H^UGnqd(*3ftz5okGCsI$28hOBjC+`8rk;oukRz_7+i2d9uRo_rem(t*zN-VE0_ zNi&%$ZiV!j*D%yKZ$8yY>m5T&SGR?${_3plB~8A`u6;Y5+#|T)3J}$+w0t#A{8Ms^ zS6a5A%fiL~FkMGsv3UiLq1}6o9%rjU+mvuAF0R{JyM%=P*lWRrccSi2Rld=!kyoIO zlOQ_}zPi7nxFtg5G!E)4&o=I1vcpHsxb1ffk8_ZI$Cs{d3k9^x({pdPm`6B==%8Z2 zMn#57C6=n{+!gPBcUSe2ib`~#w|k66uQL$e5@rfFxH6Uk9c$6yI-R8R&ZVn44sMl; zR{2p*(G=Cq`(2N&rm~^9^5Wa4lI@XEW>eYVuwqHNhGI@!2{?Xs<_jJgO{V zs6X~n(6kj_+R5tKoS%)7nHsL@^xzb-nfPKWv0S2#$;5`!j@7u?66H!(QQ4?}sQK~? zUA88^P=0gYm#*fB_~o?C(R)=y$M>B1_ucfbZ>Qhv%PD4mx$yBn-|vC^F#Ei(r|ApT z*!$@_>1+P;^!M+l@ABRB@AuR757Sq@pW?r~@$K~gucn`M{CH-ZY4Wi^Sb&vj{jZN7+iFece!*xx}>qoCEE1ly%RRy$!y8hV9 z#9x0Ew<;y9N9_znn5S)W*>q9m_!n)caB(lmS?XhK2zuZM7ZsgsSqM9#)9Uz-Xz!R&O{Nl0=x&*F4`M{0_+NOPJmzye z6Re1@K@UL2%FcheY8x>}_1?~jm#*e`8CBP*|K%Z?@SZsH)$vto4t~u=W!hOLf)|Qz z&_w5zxhQ!wANrrV9{NNb%shMjx6w4}uA|dM4HI!(W|O~MK;x^zgzukIF?EJiR-%dj z}TmJB3nG#c#PL z=`a*xvBRCt&M!E?QLtK!DH?J1MX9oNnIIwixwmm}l&y3oyL2^2!O(ENoZgY&PVdb3 zlLn;%zYJ;ATS&u=VW6rCS1VDeb6y_h#?KUqV2!%$E<-z=S@g*qYIdmU)oLyUN2j+$!II)~i8HMNwD3$$gu0~Hc3gKeu_qWZxOpQdeg^j_Ul=dt_;8__Rqr>Dsy=Fn=eW^zDu z(ft%tvf(aHU>JlloeAtG{ZibYwj<|dM$T;0Hr9^EpCyd-$6g28E{jg?km&>!dKFui zn|S$jt+MejZawvwJOmpe6Q$2%{?>h<`(&~|-O_Ee9F0tn8bmBz&9O4L&l2}J?SG~( zA+OZL9)3Vwa>&UUOx zpT}~aU@iU~aYsIJH*4Y#r08OCm9}lrDzV^-hDhh7M90&khUZqN70HC6QKf%y31j`S z*MYYE=#(9u*s}M2de&8liQkL5(odeu8(dyp>1yEZ16tvp0B|~{9BMA>xlOFRyz~YJQYn@&w?Tt?T7Y^B{i>( z{`=rRx8+~fb%HW~%VIhirk>o(Dy)e%`sX5@NTl~gUrg`I);*C(?H(T?zq4ng^7mCb z8ay0pSerXge>b_x-%U>QKTLmrv*0g(fB$IqGwAa7Kdr9s>}Tm}p5a~w|L(8iwtra< zj4ItaVeSv~)MU@OsNHLI>tuSYGab2erTh}Rd-Wz1R**FcwC%B2%kVd4s=TX&d=R~7MQ-S2SZ8VMA z>v-*zZRVLNPA@dIxc7GrCR9;y;V#qnva_Uh;N#wjvnREeo+-=(MJhI5yXVCi5$01w zm{T-~Ftp|D>a2<|a3exc{DLN2R|XPcV9k~Odd`!RsnlFhWU_)INL98LVR~KgRMVkL zs$qX@&X8|KKkTp5R{fMsk6!ysftvr+iOL*QO}xozfhs1hcPtmL$(8P>Sd{u3y9rjD zh-_01o`pH*}YDgr%$3hmP!&)o-Xl2ltmAw>xc4CK`zNkob|AJ=%?`2s$to z|3MI*;_>HHXO?i$AA7k7`KLScGTCP?&)@_42k{8jotoj^yUSi#N?bcN!&Uqfm@B4g z--#=H8e>T<BFt4K33{+kc}@$P<4OEjl9)2^0NhTC7KHU1HVQ2wdu&HKsG!pZ0TT7!_B zxQR_{Z<3IP-MqaL=fsHR#B+uzE#z z8vnpO{lsLK=ptq{Tc3!=#K5uN4K`CxCZW`^Scm-Lj`%Eft&9`@f(qwyhC1TM@%XWX4xKt`W)(WP6flnF z3wQ5nz2b-Npo~Kip^#uA_S*1C(Mi3xs*fkD(WR4!ldQ-9|abnodZb&U3*vzNUf zad)SBg%0;VwM*s;#10!kX<}F@1zt{C@Beky^%UE$mhwq|?4@UxC1kiCqIpg1z#vp6 z7>9E$I13Ufpu=9zICFhmJfYWPDfowLjF#tM#E$2Q9jX>ux4)g0L${(_d8`H@I0xRz zJ!xJ)oRs3?Draqp8gdBy(9O7()VLmTx(bGSDMAMKILihhDsYRmBhS$zA5h zm&^T3yi@!TQ(W2cfMvL9XUoPJ<+=H~5kKmg=@L3Je_S)q;$suOCW2YiT6ewwZdenDAp?nSvK zYHFtDDW?2P^z}>xnIyVg8yoE7IQuxqMl|)hzMSrSTxC2SG;~vgnFteC;&;VOb>^_t zcv>?x4=XvhdM&qH>uv3o>(bS&R%yeriRXaU%Hwj;$_TL%<=N{=MtP_4Y%d| z;t;4pTB~z;K%hq+(gjXstR~_G5PeKBXM&85!d)){aoFn=ZzJuvvvmn!{jt}9wdJYi zIbOH}oIC6_$uv(*Y!drK9_oC$dO7hkv5A@jMHsiwOE%O0H7g&7W4y21h&dXYmU2{o zY>t;(aV0)~^zq(ywrCt4oEWGz`Qu_h-0QrzM+z;UwMF8EeC$=^_z-7afr z8rsWmr?~xg+NSz(dI!o{*J&?Q7tBZBIA_3lPi2dH4MOQaP^>gjm(w1f^7Y+Yv%HmGYRy_%N*r=h~gRPi#}H6NxNO<$i# zKEim^ck3JJM*Mi%_>qladW1Avvs+jM6|Cxn*>sL==Mfh$5|wmjEW{PnHcgH;hwF+o ze6Mh;(&j+XFC6isUb{U<2W9S8)2m;l?5nGDr*SNmMLIjFe^f#=7d#`~LVh)|gIA5a zEn3X_oal%jPZ>Wlchh=57;1DeF{H{}5U$B*q$?~!gpULvSZNT#ae$M^L#k!jMV)MC zGj=lKM|J#IMu$#a-BvjF+I=_O8E1UXX@nCsN@`#gZ+7ECh5xwQa>6Wc<9c=(>h1T_ z*`sqG^t>KkS4ec}b&GX-#0ayT=@r*`q0MIM4*TP7%O4_Cd?(R%J%$0%CUk;mXu3q{ zB<94~wTKZ+992lVdbV^mS4f6>`{fkBzn$K_+b5Dx<4&>0l}L@tjD*f#O?4dZti#B| z22HrMo>H6%aaxNoSS&S8-II(Y@#@9;|UzTmx?*I4H>*F~qU)h=Dl@iO#VDx7z9k3S7f zs%v=%p2UY5G&Mbi#z>Wmek%q+6W4EMfq3l1AHMAPsBmdD6`#!IQ|ZGym-pA45%oHA zYi`iHyy>?X354kJQ9i2bCw(C9SsPJ;R$QmCp`45a7b^X97!VUqT0zc=fB$fh%WnHST@+hPwer5Ian8Q2gaAkNIqoB+)|+MVq@^-5>GeSp1-q zelh)*jghITGWSD);e@H0JI-V}{wjCqGE?vMB_Tw96E*aE#4-9E#g;Q0Hu$G9ue?@G zjrehWcW?_G-rXwhD*ll(Uv>TbiGM}M2|8q&cv|9$!jv#ystwLW=~t<*`&Z`Z81dt} z_>qmp*#yboq}EB*Q58RE_~8-ez{C%gPqt-?TXF2u^|54IQBt$V@88h!TzhAis-FJX zt=2#NU9`+jTl`o;2QJ`GP5h82+9ov|SpJY{sCN7()O_7R`%l~lc}Oh5TQC)fdQ5k4 z#E-m$aW`BZ`l7H zzZQh}oBomb!7nSbP$=pcs-5KUknL-!Rdj{aD(aWGPU2YeQ7TAk7TyH<2M%(1g**If z=l#O|F52QBOX#3YVun@mgF}Fe1PkUo!9O4({DTJOF^tsiKG`K11u{5L@DeQL((E$$ z$2I)JyH)(il$dj$qE32$*6>rhIc{TeQ1?ZAfXVn9?ZCk~^zp(&cuveF#qSnOajsm7 zj}bkNM~^u+qMSy-u0e;MuFQgOW*dbWO;pGW(4f;#5yL*)M3>lrW#FK+(^lJ3 z%H)>lsqnFliKFh5B^>m}UJ4?fdOC0kP1vjVcElu?sHUdN0 zGajZwBT0u(Z-8F1o_|J!IqGkFhzZllsu+&?D5`awH6BL(IX)vu`1OQe8mA!b?Tt!lb^hFHIFdAS~ywm&-b%ZAMU=JaQ^M|T)&)N+b^fb>>T`f z_s`Sczn>ocZu)KBPuD+8kG-E>chltGPXGUE+P-%yrwKm95EqhqLtIhwcpumKMs#s` z9{r?vSY)eo^{A?@C?mYHapik%*`*QRnjY|WmO9Q{max+wyKNLL`O!|1AadBP^o#pw zq8?RqR5=*s3jLXQWkn9Xe%{$A@R{l}ff0|I*FKyVf^uRZ{dXG)NBK(kDlT2kaWLGn zm$+q@u!haZ39?t+w2vx?{+hWS?AJ-|SWL8hOh?qgb|4We7KwZXU0Tt|(aUR+Iu&1*ub$9<`7c6-5$yMleE>bBJ>CnRJ)vCsEev^uP3 zU7rj8JsO>QMq0X><7IFi9(@(LcXZnxs5<6}uG@T0rNM3Vp*YtdhZ2(s_G}VTIoV{5 z^>8oYL{#AHw$^c8-+X>;4Yh=w{@87!XfK*jVkk7(>y&K*Ra(DZwV057)%ri~FuyiL zm`J9C;6W69IN*wvf9U@__>eK2_aCQ9OHFpkUW>U_SEN`7K` z$l`{cVonE?9jX4J3eLj=N5kNl?>ytS6dKV+x5(sjCe5if zH3-R;bKL+gM|sC?FK+H|7m;1OG0~&i5_PE4*`z|*$#nds2pPSjqrIbLbl@c>!D`Tv z4Ygu{{DRNoD0l{R&~LF_b+_jre!x(sm!X6rK=)lk$F;1acLkQN=B(saC&9M(Ng@WX zN~TH82732aA;MivcTkO^I;OW}?;pl&GYU1AYR8Mfc@G7N65{F|6%fQVWNX$Sts`S4~&R?xk%c z9E~PRIi)`~$HA>;m)f|JlRDy}#0$V*^OII%iOROuL^c2V~!DB-*{aYY27f>82xIn_I= zu6VO$FZT?837S+z=6$f-__9^b>$BIT0|O(++~_?f1S46{@%Y7 zx#TR}MB0a(vHDO|(9nxfAy2_5E#p0*yv8oBqr14|5}THm z(2;57Ds<3Na0xCG+YZtZ##H4Q6>zFy+YCe!&ZX2X5Mt&?pK3S?s?V`(2*FU}XY;DZ zwNII-!iVUgBB8OSX2DH4m(s_{t|j~;mAK48L-BmYj!dX^6+=r7LX@K~xTpOv#VOgmrBPe=7~w0c=W2gRE@R)dXirtj>&iv+xr z(N43kP0WHClNmgYdVRDGpY2~<_Wb$KyB0l$8|nC*DL&c|Ve^Hk!M~V4>WLam@P%X= zNVOto$T0CLiWRbjdN%b6bl^es5Pd*VhF-VMN3ZM7cs}XDEM4Uz{qHducG+auIo2}M z3<=z`Rq;n%ECOYJiaN&>n$3XnklKa{D_8Nz>N4r;m>Y@eCuZs1RK=eqjP=Jl&Ke@m zCy*abGoOEadFuJ=>AXli@b^>X$T8zv8i{7m#*e$8J*+SIX=e{*Ch3e!-P+*Cex+w zgJCt7Eymkspm8Jbb-KO^jxHlwi8!L7_@v_6n}HtwrXTPAI_+y{8y)5@+{@w%W&smC zX81)_H&Ex7Z`K5=+Kk>tTS;Z4HsT@Rhl}Tpw-QdcoH#9`>#pw|y)MG^+_Q8wk1&J% zJeK_=m${p;hKcazS4}2zrsNb%>{|8Zd^$B2_Jc#y_|#_E_kxG#lw}z(C*Y~X2K)I? zw)CrZ5w%(R(3ojebdoV~8mQ4Xgcv_9j(;6Rc`8$e@hb57>p`pOachcSRc*G! zdirDY=rs7xIsa*B;=@cwvPu<%gy!$|Q)xTueOIb{>Wbju}c8nlE-jv(MRNyy)bJGELZ9> z_`S#Gm49X(Apy_HY(Qcg zHAvUXGtrAs@5w}>5C;$pRn6gduCsJCk1&J(Jcj>ttnpQ0+UY`7PEpECxDWn}_2Ax^ zb>fdIAO5)iTv4hiJ|+&}4+8i1+Z~TTOBm~qy$-bP@t>SZ;eDTth!hslpe8!WRQ5NU zQ?VNnI^qn380vT);|)w-EN5h7mxwAZk!tXt&uNQUI$w!D*tG0}|HwSp}2K#v|`w7y_ zx$1jiLEh~TcPRc})5renyZ`F%|NX;+4FC53FYf;R6c>J+{`+FW3a9lKcmHwv*S8a1 zetZ9zzURN*y_vT5`>Y?Q$N%m0_`m$EGwgHzFfV+|FQoxeb4WvkA1lR$j9j;KTIFT(LYX)zWMv-y834N4(j{% zoZIj6@9zH7-T!v?f1Z5jpH9ES`Sbna?!TSB{+ql1e)`Pj+IjQ$N7}P`GdiA83{@!Q%_z%HQT3OZJJsTuw zMmlHklKCyQyuKPAQJA<#C`s8ez-J_PeRUr{M7iK0@ z>)&VT>im13qoZN%*l&IQ{aypwbj-MlI63nkS9ZSLn+9 z<2~9Qx{&|zO04Dm>b@^s&GGQ_zf}^KVQuL<_Q%e@_c=Bi){gwn=ilu$AdO;~SfyX1 zE`uW)C8X)nxuPW`)~PBX3p@9Jo?4y(JpAFS{u|IbH zz0a|+jI_&s=kxFO8jwbF-~})ppS?U3DC%d^CS1vwTybI=ZCy8qBgIKt`gKb&?Xt;= zb*{FgM)b$#XlQ!bWk~DaXX)zvd!J)t8EKdO&gb9lH6RTOrSI4uJOAG2m}m%l%

s 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 3 de redirecionamento e relacionados

', '[]', 'usuario', '/therapist/agenda', '{bcc67ff3-89a1-41e6-9dc9-b1bb95f3d14b,f7d8bf29-0849-4966-ac79-90d14e64a2b9}', true, 0, '2026-03-08 00:11:34.853254+00', '2026-03-08 00:11:34.826+00', NULL, false, 0, 0), + ('f7d8bf29-0849-4966-ac79-90d14e64a2b9', 'Titulo do documento', '

Agência PSI nasce da convergência entre tecnologia, clínica e pensamento psicanalítico. Trata-se de uma iniciativa voltada ao desenvolvimento de soluções digitais para profissionais da saúde mental, especialmente psicólogos e psicanalistas, com o objetivo de simplificar a gestão clínica sem reduzir a complexidade do cuidado humano.

Mais do que um simples software, a Agência PSI busca construir um ecossistema que integra agenda clínica, prontuário, gestão de pacientes e recursos administrativos em uma plataforma intuitiva e segura. A proposta central é permitir que o profissional concentre sua energia na escuta e no trabalho clínico, enquanto as tarefas operacionais se tornam mais organizadas e eficientes.

Inspirada na ideia de que a clínica contemporânea também se encontra atravessada pela tecnologia, a Agência PSI procura equilibrar dois campos que, muitas vezes, parecem distantes: a subjetividade humana e a lógica dos sistemas digitais. Nesse sentido, a plataforma foi pensada para respeitar a ética, o sigilo e a singularidade do atendimento psicológico.

Assim, a Agência PSI se apresenta como uma ferramenta de apoio ao trabalho clínico, promovendo autonomia, organização e profissionalização para terapeutas que desejam atuar de forma mais estruturada no cenário atual.

', '[]', 'usuario', '/therapist', '{}', true, 0, '2026-03-07 12:14:32.505605+00', '2026-03-08 02:06:21.461347+00', NULL, false, 1, 0), + ('bcc67ff3-89a1-41e6-9dc9-b1bb95f3d14b', 'Documento 2', '

teste

', '[]', 'usuario', '/therapist', '{f7d8bf29-0849-4966-ac79-90d14e64a2b9}', true, 0, '2026-03-08 00:11:04.207625+00', '2026-03-08 02:21:02.279369+00', NULL, false, 1, 0), + ('08db54a3-4601-4708-bb07-3c2efe84f132', 'Teste - Titulo do conteudo com Faq', '

Conteúdo com faq

', '[{"url": "http://127.0.0.1:54321/storage/v1/object/public/saas-docs/doc-images/6ba2a9e3-b4b8-447d-b1fa-2c746f15e55e.png", "tipo": "imagem"}, {"url": "https://www.youtube.com/embed/IIqR2zk7aKY", "tipo": "video"}]', 'usuario', '/therapist', '{bcc67ff3-89a1-41e6-9dc9-b1bb95f3d14b}', true, 0, '2026-03-08 01:01:03.605111+00', '2026-03-08 02:21:15.978317+00', 'Dashboard', true, 0, 1); + + +-- +-- Data for Name: saas_doc_votos; Type: TABLE DATA; Schema: public; Owner: supabase_admin +-- + +INSERT INTO "public"."saas_doc_votos" ("id", "doc_id", "user_id", "util", "created_at", "updated_at") VALUES + ('2a3169d2-20b7-49d9-8e11-8b4f40e5bdfe', 'f7d8bf29-0849-4966-ac79-90d14e64a2b9', 'aaaaaaaa-0002-0002-0002-000000000002', true, '2026-03-08 02:06:21.461347+00', '2026-03-08 02:06:21.461347+00'), + ('55b43fc2-d59c-45da-a78e-85b4297b7c8f', 'bcc67ff3-89a1-41e6-9dc9-b1bb95f3d14b', 'aaaaaaaa-0002-0002-0002-000000000002', true, '2026-03-08 02:21:02.279369+00', '2026-03-08 02:21:02.279369+00'), + ('017fe60d-d16d-4ef0-abb1-2caea3d43374', '08db54a3-4601-4708-bb07-3c2efe84f132', 'aaaaaaaa-0002-0002-0002-000000000002', false, '2026-03-08 02:21:13.879568+00', '2026-03-08 02:21:15.978317+00'); + + +-- +-- Data for Name: saas_faq; Type: TABLE DATA; Schema: public; Owner: supabase_admin +-- + + + +-- +-- Data for Name: saas_faq_itens; Type: TABLE DATA; Schema: public; Owner: supabase_admin +-- + +INSERT INTO "public"."saas_faq_itens" ("id", "doc_id", "pergunta", "resposta", "ordem", "ativo", "created_at", "updated_at") VALUES + ('643e1f7c-c419-47ec-81e2-2ed8641338c8', '08db54a3-4601-4708-bb07-3c2efe84f132', 'Como entender o Dashboard?', '

Resposta 1

', 0, true, '2026-03-08 01:01:03.726348+00', '2026-03-08 01:43:41.088+00'), + ('bce71119-22a9-49a7-ae4e-d6fbe42eee27', '08db54a3-4601-4708-bb07-3c2efe84f132', 'E agora, vem a pergunta 2?', '

Sim.

', 1, true, '2026-03-08 01:01:03.758901+00', '2026-03-08 01:43:41.137+00'); + + +-- +-- Data for Name: subscriptions; Type: TABLE DATA; Schema: public; Owner: supabase_admin +-- + +INSERT INTO "public"."subscriptions" ("id", "user_id", "plan_id", "status", "current_period_start", "current_period_end", "cancel_at_period_end", "provider", "provider_customer_id", "provider_subscription_id", "created_at", "updated_at", "tenant_id", "plan_key", "interval", "source", "started_at", "canceled_at", "activated_at", "past_due_since", "suspended_at", "suspended_reason", "cancelled_at", "cancel_reason", "expired_at") VALUES + ('14a232bb-95da-400b-8547-df33e3acb2cb', NULL, 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', 'active', '2026-03-01 16:10:28.586893+00', '2027-03-01 16:10:28.586893+00', false, 'manual', NULL, NULL, '2026-03-01 16:10:28.586893+00', '2026-03-01 22:46:06.127205+00', '01b89c85-8e1b-43e2-bf10-77f4428ea582', 'clinic_pro', 'year', 'manual', '2026-03-01 16:10:28.586893+00', NULL, '2026-03-01 16:10:28.586893+00', NULL, NULL, NULL, NULL, NULL, NULL), + ('c700073d-35cc-4bd9-9bea-113dd87a1b76', NULL, 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', 'active', '2026-03-01 14:17:25.099539+00', '2027-03-01 14:17:25.099539+00', false, 'manual', NULL, NULL, '2026-03-01 14:17:25.099539+00', '2026-03-01 14:17:25.099539+00', 'f491f4d4-7801-4f80-bd01-1ba18f647034', 'clinic_pro', 'year', 'manual', '2026-03-01 14:17:25.099539+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + ('29e61e41-090a-4367-b0f7-33fea2a65736', NULL, 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', 'active', '2026-03-01 23:00:29.467613+00', '2027-03-01 23:00:29.467613+00', false, 'manual', NULL, NULL, '2026-03-01 23:00:29.467613+00', '2026-03-02 13:23:55.426163+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'clinic_pro', 'year', 'manual', '2026-03-01 23:00:29.467613+00', NULL, '2026-03-01 23:00:29.467613+00', NULL, NULL, NULL, NULL, NULL, NULL), + ('a78efb68-d773-4a52-9140-ed4c74152bd7', NULL, '01a5867f-0705-4714-ac97-a23470949157', 'active', NULL, NULL, false, 'manual', NULL, NULL, '2026-03-03 19:34:19.756429+00', '2026-03-03 19:34:19.756429+00', '29686ba1-6c57-49e0-9a6d-d0ddfff3b41a', 'clinic_free', NULL, 'manual', '2026-03-03 19:34:19.756429+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + ('42abc1c8-922b-428c-82d3-7bf3d7cd92ad', NULL, '01a5867f-0705-4714-ac97-a23470949157', 'active', NULL, NULL, false, 'manual', NULL, NULL, '2026-03-03 19:34:19.756429+00', '2026-03-03 19:34:19.756429+00', 'ee7d5c69-52bc-4875-826b-5f6c9561bc6b', 'clinic_free', NULL, 'manual', '2026-03-03 19:34:19.756429+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + ('12f90a1c-9699-4990-b327-10a5c5774428', NULL, '01a5867f-0705-4714-ac97-a23470949157', 'active', NULL, NULL, false, 'manual', NULL, NULL, '2026-03-03 19:34:19.756429+00', '2026-03-03 19:34:19.756429+00', 'dfd3f623-7ac7-4b07-af4d-5ad7c3ba0a87', 'clinic_free', NULL, 'manual', '2026-03-03 19:34:19.756429+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + ('04994df5-5b28-476e-b5fa-8855816931f5', NULL, '01a5867f-0705-4714-ac97-a23470949157', 'active', NULL, NULL, false, 'manual', NULL, NULL, '2026-03-03 19:34:19.756429+00', '2026-03-03 19:34:19.756429+00', '60fc942e-fd6d-428a-b125-82190d92e4ac', 'clinic_free', NULL, 'manual', '2026-03-03 19:34:19.756429+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + ('6b73333a-2cd2-4584-ac2f-75e51e9d6b0b', NULL, '01a5867f-0705-4714-ac97-a23470949157', 'active', NULL, NULL, false, 'manual', NULL, NULL, '2026-03-03 19:34:19.756429+00', '2026-03-03 19:34:19.756429+00', 'bc4902c5-09bc-40ad-8f05-10bbeee1c073', 'clinic_free', NULL, 'manual', '2026-03-03 19:34:19.756429+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + ('9879b74d-ce28-4c51-8470-513650e8aa46', NULL, '01a5867f-0705-4714-ac97-a23470949157', 'active', '2026-03-01 23:00:05.767711+00', '2027-03-01 23:00:05.767711+00', false, 'manual', NULL, NULL, '2026-03-01 23:00:05.767711+00', '2026-03-03 19:36:32.24533+00', '51a475d2-7f11-43d7-b47d-3e78dcd3bd16', 'clinic_free', 'year', 'manual', '2026-03-01 23:00:05.767711+00', NULL, '2026-03-01 23:00:05.767711+00', NULL, NULL, NULL, NULL, NULL, NULL), + ('3f8f521f-c394-4798-b58d-029937dab649', NULL, '01a5867f-0705-4714-ac97-a23470949157', 'active', '2026-03-03 22:43:41.705072+00', '2026-04-02 22:43:41.705072+00', false, 'manual', NULL, NULL, '2026-03-03 22:43:41.705072+00', '2026-03-03 22:43:41.705072+00', 'bbbbbbbb-0003-0003-0003-000000000003', 'clinic_free', 'month', 'seed', '2026-03-03 22:43:41.705072+00', NULL, '2026-03-03 22:43:41.705072+00', NULL, NULL, NULL, NULL, NULL, NULL), + ('2cdf8eb9-8561-47af-b05e-f395e02d0aa5', NULL, '01a5867f-0705-4714-ac97-a23470949157', 'active', '2026-03-03 22:43:41.705072+00', '2026-04-02 22:43:41.705072+00', false, 'manual', NULL, NULL, '2026-03-03 22:43:41.705072+00', '2026-03-03 22:43:41.705072+00', 'bbbbbbbb-0004-0004-0004-000000000004', 'clinic_free', 'month', 'seed', '2026-03-03 22:43:41.705072+00', NULL, '2026-03-03 22:43:41.705072+00', NULL, NULL, NULL, NULL, NULL, NULL), + ('112cb9f5-3120-49e5-886d-4346ccb27edd', 'aaaaaaaa-0001-0001-0001-000000000001', 'c56fe2a8-2c17-4048-adc7-ff7fbd89461a', 'active', '2026-03-03 22:43:41.705072+00', '2026-04-02 22:43:41.705072+00', false, 'manual', NULL, NULL, '2026-03-03 22:43:41.705072+00', '2026-03-04 17:24:56.964418+00', NULL, 'therapist_free', 'month', 'seed', '2026-03-03 22:43:41.705072+00', NULL, '2026-03-03 22:43:41.705072+00', NULL, NULL, NULL, NULL, NULL, NULL), + ('d4a09e95-eeb7-40ee-b737-3d762a6ba8da', 'aaaaaaaa-0009-0009-0009-000000000009', 'c56fe2a8-2c17-4048-adc7-ff7fbd89461a', 'active', '2026-03-04 19:40:17.694488+00', '2026-04-03 19:40:17.694488+00', false, 'manual', NULL, NULL, '2026-03-04 19:40:17.694488+00', '2026-03-04 19:40:17.694488+00', NULL, 'therapist_free', 'month', 'seed', '2026-03-04 19:40:17.694488+00', NULL, '2026-03-04 19:40:17.694488+00', NULL, NULL, NULL, NULL, NULL, NULL), + ('99da40c5-81d9-4560-8a7f-811203314547', 'aaaaaaaa-0010-0010-0010-000000000010', 'c56fe2a8-2c17-4048-adc7-ff7fbd89461a', 'active', '2026-03-04 19:40:17.694488+00', '2026-04-03 19:40:17.694488+00', false, 'manual', NULL, NULL, '2026-03-04 19:40:17.694488+00', '2026-03-04 19:40:17.694488+00', NULL, 'therapist_free', 'month', 'seed', '2026-03-04 19:40:17.694488+00', NULL, '2026-03-04 19:40:17.694488+00', NULL, NULL, NULL, NULL, NULL, NULL), + ('fe15888b-60b3-4ae2-bc33-3febf6b7dff9', 'aaaaaaaa-0008-0008-0008-000000000008', 'c56fe2a8-2c17-4048-adc7-ff7fbd89461a', 'active', '2026-03-04 17:23:46.708711+00', '2026-04-03 17:23:46.708711+00', false, 'manual', NULL, NULL, '2026-03-04 17:23:46.708711+00', '2026-03-04 20:06:18.002704+00', NULL, 'therapist_free', 'month', 'fix_seed', '2026-03-04 17:23:46.708711+00', NULL, '2026-03-04 17:23:46.708711+00', NULL, NULL, NULL, NULL, NULL, NULL), + ('ca490958-d557-4407-ad04-fdfb134675f6', 'aaaaaaaa-0007-0007-0007-000000000007', 'ca28e46c-0687-45d5-9406-0a0f56a5b625', 'active', '2026-03-05 01:15:36.377017+00', '2027-03-05 01:15:36.377017+00', false, 'manual', NULL, NULL, '2026-03-04 17:23:46.708711+00', '2026-03-05 01:15:36.377017+00', NULL, 'supervisor_pro', 'year', 'manual', '2026-03-04 17:23:46.708711+00', NULL, '2026-03-04 17:23:46.708711+00', NULL, NULL, NULL, NULL, NULL, NULL), + ('5688fed8-1dc5-4bc1-9d19-91562c10a310', 'aaaaaaaa-0002-0002-0002-000000000002', '82067ba7-16f0-4803-b36f-4c4e8919d4b4', 'active', '2026-03-03 22:43:41.705072+00', '2026-04-02 22:43:41.705072+00', false, 'manual', NULL, NULL, '2026-03-03 22:43:41.705072+00', '2026-03-05 10:18:46.485009+00', NULL, 'therapist_pro', 'month', 'seed', '2026-03-03 22:43:41.705072+00', NULL, '2026-03-03 22:43:41.705072+00', NULL, NULL, NULL, NULL, NULL, NULL), + ('d2bd838f-5ac6-46f9-9282-4ddd0378e0a0', NULL, 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', 'active', '2026-03-03 22:43:41.705072+00', '2026-04-02 22:43:41.705072+00', false, 'manual', NULL, NULL, '2026-03-03 22:43:41.705072+00', '2026-03-06 02:53:19.171984+00', 'bbbbbbbb-0005-0005-0005-000000000005', 'clinic_pro', 'month', 'seed', '2026-03-03 22:43:41.705072+00', NULL, '2026-03-03 22:43:41.705072+00', NULL, NULL, NULL, NULL, NULL, NULL); + + +-- +-- Data for Name: subscription_events; Type: TABLE DATA; Schema: public; Owner: supabase_admin +-- + +INSERT INTO "public"."subscription_events" ("id", "subscription_id", "owner_id", "event_type", "old_plan_id", "new_plan_id", "created_at", "created_by", "source", "reason", "metadata", "owner_type", "owner_ref") VALUES + ('0ac1b150-4918-4f39-9606-d22a0355a7d6', '14a232bb-95da-400b-8547-df33e3acb2cb', '01b89c85-8e1b-43e2-bf10-77f4428ea582', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-01 22:46:00.062729+00', '1715ec83-9a30-4dce-b73a-2deb66dcfb13', 'admin_panel', 'Plan change via admin panel', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145"}', 'clinic', '01b89c85-8e1b-43e2-bf10-77f4428ea582'), + ('7b1abd18-2502-4a0c-ab99-8e896949ba70', '14a232bb-95da-400b-8547-df33e3acb2cb', '01b89c85-8e1b-43e2-bf10-77f4428ea582', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-01 22:46:06.127205+00', '1715ec83-9a30-4dce-b73a-2deb66dcfb13', 'admin_panel', 'Plan change via admin panel', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157"}', 'clinic', '01b89c85-8e1b-43e2-bf10-77f4428ea582'), + ('ee58e94b-956d-499d-ba8e-fcd96ce67f71', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 10:16:25.756235+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'admin_panel', 'Plan change via admin panel', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('4476c2e4-3d80-4f89-9dbd-348a3ef0c24f', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 10:16:30.237286+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'admin_panel', 'Plan change via admin panel', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('f442c7dc-9f84-48d6-ae94-91d20b584600', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 10:16:36.794144+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'admin_panel', 'Plan change via admin panel', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('d9f6da69-82e4-420a-b635-7ad387d78eb1', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 10:16:42.129262+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'admin_panel', 'Plan change via admin panel', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('24b0d04e-5aec-4a0f-97e3-5f7233ac4b34', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 10:16:55.626723+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'admin_panel', 'Plan change via admin panel', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('500b4aa4-720a-4c09-a0f7-15eba88cefb2', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 10:17:03.115842+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'admin_panel', 'Plan change via admin panel', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('22ca6007-d165-4766-965c-ac7108c1613a', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 11:15:14.983937+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('f059a638-4fa9-429b-a3ca-b14e4737ed9c', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 11:15:20.239736+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('700479d6-c51f-4440-a269-2606240627b5', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 11:16:02.350846+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('aa3b2ae1-21c1-4da1-90a1-739d26cc7321', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 11:16:08.189127+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('7aa3c6e8-0ad2-492a-9ff6-2caf0d9476a2', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 11:17:11.939539+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('5b09a306-1dc3-410e-b2dc-04b7fd2721de', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 11:17:18.090643+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('0f380398-3958-4852-9c24-1d5688609428', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 11:24:51.887608+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('5ffe2a58-64f0-4178-956c-c89bf2c28525', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 11:24:59.680817+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('50e7dec7-875b-4a63-861c-a37f8d5e68fa', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 11:25:06.579127+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('5ad68a8a-3bea-4d0f-80f3-077b1f11cd9b', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 11:25:35.147684+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('e35f9408-7cfb-4ab4-8ef1-7df333fc9ca8', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 11:25:41.854726+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('47b626fe-e46e-4b8a-abd8-cdfe0202547b', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 11:25:17.872637+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('8d968f3d-fa72-4c1f-9fad-6cca3f0c74d3', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 11:29:29.235947+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('3ca36bc3-ef72-4a3f-b398-24ad2140ae1d', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 11:29:39.054035+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('fcec216c-256b-4913-b963-12b8c49df4e3', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 11:29:44.115983+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('b1400d45-cd0a-4e3b-abcc-4de042c5004a', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 11:29:49.528958+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('6f200e77-04d3-4c01-8f62-8e41a8353805', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 11:29:54.178414+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('d871aceb-6f44-4a45-b8d5-77ed63054bb4', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 11:29:59.720946+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('55d09484-3181-45e1-8895-a8fbbc6e2b91', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 11:32:07.989229+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('a1f9b8e7-897f-4df9-9513-c2fc6a789b23', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 11:38:11.905472+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('f8f34136-eb64-48c0-adbc-0c4f11b81728', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 11:42:55.486033+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('f8d73fff-971a-4708-830d-97f7277d9b1d', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 11:43:02.514543+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('adf177c9-efe9-4ae1-a9fd-9c9931f8ee2e', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 11:53:02.703275+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('8c5b9772-951c-4af5-a35b-2f6e5c21ff8c', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 11:53:10.454794+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('a2d06936-d15f-4955-a534-4d2aa62c4a7f', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 11:56:37.131664+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('223f3a89-cc98-4660-8ff6-1a278eedba84', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 11:56:42.104606+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('11635205-cc2a-4af0-80c9-c270b9c01422', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 11:58:10.972092+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('36b3c5d6-3161-41ce-948c-8b7b9a89bece', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 11:58:18.01086+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('cbe9a080-276f-48f2-a0c6-777081c07d22', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 12:00:58.336294+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('c68c2422-f793-4a50-91b6-f0e44ebdf255', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 12:01:06.833943+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('b24b0f0e-7874-437d-a3cd-4b73a8609a00', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 12:01:12.161814+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('2128e7f1-550d-4df0-9f2a-3640de02f19b', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 12:01:20.473071+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('96f19a2b-6276-42b3-ad51-faffc7849650', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 12:02:01.959145+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('361140f4-5bc2-4b54-82e1-079831d9d2f1', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 12:02:07.315773+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('da19d476-abc8-4f90-8d83-70298dc0da20', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 12:17:38.864724+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('cc83e64d-6076-4a85-a2cb-ca1c5e95a7df', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 12:17:46.462048+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('6e076b81-1689-4a95-8de9-8bcc2fe2625a', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 12:19:13.253056+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('ac1ff98d-589c-43a5-890b-c2699ca3fbed', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 12:19:24.11638+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('8ff6d815-075d-4632-baac-66aa4fabcc58', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-02 13:23:49.772165+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('331df305-0c3c-48cf-bf7b-19dda81a9a5d', '29e61e41-090a-4367-b0f7-33fea2a65736', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-02 13:23:55.426163+00', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', '816b24fe-a0c3-4409-b79b-c6c0a6935d03'), + ('913d001f-8cc3-4f32-a71f-decfc8f03119', '9879b74d-ce28-4c51-8470-513650e8aa46', '51a475d2-7f11-43d7-b47d-3e78dcd3bd16', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-03 18:52:25.662322+00', '93ac96ab-d9d7-422b-81de-ae2fd4449fe3', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', '51a475d2-7f11-43d7-b47d-3e78dcd3bd16'), + ('8d53dddc-099a-4f36-a6ba-a8a1359a494a', '9879b74d-ce28-4c51-8470-513650e8aa46', '51a475d2-7f11-43d7-b47d-3e78dcd3bd16', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-03 18:52:33.027523+00', '93ac96ab-d9d7-422b-81de-ae2fd4449fe3', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', '51a475d2-7f11-43d7-b47d-3e78dcd3bd16'), + ('51e66650-cc8f-42df-aa2c-def6e03873d5', '9879b74d-ce28-4c51-8470-513650e8aa46', '51a475d2-7f11-43d7-b47d-3e78dcd3bd16', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-03 19:36:32.24533+00', '93ac96ab-d9d7-422b-81de-ae2fd4449fe3', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', '51a475d2-7f11-43d7-b47d-3e78dcd3bd16'), + ('6fb7cd22-5bf0-4e6d-8b30-c03179051933', 'd2bd838f-5ac6-46f9-9282-4ddd0378e0a0', 'bbbbbbbb-0005-0005-0005-000000000005', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-04 12:35:57.962865+00', 'aaaaaaaa-0005-0005-0005-000000000005', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', 'bbbbbbbb-0005-0005-0005-000000000005'), + ('5e923d5a-1b87-4993-a1f7-b3150ed86557', 'd2bd838f-5ac6-46f9-9282-4ddd0378e0a0', 'bbbbbbbb-0005-0005-0005-000000000005', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-04 12:36:02.521585+00', 'aaaaaaaa-0005-0005-0005-000000000005', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', 'bbbbbbbb-0005-0005-0005-000000000005'), + ('d0a0c6ea-6839-409c-b50c-14ac3760111a', 'd2bd838f-5ac6-46f9-9282-4ddd0378e0a0', 'bbbbbbbb-0005-0005-0005-000000000005', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-04 12:36:34.297781+00', 'aaaaaaaa-0005-0005-0005-000000000005', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', 'bbbbbbbb-0005-0005-0005-000000000005'), + ('7c023264-c2b2-4413-a7f0-4b8a3a5f3728', '112cb9f5-3120-49e5-886d-4346ccb27edd', 'aaaaaaaa-0001-0001-0001-000000000001', 'plan_changed', '984c1f29-a975-4208-93ac-2118ed1039b7', 'c56fe2a8-2c17-4048-adc7-ff7fbd89461a', '2026-03-04 17:24:56.964418+00', 'aaaaaaaa-0006-0006-0006-000000000006', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "c56fe2a8-2c17-4048-adc7-ff7fbd89461a", "new_plan_key": "therapist_free", "previous_plan": "984c1f29-a975-4208-93ac-2118ed1039b7", "new_plan_target": "therapist"}', 'therapist', 'aaaaaaaa-0001-0001-0001-000000000001'), + ('5b8c01ed-e846-4751-8d8a-7838b18a1789', 'd2bd838f-5ac6-46f9-9282-4ddd0378e0a0', 'bbbbbbbb-0005-0005-0005-000000000005', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-04 19:55:59.843618+00', 'aaaaaaaa-0008-0008-0008-000000000008', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', 'bbbbbbbb-0005-0005-0005-000000000005'), + ('3fbb8cfb-3aeb-4332-8e7e-4184f1a75705', 'fe15888b-60b3-4ae2-bc33-3febf6b7dff9', 'aaaaaaaa-0008-0008-0008-000000000008', 'plan_changed', 'c56fe2a8-2c17-4048-adc7-ff7fbd89461a', '82067ba7-16f0-4803-b36f-4c4e8919d4b4', '2026-03-04 19:56:17.664639+00', 'aaaaaaaa-0008-0008-0008-000000000008', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "82067ba7-16f0-4803-b36f-4c4e8919d4b4", "new_plan_key": "therapist_pro", "previous_plan": "c56fe2a8-2c17-4048-adc7-ff7fbd89461a", "new_plan_target": "therapist"}', 'therapist', 'aaaaaaaa-0008-0008-0008-000000000008'), + ('c4dde348-b6ba-4588-9071-5650b074f4b4', 'd2bd838f-5ac6-46f9-9282-4ddd0378e0a0', 'bbbbbbbb-0005-0005-0005-000000000005', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-04 19:56:31.853191+00', 'aaaaaaaa-0008-0008-0008-000000000008', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', 'bbbbbbbb-0005-0005-0005-000000000005'), + ('92670ac5-e24f-4e89-83c1-52da4ddf008d', 'fe15888b-60b3-4ae2-bc33-3febf6b7dff9', 'aaaaaaaa-0008-0008-0008-000000000008', 'plan_changed', '82067ba7-16f0-4803-b36f-4c4e8919d4b4', 'c56fe2a8-2c17-4048-adc7-ff7fbd89461a', '2026-03-04 19:56:49.08429+00', 'aaaaaaaa-0008-0008-0008-000000000008', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "c56fe2a8-2c17-4048-adc7-ff7fbd89461a", "new_plan_key": "therapist_free", "previous_plan": "82067ba7-16f0-4803-b36f-4c4e8919d4b4", "new_plan_target": "therapist"}', 'therapist', 'aaaaaaaa-0008-0008-0008-000000000008'), + ('6d94c18d-b062-4db1-9d73-f747ae1bb29a', 'fe15888b-60b3-4ae2-bc33-3febf6b7dff9', 'aaaaaaaa-0008-0008-0008-000000000008', 'plan_changed', 'c56fe2a8-2c17-4048-adc7-ff7fbd89461a', '82067ba7-16f0-4803-b36f-4c4e8919d4b4', '2026-03-04 20:05:46.201601+00', 'aaaaaaaa-0008-0008-0008-000000000008', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "82067ba7-16f0-4803-b36f-4c4e8919d4b4", "new_plan_key": "therapist_pro", "previous_plan": "c56fe2a8-2c17-4048-adc7-ff7fbd89461a", "new_plan_target": "therapist"}', 'therapist', 'aaaaaaaa-0008-0008-0008-000000000008'), + ('d0bd6dfb-ace7-423d-a37d-1992f96c0e88', 'fe15888b-60b3-4ae2-bc33-3febf6b7dff9', 'aaaaaaaa-0008-0008-0008-000000000008', 'plan_changed', '82067ba7-16f0-4803-b36f-4c4e8919d4b4', 'c56fe2a8-2c17-4048-adc7-ff7fbd89461a', '2026-03-04 20:05:54.037686+00', 'aaaaaaaa-0008-0008-0008-000000000008', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "c56fe2a8-2c17-4048-adc7-ff7fbd89461a", "new_plan_key": "therapist_free", "previous_plan": "82067ba7-16f0-4803-b36f-4c4e8919d4b4", "new_plan_target": "therapist"}', 'therapist', 'aaaaaaaa-0008-0008-0008-000000000008'), + ('405d716c-0b0b-42d1-b427-90b741fd4d21', 'fe15888b-60b3-4ae2-bc33-3febf6b7dff9', 'aaaaaaaa-0008-0008-0008-000000000008', 'plan_changed', 'c56fe2a8-2c17-4048-adc7-ff7fbd89461a', '82067ba7-16f0-4803-b36f-4c4e8919d4b4', '2026-03-04 20:06:11.300988+00', 'aaaaaaaa-0008-0008-0008-000000000008', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "82067ba7-16f0-4803-b36f-4c4e8919d4b4", "new_plan_key": "therapist_pro", "previous_plan": "c56fe2a8-2c17-4048-adc7-ff7fbd89461a", "new_plan_target": "therapist"}', 'therapist', 'aaaaaaaa-0008-0008-0008-000000000008'), + ('5b9adeab-64de-4da5-84d5-19d7c6fc2144', 'fe15888b-60b3-4ae2-bc33-3febf6b7dff9', 'aaaaaaaa-0008-0008-0008-000000000008', 'plan_changed', '82067ba7-16f0-4803-b36f-4c4e8919d4b4', 'c56fe2a8-2c17-4048-adc7-ff7fbd89461a', '2026-03-04 20:06:18.002704+00', 'aaaaaaaa-0008-0008-0008-000000000008', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "c56fe2a8-2c17-4048-adc7-ff7fbd89461a", "new_plan_key": "therapist_free", "previous_plan": "82067ba7-16f0-4803-b36f-4c4e8919d4b4", "new_plan_target": "therapist"}', 'therapist', 'aaaaaaaa-0008-0008-0008-000000000008'), + ('c7d31fd7-3777-4dea-ae54-453b74ef6a2e', '5688fed8-1dc5-4bc1-9d19-91562c10a310', 'aaaaaaaa-0002-0002-0002-000000000002', 'plan_changed', 'c56fe2a8-2c17-4048-adc7-ff7fbd89461a', '82067ba7-16f0-4803-b36f-4c4e8919d4b4', '2026-03-04 20:07:20.982706+00', 'aaaaaaaa-0002-0002-0002-000000000002', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "82067ba7-16f0-4803-b36f-4c4e8919d4b4", "new_plan_key": "therapist_pro", "previous_plan": "c56fe2a8-2c17-4048-adc7-ff7fbd89461a", "new_plan_target": "therapist"}', 'therapist', 'aaaaaaaa-0002-0002-0002-000000000002'), + ('51d2a479-25b6-4b72-9600-8d824ee1dbf3', '5688fed8-1dc5-4bc1-9d19-91562c10a310', 'aaaaaaaa-0002-0002-0002-000000000002', 'plan_changed', '82067ba7-16f0-4803-b36f-4c4e8919d4b4', 'c56fe2a8-2c17-4048-adc7-ff7fbd89461a', '2026-03-05 00:18:00.527748+00', 'aaaaaaaa-0002-0002-0002-000000000002', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "c56fe2a8-2c17-4048-adc7-ff7fbd89461a", "new_plan_key": "therapist_free", "previous_plan": "82067ba7-16f0-4803-b36f-4c4e8919d4b4", "new_plan_target": "therapist"}', 'therapist', 'aaaaaaaa-0002-0002-0002-000000000002'), + ('c4b00864-bc89-4338-98a9-a429ec723143', '5688fed8-1dc5-4bc1-9d19-91562c10a310', 'aaaaaaaa-0002-0002-0002-000000000002', 'plan_changed', 'c56fe2a8-2c17-4048-adc7-ff7fbd89461a', '82067ba7-16f0-4803-b36f-4c4e8919d4b4', '2026-03-05 00:18:03.728382+00', 'aaaaaaaa-0002-0002-0002-000000000002', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "82067ba7-16f0-4803-b36f-4c4e8919d4b4", "new_plan_key": "therapist_pro", "previous_plan": "c56fe2a8-2c17-4048-adc7-ff7fbd89461a", "new_plan_target": "therapist"}', 'therapist', 'aaaaaaaa-0002-0002-0002-000000000002'), + ('3c10ace6-e687-45f3-856f-8382b698d4d5', 'd2bd838f-5ac6-46f9-9282-4ddd0378e0a0', 'bbbbbbbb-0005-0005-0005-000000000005', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-05 00:18:20.9309+00', 'aaaaaaaa-0007-0007-0007-000000000007', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', 'bbbbbbbb-0005-0005-0005-000000000005'), + ('e477faad-fd05-43d5-848f-6818f9210190', 'd2bd838f-5ac6-46f9-9282-4ddd0378e0a0', 'bbbbbbbb-0005-0005-0005-000000000005', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-05 00:18:26.781326+00', 'aaaaaaaa-0007-0007-0007-000000000007', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', 'bbbbbbbb-0005-0005-0005-000000000005'), + ('9d4ac1c4-171d-4668-afd5-5c08a17d80bc', 'd2bd838f-5ac6-46f9-9282-4ddd0378e0a0', 'bbbbbbbb-0005-0005-0005-000000000005', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-05 00:18:37.931971+00', 'aaaaaaaa-0007-0007-0007-000000000007', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', 'bbbbbbbb-0005-0005-0005-000000000005'), + ('b349466b-7606-49c6-8355-3c6623bccc09', 'd2bd838f-5ac6-46f9-9282-4ddd0378e0a0', 'bbbbbbbb-0005-0005-0005-000000000005', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-05 00:18:46.62777+00', 'aaaaaaaa-0007-0007-0007-000000000007', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', 'bbbbbbbb-0005-0005-0005-000000000005'), + ('e6fb9c99-9a80-4769-9b4b-b175d7826c8b', 'd2bd838f-5ac6-46f9-9282-4ddd0378e0a0', 'bbbbbbbb-0005-0005-0005-000000000005', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-05 00:19:51.700295+00', 'aaaaaaaa-0007-0007-0007-000000000007', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', 'bbbbbbbb-0005-0005-0005-000000000005'), + ('0bbaa541-a039-488c-913d-d5158652b980', 'd2bd838f-5ac6-46f9-9282-4ddd0378e0a0', 'bbbbbbbb-0005-0005-0005-000000000005', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-05 00:55:23.989399+00', 'aaaaaaaa-0007-0007-0007-000000000007', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', 'bbbbbbbb-0005-0005-0005-000000000005'), + ('cc6c0214-9069-49de-8ab5-1974c8ea9e95', 'd2bd838f-5ac6-46f9-9282-4ddd0378e0a0', 'bbbbbbbb-0005-0005-0005-000000000005', 'plan_changed', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '01a5867f-0705-4714-ac97-a23470949157', '2026-03-05 00:55:27.507279+00', 'aaaaaaaa-0007-0007-0007-000000000007', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_key": "clinic_free", "previous_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_target": "clinic"}', 'clinic', 'bbbbbbbb-0005-0005-0005-000000000005'), + ('4f8177fb-c9a5-4d63-8455-988aa2d9f452', '5688fed8-1dc5-4bc1-9d19-91562c10a310', 'aaaaaaaa-0002-0002-0002-000000000002', 'plan_changed', '82067ba7-16f0-4803-b36f-4c4e8919d4b4', 'c56fe2a8-2c17-4048-adc7-ff7fbd89461a', '2026-03-05 10:18:42.036561+00', 'aaaaaaaa-0002-0002-0002-000000000002', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "c56fe2a8-2c17-4048-adc7-ff7fbd89461a", "new_plan_key": "therapist_free", "previous_plan": "82067ba7-16f0-4803-b36f-4c4e8919d4b4", "new_plan_target": "therapist"}', 'therapist', 'aaaaaaaa-0002-0002-0002-000000000002'), + ('5ccbf2b5-c323-4300-b74c-51817c5fd4db', '5688fed8-1dc5-4bc1-9d19-91562c10a310', 'aaaaaaaa-0002-0002-0002-000000000002', 'plan_changed', 'c56fe2a8-2c17-4048-adc7-ff7fbd89461a', '82067ba7-16f0-4803-b36f-4c4e8919d4b4', '2026-03-05 10:18:46.485009+00', 'aaaaaaaa-0002-0002-0002-000000000002', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "82067ba7-16f0-4803-b36f-4c4e8919d4b4", "new_plan_key": "therapist_pro", "previous_plan": "c56fe2a8-2c17-4048-adc7-ff7fbd89461a", "new_plan_target": "therapist"}', 'therapist', 'aaaaaaaa-0002-0002-0002-000000000002'), + ('362484d9-cce1-472c-9d7f-fd943051ae77', 'd2bd838f-5ac6-46f9-9282-4ddd0378e0a0', 'bbbbbbbb-0005-0005-0005-000000000005', 'plan_changed', '01a5867f-0705-4714-ac97-a23470949157', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '2026-03-06 02:53:19.171984+00', 'aaaaaaaa-0005-0005-0005-000000000005', 'dev_menu', 'Plan change via DEV menu', '{"new_plan": "a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145", "new_plan_key": "clinic_pro", "previous_plan": "01a5867f-0705-4714-ac97-a23470949157", "new_plan_target": "clinic"}', 'clinic', 'bbbbbbbb-0005-0005-0005-000000000005'); + + +-- +-- Data for Name: subscription_intents_legacy; Type: TABLE DATA; Schema: public; Owner: supabase_admin +-- + +INSERT INTO "public"."subscription_intents_legacy" ("id", "user_id", "email", "plan_key", "interval", "amount_cents", "currency", "status", "source", "notes", "created_at", "paid_at", "tenant_id", "created_by_user_id") VALUES + ('c03472bd-558a-4070-9b85-dd8fa9d865f5', NULL, 'teste@agenciapsi.com.br', 'clinic_pro', 'year', 149000, 'BRL', 'canceled', 'landing', NULL, '2026-03-01 12:30:19.324037+00', '2026-03-01 14:17:25.052+00', 'f491f4d4-7801-4f80-bd01-1ba18f647034', '8817508e-548c-427b-9d94-9b0bb9ef4669'), + ('b9e19fa8-e5e5-4d46-ac4c-7565d0466b6d', NULL, 'teste2@agenciapsi.com.br', 'therapist_pro', 'year', 49000, 'BRL', 'paid', 'landing', NULL, '2026-03-01 14:32:55.799941+00', '2026-03-01 14:34:01.372+00', '60fc942e-fd6d-428a-b125-82190d92e4ac', 'b7e6a203-25f2-4e28-855a-9868c4cc6e74'); + + +-- +-- Data for Name: subscription_intents_personal; Type: TABLE DATA; Schema: public; Owner: supabase_admin +-- + +INSERT INTO "public"."subscription_intents_personal" ("id", "user_id", "created_by_user_id", "email", "plan_id", "plan_key", "interval", "amount_cents", "currency", "status", "source", "notes", "created_at", "paid_at", "subscription_id") VALUES + ('b9e19fa8-e5e5-4d46-ac4c-7565d0466b6d', 'b7e6a203-25f2-4e28-855a-9868c4cc6e74', 'b7e6a203-25f2-4e28-855a-9868c4cc6e74', 'teste2@agenciapsi.com.br', '82067ba7-16f0-4803-b36f-4c4e8919d4b4', 'therapist_pro', 'year', 49000, 'BRL', 'paid', 'landing', NULL, '2026-03-01 14:32:55.799941+00', '2026-03-01 14:34:01.372+00', NULL), + ('3ac8e889-adcc-4d6f-a7fe-57ad72fdde9a', 'ff5a39cb-b651-4e42-a0db-ac77295c3370', 'ff5a39cb-b651-4e42-a0db-ac77295c3370', 'tera3@agenciapsi.com.br', '82067ba7-16f0-4803-b36f-4c4e8919d4b4', 'therapist_pro', 'year', 49000, 'BRL', 'paid', 'landing', NULL, '2026-03-01 15:03:56.75232+00', '2026-03-01 15:09:08.381+00', NULL), + ('00ef890b-c3a0-4882-a536-54f998395c94', '66216eb3-15fc-45a3-b474-c7447901798a', '66216eb3-15fc-45a3-b474-c7447901798a', 'tera4@agenciapsi.com.br', '82067ba7-16f0-4803-b36f-4c4e8919d4b4', 'therapist_pro', 'year', 49000, 'BRL', 'paid', 'landing', NULL, '2026-03-01 16:06:09.937903+00', '2026-03-01 16:07:26.95+00', NULL); + + +-- +-- Data for Name: subscription_intents_tenant; Type: TABLE DATA; Schema: public; Owner: supabase_admin +-- + +INSERT INTO "public"."subscription_intents_tenant" ("id", "user_id", "created_by_user_id", "email", "plan_id", "plan_key", "interval", "amount_cents", "currency", "status", "source", "notes", "created_at", "paid_at", "tenant_id", "subscription_id") VALUES + ('c03472bd-558a-4070-9b85-dd8fa9d865f5', '8817508e-548c-427b-9d94-9b0bb9ef4669', '8817508e-548c-427b-9d94-9b0bb9ef4669', 'teste@agenciapsi.com.br', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', 'clinic_pro', 'year', 149000, 'BRL', 'canceled', 'landing', NULL, '2026-03-01 12:30:19.324037+00', '2026-03-01 14:17:25.052+00', 'f491f4d4-7801-4f80-bd01-1ba18f647034', NULL), + ('3812bf8b-49e3-45d9-b1cc-e78bf4e8b0f6', '1715ec83-9a30-4dce-b73a-2deb66dcfb13', '1715ec83-9a30-4dce-b73a-2deb66dcfb13', 'clinic4@agenciapsi.com.br', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', 'clinic_pro', 'year', 149000, 'BRL', 'paid', 'landing', NULL, '2026-03-01 16:09:56.843502+00', '2026-03-01 16:10:28.563+00', '01b89c85-8e1b-43e2-bf10-77f4428ea582', '14a232bb-95da-400b-8547-df33e3acb2cb'); + + +-- +-- Data for Name: tenant_feature_exceptions_log; Type: TABLE DATA; Schema: public; Owner: supabase_admin +-- + + + +-- +-- Data for Name: tenant_features; Type: TABLE DATA; Schema: public; Owner: supabase_admin +-- + + + +-- +-- Data for Name: tenant_invites; Type: TABLE DATA; Schema: public; Owner: supabase_admin +-- + + + +-- +-- Data for Name: tenant_modules; Type: TABLE DATA; Schema: public; Owner: supabase_admin +-- + + + +-- +-- Data for Name: user_settings; Type: TABLE DATA; Schema: public; Owner: supabase_admin +-- + +INSERT INTO "public"."user_settings" ("user_id", "theme_mode", "preset", "primary_color", "surface_color", "menu_mode", "created_at", "updated_at") VALUES + ('aaaaaaaa-0005-0005-0005-000000000005', 'light', 'Aura', 'emerald', 'slate', 'static', '2026-03-04 03:17:57.617227+00', '2026-03-04 03:17:57.606+00'); + + +-- +-- Data for Name: buckets; Type: TABLE DATA; Schema: storage; Owner: supabase_storage_admin +-- + +INSERT INTO "storage"."buckets" ("id", "name", "owner", "created_at", "updated_at", "public", "avif_autodetection", "file_size_limit", "allowed_mime_types", "owner_id", "type") VALUES + ('avatars', 'avatars', NULL, '2026-02-13 10:57:15.112446+00', '2026-02-13 10:57:15.112446+00', true, false, NULL, NULL, NULL, 'STANDARD'), + ('saas-docs', 'saas-docs', NULL, '2026-03-07 12:18:17.11377+00', '2026-03-07 12:18:17.11377+00', true, false, NULL, NULL, NULL, 'STANDARD'); + + +-- +-- Data for Name: buckets_analytics; Type: TABLE DATA; Schema: storage; Owner: supabase_storage_admin +-- + + + +-- +-- Data for Name: buckets_vectors; Type: TABLE DATA; Schema: storage; Owner: supabase_storage_admin +-- + + + +-- +-- Data for Name: iceberg_namespaces; Type: TABLE DATA; Schema: storage; Owner: supabase_storage_admin +-- + + + +-- +-- Data for Name: iceberg_tables; Type: TABLE DATA; Schema: storage; Owner: supabase_storage_admin +-- + + + +-- +-- Data for Name: objects; Type: TABLE DATA; Schema: storage; Owner: supabase_storage_admin +-- + +INSERT INTO "storage"."objects" ("id", "bucket_id", "name", "owner", "created_at", "updated_at", "last_accessed_at", "metadata", "version", "owner_id", "user_metadata") VALUES + ('50e11318-aa1b-49b1-838c-0d72d602381b', 'avatars', 'owners/816b24fe-a0c3-4409-b79b-c6c0a6935d03/patients/feb4adf6-1c9a-4b26-9a36-a115eb913491/avatar.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-13 10:59:56.62912+00', '2026-02-13 10:59:56.62912+00', '2026-02-13 10:59:56.62912+00', '{"eTag": "\"e8298226e90e0720ff95c90c5b61e08c\"", "size": 53065, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-13T10:59:56.614Z", "contentLength": 53065, "httpStatusCode": 200}', '54d59a6b-6c83-4cf1-a035-60673d3db77a', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('844ea52c-97f9-48b2-b6ff-819cbbf20632', 'avatars', 'owners/816b24fe-a0c3-4409-b79b-c6c0a6935d03/patients/855a710d-8e38-4573-8628-d0da761880d3/avatar.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-13 11:00:14.880981+00', '2026-02-13 11:00:14.880981+00', '2026-02-13 11:00:14.880981+00', '{"eTag": "\"e8298226e90e0720ff95c90c5b61e08c\"", "size": 53065, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-13T11:00:14.873Z", "contentLength": 53065, "httpStatusCode": 200}', 'f16ae449-1a78-48bb-b8f3-fe1808a1ac3e', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('06b0429c-6637-4412-9cff-0d5507a4209b', 'avatars', 'owners/816b24fe-a0c3-4409-b79b-c6c0a6935d03/patients/185f674e-c11c-4b54-817f-78b57bf60ebd/avatar.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-13 11:04:11.155662+00', '2026-02-13 11:04:11.155662+00', '2026-02-13 11:04:11.155662+00', '{"eTag": "\"8ff97e8238a368c6f59596d7a8b9e052\"", "size": 48710, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-13T11:04:11.137Z", "contentLength": 48710, "httpStatusCode": 200}', '04cfaa5c-83d1-491b-898e-9a8337304d3d', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('e940a717-5e89-40f7-b955-64acf085117f', 'avatars', 'owners/816b24fe-a0c3-4409-b79b-c6c0a6935d03/patients/a33dfec0-c954-467f-99a6-5f859b8d5168/avatar.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-13 11:28:36.307652+00', '2026-02-13 11:28:36.307652+00', '2026-02-13 11:28:36.307652+00', '{"eTag": "\"60d363c60025fd47681d9b9d50939a8d\"", "size": 158427, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-13T11:28:36.296Z", "contentLength": 158427, "httpStatusCode": 200}', '77921ca7-ac84-4217-be5d-f1bfcbed9f12', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('565e79e7-998a-4e14-a930-5dc80d0ea229', 'avatars', 'owners/816b24fe-a0c3-4409-b79b-c6c0a6935d03/patients/073566cb-8848-4cc0-9799-63821721301a/avatar.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-14 10:45:41.332186+00', '2026-02-14 10:45:41.332186+00', '2026-02-14 10:45:41.332186+00', '{"eTag": "\"1b4616f55d72d416d545f16b064e11cb\"", "size": 11068, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-14T10:45:41.322Z", "contentLength": 11068, "httpStatusCode": 200}', '245717d3-d822-461c-8c63-ed61b2b6e7c5', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('29bbc519-9640-43d0-8793-f5c720cc1cf7', 'avatars', 'owners/816b24fe-a0c3-4409-b79b-c6c0a6935d03/patients/41a9dea9-6b78-4935-b130-f12a401e524b/avatar.jpg', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-14 22:49:41.773524+00', '2026-02-14 22:49:41.773524+00', '2026-02-14 22:49:41.773524+00', '{"eTag": "\"a52df9c148a23f1940ad5342f23d4c02\"", "size": 46616, "mimetype": "image/jpeg", "cacheControl": "max-age=3600", "lastModified": "2026-02-14T22:49:41.766Z", "contentLength": 46616, "httpStatusCode": 200}', 'c80f9964-7edd-462d-8978-ff275b03ddb8', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('7f643c66-dca6-4a7a-877f-6f95aed37333', 'avatars', 'intakes/d8e36584-bad9-4282-8ecc-85d11ef32ddf/1771113052395.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-14 23:50:52.468498+00', '2026-02-14 23:50:52.468498+00', '2026-02-14 23:50:52.468498+00', '{"eTag": "\"8ff97e8238a368c6f59596d7a8b9e052\"", "size": 48710, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-14T23:50:52.460Z", "contentLength": 48710, "httpStatusCode": 200}', '7b0ec2d7-3311-482d-808f-ac2ed5cd8382', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('9611f77f-6ddf-4686-9553-a2958dc4c0b4', 'avatars', 'owners/816b24fe-a0c3-4409-b79b-c6c0a6935d03/patients/41a9dea9-6b78-4935-b130-f12a401e524b/avatar.webp', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-14 22:41:18.666508+00', '2026-02-14 22:51:13.970348+00', '2026-02-14 22:41:18.666508+00', '{"eTag": "\"af758fda0f2989c0fe7e39c321769aae\"", "size": 62662, "mimetype": "image/webp", "cacheControl": "max-age=3600", "lastModified": "2026-02-14T22:51:13.964Z", "contentLength": 62662, "httpStatusCode": 200}', '32fb3e00-753f-4ee7-86a5-25d5080c61ce', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('099c0773-5d11-4d2a-a211-888665730eae', 'avatars', 'intakes/d8e36584-bad9-4282-8ecc-85d11ef32ddf/1771112303349.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-14 23:38:23.455894+00', '2026-02-14 23:38:23.455894+00', '2026-02-14 23:38:23.455894+00', '{"eTag": "\"74507674e136ced661770458c66ae98f\"", "size": 163818, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-14T23:38:23.441Z", "contentLength": 163818, "httpStatusCode": 200}', 'b4c571de-82a4-4bf0-8dc2-3b01f3f787ad', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('22c6f5ed-2e0e-45e8-aed9-141dd0e8f8f7', 'avatars', 'intakes/d8e36584-bad9-4282-8ecc-85d11ef32ddf/1771114348468.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-15 00:12:28.566767+00', '2026-02-15 00:12:28.566767+00', '2026-02-15 00:12:28.566767+00', '{"eTag": "\"74507674e136ced661770458c66ae98f\"", "size": 163818, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-15T00:12:28.545Z", "contentLength": 163818, "httpStatusCode": 200}', '2adbac99-15a5-4b25-a62e-59e8752fd05f', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('5e223e52-2e7e-42a5-b2bc-9842e324102b', 'avatars', 'owners/816b24fe-a0c3-4409-b79b-c6c0a6935d03/patients/41a9dea9-6b78-4935-b130-f12a401e524b/avatar.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-14 21:55:49.427204+00', '2026-02-15 03:28:17.452824+00', '2026-02-14 21:55:49.427204+00', '{"eTag": "\"8ff97e8238a368c6f59596d7a8b9e052\"", "size": 48710, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-15T03:28:17.435Z", "contentLength": 48710, "httpStatusCode": 200}', 'b827ddef-3858-43dc-8c67-4856682a9e62', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('adaca36b-0e67-491b-bd5e-65b629d8fd94', 'avatars', 'intakes/d8e36584-bad9-4282-8ecc-85d11ef32ddf/1771115670697.jpg', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-15 00:34:30.75628+00', '2026-02-15 00:34:30.75628+00', '2026-02-15 00:34:30.75628+00', '{"eTag": "\"ef32cf7cfbb4f5f02cf6232c16eab2d5\"", "size": 81994, "mimetype": "image/jpeg", "cacheControl": "max-age=3600", "lastModified": "2026-02-15T00:34:30.743Z", "contentLength": 81994, "httpStatusCode": 200}', 'f7b66f46-3eb4-49b8-b5cf-5a88de726bc1', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('3325a9e2-388e-4d50-b43f-5a15b3d431d4', 'avatars', 'owners/816b24fe-a0c3-4409-b79b-c6c0a6935d03/patients/c6d73ef9-d0f5-4f3b-8113-e06b1e0d2ed1/avatar.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-15 03:44:03.89885+00', '2026-02-15 03:44:03.89885+00', '2026-02-15 03:44:03.89885+00', '{"eTag": "\"7b64ce3cc393706c34f9717d7e37d19f\"", "size": 48619, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-15T03:44:03.892Z", "contentLength": 48619, "httpStatusCode": 200}', '18d424a8-ceaf-47ff-a77e-b174dd58e573', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('bf8becb8-d2ac-405e-8625-7b3caf34dac5', 'avatars', 'intakes/b49f3c84-6b07-4d1f-bc7e-82353518871f/1771128971606.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-15 04:16:11.704431+00', '2026-02-15 04:16:11.704431+00', '2026-02-15 04:16:11.704431+00', '{"eTag": "\"74507674e136ced661770458c66ae98f\"", "size": 163818, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-15T04:16:11.692Z", "contentLength": 163818, "httpStatusCode": 200}', '26e1e831-fed6-4aaa-8abf-175d7d6693f1', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('6d88e419-dbba-4b22-8188-293bcbfcfb29', 'avatars', 'intakes/b49f3c84-6b07-4d1f-bc7e-82353518871f/1771129446221.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-15 04:24:06.331623+00', '2026-02-15 04:24:06.331623+00', '2026-02-15 04:24:06.331623+00', '{"eTag": "\"8ff97e8238a368c6f59596d7a8b9e052\"", "size": 48710, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-15T04:24:06.318Z", "contentLength": 48710, "httpStatusCode": 200}', '24f41446-456f-49d1-b4bd-df6ffd31943f', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('9adcb0e7-0383-441a-a884-992d771f871c', 'avatars', 'intakes/b49f3c84-6b07-4d1f-bc7e-82353518871f/1771129756674.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-15 04:29:16.785291+00', '2026-02-15 04:29:16.785291+00', '2026-02-15 04:29:16.785291+00', '{"eTag": "\"d261f9999980baf36dc11dba9bddcc34\"", "size": 1093361, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-15T04:29:16.768Z", "contentLength": 1093361, "httpStatusCode": 200}', '72d36469-fab3-4f4b-ab45-ee501cb4a7e5', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('36055339-9426-4b60-a8c6-8c9f0efa5fdb', 'avatars', 'intakes/b49f3c84-6b07-4d1f-bc7e-82353518871f/1771130629382.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-15 04:43:49.458561+00', '2026-02-15 04:43:49.458561+00', '2026-02-15 04:43:49.458561+00', '{"eTag": "\"8ff97e8238a368c6f59596d7a8b9e052\"", "size": 48710, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-15T04:43:49.449Z", "contentLength": 48710, "httpStatusCode": 200}', '72c41d69-16fc-4ca8-9ab0-37be981d3298', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('d9566165-66f7-4700-a89a-ab495ed7d55e', 'avatars', 'intakes/b49f3c84-6b07-4d1f-bc7e-82353518871f/1771130649087.jpg', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-15 04:44:09.152935+00', '2026-02-15 04:44:09.152935+00', '2026-02-15 04:44:09.152935+00', '{"eTag": "\"7956953d5fe6ad5eab52078fb0ea6e02\"", "size": 179152, "mimetype": "image/jpeg", "cacheControl": "max-age=3600", "lastModified": "2026-02-15T04:44:09.140Z", "contentLength": 179152, "httpStatusCode": 200}', 'f5f626a1-37f2-4615-b838-db8dbbdde529', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('29bb63f7-6436-49fe-aba8-c90d3565fc9a', 'avatars', 'intakes/b49f3c84-6b07-4d1f-bc7e-82353518871f/1771151412345.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-15 10:30:12.47715+00', '2026-02-15 10:30:12.47715+00', '2026-02-15 10:30:12.47715+00', '{"eTag": "\"8ff97e8238a368c6f59596d7a8b9e052\"", "size": 48710, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-15T10:30:12.462Z", "contentLength": 48710, "httpStatusCode": 200}', '5b5d5c81-6405-4bc2-9c8e-e1a0786d62bf', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('e64c973d-8728-4af1-af79-81e807daf9fd', 'avatars', 'intakes/b49f3c84-6b07-4d1f-bc7e-82353518871f/1771151517004.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-15 10:31:57.105174+00', '2026-02-15 10:31:57.105174+00', '2026-02-15 10:31:57.105174+00', '{"eTag": "\"74507674e136ced661770458c66ae98f\"", "size": 163818, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-15T10:31:57.089Z", "contentLength": 163818, "httpStatusCode": 200}', 'e3e2e3f7-bcfc-4826-b93c-ec1eb04fb060', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('dbca50d8-f019-4583-9ecc-5452d8200d68', 'avatars', 'intakes/b49f3c84-6b07-4d1f-bc7e-82353518871f/1771151579058.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-15 10:32:59.171248+00', '2026-02-15 10:32:59.171248+00', '2026-02-15 10:32:59.171248+00', '{"eTag": "\"8ff97e8238a368c6f59596d7a8b9e052\"", "size": 48710, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-15T10:32:59.162Z", "contentLength": 48710, "httpStatusCode": 200}', '90e4e84e-0d73-4351-b383-af6d293d5421', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('5f20a0c6-850a-4f94-94e6-cc63f4abcb40', 'avatars', 'intakes/b49f3c84-6b07-4d1f-bc7e-82353518871f/1771151702285.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-15 10:35:02.361515+00', '2026-02-15 10:35:02.361515+00', '2026-02-15 10:35:02.361515+00', '{"eTag": "\"8ff97e8238a368c6f59596d7a8b9e052\"", "size": 48710, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-15T10:35:02.354Z", "contentLength": 48710, "httpStatusCode": 200}', 'c528b58a-28e1-4c2b-9cc7-90cc4a6c159c', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('01518d2f-b58e-4385-8936-ca9b22acbf2e', 'avatars', 'intakes/b49f3c84-6b07-4d1f-bc7e-82353518871f/1771152194733.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-15 10:43:14.814797+00', '2026-02-15 10:43:14.814797+00', '2026-02-15 10:43:14.814797+00', '{"eTag": "\"74507674e136ced661770458c66ae98f\"", "size": 163818, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-15T10:43:14.803Z", "contentLength": 163818, "httpStatusCode": 200}', 'cc9db17e-f3a9-4ff9-a7c7-ec54da6f732d', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('d87241ad-c417-4c5d-9aac-00e987975bc4', 'avatars', 'intakes/b49f3c84-6b07-4d1f-bc7e-82353518871f/1771152585748.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-15 10:49:45.814249+00', '2026-02-15 10:49:45.814249+00', '2026-02-15 10:49:45.814249+00', '{"eTag": "\"e8298226e90e0720ff95c90c5b61e08c\"", "size": 53065, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-15T10:49:45.806Z", "contentLength": 53065, "httpStatusCode": 200}', 'b2225e51-4b4b-477f-af8c-92cf179d38f2', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('05a13d1c-0bdf-47ae-a645-0f5175edaa87', 'avatars', 'intakes/b49f3c84-6b07-4d1f-bc7e-82353518871f/1771153252909.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-15 11:00:53.010494+00', '2026-02-15 11:00:53.010494+00', '2026-02-15 11:00:53.010494+00', '{"eTag": "\"60d363c60025fd47681d9b9d50939a8d\"", "size": 158427, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-15T11:00:53.000Z", "contentLength": 158427, "httpStatusCode": 200}', 'dda4b152-6a84-48ea-8b28-b829d78e55b0', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('75097354-fd27-4ef5-a54b-eb4e79da908a', 'avatars', 'intakes/b49f3c84-6b07-4d1f-bc7e-82353518871f/1771153439377.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-15 11:03:59.450908+00', '2026-02-15 11:03:59.450908+00', '2026-02-15 11:03:59.450908+00', '{"eTag": "\"8ff97e8238a368c6f59596d7a8b9e052\"", "size": 48710, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-15T11:03:59.441Z", "contentLength": 48710, "httpStatusCode": 200}', '212ffa33-f392-4a8b-a35d-64a7ab4bf9bc', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('b2071532-a0de-46be-856b-cc6e48c71a83', 'avatars', 'owners/816b24fe-a0c3-4409-b79b-c6c0a6935d03/patients/de1076a9-f4eb-4de6-9394-2225eb82bc2a/avatar.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-16 21:26:42.194776+00', '2026-02-16 21:26:42.194776+00', '2026-02-16 21:26:42.194776+00', '{"eTag": "\"8ff97e8238a368c6f59596d7a8b9e052\"", "size": 48710, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-16T21:26:42.182Z", "contentLength": 48710, "httpStatusCode": 200}', 'db34d7c5-bd0d-4694-a00b-487fc4e911a0', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('62e5bb58-eae4-41d3-90b0-55287b2edfcf', 'avatars', '816b24fe-a0c3-4409-b79b-c6c0a6935d03/avatar-1771287464893.jpg', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-17 00:17:45.046809+00', '2026-02-17 00:17:45.046809+00', '2026-02-17 00:17:45.046809+00', '{"eTag": "\"786fd3a000090ec8eada2f124aa702c8\"", "size": 902895, "mimetype": "image/jpeg", "cacheControl": "max-age=3600", "lastModified": "2026-02-17T00:17:45.029Z", "contentLength": 902895, "httpStatusCode": 200}', 'e98e9299-5240-4db1-90ed-6a62f7c799b5', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('31251500-6f03-4ac7-bce5-f4474157ed9b', 'avatars', 'owners/824f125c-55bb-40f5-a8c4-7a33618b91c7/patients/d736bf55-3905-4db3-b2d4-38ad8c06c957/avatar.png', '824f125c-55bb-40f5-a8c4-7a33618b91c7', '2026-02-21 20:14:20.585086+00', '2026-02-21 20:14:20.585086+00', '2026-02-21 20:14:20.585086+00', '{"eTag": "\"74507674e136ced661770458c66ae98f\"", "size": 163818, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-21T20:14:20.573Z", "contentLength": 163818, "httpStatusCode": 200}', 'c344dade-8b93-4243-9c38-ae571b5eae64', '824f125c-55bb-40f5-a8c4-7a33618b91c7', '{}'), + ('2fdbffe6-0bf0-472e-89d4-03da0e100ebd', 'avatars', 'owners/824f125c-55bb-40f5-a8c4-7a33618b91c7/patients/d4d4c55e-a076-4af4-bb66-b136bfc20719/avatar.png', '824f125c-55bb-40f5-a8c4-7a33618b91c7', '2026-02-24 15:13:45.0233+00', '2026-02-24 15:13:45.0233+00', '2026-02-24 15:13:45.0233+00', '{"eTag": "\"8ff97e8238a368c6f59596d7a8b9e052\"", "size": 48710, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-24T15:13:45.011Z", "contentLength": 48710, "httpStatusCode": 200}', 'acb8140d-a26c-4bd5-9320-205ae0429582', '824f125c-55bb-40f5-a8c4-7a33618b91c7', '{}'), + ('bf5ae728-1478-4951-8016-e839ddfe06f6', 'avatars', 'owners/824f125c-55bb-40f5-a8c4-7a33618b91c7/patients/ec16fb50-9c13-4bc0-8ff4-28124c195062/avatar.png', '824f125c-55bb-40f5-a8c4-7a33618b91c7', '2026-02-24 16:40:23.194179+00', '2026-02-24 16:40:23.194179+00', '2026-02-24 16:40:23.194179+00', '{"eTag": "\"7acd7fe015d57168c9d1f740e6ef9dca\"", "size": 120039, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-24T16:40:23.181Z", "contentLength": 120039, "httpStatusCode": 200}', '2a828e73-38f9-4160-adb9-f9a97ef338b7', '824f125c-55bb-40f5-a8c4-7a33618b91c7', '{}'), + ('30257c7b-6505-4a26-a406-d09a34850219', 'avatars', 'owners/824f125c-55bb-40f5-a8c4-7a33618b91c7/patients/f7f51807-ab84-4fc4-a345-1d5b2de094c4/avatar.webp', '824f125c-55bb-40f5-a8c4-7a33618b91c7', '2026-02-24 16:44:05.35217+00', '2026-02-24 16:44:05.35217+00', '2026-02-24 16:44:05.35217+00', '{"eTag": "\"7d090e1ccd302488cb8ac03ea09e5354\"", "size": 94090, "mimetype": "image/webp", "cacheControl": "max-age=3600", "lastModified": "2026-02-24T16:44:05.337Z", "contentLength": 94090, "httpStatusCode": 200}', 'f31ba834-e1aa-4e19-a6ae-c9152c223e01', '824f125c-55bb-40f5-a8c4-7a33618b91c7', '{}'), + ('842c95a4-dbb6-489b-83d3-074fdbebe251', 'avatars', 'owners/824f125c-55bb-40f5-a8c4-7a33618b91c7/patients/965e2f5e-9d4f-4044-ae09-1caaf21d5c5e/avatar.png', '824f125c-55bb-40f5-a8c4-7a33618b91c7', '2026-02-24 17:32:26.591942+00', '2026-02-24 17:32:26.591942+00', '2026-02-24 17:32:26.591942+00', '{"eTag": "\"8ff97e8238a368c6f59596d7a8b9e052\"", "size": 48710, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-24T17:32:26.587Z", "contentLength": 48710, "httpStatusCode": 200}', '649e45b0-e23a-4e92-8015-8250835dd0f6', '824f125c-55bb-40f5-a8c4-7a33618b91c7', '{}'), + ('43ee8347-87c7-478f-baeb-594261328de5', 'avatars', 'owners/824f125c-55bb-40f5-a8c4-7a33618b91c7/patients/9285890e-e35d-47ac-b553-9b469c85762b/avatar.png', '824f125c-55bb-40f5-a8c4-7a33618b91c7', '2026-02-24 17:43:23.948616+00', '2026-02-24 17:43:23.948616+00', '2026-02-24 17:43:23.948616+00', '{"eTag": "\"8ff97e8238a368c6f59596d7a8b9e052\"", "size": 48710, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-24T17:43:23.934Z", "contentLength": 48710, "httpStatusCode": 200}', 'c0c9963a-463a-4f8d-ad3c-b18d32c2baf3', '824f125c-55bb-40f5-a8c4-7a33618b91c7', '{}'), + ('0d5a672f-8a6f-4938-b191-2b588a4a6fa8', 'avatars', 'owners/816b24fe-a0c3-4409-b79b-c6c0a6935d03/patients/fe32e8e4-fd5e-43e9-a1a3-8337f9354f1d/avatar.png', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-24 17:48:16.389014+00', '2026-02-24 17:48:16.389014+00', '2026-02-24 17:48:16.389014+00', '{"eTag": "\"8ff97e8238a368c6f59596d7a8b9e052\"", "size": 48710, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-24T17:48:16.380Z", "contentLength": 48710, "httpStatusCode": 200}', '7650379e-4566-4e01-9599-03cc57cd3e01', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('2855dba0-3482-4c04-ace2-001e52c99d4f', 'avatars', 'owners/824f125c-55bb-40f5-a8c4-7a33618b91c7/patients/89bb79c8-5b30-4218-a912-4ae5a8304d1c/avatar.png', '824f125c-55bb-40f5-a8c4-7a33618b91c7', '2026-02-26 04:12:57.005928+00', '2026-02-26 04:12:57.005928+00', '2026-02-26 04:12:57.005928+00', '{"eTag": "\"8ff97e8238a368c6f59596d7a8b9e052\"", "size": 48710, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-26T04:12:56.969Z", "contentLength": 48710, "httpStatusCode": 200}', '6946c28b-6cc7-47fe-8f71-e5dbce38cdbd', '824f125c-55bb-40f5-a8c4-7a33618b91c7', '{}'), + ('895d2975-5b0a-4af1-8df7-b055939af665', 'avatars', 'owners/824f125c-55bb-40f5-a8c4-7a33618b91c7/patients/1ae4b29d-d5fd-4490-b775-ad260ef0b74d/avatar.png', '824f125c-55bb-40f5-a8c4-7a33618b91c7', '2026-02-26 04:13:20.962471+00', '2026-02-26 04:13:20.962471+00', '2026-02-26 04:13:20.962471+00', '{"eTag": "\"74507674e136ced661770458c66ae98f\"", "size": 163818, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-02-26T04:13:20.944Z", "contentLength": 163818, "httpStatusCode": 200}', '46c51cbc-2075-4d76-bf1d-4d6a3bc118ae', '824f125c-55bb-40f5-a8c4-7a33618b91c7', '{}'), + ('98bef170-3669-429f-9e9f-2f7062fd396d', 'avatars', 'intakes/dd2862f6-9436-4905-ae79-a606f9a740b6/1772079264021.webp', '824f125c-55bb-40f5-a8c4-7a33618b91c7', '2026-02-26 04:14:24.079966+00', '2026-02-26 04:14:24.079966+00', '2026-02-26 04:14:24.079966+00', '{"eTag": "\"af758fda0f2989c0fe7e39c321769aae\"", "size": 62662, "mimetype": "image/webp", "cacheControl": "max-age=3600", "lastModified": "2026-02-26T04:14:24.069Z", "contentLength": 62662, "httpStatusCode": 200}', '449142b8-9056-4851-b22e-72c8ae2b9ed0', '824f125c-55bb-40f5-a8c4-7a33618b91c7', '{}'), + ('db8022ee-9a06-4add-929f-d6a876b7988d', 'avatars', 'intakes/dd2862f6-9436-4905-ae79-a606f9a740b6/1772107266247.webp', '824f125c-55bb-40f5-a8c4-7a33618b91c7', '2026-02-26 12:01:06.345089+00', '2026-02-26 12:01:06.345089+00', '2026-02-26 12:01:06.345089+00', '{"eTag": "\"af758fda0f2989c0fe7e39c321769aae\"", "size": 62662, "mimetype": "image/webp", "cacheControl": "max-age=3600", "lastModified": "2026-02-26T12:01:06.336Z", "contentLength": 62662, "httpStatusCode": 200}', '0d559524-67a3-4973-965e-62d766d7dc60', '824f125c-55bb-40f5-a8c4-7a33618b91c7', '{}'), + ('a169dac1-45e5-4fb1-aded-94e773cb334a', 'avatars', 'intakes/b49f3c84-6b07-4d1f-bc7e-82353518871f/1772107513331.jpg', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '2026-02-26 12:05:13.392687+00', '2026-02-26 12:05:13.392687+00', '2026-02-26 12:05:13.392687+00', '{"eTag": "\"9f79c57a730113d50d24036ee9716a27\"", "size": 22299, "mimetype": "image/jpeg", "cacheControl": "max-age=3600", "lastModified": "2026-02-26T12:05:13.382Z", "contentLength": 22299, "httpStatusCode": 200}', 'c8ea0eab-017e-42ec-ae8d-f16fcd5a741f', '816b24fe-a0c3-4409-b79b-c6c0a6935d03', '{}'), + ('5b498420-915e-4b23-8772-fa0d58c52b12', 'avatars', 'aaaaaaaa-0005-0005-0005-000000000005/avatar-1772594277231.png', 'aaaaaaaa-0005-0005-0005-000000000005', '2026-03-04 03:17:57.367822+00', '2026-03-04 03:17:57.367822+00', '2026-03-04 03:17:57.367822+00', '{"eTag": "\"8ff97e8238a368c6f59596d7a8b9e052\"", "size": 48710, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-03-04T03:17:57.356Z", "contentLength": 48710, "httpStatusCode": 200}', 'ee1d7b94-43f9-480b-8824-85da41a99994', 'aaaaaaaa-0005-0005-0005-000000000005', '{}'), + ('b739f56c-e5a1-41c5-a094-2147c4a874c1', 'avatars', 'owners/aaaaaaaa-0002-0002-0002-000000000002/patients/0ef7d831-3bc7-4e1c-948b-35b40bee1ed3/avatar.png', 'aaaaaaaa-0002-0002-0002-000000000002', '2026-03-05 13:44:23.70851+00', '2026-03-05 13:44:23.70851+00', '2026-03-05 13:44:23.70851+00', '{"eTag": "\"8ff97e8238a368c6f59596d7a8b9e052\"", "size": 48710, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-03-05T13:44:23.686Z", "contentLength": 48710, "httpStatusCode": 200}', '85d47e0e-7dd2-4b7c-b634-3e081b3e0a21', 'aaaaaaaa-0002-0002-0002-000000000002', '{}'), + ('cd4130ea-4af6-4e48-97ee-635c058ac966', 'avatars', 'intakes/b1ab9b79-7cee-4c2f-8f35-ac6bbb0f7348/1772723113160.png', 'aaaaaaaa-0002-0002-0002-000000000002', '2026-03-05 15:05:13.258881+00', '2026-03-05 15:05:13.258881+00', '2026-03-05 15:05:13.258881+00', '{"eTag": "\"60d363c60025fd47681d9b9d50939a8d\"", "size": 158427, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-03-05T15:05:13.245Z", "contentLength": 158427, "httpStatusCode": 200}', '490e6713-7c03-4ef4-8ae5-1476b383c62f', 'aaaaaaaa-0002-0002-0002-000000000002', '{}'), + ('01ffed61-9d1f-4880-b9e7-b7d8ae029ae9', 'avatars', 'owners/aaaaaaaa-0005-0005-0005-000000000005/patients/70b17b2e-b637-4d6e-ae87-62c81cc34e9f/avatar.webp', 'aaaaaaaa-0005-0005-0005-000000000005', '2026-03-06 10:04:19.126607+00', '2026-03-06 10:04:19.126607+00', '2026-03-06 10:04:19.126607+00', '{"eTag": "\"14165413138636ce45667eb0c485528a\"", "size": 48808, "mimetype": "image/webp", "cacheControl": "max-age=3600", "lastModified": "2026-03-06T10:04:19.115Z", "contentLength": 48808, "httpStatusCode": 200}', '002747b3-a587-40ca-a5f9-072e8224b488', 'aaaaaaaa-0005-0005-0005-000000000005', '{}'), + ('6cf2f3e0-6652-432f-80a6-60a9ab5bb8ca', 'saas-docs', 'doc-images/6ba2a9e3-b4b8-447d-b1fa-2c746f15e55e.png', 'aaaaaaaa-0006-0006-0006-000000000006', '2026-03-08 01:00:01.166001+00', '2026-03-08 01:00:01.166001+00', '2026-03-08 01:00:01.166001+00', '{"eTag": "\"8ff97e8238a368c6f59596d7a8b9e052\"", "size": 48710, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2026-03-08T01:00:01.145Z", "contentLength": 48710, "httpStatusCode": 200}', 'c8861454-7c78-4634-96e4-1e0be16e3439', 'aaaaaaaa-0006-0006-0006-000000000006', '{}'); + + +-- +-- Data for Name: s3_multipart_uploads; Type: TABLE DATA; Schema: storage; Owner: supabase_storage_admin +-- + + + +-- +-- Data for Name: s3_multipart_uploads_parts; Type: TABLE DATA; Schema: storage; Owner: supabase_storage_admin +-- + + + +-- +-- Data for Name: vector_indexes; Type: TABLE DATA; Schema: storage; Owner: supabase_storage_admin +-- + + + +-- +-- Data for Name: hooks; Type: TABLE DATA; Schema: supabase_functions; Owner: supabase_functions_admin +-- + + + +-- +-- Name: refresh_tokens_id_seq; Type: SEQUENCE SET; Schema: auth; Owner: supabase_auth_admin +-- + +SELECT pg_catalog.setval('"auth"."refresh_tokens_id_seq"', 1204, true); + + +-- +-- Name: agenda_online_slots_id_seq; Type: SEQUENCE SET; Schema: public; Owner: supabase_admin +-- + +SELECT pg_catalog.setval('"public"."agenda_online_slots_id_seq"', 113, true); + + +-- +-- Name: hooks_id_seq; Type: SEQUENCE SET; Schema: supabase_functions; Owner: supabase_functions_admin +-- + +SELECT pg_catalog.setval('"supabase_functions"."hooks_id_seq"', 1, false); + + +-- +-- PostgreSQL database dump complete +-- + +-- \unrestrict W3AlCqJoixQ6XbedqdnuDvY0yTRx6OcqqCIS8MVAvJRGtliRjQ8MiBhgEM6GeE6 + +RESET ALL; diff --git a/schema.sql b/DBS/2026-03-11/root/full_dump.sql similarity index 86% rename from schema.sql rename to DBS/2026-03-11/root/full_dump.sql index 1b99328..e1df45b 100644 --- a/schema.sql +++ b/DBS/2026-03-11/root/full_dump.sql @@ -102,11 +102,46 @@ CREATE TYPE "public"."determined_field_type" AS ENUM ( ALTER TYPE "public"."determined_field_type" OWNER TO "supabase_admin"; +CREATE TYPE "public"."recurrence_exception_type" AS ENUM ( + 'cancel_session', + 'reschedule_session', + 'patient_missed', + 'therapist_canceled', + 'holiday_block' +); + + +ALTER TYPE "public"."recurrence_exception_type" OWNER TO "supabase_admin"; + + +CREATE TYPE "public"."recurrence_type" AS ENUM ( + 'weekly', + 'biweekly', + 'monthly', + 'yearly', + 'custom_weekdays' +); + + +ALTER TYPE "public"."recurrence_type" OWNER TO "supabase_admin"; + + +CREATE TYPE "public"."status_agenda_serie" AS ENUM ( + 'ativo', + 'pausado', + 'cancelado' +); + + +ALTER TYPE "public"."status_agenda_serie" OWNER TO "supabase_admin"; + + CREATE TYPE "public"."status_evento_agenda" AS ENUM ( 'agendado', 'realizado', 'faltou', - 'cancelado' + 'cancelado', + 'remarcar' ); @@ -201,14 +236,13 @@ declare v_plan_id uuid; v_target text; begin - -- lê pela VIEW unificada (agora ela tem plan_target e plan_id) - select * - into v_intent + -- lê pela VIEW unificada + select * into v_intent from public.subscription_intents where id = p_intent_id; if not found then - raise exception 'Intent não encontrada'; + raise exception 'Intent não encontrado: %', p_intent_id; end if; if v_intent.status <> 'paid' then @@ -228,7 +262,8 @@ begin v_target := lower(coalesce(v_target, '')); - if v_target not in ('clinic','therapist') then + -- ✅ supervisor adicionado + if v_target not in ('clinic', 'therapist', 'supervisor') then raise exception 'Target inválido em plans.target: %', v_target; end if; @@ -238,92 +273,76 @@ begin raise exception 'Intent sem tenant_id'; end if; else - -- therapist - if v_intent.tenant_id is not null then - raise exception 'Intent therapist não deve ter tenant_id'; + -- therapist ou supervisor: vinculado ao user + v_user_id := v_intent.user_id; + if v_user_id is null then + v_user_id := v_intent.created_by_user_id; end if; end if; - v_days := case when v_intent.interval = 'year' then 365 else 30 end; - - -- define user_id (compat com schema legado) - v_user_id := coalesce(v_intent.created_by_user_id, v_intent.user_id); - - -- fallback só faz sentido para therapist/personal (porque clinic NÃO usa user_id no XOR) - -- Se você quiser manter um "responsável" da clínica, faça isso em outra coluna/tabela/evento, - -- mas NÃO em subscriptions.user_id, pois quebra o XOR. - if v_target = 'therapist' and v_user_id is null then - raise exception 'Não foi possível determinar user_id para assinatura therapist.'; + if v_target in ('therapist', 'supervisor') and v_user_id is null then + raise exception 'Não foi possível determinar user_id para assinatura %.', v_target; end if; -- cancela assinatura ativa anterior if v_target = 'clinic' then - -- para clinic: uma assinatura ativa por tenant update public.subscriptions set status = 'cancelled', - cancelled_at = now(), - updated_at = now() + cancelled_at = now() where tenant_id = v_intent.tenant_id + and plan_id = v_plan_id and status = 'active'; else - -- para therapist: uma assinatura ativa por user (escopo pessoal) + -- therapist ou supervisor update public.subscriptions set status = 'cancelled', - cancelled_at = now(), - updated_at = now() + cancelled_at = now() where user_id = v_user_id - and tenant_id is null - and status = 'active'; + and plan_id = v_plan_id + and status = 'active' + and tenant_id is null; end if; - -- cria nova assinatura ativa (✅ respeita XOR) + -- duração do plano (30 dias para mensal) + v_days := case + when lower(coalesce(v_intent.interval, 'month')) = 'year' then 365 + else 30 + end; + + -- cria nova assinatura insert into public.subscriptions ( user_id, plan_id, status, - current_period_start, - current_period_end, - cancel_at_period_end, - provider, - provider_customer_id, - provider_subscription_id, - created_at, - updated_at, - + started_at, + expires_at, + cancelled_at, + activated_at, tenant_id, plan_key, interval, source, - started_at, - canceled_at, - cancelled_at, - activated_at + created_at, + updated_at ) values ( - case when v_target = 'clinic' then null else v_user_id end, -- ✅ XOR + case when v_target = 'clinic' then null else v_user_id end, v_plan_id, 'active', now(), now() + make_interval(days => v_days), - false, - 'manual', - null, null, now(), - now(), - - case when v_target = 'clinic' then v_intent.tenant_id else null end, -- ✅ XOR + case when v_target = 'clinic' then v_intent.tenant_id else null end, v_intent.plan_key, v_intent.interval, 'manual', now(), - null, - null, now() ) returning * into v_sub; - -- ✅ grava o vínculo intent → subscription (para rastreio e UI) + -- grava vínculo intent → subscription if v_target = 'clinic' then update public.subscription_intents_tenant set subscription_id = v_sub.id @@ -402,6 +421,261 @@ $$; ALTER FUNCTION "public"."agenda_cfg_sync"() OWNER TO "supabase_admin"; +CREATE OR REPLACE FUNCTION "public"."agendador_dias_disponiveis"("p_slug" "text", "p_ano" integer, "p_mes" integer) RETURNS TABLE("data" "date", "tem_slots" boolean) + LANGUAGE "plpgsql" SECURITY DEFINER + SET "search_path" TO 'public' + AS $$ +DECLARE + v_owner_id uuid; + v_antecedencia int; + v_agora timestamptz; + v_data date; + v_data_inicio date; + v_data_fim date; + v_db_dow int; + v_tem_slot boolean; +BEGIN + SELECT c.owner_id, c.antecedencia_minima_horas + INTO v_owner_id, v_antecedencia + FROM public.agendador_configuracoes c + WHERE c.link_slug = p_slug AND c.ativo = true + LIMIT 1; + + IF v_owner_id IS NULL THEN RETURN; END IF; + + v_agora := now(); + v_data_inicio := make_date(p_ano, p_mes, 1); + v_data_fim := (v_data_inicio + interval '1 month' - interval '1 day')::date; + + v_data := v_data_inicio; + WHILE v_data <= v_data_fim LOOP + v_db_dow := extract(dow from v_data::timestamp)::int; + + SELECT EXISTS ( + SELECT 1 FROM public.agenda_online_slots s + WHERE s.owner_id = v_owner_id + AND s.weekday = v_db_dow + AND s.enabled = true + AND (v_data::text || ' ' || s.time::text)::timestamp + AT TIME ZONE 'America/Sao_Paulo' + >= v_agora + (v_antecedencia || ' hours')::interval + ) INTO v_tem_slot; + + IF v_tem_slot THEN + data := v_data; + tem_slots := true; + RETURN NEXT; + END IF; + + v_data := v_data + 1; + END LOOP; +END; +$$; + + +ALTER FUNCTION "public"."agendador_dias_disponiveis"("p_slug" "text", "p_ano" integer, "p_mes" integer) OWNER TO "supabase_admin"; + + +CREATE OR REPLACE FUNCTION "public"."agendador_gerar_slug"() RETURNS "trigger" + LANGUAGE "plpgsql" + AS $$ +DECLARE + v_slug text; + v_exists boolean; +BEGIN + -- só gera se ativou e não tem slug ainda + IF NEW.ativo = true AND (NEW.link_slug IS NULL OR NEW.link_slug = '') THEN + LOOP + v_slug := lower(substring(replace(gen_random_uuid()::text, '-', ''), 1, 8)); + SELECT EXISTS ( + SELECT 1 FROM public.agendador_configuracoes + WHERE link_slug = v_slug AND owner_id <> NEW.owner_id + ) INTO v_exists; + EXIT WHEN NOT v_exists; + END LOOP; + NEW.link_slug := v_slug; + END IF; + RETURN NEW; +END; +$$; + + +ALTER FUNCTION "public"."agendador_gerar_slug"() OWNER TO "supabase_admin"; + + +CREATE OR REPLACE FUNCTION "public"."agendador_slots_disponiveis"("p_slug" "text", "p_data" "date") RETURNS TABLE("hora" time without time zone, "disponivel" boolean) + LANGUAGE "plpgsql" SECURITY DEFINER + SET "search_path" TO 'public' + AS $$ +DECLARE + v_owner_id uuid; + v_duracao int; + v_antecedencia int; + v_agora timestamptz; + v_db_dow int; + v_slot time; + v_slot_fim time; + v_slot_ts timestamptz; + v_ocupado boolean; + -- loop de recorrências + v_rule RECORD; + v_rule_start_dow int; + v_first_occ date; + v_day_diff int; + v_ex_type text; +BEGIN + SELECT c.owner_id, c.duracao_sessao_min, c.antecedencia_minima_horas + INTO v_owner_id, v_duracao, v_antecedencia + FROM public.agendador_configuracoes c + WHERE c.link_slug = p_slug AND c.ativo = true + LIMIT 1; + + IF v_owner_id IS NULL THEN RETURN; END IF; + + v_agora := now(); + v_db_dow := extract(dow from p_data::timestamp)::int; + + FOR v_slot IN + SELECT s.time + FROM public.agenda_online_slots s + WHERE s.owner_id = v_owner_id + AND s.weekday = v_db_dow + AND s.enabled = true + ORDER BY s.time + LOOP + v_slot_fim := v_slot + (v_duracao || ' minutes')::interval; + v_ocupado := false; + + -- ── Antecedência mínima ────────────────────────────────────────────────── + v_slot_ts := (p_data::text || ' ' || v_slot::text)::timestamp + AT TIME ZONE 'America/Sao_Paulo'; + IF v_slot_ts < v_agora + (v_antecedencia || ' hours')::interval THEN + v_ocupado := true; + END IF; + + -- ── Eventos avulsos internos (agenda_eventos) ──────────────────────────── + IF NOT v_ocupado THEN + SELECT EXISTS ( + SELECT 1 FROM public.agenda_eventos e + WHERE e.owner_id = v_owner_id + AND e.status::text NOT IN ('cancelado', 'faltou') + AND (e.inicio_em AT TIME ZONE 'America/Sao_Paulo')::date = p_data + AND (e.inicio_em AT TIME ZONE 'America/Sao_Paulo')::time < v_slot_fim + AND (e.fim_em AT TIME ZONE 'America/Sao_Paulo')::time > v_slot + ) INTO v_ocupado; + END IF; + + -- ── Recorrências ativas (recurrence_rules) ─────────────────────────────── + -- Loop explícito para evitar erros de tipo no cálculo do ciclo semanal + IF NOT v_ocupado THEN + FOR v_rule IN + SELECT + r.id, + r.start_date::date AS start_date, + r.end_date::date AS end_date, + r.start_time::time AS start_time, + r.end_time::time AS end_time, + COALESCE(r.interval, 1)::int AS interval + FROM public.recurrence_rules r + WHERE r.owner_id = v_owner_id + AND r.status = 'ativo' + AND p_data >= r.start_date::date + AND (r.end_date IS NULL OR p_data <= r.end_date::date) + AND v_db_dow = ANY(r.weekdays) + AND r.start_time::time < v_slot_fim + AND r.end_time::time > v_slot + LOOP + -- Calcula a primeira ocorrência do dia-da-semana a partir do start_date + v_rule_start_dow := extract(dow from v_rule.start_date)::int; + v_first_occ := v_rule.start_date + + (((v_db_dow - v_rule_start_dow + 7) % 7))::int; + v_day_diff := (p_data - v_first_occ)::int; + + -- Ocorrência válida: diff >= 0 e divisível pelo ciclo semanal + IF v_day_diff >= 0 AND v_day_diff % (7 * v_rule.interval) = 0 THEN + + -- Verifica se há exceção para esta data + v_ex_type := NULL; + SELECT ex.type INTO v_ex_type + FROM public.recurrence_exceptions ex + WHERE ex.recurrence_id = v_rule.id + AND ex.original_date = p_data + LIMIT 1; + + -- Sem exceção, ou exceção que não cancela → bloqueia o slot + IF v_ex_type IS NULL OR v_ex_type NOT IN ( + 'cancel_session', 'patient_missed', + 'therapist_canceled', 'holiday_block', + 'reschedule_session' + ) THEN + v_ocupado := true; + EXIT; -- já basta uma regra que conflite + END IF; + + END IF; + END LOOP; + END IF; + + -- ── Recorrências remarcadas para este dia (reschedule → new_date = p_data) ─ + IF NOT v_ocupado THEN + SELECT EXISTS ( + SELECT 1 + FROM public.recurrence_exceptions ex + JOIN public.recurrence_rules r ON r.id = ex.recurrence_id + WHERE r.owner_id = v_owner_id + AND r.status = 'ativo' + AND ex.type = 'reschedule_session' + AND ex.new_date = p_data + AND COALESCE(ex.new_start_time, r.start_time)::time < v_slot_fim + AND COALESCE(ex.new_end_time, r.end_time)::time > v_slot + ) INTO v_ocupado; + END IF; + + -- ── Solicitações públicas pendentes ────────────────────────────────────── + IF NOT v_ocupado THEN + SELECT EXISTS ( + SELECT 1 FROM public.agendador_solicitacoes sol + WHERE sol.owner_id = v_owner_id + AND sol.status = 'pendente' + AND sol.data_solicitada = p_data + AND sol.hora_solicitada = v_slot + AND (sol.reservado_ate IS NULL OR sol.reservado_ate > v_agora) + ) INTO v_ocupado; + END IF; + + hora := v_slot; + disponivel := NOT v_ocupado; + RETURN NEXT; + END LOOP; +END; +$$; + + +ALTER FUNCTION "public"."agendador_slots_disponiveis"("p_slug" "text", "p_data" "date") OWNER TO "supabase_admin"; + + +CREATE OR REPLACE FUNCTION "public"."cancel_recurrence_from"("p_recurrence_id" "uuid", "p_from_date" "date") RETURNS "void" + LANGUAGE "plpgsql" SECURITY DEFINER + SET "search_path" TO 'public' + AS $$ +BEGIN + UPDATE public.recurrence_rules + SET + end_date = p_from_date - INTERVAL '1 day', + open_ended = false, + status = CASE + WHEN p_from_date <= start_date THEN 'cancelado' + ELSE status + END, + updated_at = now() + WHERE id = p_recurrence_id; +END; +$$; + + +ALTER FUNCTION "public"."cancel_recurrence_from"("p_recurrence_id" "uuid", "p_from_date" "date") OWNER TO "supabase_admin"; + + CREATE OR REPLACE FUNCTION "public"."cancel_subscription"("p_subscription_id" "uuid") RETURNS "public"."subscriptions" LANGUAGE "plpgsql" SECURITY DEFINER AS $$ @@ -486,6 +760,33 @@ $$; ALTER FUNCTION "public"."cancel_subscription"("p_subscription_id" "uuid") OWNER TO "supabase_admin"; +CREATE OR REPLACE FUNCTION "public"."cancelar_eventos_serie"("p_serie_id" "uuid", "p_a_partir_de" timestamp with time zone DEFAULT "now"()) RETURNS integer + LANGUAGE "plpgsql" SECURITY DEFINER + AS $$ +DECLARE + v_count integer; +BEGIN + UPDATE public.agenda_eventos + SET status = 'cancelado', + updated_at = now() + WHERE serie_id = p_serie_id + AND inicio_em >= p_a_partir_de + AND status NOT IN ('realizado', 'cancelado'); + + GET DIAGNOSTICS v_count = ROW_COUNT; + RETURN v_count; +END; +$$; + + +ALTER FUNCTION "public"."cancelar_eventos_serie"("p_serie_id" "uuid", "p_a_partir_de" timestamp with time zone) OWNER TO "supabase_admin"; + + +COMMENT ON FUNCTION "public"."cancelar_eventos_serie"("p_serie_id" "uuid", "p_a_partir_de" timestamp with time zone) IS 'Cancela todos os eventos futuros de uma série a partir de p_a_partir_de (inclusive). + Não cancela eventos já realizados.'; + + + CREATE OR REPLACE FUNCTION "public"."change_subscription_plan"("p_subscription_id" "uuid", "p_new_plan_id" "uuid") RETURNS "public"."subscriptions" LANGUAGE "plpgsql" SECURITY DEFINER AS $$ @@ -1216,6 +1517,20 @@ $$; ALTER FUNCTION "public"."ensure_personal_tenant_for_user"("p_user_id" "uuid") OWNER TO "supabase_admin"; +CREATE OR REPLACE FUNCTION "public"."faq_votar"("faq_id" "uuid") RETURNS "void" + LANGUAGE "sql" SECURITY DEFINER + AS $$ + update public.saas_faq + set votos = votos + 1, + updated_at = now() + where id = faq_id + and ativo = true; +$$; + + +ALTER FUNCTION "public"."faq_votar"("faq_id" "uuid") OWNER TO "supabase_admin"; + + CREATE OR REPLACE FUNCTION "public"."fix_all_subscription_mismatches"() RETURNS "void" LANGUAGE "plpgsql" SECURITY DEFINER AS $$ @@ -1577,6 +1892,20 @@ $$; ALTER FUNCTION "public"."my_tenants"() OWNER TO "supabase_admin"; +CREATE OR REPLACE FUNCTION "public"."on_new_user_seed_patient_groups"() RETURNS "trigger" + LANGUAGE "plpgsql" SECURITY DEFINER + SET "search_path" TO 'public' + AS $$ + BEGIN + PERFORM public.seed_default_patient_groups(NEW.id); + RETURN NEW; + END; + $$; + + +ALTER FUNCTION "public"."on_new_user_seed_patient_groups"() OWNER TO "supabase_admin"; + + CREATE OR REPLACE FUNCTION "public"."patients_validate_member_consistency"() RETURNS "trigger" LANGUAGE "plpgsql" AS $$ @@ -1964,6 +2293,68 @@ $$; ALTER FUNCTION "public"."rotate_patient_invite_token"("p_new_token" "text") OWNER TO "supabase_admin"; +CREATE OR REPLACE FUNCTION "public"."saas_votar_doc"("p_doc_id" "uuid", "p_util" boolean) RETURNS "jsonb" + LANGUAGE "plpgsql" SECURITY DEFINER + AS $$ +declare + v_uid uuid := auth.uid(); + v_voto_antigo boolean; +begin + if v_uid is null then + raise exception 'Não autenticado'; + end if; + + -- Verifica se já votou + select util into v_voto_antigo + from public.saas_doc_votos + where doc_id = p_doc_id and user_id = v_uid; + + if found then + -- Já votou igual → cancela o voto (toggle) + if v_voto_antigo = p_util then + delete from public.saas_doc_votos + where doc_id = p_doc_id and user_id = v_uid; + + update public.saas_docs set + votos_util = greatest(0, votos_util - (case when p_util then 1 else 0 end)), + votos_nao_util = greatest(0, votos_nao_util - (case when not p_util then 1 else 0 end)), + updated_at = now() + where id = p_doc_id; + + return jsonb_build_object('acao', 'removido', 'util', null); + else + -- Mudou de voto + update public.saas_doc_votos set util = p_util, updated_at = now() + where doc_id = p_doc_id and user_id = v_uid; + + update public.saas_docs set + votos_util = greatest(0, votos_util + (case when p_util then 1 else -1 end)), + votos_nao_util = greatest(0, votos_nao_util + (case when not p_util then 1 else -1 end)), + updated_at = now() + where id = p_doc_id; + + return jsonb_build_object('acao', 'atualizado', 'util', p_util); + end if; + else + -- Primeiro voto + insert into public.saas_doc_votos (doc_id, user_id, util) + values (p_doc_id, v_uid, p_util); + + update public.saas_docs set + votos_util = votos_util + (case when p_util then 1 else 0 end), + votos_nao_util = votos_nao_util + (case when not p_util then 1 else 0 end), + updated_at = now() + where id = p_doc_id; + + return jsonb_build_object('acao', 'registrado', 'util', p_util); + end if; +end; +$$; + + +ALTER FUNCTION "public"."saas_votar_doc"("p_doc_id" "uuid", "p_util" boolean) OWNER TO "supabase_admin"; + + CREATE OR REPLACE FUNCTION "public"."seed_determined_commitments"("p_tenant_id" "uuid") RETURNS "void" LANGUAGE "plpgsql" SECURITY DEFINER AS $$ @@ -2187,6 +2578,67 @@ $$; ALTER FUNCTION "public"."set_updated_at"() OWNER TO "supabase_admin"; +CREATE OR REPLACE FUNCTION "public"."set_updated_at_recurrence"() RETURNS "trigger" + LANGUAGE "plpgsql" + AS $$ +BEGIN NEW.updated_at = now(); RETURN NEW; END; +$$; + + +ALTER FUNCTION "public"."set_updated_at_recurrence"() OWNER TO "supabase_admin"; + + +CREATE OR REPLACE FUNCTION "public"."split_recurrence_at"("p_recurrence_id" "uuid", "p_from_date" "date") RETURNS "uuid" + LANGUAGE "plpgsql" SECURITY DEFINER + SET "search_path" TO 'public' + AS $$ +DECLARE + v_old public.recurrence_rules; + v_new_id uuid; +BEGIN + -- busca a regra original + SELECT * INTO v_old + FROM public.recurrence_rules + WHERE id = p_recurrence_id; + + IF NOT FOUND THEN + RAISE EXCEPTION 'recurrence_rule % não encontrada', p_recurrence_id; + END IF; + + -- encerra a regra antiga na data anterior + UPDATE public.recurrence_rules + SET + end_date = p_from_date - INTERVAL '1 day', + open_ended = false, + updated_at = now() + WHERE id = p_recurrence_id; + + -- cria nova regra a partir de p_from_date + INSERT INTO public.recurrence_rules ( + tenant_id, owner_id, therapist_id, patient_id, + determined_commitment_id, type, interval, weekdays, + start_time, end_time, timezone, duration_min, + start_date, end_date, max_occurrences, open_ended, + modalidade, titulo_custom, observacoes, extra_fields, status + ) + SELECT + tenant_id, owner_id, therapist_id, patient_id, + determined_commitment_id, type, interval, weekdays, + start_time, end_time, timezone, duration_min, + p_from_date, v_old.end_date, v_old.max_occurrences, v_old.open_ended, + modalidade, titulo_custom, observacoes, extra_fields, status + FROM public.recurrence_rules + WHERE id = p_recurrence_id + RETURNING id INTO v_new_id; + + RETURN v_new_id; +END; +$$; + + +ALTER FUNCTION "public"."split_recurrence_at"("p_recurrence_id" "uuid", "p_from_date" "date") OWNER TO "supabase_admin"; + + CREATE OR REPLACE FUNCTION "public"."subscription_intents_view_insert"() RETURNS "trigger" LANGUAGE "plpgsql" SECURITY DEFINER AS $$ @@ -2194,7 +2646,6 @@ declare v_target text; v_plan_id uuid; begin - -- descobre o plano pelo plan_key select p.id, p.target into v_plan_id, v_target from public.plans p where p.key = new.plan_key; @@ -2203,83 +2654,44 @@ begin raise exception 'Plano inválido: plan_key=%', new.plan_key; end if; - -- clinic → tabela tenant (tenant_id obrigatório) if lower(v_target) = 'clinic' then if new.tenant_id is null then raise exception 'Intenção clinic exige tenant_id.'; end if; insert into public.subscription_intents_tenant ( - id, user_id, created_by_user_id, email, + id, tenant_id, created_by_user_id, email, plan_id, plan_key, interval, amount_cents, currency, - status, source, notes, created_at, paid_at, - tenant_id + status, source, notes, created_at, paid_at ) values ( coalesce(new.id, gen_random_uuid()), - new.user_id, - new.created_by_user_id, - new.email, - v_plan_id, - new.plan_key, - new.interval, - new.amount_cents, - new.currency, - coalesce(new.status, 'new'), - coalesce(new.source, 'manual'), - new.notes, - coalesce(new.created_at, now()), - new.paid_at, - new.tenant_id - ) - returning - id, user_id, created_by_user_id, email, - plan_id, plan_key, interval, amount_cents, currency, - status, source, notes, created_at, paid_at, - tenant_id, - 'clinic'::text - into - new.id, new.user_id, new.created_by_user_id, new.email, - new.plan_id, new.plan_key, new.interval, new.amount_cents, new.currency, - new.status, new.source, new.notes, new.created_at, new.paid_at, - new.tenant_id, - new.plan_target; + new.tenant_id, new.created_by_user_id, new.email, + v_plan_id, new.plan_key, coalesce(new.interval,'month'), + new.amount_cents, coalesce(new.currency,'BRL'), + coalesce(new.status,'pending'), coalesce(new.source,'manual'), + new.notes, coalesce(new.created_at, now()), new.paid_at + ); + new.plan_target := 'clinic'; return new; end if; - -- therapist → tabela personal (sem tenant_id) - if lower(v_target) = 'therapist' then + -- therapist ou supervisor → tabela personal + if lower(v_target) in ('therapist', 'supervisor') then insert into public.subscription_intents_personal ( id, user_id, created_by_user_id, email, plan_id, plan_key, interval, amount_cents, currency, status, source, notes, created_at, paid_at ) values ( coalesce(new.id, gen_random_uuid()), - new.user_id, - new.created_by_user_id, - new.email, - v_plan_id, - new.plan_key, - new.interval, - new.amount_cents, - new.currency, - coalesce(new.status, 'new'), - coalesce(new.source, 'manual'), - new.notes, - coalesce(new.created_at, now()), - new.paid_at - ) - returning - id, user_id, created_by_user_id, email, - plan_id, plan_key, interval, amount_cents, currency, - status, source, notes, created_at, paid_at - into - new.id, new.user_id, new.created_by_user_id, new.email, - new.plan_id, new.plan_key, new.interval, new.amount_cents, new.currency, - new.status, new.source, new.notes, new.created_at, new.paid_at; + new.user_id, new.created_by_user_id, new.email, + v_plan_id, new.plan_key, coalesce(new.interval,'month'), + new.amount_cents, coalesce(new.currency,'BRL'), + coalesce(new.status,'pending'), coalesce(new.source,'manual'), + new.notes, coalesce(new.created_at, now()), new.paid_at + ); - new.tenant_id := null; - new.plan_target := 'therapist'; + new.plan_target := lower(v_target); -- 'therapist' ou 'supervisor' return new; end if; @@ -2313,12 +2725,13 @@ BEGIN RAISE EXCEPTION 'Assinatura clinic não pode ter user_id (XOR).'; END IF; - ELSIF v_target = 'therapist' THEN + ELSIF v_target IN ('therapist', 'supervisor') THEN + -- supervisor é pessoal como therapist IF NEW.tenant_id IS NOT NULL THEN - RAISE EXCEPTION 'Assinatura therapist não deve ter tenant_id.'; + RAISE EXCEPTION 'Assinatura % não deve ter tenant_id.', v_target; END IF; IF NEW.user_id IS NULL THEN - RAISE EXCEPTION 'Assinatura therapist exige user_id.'; + RAISE EXCEPTION 'Assinatura % exige user_id.', v_target; END IF; ELSIF v_target = 'patient' THEN @@ -3214,6 +3627,28 @@ $$; ALTER FUNCTION "public"."whoami"() OWNER TO "supabase_admin"; +CREATE TABLE IF NOT EXISTS "public"."agenda_bloqueios" ( + "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, + "owner_id" "uuid" NOT NULL, + "tenant_id" "uuid", + "tipo" "text" NOT NULL, + "titulo" "text" NOT NULL, + "data_inicio" "date" NOT NULL, + "data_fim" "date", + "hora_inicio" time without time zone, + "hora_fim" time without time zone, + "recorrente" boolean DEFAULT false NOT NULL, + "dia_semana" smallint, + "observacao" "text", + "origem" "text" DEFAULT 'manual'::"text" NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, + CONSTRAINT "agenda_bloqueios_tipo_check" CHECK (("tipo" = ANY (ARRAY['feriado_nacional'::"text", 'feriado_municipal'::"text", 'bloqueio'::"text"]))) +); + + +ALTER TABLE "public"."agenda_bloqueios" OWNER TO "supabase_admin"; + + CREATE TABLE IF NOT EXISTS "public"."agenda_configuracoes" ( "owner_id" "uuid" NOT NULL, "duracao_padrao_minutos" integer DEFAULT 50 NOT NULL, @@ -3244,12 +3679,11 @@ CREATE TABLE IF NOT EXISTS "public"."agenda_configuracoes" ( "agenda_custom_end" time without time zone, "session_duration_min" integer DEFAULT 50 NOT NULL, "session_break_min" integer DEFAULT 10 NOT NULL, - "session_start_offset_min" integer DEFAULT 0 NOT NULL, "pausas_semanais" "jsonb" DEFAULT '[]'::"jsonb" NOT NULL, "setup_clinica_concluido" boolean DEFAULT false NOT NULL, "setup_clinica_concluido_em" timestamp with time zone, - "jornada_igual_todos" boolean DEFAULT true, "tenant_id" "uuid", + "jornada_igual_todos" boolean DEFAULT true, CONSTRAINT "agenda_configuracoes_admin_slot_visual_minutos_check" CHECK (("admin_slot_visual_minutos" = ANY (ARRAY[5, 10, 15, 20, 30, 60]))), CONSTRAINT "agenda_configuracoes_check" CHECK ((("usar_horario_admin_custom" = false) OR (("admin_inicio_visualizacao" IS NOT NULL) AND ("admin_fim_visualizacao" IS NOT NULL) AND ("admin_fim_visualizacao" > "admin_inicio_visualizacao")))), CONSTRAINT "agenda_configuracoes_duracao_padrao_minutos_check" CHECK ((("duracao_padrao_minutos" >= 10) AND ("duracao_padrao_minutos" <= 240))), @@ -3265,8 +3699,7 @@ CREATE TABLE IF NOT EXISTS "public"."agenda_configuracoes" ( CONSTRAINT "agenda_configuracoes_online_modo_check" CHECK (("online_modo" = ANY (ARRAY['automatico'::"text", 'aprovacao'::"text"]))), CONSTRAINT "agenda_configuracoes_online_reagendar_ate_horas_check" CHECK ((("online_reagendar_ate_horas" >= 0) AND ("online_reagendar_ate_horas" <= 720))), CONSTRAINT "session_break_min_chk" CHECK ((("session_break_min" >= 0) AND ("session_break_min" <= 60))), - CONSTRAINT "session_duration_min_chk" CHECK ((("session_duration_min" >= 10) AND ("session_duration_min" <= 240))), - CONSTRAINT "session_start_offset_min_chk" CHECK (("session_start_offset_min" = ANY (ARRAY[0, 15, 30, 45]))) + CONSTRAINT "session_duration_min_chk" CHECK ((("session_duration_min" >= 10) AND ("session_duration_min" <= 240))) ); @@ -3293,6 +3726,11 @@ CREATE TABLE IF NOT EXISTS "public"."agenda_eventos" ( "patient_id" "uuid", "determined_commitment_id" "uuid", "link_online" "text", + "titulo_custom" "text", + "extra_fields" "jsonb", + "recurrence_id" "uuid", + "recurrence_date" "date", + "modalidade" "text" DEFAULT 'presencial'::"text", CONSTRAINT "agenda_eventos_check" CHECK (("fim_em" > "inicio_em")) ); @@ -3415,6 +3853,88 @@ CREATE TABLE IF NOT EXISTS "public"."agenda_slots_regras" ( ALTER TABLE "public"."agenda_slots_regras" OWNER TO "supabase_admin"; +CREATE TABLE IF NOT EXISTS "public"."agendador_configuracoes" ( + "owner_id" "uuid" NOT NULL, + "tenant_id" "uuid", + "ativo" boolean DEFAULT false NOT NULL, + "link_slug" "text", + "imagem_fundo_url" "text", + "imagem_header_url" "text", + "logomarca_url" "text", + "cor_primaria" "text" DEFAULT '#4b6bff'::"text", + "nome_exibicao" "text", + "endereco" "text", + "botao_como_chegar_ativo" boolean DEFAULT true NOT NULL, + "maps_url" "text", + "modo_aprovacao" "text" DEFAULT 'aprovacao'::"text" NOT NULL, + "modalidade" "text" DEFAULT 'presencial'::"text" NOT NULL, + "tipos_habilitados" "jsonb" DEFAULT '["primeira", "retorno"]'::"jsonb" NOT NULL, + "duracao_sessao_min" integer DEFAULT 50 NOT NULL, + "antecedencia_minima_horas" integer DEFAULT 24 NOT NULL, + "prazo_resposta_horas" integer DEFAULT 2 NOT NULL, + "reserva_horas" integer DEFAULT 2 NOT NULL, + "pagamento_obrigatorio" boolean DEFAULT false NOT NULL, + "pix_chave" "text", + "pix_countdown_minutos" integer DEFAULT 20 NOT NULL, + "triagem_motivo" boolean DEFAULT true NOT NULL, + "triagem_como_conheceu" boolean DEFAULT false NOT NULL, + "verificacao_email" boolean DEFAULT false NOT NULL, + "exigir_aceite_lgpd" boolean DEFAULT true NOT NULL, + "mensagem_boas_vindas" "text", + "texto_como_se_preparar" "text", + "texto_termos_lgpd" "text", + "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, + "updated_at" timestamp with time zone DEFAULT "now"() NOT NULL, + CONSTRAINT "agendador_configuracoes_antecedencia_check" CHECK ((("antecedencia_minima_horas" >= 0) AND ("antecedencia_minima_horas" <= 720))), + CONSTRAINT "agendador_configuracoes_duracao_check" CHECK ((("duracao_sessao_min" >= 10) AND ("duracao_sessao_min" <= 240))), + CONSTRAINT "agendador_configuracoes_modalidade_check" CHECK (("modalidade" = ANY (ARRAY['presencial'::"text", 'online'::"text", 'ambos'::"text"]))), + CONSTRAINT "agendador_configuracoes_modo_check" CHECK (("modo_aprovacao" = ANY (ARRAY['automatico'::"text", 'aprovacao'::"text"]))), + CONSTRAINT "agendador_configuracoes_pix_countdown_check" CHECK ((("pix_countdown_minutos" >= 5) AND ("pix_countdown_minutos" <= 120))), + CONSTRAINT "agendador_configuracoes_prazo_check" CHECK ((("prazo_resposta_horas" >= 1) AND ("prazo_resposta_horas" <= 72))), + CONSTRAINT "agendador_configuracoes_reserva_check" CHECK ((("reserva_horas" >= 1) AND ("reserva_horas" <= 48))) +); + + +ALTER TABLE "public"."agendador_configuracoes" OWNER TO "supabase_admin"; + + +CREATE TABLE IF NOT EXISTS "public"."agendador_solicitacoes" ( + "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, + "owner_id" "uuid" NOT NULL, + "tenant_id" "uuid", + "paciente_nome" "text" NOT NULL, + "paciente_sobrenome" "text", + "paciente_email" "text" NOT NULL, + "paciente_celular" "text", + "paciente_cpf" "text", + "tipo" "text" NOT NULL, + "modalidade" "text" NOT NULL, + "data_solicitada" "date" NOT NULL, + "hora_solicitada" time without time zone NOT NULL, + "reservado_ate" timestamp with time zone, + "motivo" "text", + "como_conheceu" "text", + "pix_status" "text" DEFAULT 'pendente'::"text", + "pix_pago_em" timestamp with time zone, + "status" "text" DEFAULT 'pendente'::"text" NOT NULL, + "recusado_motivo" "text", + "autorizado_em" timestamp with time zone, + "autorizado_por" "uuid", + "user_id" "uuid", + "patient_id" "uuid", + "evento_id" "uuid", + "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, + "updated_at" timestamp with time zone DEFAULT "now"() NOT NULL, + CONSTRAINT "agendador_sol_modalidade_check" CHECK (("modalidade" = ANY (ARRAY['presencial'::"text", 'online'::"text"]))), + CONSTRAINT "agendador_sol_pix_check" CHECK ((("pix_status" IS NULL) OR ("pix_status" = ANY (ARRAY['pendente'::"text", 'pago'::"text", 'expirado'::"text"])))), + CONSTRAINT "agendador_sol_status_check" CHECK (("status" = ANY (ARRAY['pendente'::"text", 'autorizado'::"text", 'recusado'::"text", 'expirado'::"text", 'convertido'::"text"]))), + CONSTRAINT "agendador_sol_tipo_check" CHECK (("tipo" = ANY (ARRAY['primeira'::"text", 'retorno'::"text", 'reagendar'::"text"]))) +); + + +ALTER TABLE "public"."agendador_solicitacoes" OWNER TO "supabase_admin"; + + CREATE TABLE IF NOT EXISTS "public"."commitment_time_logs" ( "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, "tenant_id" "uuid" NOT NULL, @@ -3467,7 +3987,9 @@ CREATE TABLE IF NOT EXISTS "public"."determined_commitments" ( "name" "text" NOT NULL, "description" "text", "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "updated_at" timestamp with time zone DEFAULT "now"() NOT NULL + "updated_at" timestamp with time zone DEFAULT "now"() NOT NULL, + "bg_color" "text", + "text_color" "text" ); @@ -3514,6 +4036,25 @@ COMMENT ON COLUMN "public"."features"."descricao" IS 'Descrição humana da feat +CREATE TABLE IF NOT EXISTS "public"."feriados" ( + "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, + "tenant_id" "uuid", + "owner_id" "uuid", + "tipo" "text" DEFAULT 'municipal'::"text" NOT NULL, + "nome" "text" NOT NULL, + "data" "date" NOT NULL, + "cidade" "text", + "estado" "text", + "observacao" "text", + "bloqueia_sessoes" boolean DEFAULT false NOT NULL, + "criado_em" timestamp with time zone DEFAULT "now"() NOT NULL, + CONSTRAINT "feriados_tipo_check" CHECK (("tipo" = ANY (ARRAY['municipal'::"text", 'personalizado'::"text"]))) +); + + +ALTER TABLE "public"."feriados" OWNER TO "supabase_admin"; + + CREATE TABLE IF NOT EXISTS "public"."module_features" ( "module_id" "uuid" NOT NULL, "feature_id" "uuid" NOT NULL, @@ -3859,7 +4400,8 @@ CREATE TABLE IF NOT EXISTS "public"."plans" ( "currency" "text" DEFAULT 'BRL'::"text" NOT NULL, "billing_interval" "text" DEFAULT 'month'::"text" NOT NULL, "target" "text", - CONSTRAINT "plans_target_check" CHECK (("target" = ANY (ARRAY['patient'::"text", 'therapist'::"text", 'clinic'::"text"]))) + "max_supervisees" integer, + CONSTRAINT "plans_target_check" CHECK (("target" = ANY (ARRAY['patient'::"text", 'therapist'::"text", 'clinic'::"text", 'supervisor'::"text"]))) ); @@ -3874,6 +4416,10 @@ COMMENT ON COLUMN "public"."plans"."target" IS 'Público-alvo do plano: patient, +COMMENT ON COLUMN "public"."plans"."max_supervisees" IS 'Limite de terapeutas que podem ser supervisionados. Apenas para planos target=supervisor. NULL = sem limite.'; + + + CREATE TABLE IF NOT EXISTS "public"."profiles" ( "id" "uuid" NOT NULL, "role" "text" DEFAULT 'tenant_member'::"text" NOT NULL, @@ -3889,6 +4435,7 @@ CREATE TABLE IF NOT EXISTS "public"."profiles" ( "notify_reminders" boolean DEFAULT true NOT NULL, "notify_news" boolean DEFAULT false NOT NULL, "account_type" "text" DEFAULT 'free'::"text" NOT NULL, + "platform_roles" "text"[] DEFAULT '{}'::"text"[] NOT NULL, CONSTRAINT "profiles_account_type_check" CHECK (("account_type" = ANY (ARRAY['free'::"text", 'patient'::"text", 'therapist'::"text", 'clinic'::"text"]))), CONSTRAINT "profiles_role_check" CHECK (("role" = ANY (ARRAY['saas_admin'::"text", 'tenant_member'::"text", 'portal_user'::"text", 'patient'::"text"]))) ); @@ -3901,6 +4448,67 @@ COMMENT ON COLUMN "public"."profiles"."account_type" IS 'Tipo de conta: free=sem +COMMENT ON COLUMN "public"."profiles"."platform_roles" IS 'Papéis globais de plataforma, independentes de tenant. Ex: editor de microlearning. Atribuído pelo saas_admin.'; + + + +CREATE TABLE IF NOT EXISTS "public"."recurrence_exceptions" ( + "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, + "recurrence_id" "uuid" NOT NULL, + "tenant_id" "uuid" NOT NULL, + "original_date" "date" NOT NULL, + "type" "public"."recurrence_exception_type" NOT NULL, + "new_date" "date", + "new_start_time" time without time zone, + "new_end_time" time without time zone, + "modalidade" "text", + "observacoes" "text", + "titulo_custom" "text", + "extra_fields" "jsonb", + "reason" "text", + "agenda_evento_id" "uuid", + "created_at" timestamp with time zone DEFAULT "now"() NOT NULL +); + + +ALTER TABLE "public"."recurrence_exceptions" OWNER TO "supabase_admin"; + + +CREATE TABLE IF NOT EXISTS "public"."recurrence_rules" ( + "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, + "tenant_id" "uuid" NOT NULL, + "owner_id" "uuid" NOT NULL, + "therapist_id" "uuid", + "patient_id" "uuid", + "determined_commitment_id" "uuid", + "type" "public"."recurrence_type" DEFAULT 'weekly'::"public"."recurrence_type" NOT NULL, + "interval" smallint DEFAULT 1 NOT NULL, + "weekdays" smallint[] DEFAULT '{}'::smallint[] NOT NULL, + "start_time" time without time zone NOT NULL, + "end_time" time without time zone NOT NULL, + "timezone" "text" DEFAULT 'America/Sao_Paulo'::"text" NOT NULL, + "duration_min" smallint DEFAULT 50 NOT NULL, + "start_date" "date" NOT NULL, + "end_date" "date", + "max_occurrences" integer, + "open_ended" boolean DEFAULT true NOT NULL, + "modalidade" "text" DEFAULT 'presencial'::"text", + "titulo_custom" "text", + "observacoes" "text", + "extra_fields" "jsonb", + "status" "text" DEFAULT 'ativo'::"text" NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, + "updated_at" timestamp with time zone DEFAULT "now"() NOT NULL, + CONSTRAINT "recurrence_rules_dates_chk" CHECK ((("end_date" IS NULL) OR ("end_date" >= "start_date"))), + CONSTRAINT "recurrence_rules_interval_chk" CHECK (("interval" >= 1)), + CONSTRAINT "recurrence_rules_status_check" CHECK (("status" = ANY (ARRAY['ativo'::"text", 'pausado'::"text", 'cancelado'::"text"]))), + CONSTRAINT "recurrence_rules_times_chk" CHECK (("end_time" > "start_time")) +); + + +ALTER TABLE "public"."recurrence_rules" OWNER TO "supabase_admin"; + + CREATE TABLE IF NOT EXISTS "public"."saas_admins" ( "user_id" "uuid" NOT NULL, "created_at" timestamp with time zone DEFAULT "now"() NOT NULL @@ -3910,6 +4518,92 @@ CREATE TABLE IF NOT EXISTS "public"."saas_admins" ( ALTER TABLE "public"."saas_admins" OWNER TO "supabase_admin"; +CREATE TABLE IF NOT EXISTS "public"."saas_doc_votos" ( + "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, + "doc_id" "uuid" NOT NULL, + "user_id" "uuid" NOT NULL, + "util" boolean NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, + "updated_at" timestamp with time zone DEFAULT "now"() NOT NULL +); + + +ALTER TABLE "public"."saas_doc_votos" OWNER TO "supabase_admin"; + + +CREATE TABLE IF NOT EXISTS "public"."saas_docs" ( + "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, + "titulo" "text" NOT NULL, + "conteudo" "text" DEFAULT ''::"text" NOT NULL, + "medias" "jsonb" DEFAULT '[]'::"jsonb" NOT NULL, + "tipo_acesso" "text" DEFAULT 'usuario'::"text" NOT NULL, + "pagina_path" "text" NOT NULL, + "docs_relacionados" "uuid"[] DEFAULT '{}'::"uuid"[] NOT NULL, + "ativo" boolean DEFAULT true NOT NULL, + "ordem" integer DEFAULT 0 NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, + "updated_at" timestamp with time zone DEFAULT "now"() NOT NULL, + "categoria" "text", + "exibir_no_faq" boolean DEFAULT false NOT NULL, + "votos_util" integer DEFAULT 0 NOT NULL, + "votos_nao_util" integer DEFAULT 0 NOT NULL, + CONSTRAINT "saas_docs_tipo_acesso_check" CHECK (("tipo_acesso" = ANY (ARRAY['admin'::"text", 'usuario'::"text"]))) +); + + +ALTER TABLE "public"."saas_docs" OWNER TO "supabase_admin"; + + +COMMENT ON COLUMN "public"."saas_docs"."categoria" IS 'Agrupa docs no portal FAQ (ex: Conta, Agenda, Pagamentos)'; + + + +COMMENT ON COLUMN "public"."saas_docs"."exibir_no_faq" IS 'Se true, a doc e seus itens FAQ aparecem no portal de FAQ'; + + + +CREATE TABLE IF NOT EXISTS "public"."saas_faq" ( + "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, + "pergunta" "text" NOT NULL, + "categoria" "text", + "publico" boolean DEFAULT false NOT NULL, + "votos" integer DEFAULT 0 NOT NULL, + "titulo" "text", + "conteudo" "text", + "tipo_acesso" "text" DEFAULT 'usuario'::"text" NOT NULL, + "pagina_path" "text" NOT NULL, + "pagina_label" "text", + "medias" "jsonb" DEFAULT '[]'::"jsonb" NOT NULL, + "faqs_relacionados" "uuid"[] DEFAULT '{}'::"uuid"[] NOT NULL, + "ativo" boolean DEFAULT true NOT NULL, + "ordem" integer DEFAULT 0 NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, + "updated_at" timestamp with time zone DEFAULT "now"() NOT NULL +); + + +ALTER TABLE "public"."saas_faq" OWNER TO "supabase_admin"; + + +CREATE TABLE IF NOT EXISTS "public"."saas_faq_itens" ( + "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, + "doc_id" "uuid" NOT NULL, + "pergunta" "text" NOT NULL, + "resposta" "text", + "ordem" integer DEFAULT 0 NOT NULL, + "ativo" boolean DEFAULT true NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, + "updated_at" timestamp with time zone DEFAULT "now"() NOT NULL +); + + +ALTER TABLE "public"."saas_faq_itens" OWNER TO "supabase_admin"; + + +COMMENT ON TABLE "public"."saas_faq_itens" IS 'Pares pergunta/resposta vinculados a um documento de ajuda'; + + + CREATE TABLE IF NOT EXISTS "public"."subscription_events" ( "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, "subscription_id" "uuid" NOT NULL, @@ -4226,7 +4920,7 @@ CREATE OR REPLACE VIEW "public"."v_subscription_feature_mismatch" AS SELECT "s"."user_id" AS "owner_id", "f"."key" AS "feature_key" FROM (("public"."subscriptions" "s" - JOIN "public"."plan_features" "pf" ON (("pf"."plan_id" = "s"."plan_id") AND ("pf"."enabled" = true))) + JOIN "public"."plan_features" "pf" ON ((("pf"."plan_id" = "s"."plan_id") AND ("pf"."enabled" = true)))) JOIN "public"."features" "f" ON (("f"."id" = "pf"."feature_id"))) WHERE (("s"."status" = 'active'::"text") AND ("s"."tenant_id" IS NULL) AND ("s"."user_id" IS NOT NULL)) ), "actual" AS ( @@ -4526,6 +5220,11 @@ ALTER TABLE ONLY "public"."agenda_online_slots" ALTER COLUMN "id" SET DEFAULT "n +ALTER TABLE ONLY "public"."agenda_bloqueios" + ADD CONSTRAINT "agenda_bloqueios_pkey" PRIMARY KEY ("id"); + + + ALTER TABLE ONLY "public"."agenda_configuracoes" ADD CONSTRAINT "agenda_configuracoes_pkey" PRIMARY KEY ("owner_id"); @@ -4586,6 +5285,16 @@ ALTER TABLE ONLY "public"."agenda_slots_regras" +ALTER TABLE ONLY "public"."agendador_configuracoes" + ADD CONSTRAINT "agendador_configuracoes_pkey" PRIMARY KEY ("owner_id"); + + + +ALTER TABLE ONLY "public"."agendador_solicitacoes" + ADD CONSTRAINT "agendador_solicitacoes_pkey" PRIMARY KEY ("id"); + + + ALTER TABLE ONLY "public"."commitment_time_logs" ADD CONSTRAINT "commitment_time_logs_pkey" PRIMARY KEY ("id"); @@ -4631,6 +5340,16 @@ ALTER TABLE ONLY "public"."features" +ALTER TABLE ONLY "public"."feriados" + ADD CONSTRAINT "feriados_pkey" PRIMARY KEY ("id"); + + + +ALTER TABLE ONLY "public"."feriados" + ADD CONSTRAINT "feriados_tenant_id_data_nome_key" UNIQUE ("tenant_id", "data", "nome"); + + + ALTER TABLE ONLY "public"."module_features" ADD CONSTRAINT "module_features_pkey" PRIMARY KEY ("module_id", "feature_id"); @@ -4731,11 +5450,51 @@ ALTER TABLE ONLY "public"."profiles" +ALTER TABLE ONLY "public"."recurrence_exceptions" + ADD CONSTRAINT "recurrence_exceptions_pkey" PRIMARY KEY ("id"); + + + +ALTER TABLE ONLY "public"."recurrence_exceptions" + ADD CONSTRAINT "recurrence_exceptions_unique" UNIQUE ("recurrence_id", "original_date"); + + + +ALTER TABLE ONLY "public"."recurrence_rules" + ADD CONSTRAINT "recurrence_rules_pkey" PRIMARY KEY ("id"); + + + ALTER TABLE ONLY "public"."saas_admins" ADD CONSTRAINT "saas_admins_pkey" PRIMARY KEY ("user_id"); +ALTER TABLE ONLY "public"."saas_doc_votos" + ADD CONSTRAINT "saas_doc_votos_doc_id_user_id_key" UNIQUE ("doc_id", "user_id"); + + + +ALTER TABLE ONLY "public"."saas_doc_votos" + ADD CONSTRAINT "saas_doc_votos_pkey" PRIMARY KEY ("id"); + + + +ALTER TABLE ONLY "public"."saas_docs" + ADD CONSTRAINT "saas_docs_pkey" PRIMARY KEY ("id"); + + + +ALTER TABLE ONLY "public"."saas_faq_itens" + ADD CONSTRAINT "saas_faq_itens_pkey" PRIMARY KEY ("id"); + + + +ALTER TABLE ONLY "public"."saas_faq" + ADD CONSTRAINT "saas_faq_pkey" PRIMARY KEY ("id"); + + + ALTER TABLE ONLY "public"."subscription_events" ADD CONSTRAINT "subscription_events_pkey" PRIMARY KEY ("id"); @@ -4806,6 +5565,22 @@ ALTER TABLE ONLY "public"."user_settings" +CREATE INDEX "agenda_bloqueios_owner_data_idx" ON "public"."agenda_bloqueios" USING "btree" ("owner_id", "data_inicio", "data_fim"); + + + +CREATE INDEX "agenda_bloqueios_owner_id_idx" ON "public"."agenda_bloqueios" USING "btree" ("owner_id"); + + + +CREATE INDEX "agenda_bloqueios_recorrente_idx" ON "public"."agenda_bloqueios" USING "btree" ("owner_id", "dia_semana") WHERE ("recorrente" = true); + + + +CREATE INDEX "agenda_bloqueios_tenant_id_idx" ON "public"."agenda_bloqueios" USING "btree" ("tenant_id"); + + + CREATE INDEX "agenda_configuracoes_tenant_idx" ON "public"."agenda_configuracoes" USING "btree" ("tenant_id"); @@ -4826,6 +5601,10 @@ CREATE INDEX "agenda_eventos_owner_terapeuta_inicio_idx" ON "public"."agenda_eve +CREATE INDEX "agenda_eventos_recurrence_idx" ON "public"."agenda_eventos" USING "btree" ("recurrence_id") WHERE ("recurrence_id" IS NOT NULL); + + + CREATE INDEX "agenda_eventos_tenant_inicio_idx" ON "public"."agenda_eventos" USING "btree" ("tenant_id", "inicio_em"); @@ -4886,6 +5665,22 @@ CREATE INDEX "agenda_slots_regras_tenant_owner_idx" ON "public"."agenda_slots_re +CREATE INDEX "agendador_cfg_tenant_idx" ON "public"."agendador_configuracoes" USING "btree" ("tenant_id"); + + + +CREATE INDEX "agendador_sol_data_idx" ON "public"."agendador_solicitacoes" USING "btree" ("data_solicitada", "hora_solicitada"); + + + +CREATE INDEX "agendador_sol_owner_idx" ON "public"."agendador_solicitacoes" USING "btree" ("owner_id", "status"); + + + +CREATE INDEX "agendador_sol_tenant_idx" ON "public"."agendador_solicitacoes" USING "btree" ("tenant_id"); + + + CREATE INDEX "commitment_time_logs_calendar_event_idx" ON "public"."commitment_time_logs" USING "btree" ("calendar_event_id"); @@ -4922,6 +5717,10 @@ CREATE UNIQUE INDEX "determined_commitments_tenant_name_uniq" ON "public"."deter +CREATE UNIQUE INDEX "feriados_global_unique" ON "public"."feriados" USING "btree" ("data", "nome") WHERE ("tenant_id" IS NULL); + + + CREATE INDEX "idx_agenda_eventos_determined_commitment_id" ON "public"."agenda_eventos" USING "btree" ("determined_commitment_id"); @@ -5130,6 +5929,82 @@ CREATE INDEX "ppt_tag_idx" ON "public"."patient_patient_tag" USING "btree" ("tag +CREATE INDEX "recurrence_exceptions_rule_idx" ON "public"."recurrence_exceptions" USING "btree" ("recurrence_id"); + + + +CREATE INDEX "recurrence_exceptions_tenant_idx" ON "public"."recurrence_exceptions" USING "btree" ("tenant_id"); + + + +CREATE INDEX "recurrence_rules_active_idx" ON "public"."recurrence_rules" USING "btree" ("owner_id", "status") WHERE ("status" = 'ativo'::"text"); + + + +CREATE INDEX "recurrence_rules_owner_idx" ON "public"."recurrence_rules" USING "btree" ("owner_id"); + + + +CREATE INDEX "recurrence_rules_patient_idx" ON "public"."recurrence_rules" USING "btree" ("patient_id"); + + + +CREATE INDEX "recurrence_rules_tenant_idx" ON "public"."recurrence_rules" USING "btree" ("tenant_id"); + + + +CREATE INDEX "saas_doc_votos_doc_id_idx" ON "public"."saas_doc_votos" USING "btree" ("doc_id"); + + + +CREATE INDEX "saas_doc_votos_user_id_idx" ON "public"."saas_doc_votos" USING "btree" ("user_id"); + + + +CREATE INDEX "saas_docs_categoria_idx" ON "public"."saas_docs" USING "btree" ("categoria"); + + + +CREATE INDEX "saas_docs_exibir_no_faq_idx" ON "public"."saas_docs" USING "btree" ("exibir_no_faq") WHERE ("exibir_no_faq" = true); + + + +CREATE INDEX "saas_docs_path_ativo_idx" ON "public"."saas_docs" USING "btree" ("pagina_path", "ativo"); + + + +CREATE INDEX "saas_faq_ativo_idx" ON "public"."saas_faq" USING "btree" ("ativo"); + + + +CREATE INDEX "saas_faq_categoria_idx" ON "public"."saas_faq" USING "btree" ("categoria"); + + + +CREATE INDEX "saas_faq_fts_idx" ON "public"."saas_faq" USING "gin" ("to_tsvector"('"portuguese"'::"regconfig", ((COALESCE("pergunta", ''::"text") || ' '::"text") || COALESCE("conteudo", ''::"text")))); + + + +CREATE INDEX "saas_faq_itens_ativo_idx" ON "public"."saas_faq_itens" USING "btree" ("ativo"); + + + +CREATE INDEX "saas_faq_itens_doc_id_idx" ON "public"."saas_faq_itens" USING "btree" ("doc_id"); + + + +CREATE INDEX "saas_faq_pagina_path_idx" ON "public"."saas_faq" USING "btree" ("pagina_path"); + + + +CREATE INDEX "saas_faq_publico_idx" ON "public"."saas_faq" USING "btree" ("publico"); + + + +CREATE INDEX "saas_faq_votos_idx" ON "public"."saas_faq" USING "btree" ("votos" DESC); + + + CREATE INDEX "sint_personal_created_idx" ON "public"."subscription_intents_personal" USING "btree" ("created_at" DESC); @@ -5258,6 +6133,14 @@ CREATE UNIQUE INDEX "ux_subscriptions_active_per_tenant" ON "public"."subscripti +CREATE OR REPLACE TRIGGER "agenda_bloqueios_updated_at" BEFORE UPDATE ON "public"."agenda_bloqueios" FOR EACH ROW EXECUTE FUNCTION "public"."set_updated_at"(); + + + +CREATE OR REPLACE TRIGGER "agendador_slug_trigger" BEFORE INSERT OR UPDATE ON "public"."agendador_configuracoes" FOR EACH ROW EXECUTE FUNCTION "public"."agendador_gerar_slug"(); + + + CREATE OR REPLACE TRIGGER "prevent_saas_membership_trigger" BEFORE INSERT ON "public"."tenant_members" FOR EACH ROW EXECUTE FUNCTION "public"."prevent_saas_membership"(); @@ -5278,6 +6161,10 @@ CREATE OR REPLACE TRIGGER "tg_agenda_regras_semanais_updated_at" BEFORE UPDATE O +CREATE OR REPLACE TRIGGER "tg_recurrence_rules_updated_at" BEFORE UPDATE ON "public"."recurrence_rules" FOR EACH ROW EXECUTE FUNCTION "public"."set_updated_at_recurrence"(); + + + CREATE OR REPLACE TRIGGER "tr_plan_public_updated_at" BEFORE UPDATE ON "public"."plan_public" FOR EACH ROW EXECUTE FUNCTION "public"."set_updated_at"(); @@ -5386,6 +6273,16 @@ CREATE OR REPLACE TRIGGER "trg_user_settings_updated_at" BEFORE UPDATE ON "publi +ALTER TABLE ONLY "public"."agenda_bloqueios" + ADD CONSTRAINT "agenda_bloqueios_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "auth"."users"("id") ON DELETE CASCADE; + + + +ALTER TABLE ONLY "public"."agenda_bloqueios" + ADD CONSTRAINT "agenda_bloqueios_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE SET NULL; + + + ALTER TABLE ONLY "public"."agenda_configuracoes" ADD CONSTRAINT "agenda_configuracoes_tenant_fk" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE CASCADE; @@ -5401,6 +6298,11 @@ ALTER TABLE ONLY "public"."agenda_eventos" +ALTER TABLE ONLY "public"."agenda_eventos" + ADD CONSTRAINT "agenda_eventos_recurrence_id_fkey" FOREIGN KEY ("recurrence_id") REFERENCES "public"."recurrence_rules"("id") ON DELETE SET NULL; + + + ALTER TABLE ONLY "public"."agenda_eventos" ADD CONSTRAINT "agenda_eventos_terapeuta_fk" FOREIGN KEY ("terapeuta_id") REFERENCES "auth"."users"("id") ON DELETE SET NULL; @@ -5436,6 +6338,26 @@ ALTER TABLE ONLY "public"."agenda_slots_regras" +ALTER TABLE ONLY "public"."agendador_configuracoes" + ADD CONSTRAINT "agendador_configuracoes_owner_fk" FOREIGN KEY ("owner_id") REFERENCES "auth"."users"("id") ON DELETE CASCADE; + + + +ALTER TABLE ONLY "public"."agendador_configuracoes" + ADD CONSTRAINT "agendador_configuracoes_tenant_fk" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE CASCADE; + + + +ALTER TABLE ONLY "public"."agendador_solicitacoes" + ADD CONSTRAINT "agendador_sol_owner_fk" FOREIGN KEY ("owner_id") REFERENCES "auth"."users"("id") ON DELETE CASCADE; + + + +ALTER TABLE ONLY "public"."agendador_solicitacoes" + ADD CONSTRAINT "agendador_sol_tenant_fk" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE CASCADE; + + + ALTER TABLE ONLY "public"."commitment_time_logs" ADD CONSTRAINT "commitment_time_logs_calendar_event_id_fkey" FOREIGN KEY ("calendar_event_id") REFERENCES "public"."agenda_eventos"("id") ON DELETE SET NULL; @@ -5466,6 +6388,16 @@ ALTER TABLE ONLY "public"."determined_commitments" +ALTER TABLE ONLY "public"."feriados" + ADD CONSTRAINT "feriados_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "auth"."users"("id") ON DELETE SET NULL; + + + +ALTER TABLE ONLY "public"."feriados" + ADD CONSTRAINT "feriados_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE CASCADE; + + + ALTER TABLE ONLY "public"."module_features" ADD CONSTRAINT "module_features_feature_id_fkey" FOREIGN KEY ("feature_id") REFERENCES "public"."features"("id") ON DELETE CASCADE; @@ -5576,11 +6508,36 @@ ALTER TABLE ONLY "public"."profiles" +ALTER TABLE ONLY "public"."recurrence_exceptions" + ADD CONSTRAINT "recurrence_exceptions_agenda_evento_id_fkey" FOREIGN KEY ("agenda_evento_id") REFERENCES "public"."agenda_eventos"("id") ON DELETE SET NULL; + + + +ALTER TABLE ONLY "public"."recurrence_exceptions" + ADD CONSTRAINT "recurrence_exceptions_recurrence_id_fkey" FOREIGN KEY ("recurrence_id") REFERENCES "public"."recurrence_rules"("id") ON DELETE CASCADE; + + + ALTER TABLE ONLY "public"."saas_admins" ADD CONSTRAINT "saas_admins_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id") ON DELETE CASCADE; +ALTER TABLE ONLY "public"."saas_doc_votos" + ADD CONSTRAINT "saas_doc_votos_doc_id_fkey" FOREIGN KEY ("doc_id") REFERENCES "public"."saas_docs"("id") ON DELETE CASCADE; + + + +ALTER TABLE ONLY "public"."saas_doc_votos" + ADD CONSTRAINT "saas_doc_votos_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id") ON DELETE CASCADE; + + + +ALTER TABLE ONLY "public"."saas_faq_itens" + ADD CONSTRAINT "saas_faq_itens_doc_id_fkey" FOREIGN KEY ("doc_id") REFERENCES "public"."saas_docs"("id") ON DELETE CASCADE; + + + ALTER TABLE ONLY "public"."subscription_intents_personal" ADD CONSTRAINT "sint_personal_subscription_id_fkey" FOREIGN KEY ("subscription_id") REFERENCES "public"."subscriptions"("id") ON DELETE SET NULL; @@ -5671,14 +6628,21 @@ ALTER TABLE ONLY "public"."user_settings" +ALTER TABLE "public"."agenda_bloqueios" ENABLE ROW LEVEL SECURITY; + + ALTER TABLE "public"."agenda_configuracoes" ENABLE ROW LEVEL SECURITY; -CREATE POLICY "agenda_configuracoes_owner" ON "public"."agenda_configuracoes" FOR ALL USING (("owner_id" = "auth"."uid"())) WITH CHECK (("owner_id" = "auth"."uid"())); - CREATE POLICY "agenda_configuracoes_clinic_read" ON "public"."agenda_configuracoes" FOR SELECT USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'agenda.view'::"text"))); -CREATE POLICY "agenda_configuracoes_clinic_write" ON "public"."agenda_configuracoes" FOR ALL USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'agenda.edit'::"text"))) WITH CHECK (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'agenda.edit'::"text"))); + + +CREATE POLICY "agenda_configuracoes_clinic_write" ON "public"."agenda_configuracoes" USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'agenda.edit'::"text"))) WITH CHECK (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'agenda.edit'::"text"))); + + + +CREATE POLICY "agenda_configuracoes_owner" ON "public"."agenda_configuracoes" USING (("owner_id" = "auth"."uid"())) WITH CHECK (("owner_id" = "auth"."uid"())); @@ -5693,23 +6657,25 @@ CREATE POLICY "agenda_eventos_insert" ON "public"."agenda_eventos" FOR INSERT WI +CREATE POLICY "agenda_eventos_owner_all" ON "public"."agenda_eventos" TO "authenticated" USING (("owner_id" = "auth"."uid"())) WITH CHECK (("owner_id" = "auth"."uid"())); + + + CREATE POLICY "agenda_eventos_select" ON "public"."agenda_eventos" FOR SELECT USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'agenda.view'::"text"))); CREATE POLICY "agenda_eventos_update" ON "public"."agenda_eventos" FOR UPDATE USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'agenda.edit'::"text"))) WITH CHECK (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'agenda.edit'::"text"))); --- Permite que o terapeuta/owner gerencie seus próprios eventos de agenda -CREATE POLICY "agenda_eventos_owner_all" ON "public"."agenda_eventos" - FOR ALL TO authenticated - USING ("owner_id" = "auth"."uid"()) - WITH CHECK ("owner_id" = "auth"."uid"()); - ALTER TABLE "public"."agenda_excecoes" ENABLE ROW LEVEL SECURITY; +CREATE POLICY "agenda_excecoes_owner" ON "public"."agenda_excecoes" USING (("owner_id" = "auth"."uid"())) WITH CHECK (("owner_id" = "auth"."uid"())); + + + CREATE POLICY "agenda_excecoes_select" ON "public"."agenda_excecoes" FOR SELECT USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'agenda.view'::"text"))); @@ -5721,6 +6687,10 @@ CREATE POLICY "agenda_excecoes_write" ON "public"."agenda_excecoes" USING (("pub ALTER TABLE "public"."agenda_online_slots" ENABLE ROW LEVEL SECURITY; +CREATE POLICY "agenda_online_slots_owner" ON "public"."agenda_online_slots" USING (("owner_id" = "auth"."uid"())) WITH CHECK (("owner_id" = "auth"."uid"())); + + + CREATE POLICY "agenda_online_slots_select" ON "public"."agenda_online_slots" FOR SELECT USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'agenda.view'::"text"))); @@ -5732,6 +6702,10 @@ CREATE POLICY "agenda_online_slots_write" ON "public"."agenda_online_slots" USIN ALTER TABLE "public"."agenda_regras_semanais" ENABLE ROW LEVEL SECURITY; +CREATE POLICY "agenda_regras_semanais_owner" ON "public"."agenda_regras_semanais" USING (("owner_id" = "auth"."uid"())) WITH CHECK (("owner_id" = "auth"."uid"())); + + + CREATE POLICY "agenda_regras_semanais_select" ON "public"."agenda_regras_semanais" FOR SELECT USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'agenda.view'::"text"))); @@ -5762,6 +6736,68 @@ CREATE POLICY "agenda_slots_regras_write" ON "public"."agenda_slots_regras" USIN +CREATE POLICY "agendador_cfg_public_read" ON "public"."agendador_configuracoes" FOR SELECT TO "anon" USING ((("ativo" = true) AND ("link_slug" IS NOT NULL))); + + + +CREATE POLICY "agendador_cfg_select" ON "public"."agendador_configuracoes" FOR SELECT USING (("auth"."uid"() = "owner_id")); + + + +CREATE POLICY "agendador_cfg_write" ON "public"."agendador_configuracoes" USING (("auth"."uid"() = "owner_id")) WITH CHECK (("auth"."uid"() = "owner_id")); + + + +ALTER TABLE "public"."agendador_configuracoes" ENABLE ROW LEVEL SECURITY; + + +CREATE POLICY "agendador_sol_owner_select" ON "public"."agendador_solicitacoes" FOR SELECT USING (("auth"."uid"() = "owner_id")); + + + +CREATE POLICY "agendador_sol_owner_write" ON "public"."agendador_solicitacoes" USING (("auth"."uid"() = "owner_id")) WITH CHECK (("auth"."uid"() = "owner_id")); + + + +CREATE POLICY "agendador_sol_patient_read" ON "public"."agendador_solicitacoes" FOR SELECT TO "authenticated" USING ((("auth"."uid"() = "user_id") OR ("auth"."uid"() = "owner_id"))); + + + +CREATE POLICY "agendador_sol_public_insert" ON "public"."agendador_solicitacoes" FOR INSERT TO "anon" WITH CHECK (true); + + + +ALTER TABLE "public"."agendador_solicitacoes" ENABLE ROW LEVEL SECURITY; + + +CREATE POLICY "bloqueios_delete" ON "public"."agenda_bloqueios" FOR DELETE TO "authenticated" USING (("owner_id" = "auth"."uid"())); + + + +CREATE POLICY "bloqueios_insert" ON "public"."agenda_bloqueios" FOR INSERT TO "authenticated" WITH CHECK (("owner_id" = "auth"."uid"())); + + + +CREATE POLICY "bloqueios_select_clinic" ON "public"."agenda_bloqueios" FOR SELECT TO "authenticated" USING (("tenant_id" IN ( SELECT "tenant_members"."tenant_id" + FROM "public"."tenant_members" + WHERE (("tenant_members"."user_id" = "auth"."uid"()) AND ("tenant_members"."role" = ANY (ARRAY['admin'::"text", 'clinic_admin'::"text", 'tenant_admin'::"text", 'secretary'::"text"])))))); + + + +CREATE POLICY "bloqueios_select_own" ON "public"."agenda_bloqueios" FOR SELECT TO "authenticated" USING (("owner_id" = "auth"."uid"())); + + + +CREATE POLICY "bloqueios_update" ON "public"."agenda_bloqueios" FOR UPDATE TO "authenticated" USING (("owner_id" = "auth"."uid"())) WITH CHECK (("owner_id" = "auth"."uid"())); + + + +CREATE POLICY "clinic_admin_read_all_docs" ON "public"."saas_docs" FOR SELECT TO "authenticated" USING ((("ativo" = true) AND (EXISTS ( SELECT 1 + FROM "public"."profiles" + WHERE (("profiles"."id" = "auth"."uid"()) AND ("profiles"."role" = ANY (ARRAY['clinic_admin'::"text", 'tenant_admin'::"text"]))))))); + + + ALTER TABLE "public"."commitment_time_logs" ENABLE ROW LEVEL SECURITY; @@ -5843,6 +6879,10 @@ CREATE POLICY "dcf_update_for_active_member" ON "public"."determined_commitment_ +CREATE POLICY "delete own" ON "public"."agenda_bloqueios" FOR DELETE USING (("owner_id" = "auth"."uid"())); + + + ALTER TABLE "public"."determined_commitment_fields" ENABLE ROW LEVEL SECURITY; @@ -5881,6 +6921,32 @@ CREATE POLICY "ent_inv_write_saas" ON "public"."entitlements_invalidation" FOR I ALTER TABLE "public"."entitlements_invalidation" ENABLE ROW LEVEL SECURITY; +CREATE POLICY "faq_admin_write" ON "public"."saas_faq" TO "authenticated" USING ((EXISTS ( SELECT 1 + FROM "public"."profiles" + WHERE (("profiles"."id" = "auth"."uid"()) AND ("profiles"."role" = ANY (ARRAY['saas_admin'::"text", 'tenant_admin'::"text", 'clinic_admin'::"text"])))))); + + + +CREATE POLICY "faq_auth_read" ON "public"."saas_faq" FOR SELECT TO "authenticated" USING (("ativo" = true)); + + + +CREATE POLICY "faq_itens_admin_write" ON "public"."saas_faq_itens" TO "authenticated" USING ((EXISTS ( SELECT 1 + FROM "public"."profiles" + WHERE (("profiles"."id" = "auth"."uid"()) AND ("profiles"."role" = ANY (ARRAY['saas_admin'::"text", 'tenant_admin'::"text", 'clinic_admin'::"text"])))))); + + + +CREATE POLICY "faq_itens_auth_read" ON "public"."saas_faq_itens" FOR SELECT TO "authenticated" USING ((("ativo" = true) AND (EXISTS ( SELECT 1 + FROM "public"."saas_docs" "d" + WHERE (("d"."id" = "saas_faq_itens"."doc_id") AND ("d"."ativo" = true)))))); + + + +CREATE POLICY "faq_public_read" ON "public"."saas_faq" FOR SELECT USING ((("publico" = true) AND ("ativo" = true))); + + + ALTER TABLE "public"."features" ENABLE ROW LEVEL SECURITY; @@ -5892,6 +6958,51 @@ CREATE POLICY "features_write_saas_admin" ON "public"."features" TO "authenticat +ALTER TABLE "public"."feriados" ENABLE ROW LEVEL SECURITY; + + +CREATE POLICY "feriados_delete" ON "public"."feriados" FOR DELETE USING (("owner_id" = "auth"."uid"())); + + + +CREATE POLICY "feriados_global_select" ON "public"."feriados" FOR SELECT USING (("tenant_id" IS NULL)); + + + +CREATE POLICY "feriados_insert" ON "public"."feriados" FOR INSERT WITH CHECK (("tenant_id" IN ( SELECT "tenant_members"."tenant_id" + FROM "public"."tenant_members" + WHERE ("tenant_members"."user_id" = "auth"."uid"())))); + + + +CREATE POLICY "feriados_saas_delete" ON "public"."feriados" FOR DELETE USING ((EXISTS ( SELECT 1 + FROM "public"."saas_admins" + WHERE ("saas_admins"."user_id" = "auth"."uid"())))); + + + +CREATE POLICY "feriados_saas_insert" ON "public"."feriados" FOR INSERT WITH CHECK ((EXISTS ( SELECT 1 + FROM "public"."saas_admins" + WHERE ("saas_admins"."user_id" = "auth"."uid"())))); + + + +CREATE POLICY "feriados_saas_select" ON "public"."feriados" FOR SELECT USING ((EXISTS ( SELECT 1 + FROM "public"."saas_admins" + WHERE ("saas_admins"."user_id" = "auth"."uid"())))); + + + +CREATE POLICY "feriados_select" ON "public"."feriados" FOR SELECT USING (("tenant_id" IN ( SELECT "tenant_members"."tenant_id" + FROM "public"."tenant_members" + WHERE ("tenant_members"."user_id" = "auth"."uid"())))); + + + +CREATE POLICY "insert own" ON "public"."agenda_bloqueios" FOR INSERT WITH CHECK (("owner_id" = "auth"."uid"())); + + + ALTER TABLE "public"."module_features" ENABLE ROW LEVEL SECURITY; @@ -5924,115 +7035,95 @@ CREATE POLICY "owner_users: user can read own links" ON "public"."owner_users" F ALTER TABLE "public"."patient_group_patient" ENABLE ROW LEVEL SECURITY; +CREATE POLICY "patient_group_patient_owner_all" ON "public"."patient_group_patient" TO "authenticated" USING ((EXISTS ( SELECT 1 + FROM "public"."patients" "p" + WHERE (("p"."id" = "patient_group_patient"."patient_id") AND ("p"."owner_id" = "auth"."uid"()))))) WITH CHECK ((EXISTS ( SELECT 1 + FROM "public"."patients" "p" + WHERE (("p"."id" = "patient_group_patient"."patient_id") AND ("p"."owner_id" = "auth"."uid"()))))); + + + CREATE POLICY "patient_group_patient_select" ON "public"."patient_group_patient" FOR SELECT USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'patients.view'::"text"))); CREATE POLICY "patient_group_patient_write" ON "public"."patient_group_patient" USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'patients.edit'::"text"))) WITH CHECK (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'patients.edit'::"text"))); --- Permite que o terapeuta/owner gerencie os grupos dos seus próprios pacientes -CREATE POLICY "patient_group_patient_owner_all" ON "public"."patient_group_patient" - FOR ALL TO authenticated - USING ( - EXISTS ( - SELECT 1 FROM "public"."patients" p - WHERE p.id = "patient_id" - AND p.owner_id = "auth"."uid"() - ) - ) - WITH CHECK ( - EXISTS ( - SELECT 1 FROM "public"."patients" p - WHERE p.id = "patient_id" - AND p.owner_id = "auth"."uid"() - ) - ); - ALTER TABLE "public"."patient_groups" ENABLE ROW LEVEL SECURITY; +CREATE POLICY "patient_groups_owner_all" ON "public"."patient_groups" TO "authenticated" USING (("owner_id" = "auth"."uid"())) WITH CHECK (("owner_id" = "auth"."uid"())); + + + CREATE POLICY "patient_groups_select" ON "public"."patient_groups" FOR SELECT USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'patients.view'::"text"))); CREATE POLICY "patient_groups_write" ON "public"."patient_groups" USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'patients.edit'::"text"))) WITH CHECK (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'patients.edit'::"text"))); --- Permite que o terapeuta/owner acesse seus próprios grupos (incluindo via onboarding individual) -CREATE POLICY "patient_groups_owner_all" ON "public"."patient_groups" - FOR ALL TO authenticated - USING ("owner_id" = "auth"."uid"()) - WITH CHECK ("owner_id" = "auth"."uid"()); - ALTER TABLE "public"."patient_intake_requests" ENABLE ROW LEVEL SECURITY; +CREATE POLICY "patient_intake_requests_owner_all" ON "public"."patient_intake_requests" TO "authenticated" USING (("owner_id" = "auth"."uid"())) WITH CHECK (("owner_id" = "auth"."uid"())); + + + CREATE POLICY "patient_intake_requests_select" ON "public"."patient_intake_requests" FOR SELECT USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'patients.view'::"text"))); CREATE POLICY "patient_intake_requests_write" ON "public"."patient_intake_requests" USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'patients.edit'::"text"))) WITH CHECK (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'patients.edit'::"text"))); --- Permite que o terapeuta/owner veja e gerencie os cadastros recebidos dos seus links -CREATE POLICY "patient_intake_requests_owner_all" ON "public"."patient_intake_requests" - FOR ALL TO authenticated - USING ("owner_id" = "auth"."uid"()) - WITH CHECK ("owner_id" = "auth"."uid"()); - ALTER TABLE "public"."patient_invites" ENABLE ROW LEVEL SECURITY; +CREATE POLICY "patient_invites_owner_all" ON "public"."patient_invites" TO "authenticated" USING (("owner_id" = "auth"."uid"())) WITH CHECK (("owner_id" = "auth"."uid"())); + + + CREATE POLICY "patient_invites_select" ON "public"."patient_invites" FOR SELECT USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'patients.view'::"text"))); CREATE POLICY "patient_invites_write" ON "public"."patient_invites" USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'patients.edit'::"text"))) WITH CHECK (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'patients.edit'::"text"))); --- Permite que o terapeuta/owner gerencie seus próprios convites de cadastro externo -CREATE POLICY "patient_invites_owner_all" ON "public"."patient_invites" - FOR ALL TO authenticated - USING ("owner_id" = "auth"."uid"()) - WITH CHECK ("owner_id" = "auth"."uid"()); - ALTER TABLE "public"."patient_patient_tag" ENABLE ROW LEVEL SECURITY; +CREATE POLICY "patient_patient_tag_owner_all" ON "public"."patient_patient_tag" TO "authenticated" USING (("owner_id" = "auth"."uid"())) WITH CHECK (("owner_id" = "auth"."uid"())); + + + CREATE POLICY "patient_patient_tag_select" ON "public"."patient_patient_tag" FOR SELECT USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'patients.view'::"text"))); CREATE POLICY "patient_patient_tag_write" ON "public"."patient_patient_tag" USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'patients.edit'::"text"))) WITH CHECK (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'patients.edit'::"text"))); --- Permite que o terapeuta/owner gerencie a pivot tag<->paciente pelos seus próprios registros -CREATE POLICY "patient_patient_tag_owner_all" ON "public"."patient_patient_tag" - FOR ALL TO authenticated - USING ("owner_id" = "auth"."uid"()) - WITH CHECK ("owner_id" = "auth"."uid"()); - ALTER TABLE "public"."patient_tags" ENABLE ROW LEVEL SECURITY; +CREATE POLICY "patient_tags_owner_all" ON "public"."patient_tags" TO "authenticated" USING (("owner_id" = "auth"."uid"())) WITH CHECK (("owner_id" = "auth"."uid"())); + + + CREATE POLICY "patient_tags_select" ON "public"."patient_tags" FOR SELECT USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'patients.view'::"text"))); CREATE POLICY "patient_tags_write" ON "public"."patient_tags" USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'patients.edit'::"text"))) WITH CHECK (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'patients.edit'::"text"))); --- Permite que o terapeuta/owner acesse suas próprias tags -CREATE POLICY "patient_tags_owner_all" ON "public"."patient_tags" - FOR ALL TO authenticated - USING ("owner_id" = "auth"."uid"()) - WITH CHECK ("owner_id" = "auth"."uid"()); - ALTER TABLE "public"."patients" ENABLE ROW LEVEL SECURITY; @@ -6046,6 +7137,10 @@ CREATE POLICY "patients_insert" ON "public"."patients" FOR INSERT WITH CHECK ((" +CREATE POLICY "patients_owner_all" ON "public"."patients" TO "authenticated" USING (("owner_id" = "auth"."uid"())) WITH CHECK (("owner_id" = "auth"."uid"())); + + + CREATE POLICY "patients_select" ON "public"."patients" FOR SELECT USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'patients.view'::"text"))); @@ -6107,6 +7202,32 @@ CREATE POLICY "read plans (auth)" ON "public"."plans" FOR SELECT TO "authenticat +ALTER TABLE "public"."recurrence_exceptions" ENABLE ROW LEVEL SECURITY; + + +CREATE POLICY "recurrence_exceptions_tenant" ON "public"."recurrence_exceptions" TO "authenticated" USING (("tenant_id" IN ( SELECT "tenant_members"."tenant_id" + FROM "public"."tenant_members" + WHERE ("tenant_members"."user_id" = "auth"."uid"())))) WITH CHECK (("tenant_id" IN ( SELECT "tenant_members"."tenant_id" + FROM "public"."tenant_members" + WHERE ("tenant_members"."user_id" = "auth"."uid"())))); + + + +ALTER TABLE "public"."recurrence_rules" ENABLE ROW LEVEL SECURITY; + + +CREATE POLICY "recurrence_rules_clinic_read" ON "public"."recurrence_rules" FOR SELECT USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'agenda.view'::"text"))); + + + +CREATE POLICY "recurrence_rules_clinic_write" ON "public"."recurrence_rules" USING (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'agenda.edit'::"text"))) WITH CHECK (("public"."is_clinic_tenant"("tenant_id") AND "public"."is_tenant_member"("tenant_id") AND "public"."tenant_has_feature"("tenant_id", 'agenda.edit'::"text"))); + + + +CREATE POLICY "recurrence_rules_owner" ON "public"."recurrence_rules" TO "authenticated" USING (("owner_id" = "auth"."uid"())) WITH CHECK (("owner_id" = "auth"."uid"())); + + + CREATE POLICY "saas_admin can read subscription_intents" ON "public"."subscription_intents_legacy" FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT 1 FROM "public"."saas_admins" "a" WHERE ("a"."user_id" = "auth"."uid"())))); @@ -6121,6 +7242,14 @@ CREATE POLICY "saas_admin can update subscription_intents" ON "public"."subscrip +CREATE POLICY "saas_admin_full_access" ON "public"."saas_docs" TO "authenticated" USING ((EXISTS ( SELECT 1 + FROM "public"."saas_admins" + WHERE ("saas_admins"."user_id" = "auth"."uid"())))) WITH CHECK ((EXISTS ( SELECT 1 + FROM "public"."saas_admins" + WHERE ("saas_admins"."user_id" = "auth"."uid"())))); + + + ALTER TABLE "public"."saas_admins" ENABLE ROW LEVEL SECURITY; @@ -6128,6 +7257,22 @@ CREATE POLICY "saas_admins_select_self" ON "public"."saas_admins" FOR SELECT TO +ALTER TABLE "public"."saas_doc_votos" ENABLE ROW LEVEL SECURITY; + + +ALTER TABLE "public"."saas_docs" ENABLE ROW LEVEL SECURITY; + + +ALTER TABLE "public"."saas_faq" ENABLE ROW LEVEL SECURITY; + + +ALTER TABLE "public"."saas_faq_itens" ENABLE ROW LEVEL SECURITY; + + +CREATE POLICY "select own" ON "public"."agenda_bloqueios" FOR SELECT USING (("owner_id" = "auth"."uid"())); + + + ALTER TABLE "public"."subscription_events" ENABLE ROW LEVEL SECURITY; @@ -6228,6 +7373,10 @@ CREATE POLICY "tm_select_own_membership" ON "public"."tenant_members" FOR SELECT +CREATE POLICY "update own" ON "public"."agenda_bloqueios" FOR UPDATE USING (("owner_id" = "auth"."uid"())); + + + ALTER TABLE "public"."user_settings" ENABLE ROW LEVEL SECURITY; @@ -6243,6 +7392,18 @@ CREATE POLICY "user_settings_update_own" ON "public"."user_settings" FOR UPDATE +CREATE POLICY "users_read_usuario_docs" ON "public"."saas_docs" FOR SELECT TO "authenticated" USING ((("ativo" = true) AND ("tipo_acesso" = 'usuario'::"text"))); + + + +CREATE POLICY "votos_select_own" ON "public"."saas_doc_votos" FOR SELECT TO "authenticated" USING (("user_id" = "auth"."uid"())); + + + +CREATE POLICY "votos_upsert_own" ON "public"."saas_doc_votos" TO "authenticated" USING (("user_id" = "auth"."uid"())) WITH CHECK (("user_id" = "auth"."uid"())); + + + ALTER PUBLICATION "supabase_realtime" OWNER TO "postgres"; @@ -6597,6 +7758,34 @@ GRANT ALL ON FUNCTION "public"."agenda_cfg_sync"() TO "service_role"; +GRANT ALL ON FUNCTION "public"."agendador_dias_disponiveis"("p_slug" "text", "p_ano" integer, "p_mes" integer) TO "postgres"; +GRANT ALL ON FUNCTION "public"."agendador_dias_disponiveis"("p_slug" "text", "p_ano" integer, "p_mes" integer) TO "anon"; +GRANT ALL ON FUNCTION "public"."agendador_dias_disponiveis"("p_slug" "text", "p_ano" integer, "p_mes" integer) TO "authenticated"; +GRANT ALL ON FUNCTION "public"."agendador_dias_disponiveis"("p_slug" "text", "p_ano" integer, "p_mes" integer) TO "service_role"; + + + +GRANT ALL ON FUNCTION "public"."agendador_gerar_slug"() TO "postgres"; +GRANT ALL ON FUNCTION "public"."agendador_gerar_slug"() TO "anon"; +GRANT ALL ON FUNCTION "public"."agendador_gerar_slug"() TO "authenticated"; +GRANT ALL ON FUNCTION "public"."agendador_gerar_slug"() TO "service_role"; + + + +GRANT ALL ON FUNCTION "public"."agendador_slots_disponiveis"("p_slug" "text", "p_data" "date") TO "postgres"; +GRANT ALL ON FUNCTION "public"."agendador_slots_disponiveis"("p_slug" "text", "p_data" "date") TO "anon"; +GRANT ALL ON FUNCTION "public"."agendador_slots_disponiveis"("p_slug" "text", "p_data" "date") TO "authenticated"; +GRANT ALL ON FUNCTION "public"."agendador_slots_disponiveis"("p_slug" "text", "p_data" "date") TO "service_role"; + + + +GRANT ALL ON FUNCTION "public"."cancel_recurrence_from"("p_recurrence_id" "uuid", "p_from_date" "date") TO "postgres"; +GRANT ALL ON FUNCTION "public"."cancel_recurrence_from"("p_recurrence_id" "uuid", "p_from_date" "date") TO "anon"; +GRANT ALL ON FUNCTION "public"."cancel_recurrence_from"("p_recurrence_id" "uuid", "p_from_date" "date") TO "authenticated"; +GRANT ALL ON FUNCTION "public"."cancel_recurrence_from"("p_recurrence_id" "uuid", "p_from_date" "date") TO "service_role"; + + + GRANT ALL ON FUNCTION "public"."cancel_subscription"("p_subscription_id" "uuid") TO "postgres"; GRANT ALL ON FUNCTION "public"."cancel_subscription"("p_subscription_id" "uuid") TO "anon"; GRANT ALL ON FUNCTION "public"."cancel_subscription"("p_subscription_id" "uuid") TO "authenticated"; @@ -6604,6 +7793,13 @@ GRANT ALL ON FUNCTION "public"."cancel_subscription"("p_subscription_id" "uuid") +GRANT ALL ON FUNCTION "public"."cancelar_eventos_serie"("p_serie_id" "uuid", "p_a_partir_de" timestamp with time zone) TO "postgres"; +GRANT ALL ON FUNCTION "public"."cancelar_eventos_serie"("p_serie_id" "uuid", "p_a_partir_de" timestamp with time zone) TO "anon"; +GRANT ALL ON FUNCTION "public"."cancelar_eventos_serie"("p_serie_id" "uuid", "p_a_partir_de" timestamp with time zone) TO "authenticated"; +GRANT ALL ON FUNCTION "public"."cancelar_eventos_serie"("p_serie_id" "uuid", "p_a_partir_de" timestamp with time zone) TO "service_role"; + + + GRANT ALL ON FUNCTION "public"."cash_dist"("money", "money") TO "postgres"; GRANT ALL ON FUNCTION "public"."cash_dist"("money", "money") TO "anon"; GRANT ALL ON FUNCTION "public"."cash_dist"("money", "money") TO "authenticated"; @@ -6830,6 +8026,13 @@ GRANT ALL ON FUNCTION "public"."ensure_personal_tenant_for_user"("p_user_id" "uu +GRANT ALL ON FUNCTION "public"."faq_votar"("faq_id" "uuid") TO "postgres"; +GRANT ALL ON FUNCTION "public"."faq_votar"("faq_id" "uuid") TO "anon"; +GRANT ALL ON FUNCTION "public"."faq_votar"("faq_id" "uuid") TO "authenticated"; +GRANT ALL ON FUNCTION "public"."faq_votar"("faq_id" "uuid") TO "service_role"; + + + GRANT ALL ON FUNCTION "public"."fix_all_subscription_mismatches"() TO "postgres"; GRANT ALL ON FUNCTION "public"."fix_all_subscription_mismatches"() TO "anon"; GRANT ALL ON FUNCTION "public"."fix_all_subscription_mismatches"() TO "authenticated"; @@ -8259,6 +9462,13 @@ GRANT ALL ON FUNCTION "public"."oid_dist"("oid", "oid") TO "service_role"; +GRANT ALL ON FUNCTION "public"."on_new_user_seed_patient_groups"() TO "postgres"; +GRANT ALL ON FUNCTION "public"."on_new_user_seed_patient_groups"() TO "anon"; +GRANT ALL ON FUNCTION "public"."on_new_user_seed_patient_groups"() TO "authenticated"; +GRANT ALL ON FUNCTION "public"."on_new_user_seed_patient_groups"() TO "service_role"; + + + GRANT ALL ON FUNCTION "public"."patients_validate_member_consistency"() TO "postgres"; GRANT ALL ON FUNCTION "public"."patients_validate_member_consistency"() TO "anon"; GRANT ALL ON FUNCTION "public"."patients_validate_member_consistency"() TO "authenticated"; @@ -8399,6 +9609,13 @@ GRANT ALL ON FUNCTION "public"."rotate_patient_invite_token"("p_new_token" "text +GRANT ALL ON FUNCTION "public"."saas_votar_doc"("p_doc_id" "uuid", "p_util" boolean) TO "postgres"; +GRANT ALL ON FUNCTION "public"."saas_votar_doc"("p_doc_id" "uuid", "p_util" boolean) TO "anon"; +GRANT ALL ON FUNCTION "public"."saas_votar_doc"("p_doc_id" "uuid", "p_util" boolean) TO "authenticated"; +GRANT ALL ON FUNCTION "public"."saas_votar_doc"("p_doc_id" "uuid", "p_util" boolean) TO "service_role"; + + + GRANT ALL ON FUNCTION "public"."seed_determined_commitments"("p_tenant_id" "uuid") TO "postgres"; GRANT ALL ON FUNCTION "public"."seed_determined_commitments"("p_tenant_id" "uuid") TO "anon"; GRANT ALL ON FUNCTION "public"."seed_determined_commitments"("p_tenant_id" "uuid") TO "authenticated"; @@ -8434,6 +9651,13 @@ GRANT ALL ON FUNCTION "public"."set_updated_at"() TO "service_role"; +GRANT ALL ON FUNCTION "public"."set_updated_at_recurrence"() TO "postgres"; +GRANT ALL ON FUNCTION "public"."set_updated_at_recurrence"() TO "anon"; +GRANT ALL ON FUNCTION "public"."set_updated_at_recurrence"() TO "authenticated"; +GRANT ALL ON FUNCTION "public"."set_updated_at_recurrence"() TO "service_role"; + + + GRANT ALL ON FUNCTION "public"."show_limit"() TO "postgres"; GRANT ALL ON FUNCTION "public"."show_limit"() TO "anon"; GRANT ALL ON FUNCTION "public"."show_limit"() TO "authenticated"; @@ -8476,6 +9700,13 @@ GRANT ALL ON FUNCTION "public"."split_part"("public"."citext", "public"."citext" +GRANT ALL ON FUNCTION "public"."split_recurrence_at"("p_recurrence_id" "uuid", "p_from_date" "date") TO "postgres"; +GRANT ALL ON FUNCTION "public"."split_recurrence_at"("p_recurrence_id" "uuid", "p_from_date" "date") TO "anon"; +GRANT ALL ON FUNCTION "public"."split_recurrence_at"("p_recurrence_id" "uuid", "p_from_date" "date") TO "authenticated"; +GRANT ALL ON FUNCTION "public"."split_recurrence_at"("p_recurrence_id" "uuid", "p_from_date" "date") TO "service_role"; + + + GRANT ALL ON FUNCTION "public"."strict_word_similarity"("text", "text") TO "postgres"; GRANT ALL ON FUNCTION "public"."strict_word_similarity"("text", "text") TO "anon"; GRANT ALL ON FUNCTION "public"."strict_word_similarity"("text", "text") TO "authenticated"; @@ -8813,6 +10044,13 @@ GRANT ALL ON FUNCTION "public"."min"("public"."citext") TO "service_role"; +GRANT ALL ON TABLE "public"."agenda_bloqueios" TO "postgres"; +GRANT ALL ON TABLE "public"."agenda_bloqueios" TO "anon"; +GRANT ALL ON TABLE "public"."agenda_bloqueios" TO "authenticated"; +GRANT ALL ON TABLE "public"."agenda_bloqueios" TO "service_role"; + + + GRANT ALL ON TABLE "public"."agenda_configuracoes" TO "postgres"; GRANT ALL ON TABLE "public"."agenda_configuracoes" TO "anon"; GRANT ALL ON TABLE "public"."agenda_configuracoes" TO "authenticated"; @@ -8869,6 +10107,20 @@ GRANT ALL ON TABLE "public"."agenda_slots_regras" TO "service_role"; +GRANT ALL ON TABLE "public"."agendador_configuracoes" TO "postgres"; +GRANT ALL ON TABLE "public"."agendador_configuracoes" TO "anon"; +GRANT ALL ON TABLE "public"."agendador_configuracoes" TO "authenticated"; +GRANT ALL ON TABLE "public"."agendador_configuracoes" TO "service_role"; + + + +GRANT ALL ON TABLE "public"."agendador_solicitacoes" TO "postgres"; +GRANT ALL ON TABLE "public"."agendador_solicitacoes" TO "anon"; +GRANT ALL ON TABLE "public"."agendador_solicitacoes" TO "authenticated"; +GRANT ALL ON TABLE "public"."agendador_solicitacoes" TO "service_role"; + + + GRANT ALL ON TABLE "public"."commitment_time_logs" TO "postgres"; GRANT ALL ON TABLE "public"."commitment_time_logs" TO "anon"; GRANT ALL ON TABLE "public"."commitment_time_logs" TO "authenticated"; @@ -8918,6 +10170,13 @@ GRANT ALL ON TABLE "public"."features" TO "service_role"; +GRANT ALL ON TABLE "public"."feriados" TO "postgres"; +GRANT ALL ON TABLE "public"."feriados" TO "anon"; +GRANT ALL ON TABLE "public"."feriados" TO "authenticated"; +GRANT ALL ON TABLE "public"."feriados" TO "service_role"; + + + GRANT ALL ON TABLE "public"."module_features" TO "postgres"; GRANT ALL ON TABLE "public"."module_features" TO "anon"; GRANT ALL ON TABLE "public"."module_features" TO "authenticated"; @@ -9042,6 +10301,20 @@ GRANT ALL ON TABLE "public"."profiles" TO "service_role"; +GRANT ALL ON TABLE "public"."recurrence_exceptions" TO "postgres"; +GRANT ALL ON TABLE "public"."recurrence_exceptions" TO "anon"; +GRANT ALL ON TABLE "public"."recurrence_exceptions" TO "authenticated"; +GRANT ALL ON TABLE "public"."recurrence_exceptions" TO "service_role"; + + + +GRANT ALL ON TABLE "public"."recurrence_rules" TO "postgres"; +GRANT ALL ON TABLE "public"."recurrence_rules" TO "anon"; +GRANT ALL ON TABLE "public"."recurrence_rules" TO "authenticated"; +GRANT ALL ON TABLE "public"."recurrence_rules" TO "service_role"; + + + GRANT ALL ON TABLE "public"."saas_admins" TO "postgres"; GRANT ALL ON TABLE "public"."saas_admins" TO "anon"; GRANT ALL ON TABLE "public"."saas_admins" TO "authenticated"; @@ -9049,6 +10322,34 @@ GRANT ALL ON TABLE "public"."saas_admins" TO "service_role"; +GRANT ALL ON TABLE "public"."saas_doc_votos" TO "postgres"; +GRANT ALL ON TABLE "public"."saas_doc_votos" TO "anon"; +GRANT ALL ON TABLE "public"."saas_doc_votos" TO "authenticated"; +GRANT ALL ON TABLE "public"."saas_doc_votos" TO "service_role"; + + + +GRANT ALL ON TABLE "public"."saas_docs" TO "postgres"; +GRANT ALL ON TABLE "public"."saas_docs" TO "anon"; +GRANT ALL ON TABLE "public"."saas_docs" TO "authenticated"; +GRANT ALL ON TABLE "public"."saas_docs" TO "service_role"; + + + +GRANT ALL ON TABLE "public"."saas_faq" TO "postgres"; +GRANT ALL ON TABLE "public"."saas_faq" TO "anon"; +GRANT ALL ON TABLE "public"."saas_faq" TO "authenticated"; +GRANT ALL ON TABLE "public"."saas_faq" TO "service_role"; + + + +GRANT ALL ON TABLE "public"."saas_faq_itens" TO "postgres"; +GRANT ALL ON TABLE "public"."saas_faq_itens" TO "anon"; +GRANT ALL ON TABLE "public"."saas_faq_itens" TO "authenticated"; +GRANT ALL ON TABLE "public"."saas_faq_itens" TO "service_role"; + + + GRANT ALL ON TABLE "public"."subscription_events" TO "postgres"; GRANT ALL ON TABLE "public"."subscription_events" TO "anon"; GRANT ALL ON TABLE "public"."subscription_events" TO "authenticated"; @@ -9257,129 +10558,6 @@ GRANT ALL ON TABLE "public"."v_user_entitlements" TO "authenticated"; GRANT ALL ON TABLE "public"."v_user_entitlements" TO "service_role"; --- ============================================================= --- MIGRATIONS APLICADAS MANUALMENTE (post-dump) --- ============================================================= - --- [2025-03] Coluna jornada_igual_todos em agenda_configuracoes --- Já incluída na definição da tabela acima. --- Para aplicar em ambiente existente: --- ALTER TABLE public.agenda_configuracoes --- ADD COLUMN IF NOT EXISTS jornada_igual_todos boolean DEFAULT true; - --- [2025-03] RLS: terapeuta acessa seus próprios grupos de pacientes --- Já incluída na seção de policies acima (patient_groups_owner_all). --- Para aplicar em ambiente existente: --- CREATE POLICY "patient_groups_owner_all" ON public.patient_groups --- FOR ALL TO authenticated --- USING (owner_id = auth.uid()) --- WITH CHECK (owner_id = auth.uid()); - --- [2025-03] RLS: terapeuta gerencia pivot grupo<->paciente dos seus pacientes --- Já incluída na seção de policies acima (patient_group_patient_owner_all). --- Para aplicar em ambiente existente: --- CREATE POLICY "patient_group_patient_owner_all" ON public.patient_group_patient --- FOR ALL TO authenticated --- USING (EXISTS (SELECT 1 FROM public.patients p WHERE p.id = patient_id AND p.owner_id = auth.uid())) --- WITH CHECK (EXISTS (SELECT 1 FROM public.patients p WHERE p.id = patient_id AND p.owner_id = auth.uid())); - - --- ============================================================= --- SEEDER: Grupos padrão do sistema por owner/tenant --- ============================================================= --- Grupos criados como is_system=true por owner+tenant. --- Devem ser semeados no onboarding de cada novo usuário. --- Execute este bloco para popular usuários já existentes. --- ============================================================= - -CREATE OR REPLACE FUNCTION public.seed_system_groups_for_member( - p_owner_id uuid, - p_tenant_id uuid -) -RETURNS void -LANGUAGE plpgsql -SECURITY DEFINER -AS $$ -DECLARE - v_groups text[][] := ARRAY[ - ARRAY['Ativo', '#22c55e'], - ARRAY['Em Avaliação', '#3b82f6'], - ARRAY['Lista de Espera', '#f59e0b'], - ARRAY['Alta', '#8b5cf6'], - ARRAY['Inativo', '#6b7280'] - ]; - v_entry text[]; -BEGIN - FOREACH v_entry SLICE 1 IN ARRAY v_groups - LOOP - INSERT INTO public.patient_groups ( - owner_id, - tenant_id, - nome, - cor, - is_system, - is_active - ) - VALUES ( - p_owner_id, - p_tenant_id, - v_entry[1], - v_entry[2], - true, - true - ) - ON CONFLICT (owner_id, nome) DO NOTHING; - END LOOP; -END; -$$; - --- Semeia para todos os membros ativos que ainda não têm grupos do sistema -DO $$ -DECLARE - r record; -BEGIN - FOR r IN - SELECT DISTINCT tm.user_id, tm.tenant_id - FROM public.tenant_members tm - WHERE tm.status = 'active' - AND NOT EXISTS ( - SELECT 1 - FROM public.patient_groups pg - WHERE pg.owner_id = tm.user_id - AND pg.is_system = true - ) - LOOP - PERFORM public.seed_system_groups_for_member(r.user_id, r.tenant_id); - END LOOP; -END; -$$; - - --- ============================================================= --- TRIGGER: semeia grupos padrão ao ativar novo membro de tenant --- ============================================================= - -CREATE OR REPLACE FUNCTION public.trg_seed_system_groups_on_member_active() -RETURNS trigger -LANGUAGE plpgsql -SECURITY DEFINER -AS $$ -BEGIN - -- só age quando status muda para 'active' (insert ou update) - IF NEW.status = 'active' THEN - PERFORM public.seed_system_groups_for_member(NEW.user_id, NEW.tenant_id); - END IF; - RETURN NEW; -END; -$$; - -DROP TRIGGER IF EXISTS trg_seed_system_groups ON public.tenant_members; -CREATE TRIGGER trg_seed_system_groups - AFTER INSERT OR UPDATE OF status ON public.tenant_members - FOR EACH ROW - EXECUTE FUNCTION public.trg_seed_system_groups_on_member_active(); - - diff --git a/DBS/2026-03-11/root/schema.sql b/DBS/2026-03-11/root/schema.sql new file mode 100644 index 0000000000000000000000000000000000000000..06441f8de9d0344a03d20ac8f62b179d1810e7a0 GIT binary patch literal 1473968 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

cjgJT8fOJN>c{>lPu=WpOgnFz6DvXC_Sf8! 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

j76LoKX$h3p;#H}M)r1^ zT{#C4LbMj2x4ymYKELAW_lIp$CZ@wv^3zJ0Bum8>*|8qr6OmqzP2y)4lj6|F`$8 zy?NY7y8Sso{(~^UK|DaBv$^abJA?DVlSwk(aqO(^%q-5Hg`k^dCAvkD?Rao-e*3AX zX}a0n>~3DFip`c_*plB%^QmGz#bU8Y&gsaGV0Cd~de!%)-67TW?kTNW?a&+_o)@>K zcRh|%7jfzneCaj)I~?!UGw+|WfIpICDUz176OPqWH!IQgADH}lqQ(IgK(A>P%>8Cp z2Q&H^9tnIh7zRr zZEjQ)=LeqB&aC0CuBFVOyf5g_HD8ivK-|>#RQ=s%^?8SQ8B5w!U-x!5of##bQeFvB zgdHv1(S;-S>bKqR_Z_l|^T`Md@9hrkCM*W)w~6oc<1q8&@HouXiTUmg;WFnJARhQ% z^!F3`KgPY&c16l}61UDs+_y{z6nw)ZWp9J;3@AoLe`Hk^F+9 zjCbU>eYHsS`Rf?z(rqX&vWr^@nvVVAo)a1!_I+yKj}Pr(&6)o>Iizxq^KH((>p#zM zsPA=Tp5o>3Gi~lU@uw`rv7t1pE-6;2argeP&s;gQSk-TH4$*kVR|lh93CA*ovB`Z# zm&wYXxB4@s_DnM5MG=SF6Pjgbu5*2lIfol@ol~sSajs^6yDUeFg~YCQ*5hx-D>${p zEtqr4td6?eKr8+KyFO<=0$g82($Dkt(J%7?y0BUQTwfW(5FkU2k7uW^+namss?j-B zIh)nYoLr3iT)SjG> z*B$!NHOJ!9Qb@(+b1hE4=dXYnYI+^9daM+Fk2U?2E`IMeADmwJ$Zfo z*pID@he_|p{yc2xzdCJpYsUU;6o>cPq5Kx4L#4yev-K;X)?FnND@A(m&5u4Ej^*B) z&e_XwxLXnJ_PblW{VW4seNFQQoY7|Lt=444E~BhzzeZI!dEV0)K6&I+l zxTK5-YA(8a8~PO*h|8gGRAiVlhwL{#X?fc9iLXv0bVYP1t9#lH{yszuZah5dG|bqwP9D2`=tG^-hw*HU=`C#!j(I#zA~SQPyt#*| z9X)G36P^p3c-o!|foK3bE-(gMQCkP}7Zzl*=-qeR>;|g*ZG}I6e@HdlFWNKsvG)D2 z`7`|=r|}Ql-EH%^u2fQUkxP=~XOaWeZpe$fGfs?%CI-UEKiBWyvwSh}(Gh(Y`$mz6 ziDeM#?z-oO=(_)nIZc1l-gEG<)%H%~&WiG6w0!F$!QPU-9<87J3-vGh7`+}}?|^ag zfGqB?-M!S+l-U}^6Vmzxt$1QD8#Fl_0o{@G0rjt|?_Js(bxD1P9=xWfn4KpNKKzC( z++FpNdyzKR-XV3Rm z=rX780o{DwR;|#LG1dzEbHimT9M1jkZLe>8?&^w-K8`ju_WC7^wY&Zdb!b&NqiT4L zX*|Ncp>YFTMO*a^y@VB?9+`}YxiqDSz>Ka zD-sX2SD$V9t)`TR^J%^B2Ws_j%aY|;SL!S-)OI>Mx%YMM>PoHlX!pyUjK6=^yCe#Q(vyp#>@eFQ{H^`_tAbSARjU)=L>7jHi*>F?HF|H$L! zI%9vLTMpaKbZo(*I7n0n>DOl#1iPeQ5sfuU}3g99RN ztVVB7uYKvHbPAh1CT<|hcS5TKHh#EiD^E-nTJ*Q`wnk#n&6ra$Ug)hkw8#(%C;5eJ| zf@G43B(3kTYgwPPdvt8?U=6{)Rux)v8QS;mnr`j=@5+*A16%BK%(!sZ7HZOJ=e%E* z*gp5K{#f2i=j+RQfW8J@=G5s0rsc`AirTFJcPyV!ylQrJU_`4wmh#D@6GIKTQQLfU z7!}BzZ!>Jg^)6l9In?D^qfI~hSg+ELF^BPmJ6m^m-h4uA-KRe{v|GXMgBz~mgs;rq zG+)xle@=DlW>*CEOI*{8!0es0u|fU*AyiH&pAp(VP7F3ZaCda>$}FY-q5rWQLey(- zcT5_rY+SgKk@Nd-`VL>~sHThj+`ETET8L!>!yiwWHzw zH_R^GNVaafbR~(kOaI(#s$Mg7J#$In^g^W_Fl;{j7bppK-;Ge5`w6#)qu=aG&dN_oc6`kiE1n-yTpD zgS*gho7)ZLhi!GWTTl5Zy$WxD9g(Q8#{bz#ippC!+=!(-KREi79fdc*CVC0oJHmfO~g zy`buhEBYVS|KhB}$2&V4bFsu)ios@WW8BJ1^2``jP*Y;8e4gh^Z0xr;wE1{;_n(*U znTOBev*!Mj=j}JvvbxyeFw?%S+L{a#VYugjml^?27^iH}ow2!^e@bWYbhFIZvDe>ry0uO{kIz>9E$~?C)U$_n+W(wurD?r1$DV#$ z);jnj#E`gao!&eIxz$_#h#%8h4v&U5H;#g>Og3{d-US~Y%f?8@#kp`vL(sWwH1fxe z8Q3{xR#?|*?;SpC0Yj@!^FmAWrg6LT7O<@M?ahfFtGfa6O!eWIyHYJrdnvgV!{Y%d z46?R+*=Cd7%=#hS_~Tl4&6XS@orYb<;E=HLxb`({J_eC212C66r1PC0w4NJlM&>Nc zv#NdgoKzYXAJV>rrH8evVc{W2WGx#{$Jwx3_3mNvX;^z45(&GHMWDfeI86BTHThw) zFA&wc?iy@LjDA9^qKL?k=?`|Iy`!^?|3K@bTZq@=WRv1R8VWA^Pii0{5(|gd{!x7N`X`E9uSEb`-v*Tua{`OMQN%JR7XEE8mlG@YY+ZUT1Wu_(5 z_{># znI2!3F~~6^q-{M8EThq~_E08%y@8PgT91)eml-L@WciYYNS8$^7&W+sd*^X#(NhPA9?IIG*|R(n>i>o_!VzI)(>f}@N;NW zf|sZ#JE4;ew=yOz$z%I|xN|3W*T+d)nK!3N+cF;~LS>b-^H2=3wmanmEV}x}42yi) z``S-PjtRDn7!(rrz1+VYyX4}j6m9U^y}OqQx4B)?AKdf-z1L>v^Rn1J<@VKKt#a9M zXlqh-8`i$Go#Orz%zgK1Z<5)QRJX1A?A+Tj1M=D*wXt}$Q0xit9yHtk?p>hg9Hj#1Z+4#`vC zR3hw(w3gyxt=(dl<8ehR+XcNa+bz{THE??wv+Y<`h>W^c6N9Lv zMOYiyQXG3kKDM)Yzl7ziVIGgJE#Q>1_;EBmpXAF9l+KT&$*gHFc?e5dP|o(eraS*3##g|7>%t7;E1r>pJXW z4w<&4n3&?0q6>3t9p*{6n-H}thx7+I6+{?iy~Q)SPxkM0@5SHRdu7vBjByh&;-?T< zcbf0$PTQx=55$+b`!(WsIr!#^yA-#@U^8cs&fyAQY0h5-Pr)uz3o=GxUb&)L*;Fo78B_ncuKtkmF;kM3_b}7Q*6v@Hkjr?NS8eU(;b?uq&cpY6wKZkO z%Y5GwE3Ne`%epUzP1oyn8uaDDx3m%wBWW2sS?&RgOV>tB%#Bsc{WdPOzoE_>IltRB z_P(L`1$ReVDNvE&?oxv-J*6AyUeM3i^bOlB+PvNKg{tb+a~{8hX6?F~KS zjJ`kJ&ac!G+Ijc>X?W@h{RL*Xz3y{6AMm^Hqdi3BH*IVFX8;#8gb2=leve)`ZMC%1 zW<*~TR_xl_p--5bbx!G-=AL!8z4I0$$8+|nhLYnsW~X8PlVCeX^yio=FY=#u*y{T% zxL+`@!97{I{gVG2(=YkYvHgG-wu@& znm8v9=gPT^*!Qi_7JXKMl_+BqsciQ@)nYnM_9A2L=416eGau=&Px5h&pO}yG?fX#| z{e4I*yCxpbjnww@FUdwvXBcZgXXj3M<^@F*hJ!(I&WbL$268sE*)Q{K#e$E*_J zsfe&lJdkR&_L+!s&gfYe?cWo!R_Nw6{eRBCPJcTslCjT2%x0c&+WfO8Welq6r{tl7 zzd|HtW3f10jlZ3T2GP;W){b#PPmF&0-%LYcqkD|T&U7?6Zxmu__dvQOnvh$=lZ+$vvsjSCSm-p{L$H5jGY3D!p^D3~<&SdWARm=HntE=(MC}uV@{zu( z{(04U*O^ckf6>m4AADF%LhoSR#pJ-|A{DcOWyejdK_M4n`!jTAdl%-N>(KL>?GU4) zv7iT&>zTfF%xl?* zi|g}#%YHDdFZ=qa%@Y0S>$b|iO!pS*>cjngO`~=^*Zh){wOrIbxbtE=TLISXj@hA7 zm-LOX7;CVjJ_EMp=fe7{uYvX3mmlw%Y%R{7t)V?ZPaChe(YuKu|H?)*Vt{<+l9$o(zfCduHSDerGiJ;FEuUCsL?ETem~t8DN6dF$P| z;O0~hoW_HbHqYApGVV*SodfammgyIJPYQYl5r{pn3p?!JG@oyvCqg8&y4R@7jlrYq zAD57w)A&?BGef0ZlTBF7TTE-Ri!aG0E+~4z34%8?qT==voTgy)jEKv=znz^aRyx1m zOx20)-|~JaSAsQJ=vSNfT1LY4SWh3%nrz`;@4eM1%1hPBdh9J%f>IWWb8OEx<()c- z%2>y^{c?SaGkK1PZ8+Pa_W5iV??4_`u2TK%M^U!7&8;8X>+MdilD$1fQMR{V)44TU z^WI=pCs)bd9-}DR+rKsc+WZUs*&e%H$x8OP4~K4__iu50(EP4lBd|G9bBDo`_qmSW zQC`DV&>+Xroq^VW9j8>`W`%v)+lEuGaW44J^e;|9J7~|kGN)c4`)beX?|&vHcIZoh z+lb8lOt{$r>y}Sxy~AXA|49FvyUFz9=A-5_`h%bN8*_Wy9145qs$BzEkCv_N4{a{~ zuGzZf$E{$n&bue~YhpA`rNez9U<}q|af8xb(*#zpu4(-TI>1U0RubX6j2^5Fy$T%HQS&l$`)QsRjl1jCw79!s?YXz< z{z$$4=jJi>`8NrSsX^AM`+3LrBjKdWqt*&j{AfM8$R8`~ku`l>tVu?`F|Zz~CC59< z5dVmW6OfPE6K?x+g8PxMA3uz3sUE#bj*&HKq1@7X9E$txtkKVam3|$&67;V0H@Ml()==SrWliN z^R>Q9vu)gvIxU^GGs_I?Yj&D{&>ZeX^H-WJyC|MEKYp0er)L7p{2%ip6KOtZvjVT% zd3s)*801Afh5KNUx46#ifw;N)xOHSYk?RPTl`m4@L1Vn|_*v<_zt>tMZnsBn8o8L0 zXr`6OXuEmzUBV7tjis1kRQ%{2*IxQK8QTuu>@cq7T;KnqdD!Nrz9pZARgVMu7iSQj zk`*F%hy_@ZhN~k5~NySPFtbY zm)AzB<>j=RYjxv1II5#zZ&(#X78*B4`>heTt|RY`QzMUI z*RG`Oc&r7t)m_qrhE7tMu`cwXTw5FJRQ9e*4her?R|&xP)AlZT_oi#ChuIY~>{jgF z^WBVvPhh6^mVV-1K>OWpm930#h>fJX2oK&tTSJ^tcxg#&1b<26%q>|`YBp);vGw~T zHzTwj3FLfXsa}!ri|~3_v)?CQc1XSvxeT10hq--hZl+^lxfo|j9=Z4=v}L~7BD_U8 zE`(x`wcR6%;IGMYk7#V)C;K(OVV@*soR|k3)4$jufU*0Aatg1>(!22*m4$f6^v$q( z#lCCyUJlcov6-( zKeL{y?vdE`-jrmTeqafMBvY5$*5uL>8Xaqgg=Qsmfypu=Zm@gd zu;PQgbXWA+Tlxg{Hg@msH2-XKkoC<hWwOW zCqcc_`FlV0u01WG`(KUmOSo*3ek2|RC$Cdlm*iPI9tpdD)#ewF`$Q}-6~Wv39~&b~ zeXbwr+lax|2HB?!Ba8YNwGOSxadlnt@p*x@$tCAs)+MQg=fcdwoMD7Y9n3f2ow}Nv zU3#_qjPXTN@7CvmI>|Vsm-8etIQcw+6h1j-%OI9!=rNsCc31hCE4vOmxlqb*lMkH^ zGr90e^AeH&UFBu2>^i*ULMg*bK6E;~Y@zWxlrqHoeymprgP!f=Xu^tVOu=U z(?uzs^Ptw^ITzYeJmNNRDw_7^S&oGPgKI z3w*LSXYDt*EytYN`77;A$Bnv{Z8(1m?_RWLV;R16=Vc6;Xx}k6!JQJ5$7l6l(XIrX z?(Z_#e(!?b0po8x-#cu-1q}f^DzY!>55{}gTHQWi%l)F`tL}mZWqj)0(43C%zYDrt z(-^f!r$m0yR!AXIoF1vrFYjoqFt=FmG(Xb_gE8o!(72Iv;~VZ}?V{xvi{sFi)a`Gj zrINV`ZXHsUA2)a`&)#vjK3~o$pM-zyPU1(@kJp%OBLuR?y zl@lEwzj;x~@sty%Hs5e-wOu{COPq_5yA1DA5bAI*4OtofrC{afpuHW&Jt^6~hHR7l zy|%oO#l0+-6o=vwaB(E1WhoBCW0A1&<8~xL#uR%HE-9)zr*)ItHo`L*-j|fm#j5CX zglBWG{^#^hOy*+^ZhCd^-u}4xsQHZk;3xj3-(7>UOH)Z z!Wv-O0bU=ThE!?_nZ&a6JZ8@!31`qwypIE(8dHG~K)EeZ{ z@mA#}mGN9}h~KEgz}O6?8*T2NbBsoxKX&E_?!waAz}NP7Hdr3jHsii0T_xEPhzwiG{7 z&`4POY4aOdyV=1!cf&Dq?PgEsEv@*!q6n~DE+U5mx$?>}g9{lSU-%Hov4{(!1h>q- zkK5)eV%X99HLVBj9146x-HX{#aaLU};U(e6o|Z7#d5)e)RuGWcp{+-d0t7P=I5a-T6x||;+Nn#PN3eW z>^SlPs7p0F`A>-1sMJCAby%^YBS2-5ceL?>!{2I@4(0UV$Ku^rP!5&g^NXb7^K*e zgGz@LSjjT=g&4Q6k~?GuB2mL5{MMahWj=@3F6lc*ZNxhKZf#?kufL= zq0#?}Vr9hCVZ5%N!>MxXaW)sB97pq!>2Wd_t2_s9Xr78QV^BR~GRMHYOBpB3b+LAG z+@2Bnj^?{>=(E>tL>}|mt&PAXG^WM-lCnv8jIuIm`I?ea%6qBT6#JVMth*5*#LKJY zA<~ga@jC~R7CX~1N^;AbvApd(c8rYj97;jM&zm$9@?1&5rNxiXOq!9woLhdEGTUz7 zY3WLrui8?{@?KvWUH_pipN1cLNpo>i89a`H>&=N-&oM8Z9@oQg$gwlDeLX&fA<|#~ zUzWSByZ*WrWXl#lP3SR;AF~__C9vu-mLI(iyHoS!^|Luua!vN;Vw7ZSJ~mBu=AzYL zV|YgSi=Z_j^QrBu2HBBVOHX=C*Oo}mFX&66=S8$-)9^X*dGgvv{&_<(V>2tY+bn8`^Wx1vtx_&}WG7V1?wrZ8bpE~1XEAbxP!)b2w1Yf4t+3n}o?P2s} zk@GH^GU$00J*hOj%KRE$?H*xXIy=5zQKjDv&3ABL{W1Oar{?44qvreOS@W=Y(!8MB zoQKV0`m@tKrT_0V-!(tc&u{3RNAF+p-82S&WM@%fIOLcZ+P)r(!VqaNfNxE#cDC?o zLXTPenB`a~fmM&O{OEPqow}x0Kbun}*JN)lMoG5jW7A}3E?NyXhOb3^9kg<6KDCu~ z<1Sv*(vu$3wI!1C3;L4ic@b^dG<;6{`daNHf4szcejpv29HVnE>2Wh1r6kLaH++KU z5oLoy&L@>;PaF<@ro^@{&x$xiatt`8wT9QUcW=v;5^*w0vmp%)Hz!h2NHZf1mli+5 zR%Fpv@5uKWW~Hpt)fvHAiDT*|@^z)lS1k*$QpxgOUm9Kip)H?=ADUlzs@-$UOJ`Xj zwc^=%urM5Q>fwrr~qqSBh%)9`O?E`GIt7 za*WQwq{q#4lyWS4*_=_eIO@8;+Vq-FyqwaEN=L-aqZ}mC>`BL_$(gXcGInF^6W{L6 z3edRsM}eGi!3`sG3YWY43!ou_}0|6z#u+t=(3F;w=6Ry@anRdUjjYGr>@g& zgW;*tYco0*r!<4}@o6(Q7qJ#YwbsD4z-KL8>9Sv2Dp_BlFO9Be(Uwok55=$dZNa0& zORei0((%c%JO`I9U(=ClFz@R-vW^`pryjdv5y|l>9*G`2HwUzm zeN3kZUbUwT9=2zdp0;-k-^KN9+pFa?sL%8AvdVjqHOQ#%o61YA<@LhW>Fzz=3Hke5 zimbX7GkCmm+SB!R<>i$1bZd}L*UOccSj)rBub0-Iaex<^mr&PJgkh0ob0`K~#)YBM zVg=v&;}#girwv`U@#B_drUYJH7V}G>$N1Fs%WW_`ReEhk=i-!Ra6Ue5#^xf{Vrcj} zpuJ()cTWjw-H)4J=&@4yB@yW=t9`Eq;Wp)ma(t z&f2_{IOg2g%Q*R4FVEZ3An*H7q4rr~M$@_x0C*L<3=43j#&*m|=)s?owp z#yETAma-xbs8;KOemkbhE%Pe;UC3*{r_a5hJ7Ra}Sr=`s7uVggvRL()&#!46cBkeD z>t}PS!K84FTQm~fNkO5(mUvuR{0PgX z-O#<2$Z?##&t;@!aqAtyy57^%mSu_L9Jr)hvh3IIr+wPDdE2~dvw^q7l0)JP@_B0xJds}STbbm%PzhP|JdnP08s2AqA5HD?%e-`!5%Tdy z7!EmRhPJQArZ7Yr4B%U1tDP-;n$TkwKV~@=N?_GvEI)c3cBih<)z9Ws$u-%Vi&2uT z`PeksnTu9~jp1usU$yrdE$zrMpBmO0{hsm(P`V7amY(#Ot}T(AU(lCC&x>fwrr~qq*XwHc z9`O?E`GIt7a*WQwq{q#4l+rBQ_FbQ5R1TF>&en(q24WBc= z)>rdv8_~+Vbb9;_!y(7Y(DwDX6oyEH0eov`wX=m!6MD?z$1KM}39NdI?$oun z`q`W+xh8vaF-o#EADbpSbJ1$BF?!3Ae^C>$cwr5<_y~d2VRZCBLOxKo3&M)Xo zqUS}lWz+CE@oRInkNoix>-m9nY;ugw!KBB{bd=I8vp3?MQ#}^WGYT#hC_~#q3!E2DGZSY1Nhd- zYG(_dCiIxak6Dg|5?J*Z%a2}%-Kpzr^|Luua!vN;Vw7ZSJ~mBu=AzYLWB7WNy&uxI zyLZd?NSd{A#IBmU(qnuHspNb_8EN#qN(uQi{80SbTvvV-%@iQHz zG|S%52)6AzB5#{e8FiQxi$;b!@hEiI5{pZVA7N`(UB%=ZIyL94t+n)>&3Z}e&`0gN z-8alVVs%$@*xu9AmM&-Y<&tH833+t=h`xjx9_fgx!S2GS9V(}u7l=h9$KQA)dd!Q( zro)+2%GKP`xO_p}Irdai_V4h#yCZnm>UkHrq-#o(w_3e#Ws+pRzAT!)Lt8ox?=!!S zUUSw8G5@@DmJzaN&WGcWV`i8hwC<1z*N6rK_|~OsXA7Su^q9quS&oGgSoOv~e)Kx* zPF>fopUtU~YqB>Nqa<7Nv1zh17p(>x!`Fkqq#IN*?_H|ju%GK@eOt*_YwAjm@g<~^ z^ATmF(eo-L-mIqY;w%b!KBB}bd+)|!)-3OefFrayL-2JPC&ez z(u_(+#Lc4|B+~3j$EL}du=U|imLoce!<>$FH|jb%$*q^s)0jSw^<|Uy2qk3F_bvKT zYI&*oHHA9k<-S*$mr&OWgkh0oZ72p^mW83xVg+B8d2`*E+PzI44n3CU#rMj458JxvK2 zwR}^227e1tL%h_wej**8EZcK%>2fw5sRr}5ytlX;%fqD9V^$m(5)$for1;Ex{eC50W=-#qj!u%}IjA(5nvPSB zZx_w$=A6#zx~B6o4>x^MZHlDQ+{(ek&8R#q(mcvRr^}wOOm$zLyR*X7m)oooYH6$l zo3&-r@Cy1emGCawQtEjrzRY2r@%GRM@##a`!|)@Q_8$_6wY>ws44T|e%|>p8>#6eV zb2}HQJeTtk>T@?2vmRH&Gkbe<1Is?m;X}?Db3eP4v&M!adI`;G`-hS;N_&>FvT6II zlG5sVv-s@iHX@FAxwSn>Iznkbkb_K{#pzh(IB0Ic3aiDhlWj2)O7kiO3paz(Fi3MH z1(gmf!m@k@|J}*byZt4tAx&0l$s);WJsC8;f|gYBUM1{qr@QJ=q_v~vO|;~Y@+5lr zwY-RyMDiYFepgQ2ar(S$TI>x&A;rDW*0q=uhDYA+`PS9y<_Mo2wD`o2Sc-cRNVRy% zk6nY)sq1aEb2wFQJn+t9ar`{DO%FysC=(md1P6xDTl6~(34EV)9_{D z>WqJ_XV{}#t&baXPxWo{u6aPa$S){X!G3b{Dtt%CYrm(@y=b1c_her-H}s4Xdd4yR z_NV6K=A-8O=2`Qwc|xDrp`VZG&klY13H|$B^Ar92hTeJf{uN*TVy{JI;wXO1a$Z3K zs~+?D(d)1~HK$iUn^Ps%WN$7;Nw(%=(`08ZS`9XaXUW{1O};SzRJ3;lgZv*~Wf z)Np+IJ&ifA=XdSs_Q!U_`G!Uuy!xC@NqI$2z`2)r$887iKW*O9$cOO{@7~bqDp&N$ z1NsYH?a|L8`Yu|;sP-BC!B6fHu7u9?JU~h5|D@Lt)uv>EYaQL(o?V9~b-BJSnPol7+GN%BTkDcu!#jrU z73uuny=UB|eEb282*{&b&$tdP>UqU=$t&j(*CwZ)H(ZzG8lG@|?@#Tq+q`soo+Av0 z9HT?q*JD~3A`J%ctx?v_7CuerF^eCw91A6|>M@ody$-um*Es8EbE@Q;?9Ig}$<};q zn(WL)tHH+bwZG4sKLnj-YCpG~HGDg}*3^|A<4Z^-=OfBUqvush$fx0l;@387j|So; z*7FJJ*yNaYCjBsy%9F zy1p%~M}5w(MPhlMvK~qGeb!oJm-LA@8;>7C<&*azu}Jv29gjesbFr8-xDdyC?4#VL zYSJsJ=DV+9acfv?->yxcdR$+t~+3IzDr) zQp@%c?a~i)e3NG94chhCznWp>6B%D-4aawe!_9)yxb&E$Fa_ zAFmAKByj4mlOMS}lT+)T>Sk`L)LKl<#V5tgd|X;g%tb2AJk1)Rnz^c}CmnW|kVwWK zl#xWogOrd>+ULaAJ=N?v;-%H$e>yH17U$s6;bJ;MSw?mBGFU4#=dRv(PIImIWISZ_ zL+cSW*b|RNf-@;7G?)^PON$@*>t}bpLeFL5dbFv_`Sr;y>s{6;udW|kp9VBMX8tPL zy|*-D;d(Tw=PB1Gvz(V)qpW%!a(&XvdB@juy5cFF0>0(FQE@U#dz3UZ++0sZARqPnCCC8Uz`5oM&&^C~6e)9^#_)kw8R1Mw2; z`GjzZt*_4Whn?dO~q*;@SOr9z8 zxv)A%9;@wn*|b;@hC+%9p{;8%APkR$-Q#@1JsJ^k3%R*T{IofvYU?u9)z6x5o4?b& z<$t4}JIzD7=ln7KeA+yrf4^&fqMzT;UFeVAzcM@*WLg${`x$-f2YSwr^qfD_b05*O z{*-;&`COYXs72h$eo6PO-_o6BX3W)SlaDvc^6j@bbmAWR3z8B!kA3=iOwophq!OG! z<^pW^jpVo{X%6Y$)B|tDJElmk?YVL=N_&+&Y}$;^ zK`X~b8}r0e`Q1>A1kRqlkBtx!AvPRFOebw*H5Eg_FXCI*^b=1D{amf=uTj&|-lk@q zaC^79bs_CdYu1j2_lABjOTQ#UroIv>@k`>yTd0 z3)i3z3BL=ukt5vZ-nuyH!yrdZA$U6h9FM8xb5y-7o3(iU z8m(?L4@V)vyO`EBcoU9C*6#WC&em29+*u}{4m5bgk5+^LH64`%7jw{PFfARQ1dm=*rRsHivM%-yq1p=gu#f1Lb`T-j-lMF` zIsJid_L~E$Yem+!zELq&(Bn!RGFhfv(fEOi3Nt$aOVA^*EX@8d zo452kvH*A=@6h~8LlA#KjTg9-WSAa zyO-(#+5GryuiyUEcU=ns&4ReJ3 z{}1yP^>Hg#UO8@YA>-o~A0jz!abc9=7WO!q9N0eP2T+}TQDGer&hyx#zkXR{IkD6# zue~p~CTq(}?MvBde|6TiRb;OF@Ah-ob&dgjiQ?pywRa9=yqw@cB+DBPj5^%H-kfvV z(}sxf!5!dMoV=RcN<${etyDys+)BeJ$1U8hhnwiGD7M0R{r%Bus|?GPTAF8E__*1| zhfA7sTuAwu_cK+@foJ9KL`}bI(JzA(E9P6{vhk%>q%3y6U4HvBH}bj>UyXZfrlgRv z!KL=NtZ=yHyRL?n z@W}Ta(;w_18SZ<*ecd><<%&L2U&TD?q4VUGV*nR2K7Q~al4B1SMt*MfnS(64S(Qc( z)z;~|Git2H4R4=2q*IaVV;QI9QhbxZ$i+MvY*HMQKwE~5*gLW-b&L$Nv7r@*5qw2(vmFB!!E&TAbLZ8%^8AMZESi@{KZKFI137F#pzHt zG>)1ZUC*l=PgCWT<76%(KF;MMk>gY@HhIo;RR?Y?dPAqFozh5HW9-@2`LcXk90^Av z#f=yQTAT>Sq``%5l-Q%u!)7`#Gc!Aou^*+zyaz@`ccgU3!zD@e_z|vsi%E_tDOmJ4 z6OT@YJ(m=HVeQ@Al(k2Bjp3=z?s-nAC$pz*4C{&QK4^P-O}F#ezJrqtFh+In)HnBn zM=7f@%N*{zy-e)A4%s-p!dm)kpO|w?qmY^FpkCkP5RaNaH6J%0HR8dX*RR_+*WUGKPHUKYcj&Wf^FOk>kn$`#sJVQG7FsE9po3qA z=Lf{&ipC!ZxzO7d6^ zw+w$VyZ)`^B+gK|rP29S%TbKg*r#~d?9yNGxVw|Of47?ZZjJ2a)_^2;rLb}`R}P~j zZ>3Pzz*@}qEx+#>+}B1uZ1&?`FSDoc*28kY1bU1&dGYDd82F~&-3rrlwV=&#F1*sr z=EJGYXfEWnFuCuC>bmq(>oxom zNqZ3NqCm#poXLR-Y}_7-vpTS!DK)C7J4+y?6CH0Mjb6q_$fMTr4AOGc=@0t8t>#&V zO#k-vQ?sA&OHz~1n3AAo|KXQO-%@@XI9QOSo1%rt=y#W-c_eBI!3Y@pF0$UEGpB zLQ@h6&wz6z?2e)SxhdEQbkXkQGy92f%ET|UVu~9cu&2PDsMft+b5*019^}|BjhK(` z@<`W_5Ymzp;+`gQhy1UIWiqv;*8gv5<`XrII(YZFcEp)yuY5SaOUCuiDQO?WOkKR&c zH#{m%NBE6qKdAfepMui=RzEhf^P%ChkOO(=?BKMYGf|dVqdgkUp6sWLhrb~kyl|dT ztH1B-Z>XvDYh9Z4ThR}or9} z={x5zqM+IaBMeT@x~_1AURob=T+>3%$4x!Na$MGuL6-Z-r4F;Ic8vhluKxF@R)TT2 z%{hI`t~cy__^rPARoB0M9hh|#UL9%p2z_ZJ{6+~WG<=D^ToV2TSst9#k7}Z~o_$7D`Sa=he2S(atEz0y>`LsuBNz{&Z!;dU9AqK!4M zGY5AG=H}sD1FLf+D9!jI8f`HyrO2>l?&s)b9bSM#f-?Sq2l+ZY1BWc@@ey-b$h+YU z<}|Q2-iKf<&G0acYvXbV>e8&8!?tJIDRw)jeJJHiu!s^R& zBgc_1wJiVm@bR*b6PGOa_>f94&wmrUIbjKF%I2=-z4o-FW6CI-cMOs`ceCV6EXO!L zY)(=~D^S6(?LaUtX5 z6CWZuR&inE=az}^&>L8-*r$=lo<-3=W7C|g>7J+gnz)EjtF~Dehs09+;>5i$XEeckqD2xr1`(g$?% zP4lApw0TCqeMf)s^9jB7ZS$O7eL??!)O=5W@Q(TaPwo2;>Ai31l^;mAkLVSk#m}AQ zY5Q*;`hD_cx6P~fQ3I-{%(=ry)JGpT9}%8s)E-*hp`VZG4^O+fmiAp^wDW>=Vf4`N zt9|m%sQz;M3{ey!C|Ke?dGNEg_8j+?OrOPw8go=zcHilC@7ebdi=ELYx_4?H8OrJ| zoLPN~9NWYkn@d}Wl~QW7T1OwI`#GehHGdw@7 zZVxt;PEJdf#U|5zOS5s*QX|5dA3fu&TVEa-uT(;g)c9uYJ*4ev`X?#gdm58B7+SQP zmdbbp+ zkZJHZ7EuXC#$lA^)+=HR5cS8Y2lUF)EMfSatz#S?n?lmd32Zaak#(y+HrY zxVw}SMV9^Vlp+2b{Tybn<7Rm4(BTfP9Xum>ejsUnq#QU_TOQFW0&l)yEwa8KNs)g? zHG@=cWnHq$_~5n4sN=KOCAGAVN8S-t47f`Jm34^k`s-ieIh+0nfyyJS+Yaw0ta}z# zLSH&jVoAwl{8w3tbi7qb88v*@&EejF>rlayb)*HTAm^5&5k^Qe&n4kcMp99!W>0(!NPUN)0cC8{tuZ zw9Lk*?$7&U8+q)gru!6Jr7k%GCBWLP9i<;R7yr^--PF5Z%jY-K_(X2C1i!T zGfK9i`hr@64NA8EyEyt3G@ws3E`9Qs$=mb7oR?QF%bu2rWxUUlu#%lOpwOReKk z*RBT{fBG9mq43birDOgKkLl*t59xLIU3?CarTx9eb<1>FCH+r6Do($^fku+A`S{ks zqiL4i1!m1jzb3AQ;4I0$Fnnv`V+dkdhF;vMu`Weg4F=}ml3-jO9u0=&AY2Qh=Geck z^GwFshdy>22P1Y4@0tEH+}Qf}6kE$x>e{G@7in1@hUilEksxmz!zWWSN+XNtbtNDA&ZYIj^vVQ8J{5=5(+=CWfFb&&@ED>tkyOZVCS4 zCTP@i*jw}-v@3{sZRf)|Gneg&s8}sDpWbQyN%gs~aI=PJU$y7bOn<(<)evp{$nn0E zBz!)hoCI?IqLfS$zT}c}Q75z>1Ao$;Oofv;;VZ7mqtts&e2i>z98N*O$G^1J<+ziA zN5bx}sm}3&Dzi~rbJ~uKsMGe}ePe1Er`{c&Ct$0;ao56B?YI35=6pEW3L|q@*<;_u zh>j|CbFZYwI!X%`P1!aNz%*X#7(RhFXa)ZXLM%P zWU4Uhn-N(n;nst^N0dU$@2BLD%6ktf>=K;DIiTarhuLFyPIH*p97x*IcDeaZQV zwMfS2OV%TioX=T{j55CImh!Bj{%I*Y>+?*$@6_m%%IHbb7nPNW(+8E7MAG+^m5tx$ zbf;QQpY7azW_cFsrdq~zCxl;6<6%;gz$uu5@X13f>x-_ngCmz2A}ZQ1qR7cxXI z#iFTpxGaDA`BK(8)uM!j;RbfxP=mD)*coyG*Yxw2ZW%>oLH#?A-x7!7Wt6kl95j43 zorgls@^f%$^J940AD8=8L-m{psn9PH<6sI}Rmt^aDKlcqp;a(;Lojy0i zP?cw42u^*z&7s=XXgMcoDQ<;e(qdE?mQp+lLC4RYeVPHHp86fl2CwNSP8ohnnU%9% z6(_2S&gs?P+D{#~vq_VwIG}GL_i{s@zztyd9j69dM^%2B`qDG{wy9YMFQ0y>?Zz3O zsA|0;1PAmNTG*qXM{OSH;=`$+_N377>CV1~bVBG0`rbpjvF~yFv?uiM_^gg$%e(Yk zIgRkKuncZg_});i_kc17_Qq(Nv5vnJv5XAq-lh~@K95vJf_bmCezuN%&rpx9H%dRX z_<+17cy&bn6+FXf@Q1`USS)-hd^0k4SL7uR>Aeej$Lywav){O}0k>G-+x}1B3GmR! z1DZVr{hEH%^5f1dcv=4w+)v!J7|pF1{pVn3&Rg=j&=&HK7%?!CT+*|TJg=igV8_^F zC5ovT8TLxaQRKcaeSIl8{@rVQPUFiXw~d}+&RIX8s0=G{SeLtMd5#zjJTxnH=I#pk z2J4Y-=q#x-@?&A2_In@mEVJ@wyvqss7pw=~&>wghc$+iAc252ak?GJg?7ok2OoD^J16ZR>5A0UD0#JhQOh zQS@MDU%#U`1$Vo<^ASWBs5rt5YVUnyaq{7nT4yVHGTU({f8A!-qq_|cGU*YK2PNm& z!-YuF%kyBA^ru`1bvzexMaZ=LLY@g{_P%a?mzgKoS}){&eDfjy=jXj0-ZlPlulc<7 zi(L(-efU5f$Nc8+RN9Y3C@wECaEPyt9tYxIU?4i1)Wj%lroHaG!EkD z>4$ZbTN;b8n)8}gZeG#*FWWpRRyD5aa}P2ylo)mUPxFoEc2yQNl*jGou^NM{toz-X zGoJP9U2@dkj&`I+_3dbibJX9GRwSc>?dVA|YS@yNbfOB}vg)q@anJs8D>&?0DdK}0 z%2{4gR?@BCaNoDJe2C`YHB5EMu!0XyvY$j|&em}3QIxZ_s=s>mEg41BuNCR&p?(c< zMh#oghGeu*zkVd6ge_=CCptiGALBdLAWgOY7az`Cen79H`g5v2s@5!gp3IV?Bo8v_ zk%|W;=V-x&NYZ2TV3hQlTnKeM7c_A}c}P@%?$ay+^AuFPyJyB@-qBUDceUVny{muk zzm9s+({?oyUU8@0p@JGvoLhfUZB=I}ZAp5|(lRak*_2A?>01}v6%#l2j#YqK$Kq6J zW$ns;D~8!aW9uTuJzy~{+eKd0Y_85YN8Wral4EWzI?2&CADhlNYi@Nx*6yTThr~$u z;KOfjUa&DrDdOx60g3Znba-Gg;O6)?I-pZ-$ury7!CWUGQ6Z$E@-95 z?kv7(LU!SfzctsN&zf(Wzti~;f1{tvCp?5;+@*D}X?@__h-cK^57gR^%}>pr=|qV~ z%{L@jtaWiW1s8}HCHzGi9H;MY>tX*W`0CS;Vot} z*X{ljGa~GhjL4suIxnpFqTZ|f%!79CE%wFkx2wF!jF`3C{dT7;zKhejEMLuTm;Psd zp(o;e7;`H70sTCozsNBoBZF08bMDJ;^vdx07wx-;^aS^vn0YTM$zM|@=QhZbKpvb9 zoOdcr*XAzC-DwjyCDy9(sgY}^`3HHk7tLR(huo3!Dfzk=^v+W{NhjXBY*~Z+tcHbw z$7V$b&o{4NJT|9j;N0u()qd{Ne!^CG_}_(Jz*!y0lU`9vzLP)fllqKLxmmaC|B&&Y zpS87Uv>YpI(-1%F5W6C}_OZ@on;rQq4>0OkrnsN;^X{INcKqILXA4`M5%x!h|eGTTkL{^{q^TPDD)8~OXZSu|g(oslQG3GGyeGYqk z(ar^r8=R5(ka7}_+gZ|cit{iR1{d&-D_J=!UY1DCio@IHv*MUG<*YayMXnXUAPYop z3|Tph`6jQh*VcHP(9GH7W-$LS8LLq1wYi-z%Qc#u%OAS4-2VBnLkW;k+6|D!+U;_# z)@}O{&8(l3ww@7-Kc#=ar9314_bt8t4gLF^Ui}OGghpS`-%sh^XEY=Kp8nu-=Knvn zpMLoM6F*QN;JJ_lKR=~><&X3f^FB`1#W}dSaxRZDkPEoKp|+%24bNOGXWCqiylgG@ zEm^F&*%b4Ga9=BFt!uLwpQbDqIBg`Rop7sgxftRH=1?p%Kh6e`Yqhy-_9?kI{q3~&hOLBK zdYu0|r*jJS+trqH%2;C!2Isrtb^x=Y95(N{OJnhz#;olRdvCn16CSsvv=?qIE(b&S z9)f0>`Dr$4cF~@Zg<`}udui|E#r|B-%%p5D`7|bJqcQEt+vpq`DI0}1MO6+?;lKBw z?rhJF5y-QeF{iI9NxKYdN!}v;IJj*QJAJzBjQI`rc-s7v-mxpvYq8FdQ72TQa2t|n zRk9xumtl5l?i=ayCAIeAv^;WsxZI{z4{o8?aNk2(jii56a5?VwRM(Dd@1VL4nRzg* z-u~%JA=yLzmiYS!6(D=*hsgwIjaT9k{o!tik0 zDryT~Qk;bh9?qg%pQVOGJ#$i6+ga9}n^#yHKSCtr%;2Q77tW34Tnc#nAGAJc*E`KQ zrc;(`s_;x5?5`_XkL%m*SROmy*=^YuCRv&-OCs^x+;acA@f7wSoYP#v+!J=$o|lUi zuKR2R`rDT)o70%J5r5CPJ}!K$OldFN8@QPIwwf;evbRsQQFunIH(=Mx`sTE28@D>k znbMoAy~ehxVYN$`_-z+iWmECDN1hgYwA>qB*D@!G@kdJ%O<7fV|Hk?UM9?_p-OMrX z*LeKnR$og~y_B=|hl?B*?CQKER$~SHKEHt8_FJA$S5vl; zXMZs*Nm}6?4k=s2S!?$ZJSuYMD_h~Az}>OFByBRhHF>+7#=>oz_P&#~#5o~zoDQ?K zhh?p}24m_{np)U9%FUpjy$tY;6{>9=_Fs|$FJKR zJL8ivQuau@|9LK|S8I98-E7M~BlMJ*~yieP;Qx*(|hK zLq4TCu+Xz{^4sR!Q|9)iId=xu4(UB)11yWQ#5IK`_@d+p00ZKM9yxb1SP6=_@aw<~FXzmd1Zc|tXNOvH1p z6!JFcZ;#&!r`nOXLx0P1mWWI`Do9ObkiEC8R-ZT}jkIMhwaaax%k4>9>Joxni}lrV zxY6fS`>9nbZe%DGiH>D*TOG!uVG^cVwj`ENYnR24$^c1JxvX$w>;B9d>)mF>8Mk4h z9jsPe&|lnRS!aYhFH@@JyE>fXUs&s*w$9yZs&(_?khAA566t5ZkcGvZZ7Vh&FQ>HK zrz7I#LJksXexzg5;f(9O>h%7uhFxhi?cdj~q?P;I)3jwD0x64yCpTwHAlBVVCV5#Z zSqlztpVyLO+Lg8Fa3s=}jrtR0R}Sef&he=^-)FTtC6kU-FSRaX)61>uSo9JOPJ4!} zp0}0ExAd=ByL9(kVnzC-qPb-=1_P(_O4s5Kp&J*sj1Bo(;ISe9lVxnk*A}M@ol_q5h`bQS+&x+atJ5pZOTlkn zVeRExTWCA{winj2lqJ?PLvi)g&FT2&)Bfl4T2_Z!Vy~EA0#3`hBJTx_)a$>dCE)j6 z%WdUbS4bQDK5MyEPOIy$>h!I=mPl+)27b#6X)WLO!dl_CzL0h~?eFr#i2*~uXYX1> z)ki; zSMPJoCR4cA?rgcFIr0@nnEm%^@uz*%a}x1eVtm{A)|t{Kzs1I*(6Qoryydh8yE!Z0 zTsx#SN!#pXl9-2wNGEB3*yW8XWZaUm*RFc}NZH)IpmBRz7Bg;H(n5y1hCe!~ zrW$vMe)xYQjl9Lox6405F105gxy>Vxv{=)p^+s$Kzr0lrTjICFaSQU6H*8bR)@rq} zE^3yV33M%R+m!ocXr;RxfZ1?>~(t< zEv&4b%v-0Y4!x{}joab1FyHfKEo|JPyoKT97t}>z1+A_Oh0o%K(r8)WRJ&3ZIo+O? zg-#)mu-KYnHe;1t6v7#;4WG?tT^(MTjK~lo#5^QM|_X^5_3}Q6^)GUEfz26&crKv7n%5n%{R^CHcop^Pq4Ss;T<=l zuAjjVmx$l);@i%*$doquZ8aW+ycJ)+uY0e@Gy1jI$)RPj;})gt)Yp=hb&lKSv`O5X zx=*9>9{p=?n5oAS{pk7aZ@!&;t6O?Lzpc%;C}UwbJ?oGx?G63BrN1@W*;ociYnyJ3 z)8^({k+i(&b|vkvUaRY7fqb*p&JUR0=-S}7F!$N=cGa~eV@)q<#Qe3I3~<-a2DhZw z>bJmYN5dyeT2a3(NgKl15@z2M~H}n@3k~LXkh%^#58PhI@b;h+PVW%+&bS&1?ds>^t&Ip|9fHPuo*5z46`*L{)*g;QlL4Wq%CN%S6u5=~Y;KQNG1b_P_S>Qudf&p8z z`EpinTh_DduElbeY%!Fu-Mx0*{Dh*JLt59|nkDz8vwG&tZ-tH`s7|n2wm9^x+^+|T zYLD=7)u$0o2Dqbx@AQcA>OQoD8y9L}LAr$20{NJbk0qZC92odVfqYb2tf(g|GpExo zGp}RaU3;eE%KB#*> zug`IxE9+yrmN+fPo|$9ruDxw5H!montH+9_CE)ib%WdUbS4bQDmbTm~r`6#$0qb|W zdnr)$Hmm}!p>{Y-8h&exYd7CAW834m(l`X%7VEza3zc)&k6qIZD$wJyG%^+&-Y$>D z##UigzPww5= z?6e$Gwz}LRmyL$BBxRe+ZFAe?^tx65zL>rCM%f$s7iT15&u1;UN?2^Vlrr|5kB7(F zIdI5uAs?9@Q?UOTGsoM_u)>u{n*qMIrLEoHrnY7KP?WJ^>?ZtTBOcz>s*$UtMfVYC z+V!yIlGfeF!foT`T*Yx-0U4Yc^CKbh$k=pD%RIIm*P@IK$6(;MUF^DmE^jGr?dLeA zVxpQN@&1~6n0!*U9j|GNgv-`*5J=g6Iwn~z02lIowcdM$d1&AIrzEmg##ciT-?oH> zFUf1ylI`aX+g!sjouKlk=Huq0=KJOuojmoVdC{Ig^_Whe!VM8m=-(Ig`k(3l-wsZo z+NC%)R_kS~7?rx_M9O--x$U^ar;G$K9-h8yrj>;3>@kO?*B4)-JUr%hmbTr5L)@ssu0L$N!`GiT-^;8D8wxn6fk6)`d(lq>s4|P>ZW$ zNro+B4D#!^FPpXKSpM=Oh~xB6l$n1>dvef=CKu0-Xqx3Zt%vho15c_a;O`e$w(O{V zKrI|LzYzQ5Zp}j#$7LJ6WA!d%r0##ijW*I&4*JjArBTe4WQy%O%|B?h>qYZdVv`$n zJ*73T7xWGoHeM~8j>*DMq*|1_IuO@bV?R;Od|(&5u8vI3?F1xVKM6By){}=_-GU&pS&f-ppdkuI2?Rdh5Bcl zN4Yg?a^=#uB46v8*5hwK-D)n$Mt&w6!5CJz*Xc`QEn_(EmX5^zC?w)7e@ij881B)h z+Df;(o3>KyoMulrSrIp?qk0ghB4O@{8|zTxRkuZk%4lsh+)83&nph+;RwR!_-pb5r za#;r`sx?@mA6L3nx^pUIi!aF2;pB*QMryJAo|8`A)GrbNi#L_gm;7S&P4SOWU@~1L@xAjoF=WaFC+Iews z+Blwt3ZK|j-ZvCgn7lxU4TnV_@CkMucY04^hZOZ7uC!COoR)v;qjz!o)^wIparQFiF6iZVl()eNTDGp|?)3b!2G(K? z;Yf2W1UC8|G3O^@9ZvN9k=XR8`8)ju3sG0}oL>EoDj%NF&*6yue6$WfeBMLi<>U5K z&&m31eK+ZXSc^8Xf^ShbZQydPdSgT2lwtuc)yo-IjMqJ2>z7Imz}{ z`rZ$uzfPWhfGCBoPCbW3hWn{LuSOkLJjWn{!!jXvT=TKa=@f%2iI!3Z%w9 zn+Nre;yyWeM)dF*#hOP&pMJt3IIH(z{<)5Ro*qSp8SZlZ?0S`ZCi^UPj>)d}rbd`@ zeaq>qO+NFAW@Eon1xJnS?MpD%t7E-Q^{woT%X&ZmsKX&oKOb7gtMbS(pJA<6GTmIw zc*IH{6Z-wSZI3b5TiqUGTAsQ*#+)2=dyHwxbUlU}0p0rw8z0R@7p}(Y_7Xlx>hceM z3F`I?KACiV!Z?2B@(iff#LoOP$`>7OU>4GsXU=Pkb-I4v!6DuH{0Wa#>-RAna_ah> zaZGgYckD`Ye>N80w_}}d$?r@{SF_)llWI$TXIf5OzvD(+_Z}zL<6RtU ztEgGC517-Qlt<(D2W6y?_YEcF()APLStw&K zM7o}UGygxlvB+}mpI-ZxL$DKnRY~3=)x|5GiWi4}BB7Mtr z$I*M6+<$)tGwvXm^OmmGYPUw8Ec$lHId(7IM>C9fB_jA?8~$jqk95xB#`=-BJ3Sfr zBX>>gYniiiSd(tVJ{}3v$DqFSyl3TxoywLHRs~Pb8+m^A3ixZMsfSqqF+D9{iy3>w@(gTUXNqc z9Cq`ZalW=%y>Vt?d@}ml<^f~OomQuO#&YkaNy+a|)+L?1-&vEqy8dY#|J?hh;TgMQ z>xlDDV;$Q_U>I$bTxFD#atr=xx)0Y`eCx z<0PM?xgO}0atH8_$8?|Q_*8>4svpHI+qjeJti5~hdUW5ww{%wl?gqi#1-J?15#3pU zTMM3f?;Q9n^PHJ)=(*p1xMyU#?HxMPCRQ?A>3Gwg%DG4KUX$Ec?R{-KBwhc{KiZoI za0>zY<$L;R?j(57d_uP$;6{TV>9ud0|D^Y!pXc=cQ~LQy^Lyusc>i0v#o(v*Q@H2B z+@xa9&)*^KkI!{Bcc|bF*swl(Ky8|M3b~ zoRdn&K8HS$$AgZob52rD8=Y%M$5JoIbAXlGuuz{gI+iIlx{qzsCnKj#`kpUgi}2Fd zG*ZL*?5OsZ?C_Sx@K@E0-}6$$+Foi5IFBOTI_94%Zxtr$-fL>Ni?JNmGNxx3Jhm`y znadi+Pv)|RAA9TA&*@g=#}vh)((so49?)ORb@9q;ih!@^w?p~{emiSNv*QnQ2Rq04 zKlI6q_Et^!o9p(J(_8x95AA&RhGuP#=zj1g^!iKs?JeEQ_=ei}H~QokG!OgN=1Yni z|D8VlpEQ&EcY6Pz`5S%iIX(4rYWW}Zy(^lvoi+cYZ+_Xv;%7AT`zL+kSNh*Ey>?EY S$M4VR)4$Q{|C_#J(fxl11!ork literal 0 HcmV?d00001 diff --git a/DBS/2026-03-11/src-sql-arquivos/01_profiles.sql b/DBS/2026-03-11/src-sql-arquivos/01_profiles.sql new file mode 100644 index 0000000..ff1694d --- /dev/null +++ b/DBS/2026-03-11/src-sql-arquivos/01_profiles.sql @@ -0,0 +1,110 @@ +-- ========================================================= +-- Agência PSI — Profiles (v2) + Trigger + RLS +-- - 1 profile por auth.users.id +-- - role base (admin|therapist|patient) +-- - pronto para evoluir p/ multi-tenant depois +-- ========================================================= + +-- 0) Função padrão updated_at (se já existir, mantém) +create or replace function public.set_updated_at() +returns trigger +language plpgsql +as $$ +begin + new.updated_at = now(); + return new; +end; +$$; + +-- 1) Tabela profiles +create table if not exists public.profiles ( + id uuid primary key, -- = auth.users.id + email text, + full_name text, + avatar_url text, + + role text not null default 'patient', + status text not null default 'active', + + created_at timestamptz not null default now(), + updated_at timestamptz not null default now(), + + constraint profiles_role_check check (role in ('admin','therapist','patient')), + constraint profiles_status_check check (status in ('active','inactive','invited')) +); + +-- FK opcional (em Supabase costuma ser ok) +do $$ +begin + if not exists ( + select 1 + from pg_constraint + where conname = 'profiles_id_fkey' + ) then + alter table public.profiles + add constraint profiles_id_fkey + foreign key (id) references auth.users(id) + on delete cascade; + end if; +end $$; + +-- Índices úteis +create index if not exists profiles_role_idx on public.profiles(role); +create index if not exists profiles_status_idx on public.profiles(status); + +-- 2) Trigger updated_at +drop trigger if exists t_profiles_set_updated_at on public.profiles; +create trigger t_profiles_set_updated_at +before update on public.profiles +for each row execute function public.set_updated_at(); + +-- 3) Trigger pós-signup: cria profile automático +-- Observação: roda como SECURITY DEFINER +create or replace function public.handle_new_user() +returns trigger +language plpgsql +security definer +set search_path = public +as $$ +begin + insert into public.profiles (id, email, role, status) + values (new.id, new.email, 'patient', 'active') + on conflict (id) do update + set email = excluded.email; + + return new; +end; +$$; + +drop trigger if exists on_auth_user_created on auth.users; +create trigger on_auth_user_created +after insert on auth.users +for each row execute function public.handle_new_user(); + +-- 4) RLS +alter table public.profiles enable row level security; + +-- Leitura do próprio profile +drop policy if exists "profiles_select_own" on public.profiles; +create policy "profiles_select_own" +on public.profiles +for select +to authenticated +using (id = auth.uid()); + +-- Update do próprio profile (campos não-sensíveis) +drop policy if exists "profiles_update_own" on public.profiles; +create policy "profiles_update_own" +on public.profiles +for update +to authenticated +using (id = auth.uid()) +with check (id = auth.uid()); + +-- Insert só do próprio (na prática quem insere é trigger, mas deixa coerente) +drop policy if exists "profiles_insert_own" on public.profiles; +create policy "profiles_insert_own" +on public.profiles +for insert +to authenticated +with check (id = auth.uid()); diff --git a/DBS/2026-03-11/src-sql-arquivos/supabase_cadastro_externo.sql b/DBS/2026-03-11/src-sql-arquivos/supabase_cadastro_externo.sql new file mode 100644 index 0000000..e9b170f --- /dev/null +++ b/DBS/2026-03-11/src-sql-arquivos/supabase_cadastro_externo.sql @@ -0,0 +1,212 @@ +-- ========================================================= +-- Agência PSI Quasar — Cadastro Externo de Paciente (Supabase/Postgres) +-- Objetivo: +-- - Ter um link público com TOKEN que o terapeuta envia ao paciente +-- - Paciente preenche um formulário público +-- - Salva em "intake requests" (pré-cadastro) +-- - Terapeuta revisa e converte em paciente dentro do sistema +-- +-- Tabelas: +-- - patient_invites +-- - patient_intake_requests +-- +-- Funções: +-- - create_patient_intake_request (RPC pública - anon) +-- +-- Segurança: +-- - RLS habilitada +-- - Público (anon) não lê nada, só executa RPC +-- - Terapeuta (authenticated) lê/atualiza somente seus registros +-- ========================================================= + +-- 0) Tabelas +create table if not exists public.patient_invites ( + id uuid primary key default gen_random_uuid(), + owner_id uuid not null, + token text not null unique, + active boolean not null default true, + expires_at timestamptz null, + max_uses int null, + uses int not null default 0, + created_at timestamptz not null default now() +); + +create index if not exists patient_invites_owner_id_idx on public.patient_invites(owner_id); +create index if not exists patient_invites_token_idx on public.patient_invites(token); + +create table if not exists public.patient_intake_requests ( + id uuid primary key default gen_random_uuid(), + owner_id uuid not null, + token text not null, + name text not null, + email text null, + phone text null, + notes text null, + consent boolean not null default false, + status text not null default 'new', -- new | converted | rejected + created_at timestamptz not null default now() +); + +create index if not exists patient_intake_owner_id_idx on public.patient_intake_requests(owner_id); +create index if not exists patient_intake_token_idx on public.patient_intake_requests(token); +create index if not exists patient_intake_status_idx on public.patient_intake_requests(status); + +-- 1) RLS +alter table public.patient_invites enable row level security; +alter table public.patient_intake_requests enable row level security; + +-- 2) Fechar acesso direto para anon (público) +revoke all on table public.patient_invites from anon; +revoke all on table public.patient_intake_requests from anon; + +-- 3) Policies: terapeuta (authenticated) - somente próprios registros + +-- patient_invites +drop policy if exists invites_select_own on public.patient_invites; +create policy invites_select_own +on public.patient_invites for select +to authenticated +using (owner_id = auth.uid()); + +drop policy if exists invites_insert_own on public.patient_invites; +create policy invites_insert_own +on public.patient_invites for insert +to authenticated +with check (owner_id = auth.uid()); + +drop policy if exists invites_update_own on public.patient_invites; +create policy invites_update_own +on public.patient_invites for update +to authenticated +using (owner_id = auth.uid()) +with check (owner_id = auth.uid()); + +-- patient_intake_requests +drop policy if exists intake_select_own on public.patient_intake_requests; +create policy intake_select_own +on public.patient_intake_requests for select +to authenticated +using (owner_id = auth.uid()); + +drop policy if exists intake_update_own on public.patient_intake_requests; +create policy intake_update_own +on public.patient_intake_requests for update +to authenticated +using (owner_id = auth.uid()) +with check (owner_id = auth.uid()); + +-- 4) RPC pública para criar intake (página pública) +-- Importantíssimo: security definer + search_path fixo +create or replace function public.create_patient_intake_request( + p_token text, + p_name text, + p_email text default null, + p_phone text default null, + p_notes text default null, + p_consent boolean default false +) +returns uuid +language plpgsql +security definer +set search_path = public +as $$ +declare + v_owner uuid; + v_active boolean; + v_expires timestamptz; + v_max_uses int; + v_uses int; + v_id uuid; +begin + select owner_id, active, expires_at, max_uses, uses + into v_owner, v_active, v_expires, v_max_uses, v_uses + from public.patient_invites + where token = p_token + limit 1; + + if v_owner is null then + raise exception 'Token inválido'; + end if; + + if v_active is not true then + raise exception 'Link desativado'; + end if; + + if v_expires is not null and now() > v_expires then + raise exception 'Link expirado'; + end if; + + if v_max_uses is not null and v_uses >= v_max_uses then + raise exception 'Limite de uso atingido'; + end if; + + if p_name is null or length(trim(p_name)) = 0 then + raise exception 'Nome é obrigatório'; + end if; + + insert into public.patient_intake_requests + (owner_id, token, name, email, phone, notes, consent, status) + values + (v_owner, p_token, trim(p_name), + nullif(lower(trim(p_email)), ''), + nullif(trim(p_phone), ''), + nullif(trim(p_notes), ''), + coalesce(p_consent, false), + 'new') + returning id into v_id; + + update public.patient_invites + set uses = uses + 1 + where token = p_token; + + return v_id; +end; +$$; + +grant execute on function public.create_patient_intake_request(text, text, text, text, text, boolean) to anon; +grant execute on function public.create_patient_intake_request(text, text, text, text, text, boolean) to authenticated; + +-- 5) (Opcional) helper para rotacionar token no painel (somente authenticated) +-- Você pode usar no front via supabase.rpc('rotate_patient_invite_token') +create or replace function public.rotate_patient_invite_token( + p_new_token text +) +returns uuid +language plpgsql +security definer +set search_path = public +as $$ +declare + v_uid uuid; + v_id uuid; +begin + -- pega o usuário logado + v_uid := auth.uid(); + if v_uid is null then + raise exception 'Usuário não autenticado'; + end if; + + -- desativa tokens antigos ativos do usuário + update public.patient_invites + set active = false + where owner_id = v_uid + and active = true; + + -- cria novo token + insert into public.patient_invites (owner_id, token, active) + values (v_uid, p_new_token, true) + returning id into v_id; + + return v_id; +end; +$$; + +grant execute on function public.rotate_patient_invite_token(text) to authenticated; + +grant select, insert, update, delete on table public.patient_invites to authenticated; +grant select, insert, update, delete on table public.patient_intake_requests to authenticated; + +-- anon não precisa acessar tabelas diretamente +revoke all on table public.patient_invites from anon; +revoke all on table public.patient_intake_requests from anon; + diff --git a/DBS/2026-03-11/src-sql-arquivos/supabase_cadastro_pacientes.sql b/DBS/2026-03-11/src-sql-arquivos/supabase_cadastro_pacientes.sql new file mode 100644 index 0000000..4eb0d54 --- /dev/null +++ b/DBS/2026-03-11/src-sql-arquivos/supabase_cadastro_pacientes.sql @@ -0,0 +1,266 @@ +-- ========================================================= +-- PATCH — Completar cadastro para bater com PatientsCadastroPage.vue +-- (rode DEPOIS do seu supabase_cadastro_pacientes.sql) +-- ========================================================= + +create extension if not exists pgcrypto; + +-- --------------------------------------------------------- +-- 1) Completar colunas que o front usa e hoje faltam em patients +-- --------------------------------------------------------- +do $$ +begin + if not exists ( + select 1 from information_schema.columns + where table_schema='public' and table_name='patients' and column_name='email_alt' + ) then + alter table public.patients add column email_alt text; + end if; + + if not exists ( + select 1 from information_schema.columns + where table_schema='public' and table_name='patients' and column_name='phones' + ) then + -- array de textos (Postgres). No JS você manda ["...","..."] normalmente. + alter table public.patients add column phones text[]; + end if; + + if not exists ( + select 1 from information_schema.columns + where table_schema='public' and table_name='patients' and column_name='gender' + ) then + alter table public.patients add column gender text; + end if; + + if not exists ( + select 1 from information_schema.columns + where table_schema='public' and table_name='patients' and column_name='marital_status' + ) then + alter table public.patients add column marital_status text; + end if; +end $$; + +-- (opcional) índices úteis pra busca/filtro por nome/email +create index if not exists idx_patients_owner_name on public.patients(owner_id, name); +create index if not exists idx_patients_owner_email on public.patients(owner_id, email); + +-- --------------------------------------------------------- +-- 2) patient_groups +-- --------------------------------------------------------- +create table if not exists public.patient_groups ( + id uuid primary key default gen_random_uuid(), + owner_id uuid not null references auth.users(id) on delete cascade, + name text not null, + color text, + is_system boolean not null default false, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now() +); + +-- nome único por owner +do $$ +begin + if not exists ( + select 1 from pg_constraint + where conname = 'patient_groups_owner_name_uniq' + and conrelid = 'public.patient_groups'::regclass + ) then + alter table public.patient_groups + add constraint patient_groups_owner_name_uniq unique(owner_id, name); + end if; +end $$; + +drop trigger if exists trg_patient_groups_set_updated_at on public.patient_groups; +create trigger trg_patient_groups_set_updated_at +before update on public.patient_groups +for each row execute function public.set_updated_at(); + +create index if not exists idx_patient_groups_owner on public.patient_groups(owner_id); + +alter table public.patient_groups enable row level security; + +drop policy if exists "patient_groups_select_own" on public.patient_groups; +create policy "patient_groups_select_own" +on public.patient_groups for select +to authenticated +using (owner_id = auth.uid()); + +drop policy if exists "patient_groups_insert_own" on public.patient_groups; +create policy "patient_groups_insert_own" +on public.patient_groups for insert +to authenticated +with check (owner_id = auth.uid()); + +drop policy if exists "patient_groups_update_own" on public.patient_groups; +create policy "patient_groups_update_own" +on public.patient_groups for update +to authenticated +using (owner_id = auth.uid()) +with check (owner_id = auth.uid()); + +drop policy if exists "patient_groups_delete_own" on public.patient_groups; +create policy "patient_groups_delete_own" +on public.patient_groups for delete +to authenticated +using (owner_id = auth.uid()); + +grant select, insert, update, delete on public.patient_groups to authenticated; + +-- --------------------------------------------------------- +-- 3) patient_tags +-- --------------------------------------------------------- +create table if not exists public.patient_tags ( + id uuid primary key default gen_random_uuid(), + owner_id uuid not null references auth.users(id) on delete cascade, + name text not null, + color text, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now() +); + +do $$ +begin + if not exists ( + select 1 from pg_constraint + where conname = 'patient_tags_owner_name_uniq' + and conrelid = 'public.patient_tags'::regclass + ) then + alter table public.patient_tags + add constraint patient_tags_owner_name_uniq unique(owner_id, name); + end if; +end $$; + +drop trigger if exists trg_patient_tags_set_updated_at on public.patient_tags; +create trigger trg_patient_tags_set_updated_at +before update on public.patient_tags +for each row execute function public.set_updated_at(); + +create index if not exists idx_patient_tags_owner on public.patient_tags(owner_id); + +alter table public.patient_tags enable row level security; + +drop policy if exists "patient_tags_select_own" on public.patient_tags; +create policy "patient_tags_select_own" +on public.patient_tags for select +to authenticated +using (owner_id = auth.uid()); + +drop policy if exists "patient_tags_insert_own" on public.patient_tags; +create policy "patient_tags_insert_own" +on public.patient_tags for insert +to authenticated +with check (owner_id = auth.uid()); + +drop policy if exists "patient_tags_update_own" on public.patient_tags; +create policy "patient_tags_update_own" +on public.patient_tags for update +to authenticated +using (owner_id = auth.uid()) +with check (owner_id = auth.uid()); + +drop policy if exists "patient_tags_delete_own" on public.patient_tags; +create policy "patient_tags_delete_own" +on public.patient_tags for delete +to authenticated +using (owner_id = auth.uid()); + +grant select, insert, update, delete on public.patient_tags to authenticated; + +-- --------------------------------------------------------- +-- 4) pivôs (patient_group_patient / patient_patient_tag) +-- --------------------------------------------------------- +create table if not exists public.patient_group_patient ( + patient_id uuid not null references public.patients(id) on delete cascade, + patient_group_id uuid not null references public.patient_groups(id) on delete cascade, + created_at timestamptz not null default now(), + primary key (patient_id, patient_group_id) +); + +create index if not exists idx_pgp_patient on public.patient_group_patient(patient_id); +create index if not exists idx_pgp_group on public.patient_group_patient(patient_group_id); + +alter table public.patient_group_patient enable row level security; + +-- a pivot “herda” tenant via join; policy usando exists pra validar owner do patient +drop policy if exists "pgp_select_own" on public.patient_group_patient; +create policy "pgp_select_own" +on public.patient_group_patient for select +to authenticated +using ( + exists ( + select 1 from public.patients p + where p.id = patient_group_patient.patient_id + and p.owner_id = auth.uid() + ) +); + +drop policy if exists "pgp_write_own" on public.patient_group_patient; +create policy "pgp_write_own" +on public.patient_group_patient for all +to authenticated +using ( + exists ( + select 1 from public.patients p + where p.id = patient_group_patient.patient_id + and p.owner_id = auth.uid() + ) +) +with check ( + exists ( + select 1 from public.patients p + where p.id = patient_group_patient.patient_id + and p.owner_id = auth.uid() + ) +); + +grant select, insert, update, delete on public.patient_group_patient to authenticated; + +-- tags pivot (ATENÇÃO: coluna é tag_id, como teu Vue usa!) +create table if not exists public.patient_patient_tag ( + patient_id uuid not null references public.patients(id) on delete cascade, + tag_id uuid not null references public.patient_tags(id) on delete cascade, + created_at timestamptz not null default now(), + primary key (patient_id, tag_id) +); + +create index if not exists idx_ppt_patient on public.patient_patient_tag(patient_id); +create index if not exists idx_ppt_tag on public.patient_patient_tag(tag_id); + +alter table public.patient_patient_tag enable row level security; + +drop policy if exists "ppt_select_own" on public.patient_patient_tag; +create policy "ppt_select_own" +on public.patient_patient_tag for select +to authenticated +using ( + exists ( + select 1 from public.patients p + where p.id = patient_patient_tag.patient_id + and p.owner_id = auth.uid() + ) +); + +drop policy if exists "ppt_write_own" on public.patient_patient_tag; +create policy "ppt_write_own" +on public.patient_patient_tag for all +to authenticated +using ( + exists ( + select 1 from public.patients p + where p.id = patient_patient_tag.patient_id + and p.owner_id = auth.uid() + ) +) +with check ( + exists ( + select 1 from public.patients p + where p.id = patient_patient_tag.patient_id + and p.owner_id = auth.uid() + ) +); + +grant select, insert, update, delete on public.patient_patient_tag to authenticated; + +-- ========================================================= +-- FIM PATCH +-- ========================================================= diff --git a/DBS/2026-03-11/src-sql-arquivos/supabase_cadastros_recebidos(intakes).sql b/DBS/2026-03-11/src-sql-arquivos/supabase_cadastros_recebidos(intakes).sql new file mode 100644 index 0000000..3e43d42 --- /dev/null +++ b/DBS/2026-03-11/src-sql-arquivos/supabase_cadastros_recebidos(intakes).sql @@ -0,0 +1,105 @@ +-- ========================================================= +-- INTakes / Cadastros Recebidos - Supabase Local +-- ========================================================= + +-- 0) Extensões úteis (geralmente já existem no Supabase, mas é seguro) +create extension if not exists pgcrypto; + +-- 1) Função padrão para updated_at +create or replace function public.set_updated_at() +returns trigger +language plpgsql +as $$ +begin + new.updated_at = now(); + return new; +end; +$$; + +-- 2) Tabela patient_intake_requests (espelhando nuvem) +create table if not exists public.patient_intake_requests ( + id uuid primary key default gen_random_uuid(), + owner_id uuid not null, + token text, + name text, + email text, + phone text, + notes text, + consent boolean not null default false, + status text not null default 'new', + created_at timestamptz not null default now(), + updated_at timestamptz not null default now(), + payload jsonb +); + +-- 3) Índices (performance em listagem e filtros) +create index if not exists idx_intakes_owner_created + on public.patient_intake_requests (owner_id, created_at desc); + +create index if not exists idx_intakes_owner_status_created + on public.patient_intake_requests (owner_id, status, created_at desc); + +create index if not exists idx_intakes_status_created + on public.patient_intake_requests (status, created_at desc); + +-- 4) Trigger updated_at +drop trigger if exists trg_patient_intake_requests_updated_at on public.patient_intake_requests; + +create trigger trg_patient_intake_requests_updated_at +before update on public.patient_intake_requests +for each row execute function public.set_updated_at(); + +-- 5) RLS +alter table public.patient_intake_requests enable row level security; + +-- 6) Policies (iguais às que você mostrou na nuvem) +drop policy if exists intake_select_own on public.patient_intake_requests; +create policy intake_select_own +on public.patient_intake_requests +for select +to authenticated +using (owner_id = auth.uid()); + +drop policy if exists intake_update_own on public.patient_intake_requests; +create policy intake_update_own +on public.patient_intake_requests +for update +to authenticated +using (owner_id = auth.uid()) +with check (owner_id = auth.uid()); + +drop policy if exists "delete own intake requests" on public.patient_intake_requests; +create policy "delete own intake requests" +on public.patient_intake_requests +for delete +to authenticated +using (owner_id = auth.uid()); + +-- ========================================================= +-- OPCIONAL (RECOMENDADO): registrar conversão +-- ========================================================= +-- Se você pretende marcar intake como convertido e guardar o patient_id: +alter table public.patient_intake_requests + add column if not exists converted_patient_id uuid; + +create index if not exists idx_intakes_converted_patient_id + on public.patient_intake_requests (converted_patient_id); + +-- Opcional: impedir delete de intakes convertidos (melhor para auditoria) +-- (Se quiser manter delete liberado como na nuvem, comente este bloco.) +drop policy if exists "delete own intake requests" on public.patient_intake_requests; +create policy "delete_own_intakes_not_converted" +on public.patient_intake_requests +for delete +to authenticated +using (owner_id = auth.uid() and status <> 'converted'); + +-- ========================================================= +-- OPCIONAL: check de status (evita status inválido) +-- ========================================================= +alter table public.patient_intake_requests + drop constraint if exists chk_intakes_status; + +alter table public.patient_intake_requests + add constraint chk_intakes_status + check (status in ('new', 'converted', 'rejected')); diff --git a/DBS/2026-03-11/src-sql-arquivos/supabase_patient_groups.sql b/DBS/2026-03-11/src-sql-arquivos/supabase_patient_groups.sql new file mode 100644 index 0000000..08070b4 --- /dev/null +++ b/DBS/2026-03-11/src-sql-arquivos/supabase_patient_groups.sql @@ -0,0 +1,174 @@ +/* + patient_groups_setup.sql + Setup completo para: + - public.patient_groups + - public.patient_group_patient (tabela ponte) + - view public.v_patient_groups_with_counts + - índice único por owner + nome (case-insensitive) + - 3 grupos padrão do sistema (Crianças, Adolescentes, Idosos) NÃO editáveis / NÃO removíveis + - triggers de proteção + + Observação (importante): + - Os grupos padrão são criados com owner_id = '00000000-0000-0000-0000-000000000000' (SYSTEM_OWNER), + para ficarem "globais" e não dependerem de auth.uid() em migrations. + - Se você quiser que os grupos padrão pertençam a um owner específico (tenant), + basta trocar o SYSTEM_OWNER abaixo por esse UUID. +*/ + +begin; + +-- =========================== +-- 0) Constante de "dono do sistema" +-- =========================== +-- Troque aqui se você quiser que os grupos padrão pertençam a um owner específico. +-- Ex.: '816b24fe-a0c3-4409-b79b-c6c0a6935d03' +do $$ +begin + -- só para documentar; não cria nada +end $$; + +-- =========================== +-- 1) Tabela principal: patient_groups +-- =========================== +create table if not exists public.patient_groups ( + id uuid primary key default gen_random_uuid(), + name text not null, + description text, + color text, + is_active boolean not null default true, + is_system boolean not null default false, + owner_id uuid not null, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now() +); + +-- (Opcional, mas recomendado) Garante que name não seja só espaços +-- e evita nomes vazios. +alter table public.patient_groups + drop constraint if exists patient_groups_name_not_blank_check; + +alter table public.patient_groups + add constraint patient_groups_name_not_blank_check + check (length(btrim(name)) > 0); + +-- =========================== +-- 2) Tabela ponte: patient_group_patient +-- =========================== +-- Se você já tiver essa tabela com FKs, ajuste aqui conforme seu schema. +create table if not exists public.patient_group_patient ( + patient_group_id uuid not null references public.patient_groups(id) on delete cascade, + patient_id uuid not null references public.patients(id) on delete cascade, + created_at timestamptz not null default now() +); + +-- Evita duplicar vínculo paciente<->grupo +create unique index if not exists patient_group_patient_unique +on public.patient_group_patient (patient_group_id, patient_id); + +-- =========================== +-- 3) View com contagem +-- =========================== +create or replace view public.v_patient_groups_with_counts as +select + g.*, + coalesce(count(distinct pgp.patient_id), 0)::int as patients_count +from public.patient_groups g +left join public.patient_group_patient pgp + on pgp.patient_group_id = g.id +group by g.id; + +-- =========================== +-- 4) Índice único: não permitir mesmo nome por owner (case-insensitive) +-- =========================== +-- Atenção: se já existirem duplicados, este índice pode falhar ao criar. +create unique index if not exists patient_groups_owner_name_unique +on public.patient_groups (owner_id, (lower(name))); + +-- =========================== +-- 5) Triggers de proteção: system não edita / não remove +-- =========================== +create or replace function public.prevent_system_group_changes() +returns trigger +language plpgsql +as $$ +begin + if old.is_system = true then + raise exception 'Grupos padrão do sistema não podem ser alterados ou excluídos.'; + end if; + + if tg_op = 'DELETE' then + return old; + end if; + + return new; +end; +$$; + +drop trigger if exists trg_prevent_system_group_changes on public.patient_groups; + +create trigger trg_prevent_system_group_changes +before update or delete on public.patient_groups +for each row +execute function public.prevent_system_group_changes(); + +-- Impede "promover" um grupo comum para system +create or replace function public.prevent_promoting_to_system() +returns trigger +language plpgsql +as $$ +begin + if new.is_system = true and old.is_system is distinct from true then + raise exception 'Não é permitido transformar um grupo comum em grupo do sistema.'; + end if; + return new; +end; +$$; + +drop trigger if exists trg_prevent_promoting_to_system on public.patient_groups; + +create trigger trg_prevent_promoting_to_system +before update on public.patient_groups +for each row +execute function public.prevent_promoting_to_system(); + +-- =========================== +-- 6) Inserir 3 grupos padrão (imutáveis) +-- =========================== +-- Dono "global" do sistema (mude se quiser): +-- 00000000-0000-0000-0000-000000000000 +with sys_owner as ( + select '00000000-0000-0000-0000-000000000000'::uuid as owner_id +) +insert into public.patient_groups (name, description, color, is_active, is_system, owner_id) +select v.name, v.description, v.color, v.is_active, v.is_system, s.owner_id +from sys_owner s +join (values + ('Crianças', 'Grupo padrão do sistema', null, true, true), + ('Adolescentes', 'Grupo padrão do sistema', null, true, true), + ('Idosos', 'Grupo padrão do sistema', null, true, true) +) as v(name, description, color, is_active, is_system) +on true +where not exists ( + select 1 + from public.patient_groups g + where g.owner_id = s.owner_id + and lower(g.name) = lower(v.name) +); + +commit; + +/* + Testes rápidos: + 1) Ver tudo: + select * from public.v_patient_groups_with_counts order by is_system desc, name; + + 2) Tentar editar um system (deve falhar): + update public.patient_groups set name='X' where name='Crianças'; + + 3) Tentar deletar um system (deve falhar): + delete from public.patient_groups where name='Crianças'; + + 4) Tentar duplicar nome no mesmo owner (deve falhar por índice único): + insert into public.patient_groups (name, is_active, is_system, owner_id) + values ('teste22', true, false, '816b24fe-a0c3-4409-b79b-c6c0a6935d03'); +*/ diff --git a/DBS/2026-03-11/src-sql-arquivos/supabase_patient_index_page.sql b/DBS/2026-03-11/src-sql-arquivos/supabase_patient_index_page.sql new file mode 100644 index 0000000..6a6dbd5 --- /dev/null +++ b/DBS/2026-03-11/src-sql-arquivos/supabase_patient_index_page.sql @@ -0,0 +1,147 @@ +-- ========================================================= +-- pacientesIndexPage.sql +-- Views + índices para a tela PatientsListPage +-- ========================================================= + +-- 0) Extensões úteis +create extension if not exists pg_trgm; + +-- 1) updated_at automático (se você quiser manter updated_at sempre correto) +create or replace function public.set_updated_at() +returns trigger +language plpgsql +as $$ +begin + new.updated_at = now(); + return new; +end; +$$; + +drop trigger if exists trg_patients_set_updated_at on public.patients; +create trigger trg_patients_set_updated_at +before update on public.patients +for each row execute function public.set_updated_at(); + + +-- ========================================================= +-- 2) Views de contagem (usadas em KPIs e telas auxiliares) +-- ========================================================= + +-- 2.1) Grupos com contagem de pacientes +create or replace view public.v_patient_groups_with_counts as +select + g.id, + g.name, + g.color, + coalesce(count(pgp.patient_id), 0)::int as patients_count +from public.patient_groups g +left join public.patient_group_patient pgp + on pgp.patient_group_id = g.id +group by g.id, g.name, g.color; + +-- 2.2) Tags com contagem de pacientes +create or replace view public.v_tag_patient_counts as +select + t.id, + t.name, + t.color, + coalesce(count(ppt.patient_id), 0)::int as patients_count +from public.patient_tags t +left join public.patient_patient_tag ppt + on ppt.tag_id = t.id +group by t.id, t.name, t.color; + + +-- ========================================================= +-- 3) View principal da Index (pacientes + grupos/tags agregados) +-- ========================================================= + +create or replace view public.v_patients_index as +select + p.*, + + -- array JSON com os grupos do paciente + coalesce(gx.groups, '[]'::jsonb) as groups, + + -- array JSON com as tags do paciente + coalesce(tx.tags, '[]'::jsonb) as tags, + + -- contagens para UI/KPIs + coalesce(gx.groups_count, 0)::int as groups_count, + coalesce(tx.tags_count, 0)::int as tags_count + +from public.patients p + +left join lateral ( + select + jsonb_agg( + distinct jsonb_build_object( + 'id', g.id, + 'name', g.name, + 'color', g.color + ) + ) filter (where g.id is not null) as groups, + count(distinct g.id) as groups_count + from public.patient_group_patient pgp + join public.patient_groups g + on g.id = pgp.patient_group_id + where pgp.patient_id = p.id +) gx on true + +left join lateral ( + select + jsonb_agg( + distinct jsonb_build_object( + 'id', t.id, + 'name', t.name, + 'color', t.color + ) + ) filter (where t.id is not null) as tags, + count(distinct t.id) as tags_count + from public.patient_patient_tag ppt + join public.patient_tags t + on t.id = ppt.tag_id + where ppt.patient_id = p.id +) tx on true; + + +-- ========================================================= +-- 4) Índices recomendados (performance real na listagem/filtros) +-- ========================================================= + +-- Patients +create index if not exists idx_patients_owner_id + on public.patients (owner_id); + +create index if not exists idx_patients_created_at + on public.patients (created_at desc); + +create index if not exists idx_patients_status + on public.patients (status); + +create index if not exists idx_patients_last_attended_at + on public.patients (last_attended_at desc); + +-- Busca rápida (name/email/phone) +create index if not exists idx_patients_name_trgm + on public.patients using gin (name gin_trgm_ops); + +create index if not exists idx_patients_email_trgm + on public.patients using gin (email gin_trgm_ops); + +create index if not exists idx_patients_phone_trgm + on public.patients using gin (phone gin_trgm_ops); + +-- Pivot: grupos +create index if not exists idx_pgp_patient_id + on public.patient_group_patient (patient_id); + +create index if not exists idx_pgp_group_id + on public.patient_group_patient (patient_group_id); + +-- Pivot: tags +create index if not exists idx_ppt_patient_id + on public.patient_patient_tag (patient_id); + +create index if not exists idx_ppt_tag_id + on public.patient_patient_tag (tag_id); diff --git a/src/features/agenda/domain/agenda.mappers.js b/DBS/2026-03-11/src-sql-arquivos/supabase_patients_populate.sql similarity index 100% rename from src/features/agenda/domain/agenda.mappers.js rename to DBS/2026-03-11/src-sql-arquivos/supabase_patients_populate.sql diff --git a/DBS/2026-03-11/src-sql-arquivos/supabase_tags.sql b/DBS/2026-03-11/src-sql-arquivos/supabase_tags.sql new file mode 100644 index 0000000..42668af --- /dev/null +++ b/DBS/2026-03-11/src-sql-arquivos/supabase_tags.sql @@ -0,0 +1,134 @@ +create extension if not exists pgcrypto; + +-- =============================== +-- TABELA: patient_tags +-- =============================== +create table if not exists public.patient_tags ( + id uuid primary key default gen_random_uuid(), + owner_id uuid not null, + name text not null, + color text, + is_native boolean not null default false, + created_at timestamptz not null default now(), + updated_at timestamptz +); + +create unique index if not exists patient_tags_owner_name_uq + on public.patient_tags (owner_id, lower(name)); + +-- =============================== +-- TABELA: patient_patient_tag (pivot) +-- =============================== +create table if not exists public.patient_patient_tag ( + owner_id uuid not null, + patient_id uuid not null, + tag_id uuid not null, + created_at timestamptz not null default now(), + primary key (patient_id, tag_id) +); + +create index if not exists ppt_owner_idx on public.patient_patient_tag(owner_id); +create index if not exists ppt_tag_idx on public.patient_patient_tag(tag_id); +create index if not exists ppt_patient_idx on public.patient_patient_tag(patient_id); + +-- =============================== +-- FOREIGN KEYS (com checagem) +-- =============================== +do $$ +begin + if not exists ( + select 1 from pg_constraint + where conname = 'ppt_tag_fk' + and conrelid = 'public.patient_patient_tag'::regclass + ) then + alter table public.patient_patient_tag + add constraint ppt_tag_fk + foreign key (tag_id) + references public.patient_tags(id) + on delete cascade; + end if; +end $$; + +do $$ +begin + if not exists ( + select 1 from pg_constraint + where conname = 'ppt_patient_fk' + and conrelid = 'public.patient_patient_tag'::regclass + ) then + alter table public.patient_patient_tag + add constraint ppt_patient_fk + foreign key (patient_id) + references public.patients(id) + on delete cascade; + end if; +end $$; + +-- =============================== +-- VIEW: contagem por tag +-- =============================== +create or replace view public.v_tag_patient_counts as +select + t.id, + t.owner_id, + t.name, + t.color, + t.is_native, + t.created_at, + t.updated_at, + coalesce(count(ppt.patient_id), 0)::int as patient_count +from public.patient_tags t +left join public.patient_patient_tag ppt + on ppt.tag_id = t.id + and ppt.owner_id = t.owner_id +group by + t.id, t.owner_id, t.name, t.color, t.is_native, t.created_at, t.updated_at; + +-- =============================== +-- RLS +-- =============================== +alter table public.patient_tags enable row level security; +alter table public.patient_patient_tag enable row level security; + +drop policy if exists tags_select_own on public.patient_tags; +create policy tags_select_own +on public.patient_tags +for select +using (owner_id = auth.uid()); + +drop policy if exists tags_insert_own on public.patient_tags; +create policy tags_insert_own +on public.patient_tags +for insert +with check (owner_id = auth.uid()); + +drop policy if exists tags_update_own on public.patient_tags; +create policy tags_update_own +on public.patient_tags +for update +using (owner_id = auth.uid()) +with check (owner_id = auth.uid()); + +drop policy if exists tags_delete_own on public.patient_tags; +create policy tags_delete_own +on public.patient_tags +for delete +using (owner_id = auth.uid()); + +drop policy if exists ppt_select_own on public.patient_patient_tag; +create policy ppt_select_own +on public.patient_patient_tag +for select +using (owner_id = auth.uid()); + +drop policy if exists ppt_insert_own on public.patient_patient_tag; +create policy ppt_insert_own +on public.patient_patient_tag +for insert +with check (owner_id = auth.uid()); + +drop policy if exists ppt_delete_own on public.patient_patient_tag; +create policy ppt_delete_own +on public.patient_patient_tag +for delete +using (owner_id = auth.uid()); diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 116.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 116.sql new file mode 100644 index 0000000..a623ce1 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 116.sql @@ -0,0 +1,2 @@ + ALTER TABLE public.agenda_configuracoes DROP COLUMN IF EXISTS + session_start_offset_min; \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 130.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 130.sql new file mode 100644 index 0000000..9262341 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 130.sql @@ -0,0 +1 @@ +select pg_get_functiondef('public.NOME_DA_FUNCAO(args_aqui)'::regprocedure); \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 132.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 132.sql new file mode 100644 index 0000000..4e31c77 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 132.sql @@ -0,0 +1,45 @@ +-- 1) Tabela profiles +create table if not exists public.profiles ( + id uuid primary key references auth.users(id) on delete cascade, + role text not null default 'patient' check (role in ('admin','therapist','patient')), + full_name text, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now() +); + +-- 2) updated_at automático +create or replace function public.set_updated_at() +returns trigger +language plpgsql +as $$ +begin + new.updated_at = now(); + return new; +end; +$$; + +drop trigger if exists trg_profiles_updated_at on public.profiles; +create trigger trg_profiles_updated_at +before update on public.profiles +for each row execute function public.set_updated_at(); + +-- 3) Trigger: cria profile automaticamente quando usuário nasce no auth +create or replace function public.handle_new_user() +returns trigger +language plpgsql +security definer +set search_path = public +as $$ +begin + insert into public.profiles (id, role) + values (new.id, 'patient') + on conflict (id) do nothing; + + return new; +end; +$$; + +drop trigger if exists on_auth_user_created on auth.users; +create trigger on_auth_user_created +after insert on auth.users +for each row execute function public.handle_new_user(); diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 157.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 157.sql new file mode 100644 index 0000000..e6e3802 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 157.sql @@ -0,0 +1,20 @@ +do $$ +begin + if exists ( + select 1 + from information_schema.columns + where table_schema = 'public' + and table_name = 'patient_patient_tag' + and column_name = 'patient_tag_id' + ) + and not exists ( + select 1 + from information_schema.columns + where table_schema = 'public' + and table_name = 'patient_patient_tag' + and column_name = 'tag_id' + ) then + alter table public.patient_patient_tag + rename column patient_tag_id to tag_id; + end if; +end $$; diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 159.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 159.sql new file mode 100644 index 0000000..6ca2eb5 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 159.sql @@ -0,0 +1,5 @@ +insert into public.profiles (id, role) +select u.id, 'patient' +from auth.users u +left join public.profiles p on p.id = u.id +where p.id is null; diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 174.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 174.sql new file mode 100644 index 0000000..d6098a6 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 174.sql @@ -0,0 +1,12 @@ +select + id, name, email, phone, + birth_date, cpf, rg, gender, + marital_status, profession, + place_of_birth, education_level, + cep, address_street, address_number, + address_neighborhood, address_city, address_state, + phone_alt, + notes, consent, created_at +from public.patient_intake_requests +order by created_at desc +limit 1; diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 209.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 209.sql new file mode 100644 index 0000000..24e9855 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 209.sql @@ -0,0 +1,23 @@ +create or replace function public.agenda_cfg_sync() +returns trigger +language plpgsql +as $$ +begin + if new.agenda_view_mode = 'custom' then + new.usar_horario_admin_custom := true; + new.admin_inicio_visualizacao := new.agenda_custom_start; + new.admin_fim_visualizacao := new.agenda_custom_end; + else + new.usar_horario_admin_custom := false; + end if; + + return new; +end; +$$; + +drop trigger if exists trg_agenda_cfg_sync on public.agenda_configuracoes; + +create trigger trg_agenda_cfg_sync +before insert or update on public.agenda_configuracoes +for each row +execute function public.agenda_cfg_sync(); \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 216.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 216.sql new file mode 100644 index 0000000..090476f --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 216.sql @@ -0,0 +1,2 @@ +drop index if exists public.uq_subscriptions_tenant; +drop index if exists public.uq_subscriptions_personal_user; \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 219.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 219.sql new file mode 100644 index 0000000..610a5b1 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 219.sql @@ -0,0 +1,6 @@ +-- Limpa TUDO da agenda (eventos, regras, exceções) +-- Execute no Supabase Studio — não tem volta! + +DELETE FROM recurrence_exceptions; +DELETE FROM recurrence_rules; +DELETE FROM agenda_eventos; \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 221.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 221.sql new file mode 100644 index 0000000..f80fe77 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 221.sql @@ -0,0 +1,12 @@ +select + t.tgname as trigger_name, + pg_get_triggerdef(t.oid) as trigger_def, + p.proname as function_name, + n.nspname as function_schema +from pg_trigger t +join pg_proc p on p.oid = t.tgfoid +join pg_namespace n on n.oid = p.pronamespace +join pg_class c on c.oid = t.tgrelid +where not t.tgisinternal + and c.relname = 'patient_intake_requests' +order by t.tgname; diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 235.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 235.sql new file mode 100644 index 0000000..d99d5cf --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 235.sql @@ -0,0 +1,46 @@ +-- ============================================================ + -- LIMPEZA DE DADOS DE TESTE — filtra por tenant/owner + -- Execute no Supabase Studio com cuidado -- ============================================================ + DO $$ DECLARE + v_tenant_id uuid := 'bbbbbbbb-0002-0002-0002-000000000002'; + v_owner_id uuid := 'aaaaaaaa-0002-0002-0002-000000000002'; + n_exc int; + n_ev int; + n_rule int; + n_sol int; + BEGIN + + -- 1. Exceções (filha de recurrence_rules — apagar primeiro) + DELETE FROM public.recurrence_exceptions + WHERE recurrence_id IN ( + SELECT id FROM public.recurrence_rules + WHERE (v_tenant_id IS NULL OR tenant_id = v_tenant_id) + AND (v_owner_id IS NULL OR owner_id = v_owner_id) + ); + GET DIAGNOSTICS n_exc = ROW_COUNT; + + -- 2. Regras de recorrência + DELETE FROM public.recurrence_rules + WHERE (v_tenant_id IS NULL OR tenant_id = v_tenant_id) + AND (v_owner_id IS NULL OR owner_id = v_owner_id); + GET DIAGNOSTICS n_rule = ROW_COUNT; + + -- 3. Eventos da agenda + DELETE FROM public.agenda_eventos + WHERE (v_tenant_id IS NULL OR tenant_id = v_tenant_id) + AND (v_owner_id IS NULL OR owner_id = v_owner_id); + GET DIAGNOSTICS n_ev = ROW_COUNT; + + -- 4. Solicitações públicas (agendador online) + DELETE FROM public.agendador_solicitacoes + WHERE (v_tenant_id IS NULL OR tenant_id = v_tenant_id) + AND (v_owner_id IS NULL OR owner_id = v_owner_id); + GET DIAGNOSTICS n_sol = ROW_COUNT; + + RAISE NOTICE '✅ Limpeza concluída:'; + RAISE NOTICE ' recurrence_exceptions : %', n_exc; + RAISE NOTICE ' recurrence_rules : %', n_rule; + RAISE NOTICE ' agenda_eventos : %', n_ev; + RAISE NOTICE ' agendador_solicitacoes : %', n_sol; + END; + $$; diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 271.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 271.sql new file mode 100644 index 0000000..a658306 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 271.sql @@ -0,0 +1,10 @@ +select + id as tenant_member_id, + tenant_id, + user_id, + role, + status, + created_at +from public.tenant_members +where user_id = '824f125c-55bb-40f5-a8c4-7a33618b91c7' +order by created_at desc; \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 277.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 277.sql new file mode 100644 index 0000000..24ec0cb --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 277.sql @@ -0,0 +1,4 @@ +select * +from agenda_eventos +order by created_at desc nulls last +limit 10; \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 319.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 319.sql new file mode 100644 index 0000000..6ee16fd --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 319.sql @@ -0,0 +1,6 @@ +select + routine_name, + routine_type +from information_schema.routines +where routine_schema = 'public' + and routine_name ilike '%intake%'; diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 323.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 323.sql new file mode 100644 index 0000000..24bb689 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 323.sql @@ -0,0 +1,4 @@ +select id as owner_id, email, created_at +from auth.users +where email = 'admin@agendapsi.com.br' +limit 1; diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 324.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 324.sql new file mode 100644 index 0000000..178f63a --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 324.sql @@ -0,0 +1,8 @@ +select + id, + owner_id, + status, + created_at, + converted_patient_id +from public.patient_intake_requests +where id = '54daa09a-b2cb-4a0b-91aa-e4cea1915efe'; \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 330.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 330.sql new file mode 100644 index 0000000..28ae3d2 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 330.sql @@ -0,0 +1,6 @@ +select f.key as feature_key +from public.plan_features pf +join public.features f on f.id = pf.feature_id +where pf.plan_id = 'fdc2813d-dfaa-4e2c-b71d-ef7b84dfd9e9' + and pf.enabled = true +order by f.key; \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 361.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 361.sql new file mode 100644 index 0000000..a339a14 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 361.sql @@ -0,0 +1,3 @@ +select id, key, name +from public.plans +order by key; diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 376.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 376.sql new file mode 100644 index 0000000..cbfe1ee --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 376.sql @@ -0,0 +1 @@ + SELECT * FROM public.agendador_solicitacoes LIMIT 5; \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 431.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 431.sql new file mode 100644 index 0000000..8acc511 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 431.sql @@ -0,0 +1,5 @@ +select table_schema, table_name, column_name +from information_schema.columns +where column_name in ('owner_id', 'tenant_id') + and table_schema = 'public' +order by table_name; diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 437.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 437.sql new file mode 100644 index 0000000..5418bb1 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 437.sql @@ -0,0 +1,12 @@ +alter table public.patient_groups enable row level security; + +drop policy if exists patient_groups_select on public.patient_groups; + +create policy patient_groups_select +on public.patient_groups +for select +to authenticated +using ( + owner_id = auth.uid() + or owner_id is null +); diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 439.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 439.sql new file mode 100644 index 0000000..cfb5556 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 439.sql @@ -0,0 +1,9 @@ + + + select * +from public.owner_feature_entitlements +where owner_id = '816b24fe-a0c3-4409-b79b-c6c0a6935d03'::uuid +order by feature_key; + +select public.has_feature('816b24fe-a0c3-4409-b79b-c6c0a6935d03'::uuid, 'online_scheduling.manage') as can_manage; + diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 449.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 449.sql new file mode 100644 index 0000000..1fad21f --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 449.sql @@ -0,0 +1,5 @@ +create index if not exists idx_patient_group_patient_group_id + on public.patient_group_patient (patient_group_id); + +create index if not exists idx_patient_groups_owner_system_nome + on public.patient_groups (owner_id, is_system, nome); diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 457.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 457.sql new file mode 100644 index 0000000..721fd3c --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 457.sql @@ -0,0 +1,9 @@ +-- 1) Marcar como SaaS master +insert into public.saas_admins (user_id) +values ('40a4b683-a0c9-4890-a201-20faf41fca06') +on conflict (user_id) do nothing; + +-- 2) Garantir profile (seu session.js busca role em profiles) +insert into public.profiles (id, role) +values ('40a4b683-a0c9-4890-a201-20faf41fca06', 'saas_admin') +on conflict (id) do update set role = excluded.role; \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 468.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 468.sql new file mode 100644 index 0000000..5bbc486 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 468.sql @@ -0,0 +1,5 @@ +select * +from public.owner_feature_entitlements +where owner_id = '816b24fe-a0c3-4409-b79b-c6c0a6935d03'::uuid +order by feature_key; + diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 476.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 476.sql new file mode 100644 index 0000000..6fca30d --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 476.sql @@ -0,0 +1,5 @@ +select column_name, data_type +from information_schema.columns +where table_schema = 'public' + and table_name = 'patient_patient_tag' +order by ordinal_position; diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 508.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 508.sql new file mode 100644 index 0000000..5aedcee --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 508.sql @@ -0,0 +1,18 @@ +create or replace function public.prevent_promoting_to_system() +returns trigger +language plpgsql +as $$ +begin + if new.is_system = true and old.is_system is distinct from true then + raise exception 'Não é permitido transformar um grupo comum em grupo do sistema.'; + end if; + return new; +end; +$$; + +drop trigger if exists trg_prevent_promoting_to_system on public.patient_groups; + +create trigger trg_prevent_promoting_to_system +before update on public.patient_groups +for each row +execute function public.prevent_promoting_to_system(); diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 521.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 521.sql new file mode 100644 index 0000000..a104170 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 521.sql @@ -0,0 +1,4 @@ +select id, tenant_id, user_id, role, status, created_at +from tenant_members +where user_id = '1715ec83-9a30-4dce-b73a-2deb66dcfb13' +order by created_at desc; \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 566.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 566.sql new file mode 100644 index 0000000..22e0403 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 566.sql @@ -0,0 +1,2 @@ +const { data, error } = await supabase.rpc('my_tenants') +console.log({ data, error }) diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 633.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 633.sql new file mode 100644 index 0000000..7cccd7a --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 633.sql @@ -0,0 +1,6 @@ +select id, tenant_id, user_id, role, status, created_at +from tenant_members +where tenant_id = '816b24fe-a0c3-4409-b79b-c6c0a6935d03'::uuid +order by + (case when role = 'clinic_admin' then 0 else 1 end), + created_at; \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 641.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 641.sql new file mode 100644 index 0000000..a8677bd --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 641.sql @@ -0,0 +1,15 @@ +-- Para o tenant A: +select id as responsible_member_id +from public.tenant_members +where tenant_id = '816b24fe-a0c3-4409-b79b-c6c0a6935d03' + and user_id = '824f125c-55bb-40f5-a8c4-7a33618b91c7' + and status = 'active' +limit 1; + +-- Para o tenant B: +select id as responsible_member_id +from public.tenant_members +where tenant_id = 'e8b10543-fb36-4e75-9d37-6fece9745637' + and user_id = '824f125c-55bb-40f5-a8c4-7a33618b91c7' + and status = 'active' +limit 1; \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 649.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 649.sql new file mode 100644 index 0000000..b4fa608 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 649.sql @@ -0,0 +1,4 @@ +select id, name, kind, created_at +from public.tenants +order by created_at desc +limit 10; \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 677.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 677.sql new file mode 100644 index 0000000..a4d6756 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 677.sql @@ -0,0 +1,5 @@ +select id as member_id +from tenant_members +where tenant_id = '816b24fe-a0c3-4409-b79b-c6c0a6935d03' + and user_id = '824f125c-55bb-40f5-a8c4-7a33618b91c7' +limit 1; \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 744.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 744.sql new file mode 100644 index 0000000..096d873 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 744.sql @@ -0,0 +1,2 @@ +insert into public.users (id, created_at) +values ('e8b10543-fb36-4e75-9d37-6fece9745637', now()); \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 781.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 781.sql new file mode 100644 index 0000000..e455447 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 781.sql @@ -0,0 +1,4 @@ +select * +from public.tenant_members +where tenant_id = 'UUID_AQUI' +order by created_at desc; \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 790.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 790.sql new file mode 100644 index 0000000..a7c1bba --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 790.sql @@ -0,0 +1,17 @@ +create table if not exists public.subscriptions ( + id uuid primary key default gen_random_uuid(), + user_id uuid not null references auth.users(id) on delete cascade, + plan_key text not null, + interval text not null check (interval in ('month','year')), + status text not null check (status in ('active','canceled','past_due','trial')) default 'active', + started_at timestamptz not null default now(), + current_period_start timestamptz not null default now(), + current_period_end timestamptz null, + canceled_at timestamptz null, + source text not null default 'manual', + created_at timestamptz not null default now(), + updated_at timestamptz not null default now() +); + +create index if not exists subscriptions_user_id_idx on public.subscriptions(user_id); +create index if not exists subscriptions_status_idx on public.subscriptions(status); diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 830.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 830.sql new file mode 100644 index 0000000..16f2509 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 830.sql @@ -0,0 +1,13 @@ +-- Ver todas as regras no banco +SELECT + id, + owner_id, + status, + type, + weekdays, + start_date, + end_date, + start_time, + created_at +FROM recurrence_rules +ORDER BY created_at DESC; \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 843.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 843.sql new file mode 100644 index 0000000..1f210fe --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 843.sql @@ -0,0 +1,3 @@ +select id, name, created_at +from public.tenants +order by created_at desc; \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 856.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 856.sql new file mode 100644 index 0000000..2984797 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 856.sql @@ -0,0 +1,8 @@ +alter table public.profiles enable row level security; + +drop policy if exists "profiles_select_own" on public.profiles; +create policy "profiles_select_own" +on public.profiles +for select +to authenticated +using (id = auth.uid()); diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 869.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 869.sql new file mode 100644 index 0000000..ebd1632 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 869.sql @@ -0,0 +1,7 @@ +-- 2) Tenho membership ativa no tenant atual? +select * +from tenant_members +where tenant_id = 'e8b10543-fb36-4e75-9d37-6fece9745637' + and user_id = auth.uid() +order by created_at desc; + diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 880.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 880.sql new file mode 100644 index 0000000..9fe1f32 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 880.sql @@ -0,0 +1,8 @@ +select + n.nspname as schema, + p.proname as function_name, + pg_get_functiondef(p.oid) as definition +from pg_proc p +join pg_namespace n on n.oid = p.pronamespace +where n.nspname = 'public' + and pg_get_functiondef(p.oid) ilike '%entitlements_invalidation%'; diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 886.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 886.sql new file mode 100644 index 0000000..4eb0d54 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 886.sql @@ -0,0 +1,266 @@ +-- ========================================================= +-- PATCH — Completar cadastro para bater com PatientsCadastroPage.vue +-- (rode DEPOIS do seu supabase_cadastro_pacientes.sql) +-- ========================================================= + +create extension if not exists pgcrypto; + +-- --------------------------------------------------------- +-- 1) Completar colunas que o front usa e hoje faltam em patients +-- --------------------------------------------------------- +do $$ +begin + if not exists ( + select 1 from information_schema.columns + where table_schema='public' and table_name='patients' and column_name='email_alt' + ) then + alter table public.patients add column email_alt text; + end if; + + if not exists ( + select 1 from information_schema.columns + where table_schema='public' and table_name='patients' and column_name='phones' + ) then + -- array de textos (Postgres). No JS você manda ["...","..."] normalmente. + alter table public.patients add column phones text[]; + end if; + + if not exists ( + select 1 from information_schema.columns + where table_schema='public' and table_name='patients' and column_name='gender' + ) then + alter table public.patients add column gender text; + end if; + + if not exists ( + select 1 from information_schema.columns + where table_schema='public' and table_name='patients' and column_name='marital_status' + ) then + alter table public.patients add column marital_status text; + end if; +end $$; + +-- (opcional) índices úteis pra busca/filtro por nome/email +create index if not exists idx_patients_owner_name on public.patients(owner_id, name); +create index if not exists idx_patients_owner_email on public.patients(owner_id, email); + +-- --------------------------------------------------------- +-- 2) patient_groups +-- --------------------------------------------------------- +create table if not exists public.patient_groups ( + id uuid primary key default gen_random_uuid(), + owner_id uuid not null references auth.users(id) on delete cascade, + name text not null, + color text, + is_system boolean not null default false, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now() +); + +-- nome único por owner +do $$ +begin + if not exists ( + select 1 from pg_constraint + where conname = 'patient_groups_owner_name_uniq' + and conrelid = 'public.patient_groups'::regclass + ) then + alter table public.patient_groups + add constraint patient_groups_owner_name_uniq unique(owner_id, name); + end if; +end $$; + +drop trigger if exists trg_patient_groups_set_updated_at on public.patient_groups; +create trigger trg_patient_groups_set_updated_at +before update on public.patient_groups +for each row execute function public.set_updated_at(); + +create index if not exists idx_patient_groups_owner on public.patient_groups(owner_id); + +alter table public.patient_groups enable row level security; + +drop policy if exists "patient_groups_select_own" on public.patient_groups; +create policy "patient_groups_select_own" +on public.patient_groups for select +to authenticated +using (owner_id = auth.uid()); + +drop policy if exists "patient_groups_insert_own" on public.patient_groups; +create policy "patient_groups_insert_own" +on public.patient_groups for insert +to authenticated +with check (owner_id = auth.uid()); + +drop policy if exists "patient_groups_update_own" on public.patient_groups; +create policy "patient_groups_update_own" +on public.patient_groups for update +to authenticated +using (owner_id = auth.uid()) +with check (owner_id = auth.uid()); + +drop policy if exists "patient_groups_delete_own" on public.patient_groups; +create policy "patient_groups_delete_own" +on public.patient_groups for delete +to authenticated +using (owner_id = auth.uid()); + +grant select, insert, update, delete on public.patient_groups to authenticated; + +-- --------------------------------------------------------- +-- 3) patient_tags +-- --------------------------------------------------------- +create table if not exists public.patient_tags ( + id uuid primary key default gen_random_uuid(), + owner_id uuid not null references auth.users(id) on delete cascade, + name text not null, + color text, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now() +); + +do $$ +begin + if not exists ( + select 1 from pg_constraint + where conname = 'patient_tags_owner_name_uniq' + and conrelid = 'public.patient_tags'::regclass + ) then + alter table public.patient_tags + add constraint patient_tags_owner_name_uniq unique(owner_id, name); + end if; +end $$; + +drop trigger if exists trg_patient_tags_set_updated_at on public.patient_tags; +create trigger trg_patient_tags_set_updated_at +before update on public.patient_tags +for each row execute function public.set_updated_at(); + +create index if not exists idx_patient_tags_owner on public.patient_tags(owner_id); + +alter table public.patient_tags enable row level security; + +drop policy if exists "patient_tags_select_own" on public.patient_tags; +create policy "patient_tags_select_own" +on public.patient_tags for select +to authenticated +using (owner_id = auth.uid()); + +drop policy if exists "patient_tags_insert_own" on public.patient_tags; +create policy "patient_tags_insert_own" +on public.patient_tags for insert +to authenticated +with check (owner_id = auth.uid()); + +drop policy if exists "patient_tags_update_own" on public.patient_tags; +create policy "patient_tags_update_own" +on public.patient_tags for update +to authenticated +using (owner_id = auth.uid()) +with check (owner_id = auth.uid()); + +drop policy if exists "patient_tags_delete_own" on public.patient_tags; +create policy "patient_tags_delete_own" +on public.patient_tags for delete +to authenticated +using (owner_id = auth.uid()); + +grant select, insert, update, delete on public.patient_tags to authenticated; + +-- --------------------------------------------------------- +-- 4) pivôs (patient_group_patient / patient_patient_tag) +-- --------------------------------------------------------- +create table if not exists public.patient_group_patient ( + patient_id uuid not null references public.patients(id) on delete cascade, + patient_group_id uuid not null references public.patient_groups(id) on delete cascade, + created_at timestamptz not null default now(), + primary key (patient_id, patient_group_id) +); + +create index if not exists idx_pgp_patient on public.patient_group_patient(patient_id); +create index if not exists idx_pgp_group on public.patient_group_patient(patient_group_id); + +alter table public.patient_group_patient enable row level security; + +-- a pivot “herda” tenant via join; policy usando exists pra validar owner do patient +drop policy if exists "pgp_select_own" on public.patient_group_patient; +create policy "pgp_select_own" +on public.patient_group_patient for select +to authenticated +using ( + exists ( + select 1 from public.patients p + where p.id = patient_group_patient.patient_id + and p.owner_id = auth.uid() + ) +); + +drop policy if exists "pgp_write_own" on public.patient_group_patient; +create policy "pgp_write_own" +on public.patient_group_patient for all +to authenticated +using ( + exists ( + select 1 from public.patients p + where p.id = patient_group_patient.patient_id + and p.owner_id = auth.uid() + ) +) +with check ( + exists ( + select 1 from public.patients p + where p.id = patient_group_patient.patient_id + and p.owner_id = auth.uid() + ) +); + +grant select, insert, update, delete on public.patient_group_patient to authenticated; + +-- tags pivot (ATENÇÃO: coluna é tag_id, como teu Vue usa!) +create table if not exists public.patient_patient_tag ( + patient_id uuid not null references public.patients(id) on delete cascade, + tag_id uuid not null references public.patient_tags(id) on delete cascade, + created_at timestamptz not null default now(), + primary key (patient_id, tag_id) +); + +create index if not exists idx_ppt_patient on public.patient_patient_tag(patient_id); +create index if not exists idx_ppt_tag on public.patient_patient_tag(tag_id); + +alter table public.patient_patient_tag enable row level security; + +drop policy if exists "ppt_select_own" on public.patient_patient_tag; +create policy "ppt_select_own" +on public.patient_patient_tag for select +to authenticated +using ( + exists ( + select 1 from public.patients p + where p.id = patient_patient_tag.patient_id + and p.owner_id = auth.uid() + ) +); + +drop policy if exists "ppt_write_own" on public.patient_patient_tag; +create policy "ppt_write_own" +on public.patient_patient_tag for all +to authenticated +using ( + exists ( + select 1 from public.patients p + where p.id = patient_patient_tag.patient_id + and p.owner_id = auth.uid() + ) +) +with check ( + exists ( + select 1 from public.patients p + where p.id = patient_patient_tag.patient_id + and p.owner_id = auth.uid() + ) +); + +grant select, insert, update, delete on public.patient_patient_tag to authenticated; + +-- ========================================================= +-- FIM PATCH +-- ========================================================= diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 899.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 899.sql new file mode 100644 index 0000000..6bcb015 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 899.sql @@ -0,0 +1,42 @@ +-- BUCKET avatars: RLS por pasta do usuário "/..." +-- Requer que seu path seja: `${auth.uid()}/...` (no seu código já é) + +drop policy if exists "avatars_select_own" on storage.objects; +create policy "avatars_select_own" +on storage.objects for select +to authenticated +using ( + bucket_id = 'avatars' + and name like auth.uid()::text || '/%' +); + +drop policy if exists "avatars_insert_own" on storage.objects; +create policy "avatars_insert_own" +on storage.objects for insert +to authenticated +with check ( + bucket_id = 'avatars' + and name like auth.uid()::text || '/%' +); + +drop policy if exists "avatars_update_own" on storage.objects; +create policy "avatars_update_own" +on storage.objects for update +to authenticated +using ( + bucket_id = 'avatars' + and name like auth.uid()::text || '/%' +) +with check ( + bucket_id = 'avatars' + and name like auth.uid()::text || '/%' +); + +drop policy if exists "avatars_delete_own" on storage.objects; +create policy "avatars_delete_own" +on storage.objects for delete +to authenticated +using ( + bucket_id = 'avatars' + and name like auth.uid()::text || '/%' +); diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 934.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 934.sql new file mode 100644 index 0000000..5be15f1 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 934.sql @@ -0,0 +1,3 @@ +select * +from tenant_members +where user_id = 'SEU_USER_ID'; \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 938.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 938.sql new file mode 100644 index 0000000..a4d2f11 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 938.sql @@ -0,0 +1,14 @@ +select + tm.id as responsible_member_id, + tm.tenant_id, + tm.user_id, + tm.role, + tm.status, + tm.created_at +from public.tenant_members tm +where tm.tenant_id = ( + select owner_id from public.patient_intake_requests + where id = '54daa09a-b2cb-4a0b-91aa-e4cea1915efe' +) +and tm.user_id = '824f125c-55bb-40f5-a8c4-7a33618b91c7' +limit 10; \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/Untitled query 975.sql b/DBS/2026-03-11/supabase-snippets/Untitled query 975.sql new file mode 100644 index 0000000..ce7959e --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/Untitled query 975.sql @@ -0,0 +1,17 @@ +-- 1) Qual é meu uid? +select auth.uid() as my_uid; + +-- 2) Tenho membership ativa no tenant atual? +select * +from tenant_members +where tenant_id = 'e8b10543-fb36-4e75-9d37-6fece9745637' + and user_id = auth.uid() +order by created_at desc; + +-- 3) Se você usa status: +select * +from tenant_members +where tenant_id = 'e8b10543-fb36-4e75-9d37-6fece9745637' + and user_id = auth.uid() + and status = 'active' +order by created_at desc; \ No newline at end of file diff --git a/DBS/2026-03-11/supabase-snippets/saas_docs.sql b/DBS/2026-03-11/supabase-snippets/saas_docs.sql new file mode 100644 index 0000000..d12c728 --- /dev/null +++ b/DBS/2026-03-11/supabase-snippets/saas_docs.sql @@ -0,0 +1,123 @@ +-- ============================================================ +-- saas_docs — Documentação dinâmica do sistema +-- Exibida nas páginas do frontend via botão "Ajuda" +-- ============================================================ + +-- ------------------------------------------------------------ +-- 1. TABELA +-- ------------------------------------------------------------ +CREATE TABLE IF NOT EXISTS public.saas_docs ( + id uuid PRIMARY KEY DEFAULT gen_random_uuid(), + titulo text NOT NULL, + conteudo text NOT NULL DEFAULT '', + medias jsonb NOT NULL DEFAULT '[]'::jsonb, + -- formato: [{ "tipo": "imagem"|"video", "url": "..." }, ...] + + tipo_acesso text NOT NULL DEFAULT 'usuario' + CHECK (tipo_acesso IN ('usuario', 'admin')), + -- 'usuario' → todos os autenticados + -- 'admin' → clinic_admin, tenant_admin, saas_admin + + pagina_path text NOT NULL, + -- path da rota do frontend, ex: '/therapist/agenda' + + pagina_label text, + -- label amigável (informativo, não usado no match) + + docs_relacionados uuid[] NOT NULL DEFAULT '{}', + -- IDs de outros saas_docs exibidos como "Veja também" + + ativo boolean NOT NULL DEFAULT true, + ordem int NOT NULL DEFAULT 0, + created_at timestamptz NOT NULL DEFAULT now(), + updated_at timestamptz NOT NULL DEFAULT now() +); + +-- ------------------------------------------------------------ +-- 2. ÍNDICE +-- ------------------------------------------------------------ +-- Query principal do frontend: filtra por path + ativo +CREATE INDEX IF NOT EXISTS saas_docs_path_ativo_idx + ON public.saas_docs (pagina_path, ativo); + +-- ------------------------------------------------------------ +-- 3. RLS +-- ------------------------------------------------------------ +ALTER TABLE public.saas_docs ENABLE ROW LEVEL SECURITY; + +-- SaaS admin: acesso total (SELECT, INSERT, UPDATE, DELETE) +-- Verificado via tabela saas_admins +CREATE POLICY "saas_admin_full_access" ON public.saas_docs + FOR ALL + TO authenticated + USING ( + EXISTS ( + SELECT 1 FROM public.saas_admins + WHERE saas_admins.user_id = auth.uid() + ) + ) + WITH CHECK ( + EXISTS ( + SELECT 1 FROM public.saas_admins + WHERE saas_admins.user_id = auth.uid() + ) + ); + +-- Admins de clínica: leem todos os docs ativos (usuario + admin) +CREATE POLICY "clinic_admin_read_all_docs" ON public.saas_docs + FOR SELECT + TO authenticated + USING ( + ativo = true + AND EXISTS ( + SELECT 1 FROM public.profiles + WHERE profiles.id = auth.uid() + AND profiles.role IN ('clinic_admin', 'tenant_admin') + ) + ); + +-- Demais usuários autenticados: leem apenas docs do tipo 'usuario' +CREATE POLICY "users_read_usuario_docs" ON public.saas_docs + FOR SELECT + TO authenticated + USING ( + ativo = true + AND tipo_acesso = 'usuario' + ); + +-- ------------------------------------------------------------ +-- 4. STORAGE — bucket saas-docs (imagens dos documentos) +-- ------------------------------------------------------------ +INSERT INTO storage.buckets (id, name, public) +VALUES ('saas-docs', 'saas-docs', true) +ON CONFLICT (id) DO NOTHING; + +-- SaaS admin: pode fazer upload +CREATE POLICY "saas_admin_storage_upload" ON storage.objects + FOR INSERT + TO authenticated + WITH CHECK ( + bucket_id = 'saas-docs' + AND EXISTS ( + SELECT 1 FROM public.saas_admins + WHERE saas_admins.user_id = auth.uid() + ) + ); + +-- SaaS admin: pode deletar +CREATE POLICY "saas_admin_storage_delete" ON storage.objects + FOR DELETE + TO authenticated + USING ( + bucket_id = 'saas-docs' + AND EXISTS ( + SELECT 1 FROM public.saas_admins + WHERE saas_admins.user_id = auth.uid() + ) + ); + +-- Leitura pública (bucket é público, mas policy explícita para clareza) +CREATE POLICY "saas_docs_public_read" ON storage.objects + FOR SELECT + TO public + USING (bucket_id = 'saas-docs'); diff --git a/Debugs/agenda-terapeuta-debug.txt b/Debugs/agenda-terapeuta-debug.txt new file mode 100644 index 0000000..881a724 --- /dev/null +++ b/Debugs/agenda-terapeuta-debug.txt @@ -0,0 +1,87 @@ +Debug Agenda + +Funcionando : + +- Cadastrar compromisso do tipo Sessão, ok +- Editar compromisso do tipo Sessão, ok +- Trocar Valor do compromisso do tipo sessão, ok +- Ajustar horário arrastando do compromisso do tipo sessão, ok + +- Cada compromisso exibe sua cor própria ao ser adicionado na agenda, ok +- Ao Atualizar as cores na Sessão de Compromissos, elas são ajustadas na agenda também, ok + +- Status [Agendado, Realizado, Faltou, Cancelado e Remarcar] Todos estão funcionando, ok +- O criar compromisso do tipo sessão está trazendo o valor padrão das configuraçãoes, ok +- O editar está salvando o novo valor informado, ok + +- Modalidade [Presencial, Online] está sendo salva ao editar, ok + +- Ajuste de Mensagem : "Conflito com X às HH:MM" não é do samePatientConflict : Encontrei o bug. Na timeConflict (linha 1785), a exclusão do evento atual usa form.value.id — mas ocorrências virtuais têm id: null, então nunca são excluídas. A ocorrência fica conflitando consigo mesma. + Causa: ocorrências virtuais têm id: null, então if (form.value.id && ...) nunca excluía a própria ocorrência da checagem — ela conflitava consigo mesma. Agora, para ocorrências virtuais, a exclusão é feita pelo par recurrence_id + original_date. + +- Adição de Recorrencia, ok +- Remoção de reorrencia, ok +- Remoção de recorrencias futuras, ok +- Remoção de todas as recorrencias, mantendo o compromisso raiz (inicial), ok +- Adicionado Confirmação de remoção e frase de efeito, ok +- "Todos os agendamentos futuros da série serão removidos permanentemente. Esta sessão será mantida como avulsa. Esta ação é irreversível." +- "A série foi encerrada. Esta sessão foi mantida como avulsa." + +Bugs conhecidos corrigidos : + + Feito. Resumo dos 4 fixes: + + ┌──────┬─────────────────────────────────────────┬───────────────────────────────────────────────────────────────┐ + │ # │ Problema │ Solução │ ├──────┼─────────────────────────────────────────┼───────────────────────────────────────────────────────────────┤ + │ Bug │ Recorrência em evento existente → só │ Removida condição !id — agora cria a regra e vincula o evento │ │ 1 │ fazia update │ existente │ + ├──────┼─────────────────────────────────────────┼───────────────────────────────────────────────────────────────┤ + │ Bug │ Botão de lixeira some quando form.id é │ Substituído por botão "Encerrar série" para hasSerie, lixeira │ + │ 2a │ null (virtual) │ simples para eventos avulsos │ + ├──────┼─────────────────────────────────────────┼───────────────────────────────────────────────────────────────┤ + │ Bug │ X das pills some para sessões │ Removida restrição v-if="!isPast" — X sempre visível │ + │ 2b │ passadas/canceladas │ │ + ├──────┼─────────────────────────────────────────┼───────────────────────────────────────────────────────────────┤ + │ Bug │ Sem confirmação ao encerrar série pelo │ onEncerrarSerie() com confirm.require() e aviso de │ + │ 2c │ botão novo │ irreversibilidade │ + └──────┴─────────────────────────────────────────┴───────────────────────────────────────────────────────────────┘ + +- Dots (mini-day-dot) adicionados em todos os dias que possuem compromissos, ok + + Corrigido também na AgendaClinicaPage: + + ┌────────────────────────┬────────────────────────────────────────────────────────────────────────────────────────┐ + │ Fix │ O que foi feito │ ├────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────┤ + │ Mini-day-dot │ loadMiniMonthEvents agora itera sobre todos os ownerIds da clínica chamando │ │ │ loadAndExpand para incluir ocorrências virtuais de recorrência │ + ├────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────┤ + │ 'todos' delete │ Mantém sessão atual como avulsa antes de cancelar a regra (igual ao terapeuta, usando │ + │ │ createClinic/updateClinic) │ + ├────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────┤ + │ Recorrente em evento │ Removida condição !id, cria a regra e vincula evento via updateClinic │ + │ existente │ │ + ├────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────┤ + │ ConfirmDialog │ Adicionado na página para as confirmações funcionarem corretamente │ + └────────────────────────┴────────────────────────────────────────────────────────────────────────────────────────┘ + +Quando adiciona um compromisso na agenda e não aparece : + + 1. Join FK errada (!determined_commitment_id → !agenda_eventos_determined_commitment_fk) em ambos + agendaClinicRepository.js e useAgendaEvents.js — esse era o bug principal. O Supabase usava o nome do constraint FK (agenda_eventos_determined_commitment_fk), não o nome da coluna. A query estava falhando silenciosamente, mantendo + rows.value no estado anterior (vazio na primeira carga). 2. modalidade ausente do pickDbFields — adicionado para não perder a modalidade selecionada pelo usuário. + 3. Toast de erro após _reloadRange — agora, se o reload falhar, um warning aparece em vez de mostrar sucesso sem + eventos. + +Para colorir o background dos compromissos : + + Pronto. Adicionei eventContent no buildFcOptions do AgendaClinicMosaic — mesmo código do AgendaTerapeutaPage — com + avatar (foto ou iniciais), horário, título e observações. O CSS foi adicionado em bloco não-scoped para que o HTML + injetado pelo FullCalendar seja estilizado corretamente. + + As cores dos compromissos já chegavam via backgroundColor no mapper (tanto para o terapeuta quanto para a clínica), o + que estava faltando era o eventContent customizado que dá o mesmo visual. + + + + + + + \ No newline at end of file diff --git a/TESTES.md b/TESTES.md new file mode 100644 index 0000000..261df62 --- /dev/null +++ b/TESTES.md @@ -0,0 +1,232 @@ +# Guia de Testes — AgenciaPsi + +## Testes Automatizados + +### Pré-requisito +Vitest já instalado (`npm install` resolve). Não precisa de banco, Supabase ou variáveis de ambiente. + +### Comandos + +| Comando | Descrição | +|---|---| +| `npm test` | Roda todos os testes uma vez e exibe resultado | +| `npm run test:watch` | Modo watch — re-roda ao salvar arquivos | +| `npm run test:ui` | Abre UI visual no browser (`http://localhost:51204`) | + +### Arquivos de teste + +| Arquivo | O que cobre | +|---|---| +| `src/features/agenda/composables/__tests__/useRecurrence.spec.js` | Geração de datas por tipo de regra, max_occurrences global, exceções, remarcação cross-range | +| `src/features/agenda/services/__tests__/agendaMappers.spec.js` | Mapeamento para FullCalendar, ícones de status, cores, buildNextSessions, minutesToDuration, buildWeeklyBreakBackgroundEvents | + +### Quando rodar +- Antes de commitar qualquer mudança em `useRecurrence.js` ou `agendaMappers.js` +- Ao adicionar novo tipo de frequência (mensal, quinzenal, etc.) +- Ao mexer em exceções de recorrência +- Em CI/CD antes do deploy + +--- + +## Testes Manuais + +### Preparação +1. Limpar dados de teste no banco: +```sql +TRUNCATE TABLE recurrence_exceptions CASCADE; +TRUNCATE TABLE recurrence_rules CASCADE; +TRUNCATE TABLE agenda_eventos CASCADE; +TRUNCATE TABLE agendador_solicitacoes CASCADE; +``` +2. Fazer login com seu usuário real +3. Selecionar a clínica/tenant correto + +--- + +### 1. Evento Avulso + +| Passo | Esperado | +|---|---| +| Clicar em um horário livre na agenda | Dialog de criação abre | +| Preencher paciente, horário, modalidade → Salvar | Evento aparece no calendário | +| Clicar no evento → Editar horário → Salvar | Horário atualiza | +| Clicar no evento → Marcar como "Faltou" | Cor muda para vermelho, ícone ✗ | +| Clicar no evento → Marcar como "Realizado" | Cor muda para cinza, ícone ✓ | +| Clicar no evento → Cancelar sessão | Cor muda para laranja, ícone ∅ | +| Clicar no evento → Excluir | Evento some do calendário | + +--- + +### 2. Recorrência Semanal + +| Passo | Esperado | +|---|---| +| Criar evento com frequência "Semanal" | Ocorrências aparecem em todas as semanas seguintes com ícone ↻ | +| Navegar para a semana seguinte | Ocorrências continuam aparecendo | +| Navegar para além do end_date | Não aparecem ocorrências após a data final | +| Criar série com "4 sessões" (max_occurrences) | Exatamente 4 ocorrências visíveis no calendário | + +--- + +### 3. Recorrência Quinzenal e Dias Específicos + +| Passo | Esperado | +|---|---| +| Criar série "Quinzenal" | Ocorrências aparecem a cada 2 semanas | +| Criar série "Dias específicos" (ex: seg + qua) | Ambos os dias aparecem toda semana | +| Navegar para semanas futuras | Padrão se mantém | + +--- + +### 4. Edição de Série + +| Passo | Esperado | +|---|---| +| Clicar em ocorrência → Editar → "Somente este" → mudar horário | Só aquela data muda; as outras continuam iguais | +| Clicar em ocorrência → Cancelar → "Somente este" | Só aquela data some (ou aparece cancelada) | +| Clicar em ocorrência → Cancelar → "Este e os seguintes" | A partir daquela data, sem mais ocorrências | +| Clicar em ocorrência → Cancelar → "Todos" | Série inteira some | + +--- + +### 5. Remarcação Cross-Range ⭐ + +Este é o caso mais importante a testar. + +| Passo | Esperado | +|---|---| +| Criar série semanal (ex: toda segunda) | Ocorrências nas segundas | +| Clicar na sessão da **semana 1** → Remarcar para **terça da semana 2** | — | +| Navegar para a **semana 1** | Segunda da semana 1 aparece vazia ou como "remarcado" | +| Navegar para a **semana 2** | Terça aparece com ícone ↺ e status "remarcado" | + +--- + +### 6. Bloqueio de Agenda + +| Passo | Esperado | +|---|---| +| Criar bloqueio de horário | Aparece no calendário com visual diferente (ícone ⊘) | +| Tentar agendar no horário bloqueado | Aviso de conflito | + +--- + +### 7. Agendamento Online (Agendador Público) + +| Passo | Esperado | +|---|---| +| Acessar URL pública do agendador | Página pública abre sem login | +| Selecionar data/horário disponível → Enviar solicitação | Confirmação exibida | +| No painel do terapeuta → "Agendamentos Recebidos" | Solicitação aparece na lista | +| Clicar em "Confirmar" | Evento criado na agenda | +| Clicar em "Recusar" | Solicitação removida, sem evento na agenda | + +--- + +### 8. Suporte Técnico SaaS + +| Passo | Esperado | +|---|---| +| Logar como `saas_admin` → Menu "Suporte Técnico" | Página de suporte abre | +| Selecionar um tenant → "Criar Sessão de Suporte" | URL com token é gerada | +| Copiar URL e abrir em outra aba | Agenda do terapeuta abre com banner de debug no rodapé | +| No banner → filtrar logs por categoria | Logs filtram corretamente | +| No banner → "Desativar suporte" | Banner some | +| No painel SaaS → "Revogar" na sessão ativa | Token invalidado | + +--- + +### 9. Multi-Tenancy (se você tem 2 clínicas cadastradas) + +| Passo | Esperado | +|---|---| +| Criar evento na clínica A | Evento aparece na agenda da clínica A | +| Trocar para clínica B | Evento da clínica A **não aparece** | +| Criar evento na clínica B | Aparece apenas na clínica B | + +--- + +## Pedindo ao Claude para Executar os Testes + +### Como usar o Claude Code para rodar e corrigir testes + +O Claude Code (este agente) consegue rodar os testes, ler os erros e corrigir os problemas automaticamente. Basta iniciar a conversa com o contexto certo. + +### Prompt de retomada recomendado + +Cole isso no início de uma nova sessão com o Claude: + +--- + +> Estou desenvolvendo o AgenciaPsi. Temos testes automatizados com Vitest. +> +> **Arquivos de teste:** +> - `src/features/agenda/composables/__tests__/useRecurrence.spec.js` — testa `generateDates`, `expandRules`, `mergeWithStoredSessions` +> - `src/features/agenda/services/__tests__/agendaMappers.spec.js` — testa mapeamento para FullCalendar +> +> **Rodar os testes:** `npm test` +> +> Por favor, rode os testes agora e me informe o resultado. Se houver falhas, analise a causa e corrija. + +--- + +### O que o Claude consegue fazer automaticamente + +| Pedido | O Claude faz | +|---|---| +| "Rode os testes" | Executa `npm test` e exibe o resultado | +| "Tem algum teste falhando?" | Roda e diagnóstica a causa raiz | +| "Corrija os testes que falham" | Analisa erro, ajusta o código ou o teste e re-roda | +| "Adicionei a funcionalidade X, crie testes para ela" | Lê o código e escreve novos casos no spec | +| "O teste Y está errado, o comportamento correto é Z" | Atualiza a asserção e confirma que passa | + +### Boas práticas ao pedir testes ao Claude + +- **Forneça o `AUDITORIA.md`** no início da sessão — dá contexto sobre a arquitetura e decisões já tomadas +- **Descreva o comportamento esperado** em português, não o código — o Claude escreve o código do teste +- **Se um teste falhar e você achar que o código está certo**, diga isso explicitamente: *"o teste está errado, não o código"* — o Claude vai ajustar a asserção +- **Se um teste falhar e você achar que o código está errado**, diga: *"o comportamento esperado é X"* — o Claude vai corrigir a implementação + +### Exemplo de sessão típica + +``` +Você: Rodei npm test e 2 testes falharam. Analise e corrija. + +Claude: [roda npm test, lê os erros, corrige o código ou as asserções, re-roda até 63/63 passarem] +``` + +--- + +## Adicionando Novos Testes + +### Para `useRecurrence.spec.js` + +```js +import { generateDates, expandRules, mergeWithStoredSessions } from '../useRecurrence.js' + +it('meu novo caso', () => { + const r = { + id: 'rule-1', type: 'weekly', weekdays: [1], interval: 1, + start_date: '2026-03-02', end_date: null, max_occurrences: null, + status: 'ativo', start_time: '09:00', end_time: '10:00', + // ... outros campos necessários + } + const dates = generateDates(r, new Date(2026, 2, 1), new Date(2026, 2, 31)) + expect(dates.length).toBe(/* esperado */) +}) +``` + +### Para `agendaMappers.spec.js` + +```js +import { mapAgendaEventosToCalendarEvents } from '../agendaMappers.js' + +it('meu novo caso de mapeamento', () => { + const [ev] = mapAgendaEventosToCalendarEvents([{ + id: 'ev-1', titulo: 'Teste', tipo: 'sessao', status: 'agendado', + inicio_em: '2026-03-10T09:00:00', fim_em: '2026-03-10T10:00:00', + owner_id: 'owner-1', + }]) + expect(ev.extendedProps./* campo */).toBe(/* esperado */) +}) +``` diff --git a/comandos.txt b/comandos.txt new file mode 100644 index 0000000..a060343 --- /dev/null +++ b/comandos.txt @@ -0,0 +1,15 @@ +para gerar o sql +supabase db dump --local -f full_dump.sql + +para exportar todo o banco: +docker exec -i supabase_db_agenciapsi-primesakai pg_dump -U postgres postgres > backup.sql + +para exportar o schema.sql: +docker exec -i supabase_db_agenciapsi-primesakai pg_dump -U postgres --schema-only postgres > schema.sql + +para restaurar o banco: +docker exec -i supabase_db_agenciapsi-primesakai psql -U postgres postgres < backup.sql + +para exportar sem ownership e ACLs (deixa o dump portável para outro ambiente): +docker exec -i supabase_db_agenciapsi-primesakai pg_dump -U postgres --no-owner --no-acl postgres > full_dump.sql + diff --git a/estrutura_src.txt b/estrutura_src.txt new file mode 100644 index 0000000000000000000000000000000000000000..9252549f701775d4a736fb95613654520606d414 GIT binary patch literal 19640 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 BkAMIG literal 0 HcmV?d00001 diff --git a/logs/simulation-cleanup.sql b/logs/simulation-cleanup.sql new file mode 100644 index 0000000..5fc94ee --- /dev/null +++ b/logs/simulation-cleanup.sql @@ -0,0 +1,29 @@ +-- ============================================================ +-- CLEANUP — remove dados da simulação AgenciaPsi +-- Data: 11/03/2026, 13:48:50 +-- ============================================================ + +SET session_replication_role = replica; + +BEGIN; + +DELETE FROM recurrence_exceptions WHERE id IN ('036ec898-d994-4892-9f6d-d0367d941e7f', '153bbd3a-d6f8-4199-bd1b-f744ad400e50', '8e4af6a8-beba-4cae-86cf-be8bbc02f8a9', 'a568ceac-0be6-4ec6-b4c8-1d666ff27fd5', '37a01ea8-65d1-4810-b8d6-869100251f47', '50c4b11e-a4ca-4f1f-ac09-05da87db3cd9', '3721079d-4ee3-46e5-a873-a33fce0e8080', '0e99db44-019d-40b5-a67e-cd55b4a096c2'); + +DELETE FROM agenda_eventos WHERE id IN ('19a93b33-68be-4916-9069-48587ba5b11f', '30d76055-1a5d-409a-b716-5e27aa109b0f', 'aa3d5832-a462-4380-8d4c-390aff127952', '32fc2417-ab45-4091-be6d-8b66b9231fc7', '42bd5e8b-4bc3-4fa2-abad-5cc8c520d44d', '7f180aac-b117-4237-a725-18333b3e6791', '3122bb93-3cea-4cfc-a3a3-ce66be7ccb0d', 'bb8536db-35c5-47f4-88d6-c8bab4bfad8e', 'e10632b8-2a40-4fb6-a318-7e95db39b216', 'c8d815ea-9445-4c33-8777-9a4d0af7977e', '0041d195-5203-4e83-9b18-c60b5ececa40', '25672cbd-939d-4f64-bf3a-807cb206b0aa', '94eeb1cb-2bc3-49c9-8394-1cda9ff51638', 'a008de79-810b-4b6f-ad1f-313053955c09', 'db00a8cc-44a8-4c23-a577-0eb75e750f18', '12efaf45-57a9-4c91-8020-d3bf6fbca1be', '0a5fd25c-d8c6-4f07-b88a-49db13881e09', '64d0e09a-dd16-46cb-90dd-2973bae26327', '49b90ec6-3136-446d-a6f0-c0a3ae06f4f8', 'f981e635-d536-409c-b6c6-ff6d9276394a', 'c609091f-0414-4bb6-99a5-0db40cf18148', '7cdc08f3-8ae0-42f9-a324-4f751782ff2a', '90c2a326-d173-4ad2-b716-86db878d035e', '1bd0b8ff-e058-4fdc-905e-87f958a9b9cd', '049aac05-cfc2-4107-8e07-2178174a4c91', 'f045c147-758e-4cc8-b4fd-633488e263e2', 'b097f0ac-67fd-4c6e-8cab-6417772a24ff', 'c0256c42-c125-4d17-ac8d-e210b50ca56f', 'd43bd403-ac9a-4e3d-a00d-91b2fdaa8b84', '8515afad-90a0-4a7f-936a-9b6977759bf6', 'a8f0bdb6-9502-49e5-8c2b-a00822113847', '041a0295-4986-43ba-9ef1-49eb962a64e1', '074d85af-d24e-4de6-8c90-0073f1411a0b', 'a07e5625-6c44-4c05-9607-e60cea9ab226'); + +DELETE FROM recurrence_rules WHERE id IN ('f94e562a-dee3-4b6c-9a63-62f54173f7e5', '84614add-030b-4110-8542-fbb2af844648', '9e493b9e-06a5-4adc-b5df-3124bbf56869', 'f4d992a3-8ca6-4930-b39c-1f9454bc4df1', 'b5c62afc-75c2-4dd3-a35a-037d7e1d4609', '6cd1c566-eee0-4bf4-b68b-c5d9ad24714c'); + +DELETE FROM agendador_solicitacoes WHERE id IN ('891b1bd8-05a6-4aac-8346-8aa99d889ebf', 'e80d1e72-dbdd-48c3-be6f-117d2f5f4267', 'db89a451-74ab-4b43-ad16-91b69172fff5'); + +DELETE FROM agenda_regras_semanais WHERE id IN ('815e4214-e3c6-4934-9a85-458d03ccb801', '9ab48292-3170-475f-b66b-7adf50477ae5', 'b9d6ec37-b290-4cd1-b82a-7e13c2cecdff', 'a9d2c596-8e9c-4f7b-b3d0-7078080f63be', '1ad0afcd-e59d-41d4-9e07-c53ec210e23e'); + +-- Descomente se quiser remover também as configurações de agenda: +-- DELETE FROM agenda_configuracoes WHERE owner_id = 'aaaaaaaa-0002-0002-0002-000000000002'; + +DELETE FROM patients WHERE id IN ('7910bd11-fdd3-4719-8d31-7352e33b0871', 'c23586a1-7f89-437b-9b15-0894c6f4e766', '56410d42-c489-47ef-a324-6177d0d54b6c', 'd7faec09-1ac0-47c6-bb75-ac3872188c66', '7d407456-ff3b-44ff-b8a6-f555987206a1', '86fcfccb-6230-42fa-a111-987d707fd4be', 'f408f949-c5cd-46c1-aa98-446eb378c653', '82b39d67-aac3-4117-b740-cdbec1d61ffc'); + +COMMIT; + +SET session_replication_role = DEFAULT; + +-- ─── Fim do cleanup ───────────────────────────────────────────────────────── \ No newline at end of file diff --git a/logs/simulation-log.txt b/logs/simulation-log.txt new file mode 100644 index 0000000..9076136 --- /dev/null +++ b/logs/simulation-log.txt @@ -0,0 +1,15 @@ +[INFO] 2026-03-11 16:48:50 Iniciando simulação... +[INFO] 2026-03-11 16:48:50 OWNER_ID: aaaaaaaa-0002-0002-0002-000000000002 +[INFO] 2026-03-11 16:48:50 TENANT_ID: bbbbbbbb-0002-0002-0002-000000000002 +[INFO] 2026-03-11 16:48:50 Período: 2026-02-09 → 2026-06-09 +[INFO] 2026-03-11 16:48:50 ✔ 8 pacientes criados +[INFO] 2026-03-11 16:48:50 ✔ agenda_configuracoes inserida +[INFO] 2026-03-11 16:48:50 ✔ 5 regras semanais inseridas +[INFO] 2026-03-11 16:48:50 ✔ 2 eventos avulsos criados +[INFO] 2026-03-11 16:48:50 ✔ 6 regras de recorrência criadas +[INFO] 2026-03-11 16:48:50 ✔ Exceções: 6 faltou, 2 remarcado, 0 cancelado +[INFO] 2026-03-11 16:48:50 ✔ 32 sessões reais (passado) criadas +[INFO] 2026-03-11 16:48:50 ✔ 5 solicitações do agendador criadas +[INFO] 2026-03-11 16:48:50 ✔ Seed SQL: D:\leonohama\AgenciaPsi.com.br\Sistema\agenciapsi-primesakai\logs\simulation-seed.sql +[INFO] 2026-03-11 16:48:50 ✔ Cleanup SQL: D:\leonohama\AgenciaPsi.com.br\Sistema\agenciapsi-primesakai\logs\simulation-cleanup.sql +[INFO] 2026-03-11 16:48:50 ✔ Relatório: D:\leonohama\AgenciaPsi.com.br\Sistema\agenciapsi-primesakai\logs\simulation-report.txt \ No newline at end of file diff --git a/logs/simulation-report.txt b/logs/simulation-report.txt new file mode 100644 index 0000000..51a9e12 --- /dev/null +++ b/logs/simulation-report.txt @@ -0,0 +1,63 @@ +============================================================ + RELATÓRIO DE SIMULAÇÃO — AgenciaPsi + Gerado em: 11/03/2026, 13:48:50 +============================================================ + +OWNER_ID: aaaaaaaa-0002-0002-0002-000000000002 +TENANT_ID: bbbbbbbb-0002-0002-0002-000000000002 + +─── Dados gerados ───────────────────────────────────────── + Pacientes: 8 + Séries de recorrência: 6 + Sessões reais (passado): 32 + Eventos avulsos: 2 + Exceções — faltou: 6 + Exceções — remarcado: 2 + Exceções — cancelado: 0 + Solicitações agendador: 5 + +─── Pacientes criados ───────────────────────────────────── + [7910bd11-fdd3-4719-8d31-7352e33b0871] Isabela Carvalho — isabela.carvalho82@hotmail.com + [c23586a1-7f89-437b-9b15-0894c6f4e766] Ana Souza — ana.souza58@gmail.com + [56410d42-c489-47ef-a324-6177d0d54b6c] Helena Santos — helena.santos3@gmail.com + [d7faec09-1ac0-47c6-bb75-ac3872188c66] Daniel Carvalho — daniel.carvalho86@outlook.com + [7d407456-ff3b-44ff-b8a6-f555987206a1] Mariana Rocha — mariana.rocha79@gmail.com + [86fcfccb-6230-42fa-a111-987d707fd4be] Fernanda Silva — fernanda.silva87@hotmail.com + [f408f949-c5cd-46c1-aa98-446eb378c653] Juliana Almeida — juliana.almeida64@outlook.com + [82b39d67-aac3-4117-b740-cdbec1d61ffc] Karen Nunes — karen.nunes25@gmail.com + +─── Séries de recorrência ───────────────────────────────── + [f94e562a-dee3-4b6c-9a63-62f54173f7e5] + Paciente: Isabela Carvalho + Tipo: weekly | Dias: Seg + Período: 2026-02-09 → 2026-06-09 + [84614add-030b-4110-8542-fbb2af844648] + Paciente: Ana Souza + Tipo: weekly | Dias: Ter + Período: 2026-02-09 → 2026-06-09 + [9e493b9e-06a5-4adc-b5df-3124bbf56869] + Paciente: Helena Santos + Tipo: weekly | Dias: Qui + Período: 2026-02-09 → 2026-06-09 + [f4d992a3-8ca6-4930-b39c-1f9454bc4df1] + Paciente: Daniel Carvalho + Tipo: biweekly | Dias: Seg + Período: 2026-02-09 → 2026-06-09 + [b5c62afc-75c2-4dd3-a35a-037d7e1d4609] + Paciente: Mariana Rocha + Tipo: custom_weekdays | Dias: Seg, Qua + Período: 2026-02-09 → 2026-06-09 + [6cd1c566-eee0-4bf4-b68b-c5d9ad24714c] + Paciente: Fernanda Silva + Tipo: weekly | Dias: Qua + Período: 2026-02-09 → 2026-06-09 + +─── Como testar ─────────────────────────────────────────── + 1. Abra o Supabase SQL Editor + 2. Cole e rode: logs/simulation-seed.sql + 3. Acesse a agenda — os eventos devem aparecer + 4. Acesse Pacientes — pacientes simulados aparecem na lista + 5. Acesse Agendamentos Recebidos — solicitações pendentes + 6. Quando terminar, rode: logs/simulation-cleanup.sql + +============================================================ \ No newline at end of file diff --git a/logs/simulation-seed.sql b/logs/simulation-seed.sql new file mode 100644 index 0000000..00f9a56 --- /dev/null +++ b/logs/simulation-seed.sql @@ -0,0 +1,237 @@ +-- ============================================================ +-- SIMULAÇÃO AgenciaPsi — gerado por npm run simulate +-- Data: 11/03/2026, 13:48:50 +-- ============================================================ + +-- Desabilita triggers para permitir inserts de simulação +SET session_replication_role = replica; + +BEGIN; + +-- ─── 1. Pacientes ─────────────────────────────────────────────────────────── + +INSERT INTO patients (id, tenant_id, owner_id, responsible_member_id, nome_completo, email_principal, telefone, cpf, patient_scope, status) + VALUES ('7910bd11-fdd3-4719-8d31-7352e33b0871', 'bbbbbbbb-0002-0002-0002-000000000002', 'aaaaaaaa-0002-0002-0002-000000000002', + (SELECT id FROM tenant_members WHERE user_id = 'aaaaaaaa-0002-0002-0002-000000000002' AND tenant_id = 'bbbbbbbb-0002-0002-0002-000000000002' LIMIT 1), + 'Isabela Carvalho', 'isabela.carvalho82@hotmail.com', '(51) 93447-7268', '36694226368', 'clinic', 'Ativo'); +INSERT INTO patients (id, tenant_id, owner_id, responsible_member_id, nome_completo, email_principal, telefone, cpf, patient_scope, status) + VALUES ('c23586a1-7f89-437b-9b15-0894c6f4e766', 'bbbbbbbb-0002-0002-0002-000000000002', 'aaaaaaaa-0002-0002-0002-000000000002', + (SELECT id FROM tenant_members WHERE user_id = 'aaaaaaaa-0002-0002-0002-000000000002' AND tenant_id = 'bbbbbbbb-0002-0002-0002-000000000002' LIMIT 1), + 'Ana Souza', 'ana.souza58@gmail.com', '(11) 91789-2404', '76394836115', 'clinic', 'Ativo'); +INSERT INTO patients (id, tenant_id, owner_id, responsible_member_id, nome_completo, email_principal, telefone, cpf, patient_scope, status) + VALUES ('56410d42-c489-47ef-a324-6177d0d54b6c', 'bbbbbbbb-0002-0002-0002-000000000002', 'aaaaaaaa-0002-0002-0002-000000000002', + (SELECT id FROM tenant_members WHERE user_id = 'aaaaaaaa-0002-0002-0002-000000000002' AND tenant_id = 'bbbbbbbb-0002-0002-0002-000000000002' LIMIT 1), + 'Helena Santos', 'helena.santos3@gmail.com', '(11) 92531-4591', '98615983257', 'clinic', 'Ativo'); +INSERT INTO patients (id, tenant_id, owner_id, responsible_member_id, nome_completo, email_principal, telefone, cpf, patient_scope, status) + VALUES ('d7faec09-1ac0-47c6-bb75-ac3872188c66', 'bbbbbbbb-0002-0002-0002-000000000002', 'aaaaaaaa-0002-0002-0002-000000000002', + (SELECT id FROM tenant_members WHERE user_id = 'aaaaaaaa-0002-0002-0002-000000000002' AND tenant_id = 'bbbbbbbb-0002-0002-0002-000000000002' LIMIT 1), + 'Daniel Carvalho', 'daniel.carvalho86@outlook.com', '(11) 95077-3606', '58936177264', 'clinic', 'Ativo'); +INSERT INTO patients (id, tenant_id, owner_id, responsible_member_id, nome_completo, email_principal, telefone, cpf, patient_scope, status) + VALUES ('7d407456-ff3b-44ff-b8a6-f555987206a1', 'bbbbbbbb-0002-0002-0002-000000000002', 'aaaaaaaa-0002-0002-0002-000000000002', + (SELECT id FROM tenant_members WHERE user_id = 'aaaaaaaa-0002-0002-0002-000000000002' AND tenant_id = 'bbbbbbbb-0002-0002-0002-000000000002' LIMIT 1), + 'Mariana Rocha', 'mariana.rocha79@gmail.com', '(21) 92159-7795', '14818998161', 'clinic', 'Ativo'); +INSERT INTO patients (id, tenant_id, owner_id, responsible_member_id, nome_completo, email_principal, telefone, cpf, patient_scope, status) + VALUES ('86fcfccb-6230-42fa-a111-987d707fd4be', 'bbbbbbbb-0002-0002-0002-000000000002', 'aaaaaaaa-0002-0002-0002-000000000002', + (SELECT id FROM tenant_members WHERE user_id = 'aaaaaaaa-0002-0002-0002-000000000002' AND tenant_id = 'bbbbbbbb-0002-0002-0002-000000000002' LIMIT 1), + 'Fernanda Silva', 'fernanda.silva87@hotmail.com', '(21) 97345-9576', '15668565266', 'clinic', 'Ativo'); +INSERT INTO patients (id, tenant_id, owner_id, responsible_member_id, nome_completo, email_principal, telefone, cpf, patient_scope, status) + VALUES ('f408f949-c5cd-46c1-aa98-446eb378c653', 'bbbbbbbb-0002-0002-0002-000000000002', 'aaaaaaaa-0002-0002-0002-000000000002', + (SELECT id FROM tenant_members WHERE user_id = 'aaaaaaaa-0002-0002-0002-000000000002' AND tenant_id = 'bbbbbbbb-0002-0002-0002-000000000002' LIMIT 1), + 'Juliana Almeida', 'juliana.almeida64@outlook.com', '(71) 95914-2804', '54146327124', 'clinic', 'Ativo'); +INSERT INTO patients (id, tenant_id, owner_id, responsible_member_id, nome_completo, email_principal, telefone, cpf, patient_scope, status) + VALUES ('82b39d67-aac3-4117-b740-cdbec1d61ffc', 'bbbbbbbb-0002-0002-0002-000000000002', 'aaaaaaaa-0002-0002-0002-000000000002', + (SELECT id FROM tenant_members WHERE user_id = 'aaaaaaaa-0002-0002-0002-000000000002' AND tenant_id = 'bbbbbbbb-0002-0002-0002-000000000002' LIMIT 1), + 'Karen Nunes', 'karen.nunes25@gmail.com', '(31) 90712-9951', '78969125499', 'clinic', 'Ativo'); + +-- ─── 2. Configurações de agenda ───────────────────────────────────────────── + +INSERT INTO agenda_configuracoes (owner_id, tenant_id, session_duration_min, session_break_min, pausas_semanais, online_ativo, setup_clinica_concluido) + VALUES ('aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', + 50, 10, '[{"weekday":1,"start":"12:00","end":"13:00","label":"Almoço"},{"weekday":2,"start":"12:00","end":"13:00","label":"Almoço"},{"weekday":3,"start":"12:00","end":"13:00","label":"Almoço"},{"weekday":4,"start":"12:00","end":"13:00","label":"Almoço"},{"weekday":5,"start":"12:00","end":"13:00","label":"Almoço"}]'::jsonb, true, true) + ON CONFLICT (owner_id) DO NOTHING; + +-- ─── 3. Regras semanais ───────────────────────────────────────────────────── + +INSERT INTO agenda_regras_semanais (id, owner_id, tenant_id, dia_semana, hora_inicio, hora_fim, ativo) + VALUES ('815e4214-e3c6-4934-9a85-458d03ccb801', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', 1, '08:00', '18:00', true); +INSERT INTO agenda_regras_semanais (id, owner_id, tenant_id, dia_semana, hora_inicio, hora_fim, ativo) + VALUES ('9ab48292-3170-475f-b66b-7adf50477ae5', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', 2, '08:00', '18:00', true); +INSERT INTO agenda_regras_semanais (id, owner_id, tenant_id, dia_semana, hora_inicio, hora_fim, ativo) + VALUES ('b9d6ec37-b290-4cd1-b82a-7e13c2cecdff', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', 3, '08:00', '18:00', true); +INSERT INTO agenda_regras_semanais (id, owner_id, tenant_id, dia_semana, hora_inicio, hora_fim, ativo) + VALUES ('a9d2c596-8e9c-4f7b-b3d0-7078080f63be', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', 4, '08:00', '18:00', true); +INSERT INTO agenda_regras_semanais (id, owner_id, tenant_id, dia_semana, hora_inicio, hora_fim, ativo) + VALUES ('1ad0afcd-e59d-41d4-9e07-c53ec210e23e', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', 5, '08:00', '18:00', true); + +-- ─── 4. Eventos avulsos (passado) ────────────────────────────────────────── + +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, titulo) + VALUES ('19a93b33-68be-4916-9069-48587ba5b11f', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '7910bd11-fdd3-4719-8d31-7352e33b0871', + 'sessao', 'faltou', '2026-02-23T13:00:00', '2026-02-23T13:50:00', 'online', 'Sessão avulsa'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, titulo) + VALUES ('30d76055-1a5d-409a-b716-5e27aa109b0f', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '56410d42-c489-47ef-a324-6177d0d54b6c', + 'sessao', 'agendado', '2026-02-16T13:00:00', '2026-02-16T13:50:00', 'presencial', 'Sessão avulsa'); + +-- ─── 5. Séries de recorrência ─────────────────────────────────────────────── + +INSERT INTO recurrence_rules (id, owner_id, tenant_id, patient_id, type, weekdays, interval, start_date, end_date, status, start_time, end_time, modalidade) + VALUES ('f94e562a-dee3-4b6c-9a63-62f54173f7e5', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '7910bd11-fdd3-4719-8d31-7352e33b0871', + 'weekly', ARRAY[1]::smallint[], 1, '2026-02-09', '2026-06-09', + 'ativo', '09:00', '09:50', 'online'); +INSERT INTO recurrence_rules (id, owner_id, tenant_id, patient_id, type, weekdays, interval, start_date, end_date, status, start_time, end_time, modalidade) + VALUES ('84614add-030b-4110-8542-fbb2af844648', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', 'c23586a1-7f89-437b-9b15-0894c6f4e766', + 'weekly', ARRAY[2]::smallint[], 1, '2026-02-09', '2026-06-09', + 'ativo', '10:00', '10:50', 'presencial'); +INSERT INTO recurrence_rules (id, owner_id, tenant_id, patient_id, type, weekdays, interval, start_date, end_date, status, start_time, end_time, modalidade) + VALUES ('9e493b9e-06a5-4adc-b5df-3124bbf56869', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '56410d42-c489-47ef-a324-6177d0d54b6c', + 'weekly', ARRAY[4]::smallint[], 1, '2026-02-09', '2026-06-09', + 'ativo', '11:00', '11:50', 'presencial'); +INSERT INTO recurrence_rules (id, owner_id, tenant_id, patient_id, type, weekdays, interval, start_date, end_date, status, start_time, end_time, modalidade) + VALUES ('f4d992a3-8ca6-4930-b39c-1f9454bc4df1', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', 'd7faec09-1ac0-47c6-bb75-ac3872188c66', + 'biweekly', ARRAY[1]::smallint[], 1, '2026-02-09', '2026-06-09', + 'ativo', '14:00', '14:50', 'online'); +INSERT INTO recurrence_rules (id, owner_id, tenant_id, patient_id, type, weekdays, interval, start_date, end_date, status, start_time, end_time, modalidade) + VALUES ('b5c62afc-75c2-4dd3-a35a-037d7e1d4609', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '7d407456-ff3b-44ff-b8a6-f555987206a1', + 'custom_weekdays', ARRAY[1,3]::smallint[], 1, '2026-02-09', '2026-06-09', + 'ativo', '15:00', '15:50', 'online'); +INSERT INTO recurrence_rules (id, owner_id, tenant_id, patient_id, type, weekdays, interval, start_date, end_date, status, start_time, end_time, modalidade) + VALUES ('6cd1c566-eee0-4bf4-b68b-c5d9ad24714c', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '86fcfccb-6230-42fa-a111-987d707fd4be', + 'weekly', ARRAY[3]::smallint[], 1, '2026-02-09', '2026-06-09', + 'ativo', '16:00', '16:50', 'online'); + +-- ─── 6. Exceções de recorrência ──────────────────────────────────────────── + +INSERT INTO recurrence_exceptions (id, recurrence_id, tenant_id, original_date, type, new_date) + VALUES ('036ec898-d994-4892-9f6d-d0367d941e7f', '9e493b9e-06a5-4adc-b5df-3124bbf56869', 'bbbbbbbb-0002-0002-0002-000000000002', '2026-02-19', 'patient_missed', NULL); +INSERT INTO recurrence_exceptions (id, recurrence_id, tenant_id, original_date, type, new_date) + VALUES ('153bbd3a-d6f8-4199-bd1b-f744ad400e50', '9e493b9e-06a5-4adc-b5df-3124bbf56869', 'bbbbbbbb-0002-0002-0002-000000000002', '2026-03-05', 'patient_missed', NULL); +INSERT INTO recurrence_exceptions (id, recurrence_id, tenant_id, original_date, type, new_date) + VALUES ('8e4af6a8-beba-4cae-86cf-be8bbc02f8a9', 'f4d992a3-8ca6-4930-b39c-1f9454bc4df1', 'bbbbbbbb-0002-0002-0002-000000000002', '2026-02-23', 'reschedule_session', '2026-02-27'); +INSERT INTO recurrence_exceptions (id, recurrence_id, tenant_id, original_date, type, new_date) + VALUES ('a568ceac-0be6-4ec6-b4c8-1d666ff27fd5', 'b5c62afc-75c2-4dd3-a35a-037d7e1d4609', 'bbbbbbbb-0002-0002-0002-000000000002', '2026-02-09', 'patient_missed', NULL); +INSERT INTO recurrence_exceptions (id, recurrence_id, tenant_id, original_date, type, new_date) + VALUES ('37a01ea8-65d1-4810-b8d6-869100251f47', 'b5c62afc-75c2-4dd3-a35a-037d7e1d4609', 'bbbbbbbb-0002-0002-0002-000000000002', '2026-02-16', 'patient_missed', NULL); +INSERT INTO recurrence_exceptions (id, recurrence_id, tenant_id, original_date, type, new_date) + VALUES ('50c4b11e-a4ca-4f1f-ac09-05da87db3cd9', 'b5c62afc-75c2-4dd3-a35a-037d7e1d4609', 'bbbbbbbb-0002-0002-0002-000000000002', '2026-02-18', 'patient_missed', NULL); +INSERT INTO recurrence_exceptions (id, recurrence_id, tenant_id, original_date, type, new_date) + VALUES ('3721079d-4ee3-46e5-a873-a33fce0e8080', 'b5c62afc-75c2-4dd3-a35a-037d7e1d4609', 'bbbbbbbb-0002-0002-0002-000000000002', '2026-02-25', 'patient_missed', NULL); +INSERT INTO recurrence_exceptions (id, recurrence_id, tenant_id, original_date, type, new_date) + VALUES ('0e99db44-019d-40b5-a67e-cd55b4a096c2', '6cd1c566-eee0-4bf4-b68b-c5d9ad24714c', 'bbbbbbbb-0002-0002-0002-000000000002', '2026-02-25', 'reschedule_session', '2026-02-26'); + +-- ─── 7. Sessões reais (passado — realizado/faltou) ──────────────────────── + +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('aa3d5832-a462-4380-8d4c-390aff127952', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '7910bd11-fdd3-4719-8d31-7352e33b0871', + 'sessao', 'realizado', '2026-02-09T09:00:00', '2026-02-09T09:50:00', 'online', 'f94e562a-dee3-4b6c-9a63-62f54173f7e5', '2026-02-09'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('32fc2417-ab45-4091-be6d-8b66b9231fc7', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '7910bd11-fdd3-4719-8d31-7352e33b0871', + 'sessao', 'realizado', '2026-02-16T09:00:00', '2026-02-16T09:50:00', 'online', 'f94e562a-dee3-4b6c-9a63-62f54173f7e5', '2026-02-16'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('42bd5e8b-4bc3-4fa2-abad-5cc8c520d44d', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '7910bd11-fdd3-4719-8d31-7352e33b0871', + 'sessao', 'realizado', '2026-02-23T09:00:00', '2026-02-23T09:50:00', 'online', 'f94e562a-dee3-4b6c-9a63-62f54173f7e5', '2026-02-23'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('7f180aac-b117-4237-a725-18333b3e6791', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '7910bd11-fdd3-4719-8d31-7352e33b0871', + 'sessao', 'realizado', '2026-03-02T09:00:00', '2026-03-02T09:50:00', 'online', 'f94e562a-dee3-4b6c-9a63-62f54173f7e5', '2026-03-02'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('3122bb93-3cea-4cfc-a3a3-ce66be7ccb0d', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '7910bd11-fdd3-4719-8d31-7352e33b0871', + 'sessao', 'realizado', '2026-03-09T09:00:00', '2026-03-09T09:50:00', 'online', 'f94e562a-dee3-4b6c-9a63-62f54173f7e5', '2026-03-09'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('bb8536db-35c5-47f4-88d6-c8bab4bfad8e', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', 'c23586a1-7f89-437b-9b15-0894c6f4e766', + 'sessao', 'realizado', '2026-02-10T10:00:00', '2026-02-10T10:50:00', 'presencial', '84614add-030b-4110-8542-fbb2af844648', '2026-02-10'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('e10632b8-2a40-4fb6-a318-7e95db39b216', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', 'c23586a1-7f89-437b-9b15-0894c6f4e766', + 'sessao', 'realizado', '2026-02-17T10:00:00', '2026-02-17T10:50:00', 'presencial', '84614add-030b-4110-8542-fbb2af844648', '2026-02-17'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('c8d815ea-9445-4c33-8777-9a4d0af7977e', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', 'c23586a1-7f89-437b-9b15-0894c6f4e766', + 'sessao', 'realizado', '2026-02-24T10:00:00', '2026-02-24T10:50:00', 'presencial', '84614add-030b-4110-8542-fbb2af844648', '2026-02-24'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('0041d195-5203-4e83-9b18-c60b5ececa40', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', 'c23586a1-7f89-437b-9b15-0894c6f4e766', + 'sessao', 'realizado', '2026-03-03T10:00:00', '2026-03-03T10:50:00', 'presencial', '84614add-030b-4110-8542-fbb2af844648', '2026-03-03'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('25672cbd-939d-4f64-bf3a-807cb206b0aa', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', 'c23586a1-7f89-437b-9b15-0894c6f4e766', + 'sessao', 'realizado', '2026-03-10T10:00:00', '2026-03-10T10:50:00', 'presencial', '84614add-030b-4110-8542-fbb2af844648', '2026-03-10'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('94eeb1cb-2bc3-49c9-8394-1cda9ff51638', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '56410d42-c489-47ef-a324-6177d0d54b6c', + 'sessao', 'realizado', '2026-02-12T11:00:00', '2026-02-12T11:50:00', 'presencial', '9e493b9e-06a5-4adc-b5df-3124bbf56869', '2026-02-12'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('a008de79-810b-4b6f-ad1f-313053955c09', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '56410d42-c489-47ef-a324-6177d0d54b6c', + 'sessao', 'realizado', '2026-02-19T11:00:00', '2026-02-19T11:50:00', 'presencial', '9e493b9e-06a5-4adc-b5df-3124bbf56869', '2026-02-19'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('db00a8cc-44a8-4c23-a577-0eb75e750f18', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '56410d42-c489-47ef-a324-6177d0d54b6c', + 'sessao', 'realizado', '2026-02-26T11:00:00', '2026-02-26T11:50:00', 'presencial', '9e493b9e-06a5-4adc-b5df-3124bbf56869', '2026-02-26'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('12efaf45-57a9-4c91-8020-d3bf6fbca1be', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '56410d42-c489-47ef-a324-6177d0d54b6c', + 'sessao', 'realizado', '2026-03-05T11:00:00', '2026-03-05T11:50:00', 'presencial', '9e493b9e-06a5-4adc-b5df-3124bbf56869', '2026-03-05'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('0a5fd25c-d8c6-4f07-b88a-49db13881e09', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', 'd7faec09-1ac0-47c6-bb75-ac3872188c66', + 'sessao', 'realizado', '2026-02-09T14:00:00', '2026-02-09T14:50:00', 'online', 'f4d992a3-8ca6-4930-b39c-1f9454bc4df1', '2026-02-09'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('64d0e09a-dd16-46cb-90dd-2973bae26327', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', 'd7faec09-1ac0-47c6-bb75-ac3872188c66', + 'sessao', 'faltou', '2026-02-16T14:00:00', '2026-02-16T14:50:00', 'online', 'f4d992a3-8ca6-4930-b39c-1f9454bc4df1', '2026-02-16'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('49b90ec6-3136-446d-a6f0-c0a3ae06f4f8', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', 'd7faec09-1ac0-47c6-bb75-ac3872188c66', + 'sessao', 'realizado', '2026-02-23T14:00:00', '2026-02-23T14:50:00', 'online', 'f4d992a3-8ca6-4930-b39c-1f9454bc4df1', '2026-02-23'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('f981e635-d536-409c-b6c6-ff6d9276394a', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', 'd7faec09-1ac0-47c6-bb75-ac3872188c66', + 'sessao', 'realizado', '2026-03-02T14:00:00', '2026-03-02T14:50:00', 'online', 'f4d992a3-8ca6-4930-b39c-1f9454bc4df1', '2026-03-02'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('c609091f-0414-4bb6-99a5-0db40cf18148', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', 'd7faec09-1ac0-47c6-bb75-ac3872188c66', + 'sessao', 'realizado', '2026-03-09T14:00:00', '2026-03-09T14:50:00', 'online', 'f4d992a3-8ca6-4930-b39c-1f9454bc4df1', '2026-03-09'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('7cdc08f3-8ae0-42f9-a324-4f751782ff2a', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '7d407456-ff3b-44ff-b8a6-f555987206a1', + 'sessao', 'realizado', '2026-02-09T15:00:00', '2026-02-09T15:50:00', 'online', 'b5c62afc-75c2-4dd3-a35a-037d7e1d4609', '2026-02-09'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('90c2a326-d173-4ad2-b716-86db878d035e', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '7d407456-ff3b-44ff-b8a6-f555987206a1', + 'sessao', 'realizado', '2026-02-11T15:00:00', '2026-02-11T15:50:00', 'online', 'b5c62afc-75c2-4dd3-a35a-037d7e1d4609', '2026-02-11'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('1bd0b8ff-e058-4fdc-905e-87f958a9b9cd', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '7d407456-ff3b-44ff-b8a6-f555987206a1', + 'sessao', 'realizado', '2026-02-16T15:00:00', '2026-02-16T15:50:00', 'online', 'b5c62afc-75c2-4dd3-a35a-037d7e1d4609', '2026-02-16'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('049aac05-cfc2-4107-8e07-2178174a4c91', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '7d407456-ff3b-44ff-b8a6-f555987206a1', + 'sessao', 'faltou', '2026-02-18T15:00:00', '2026-02-18T15:50:00', 'online', 'b5c62afc-75c2-4dd3-a35a-037d7e1d4609', '2026-02-18'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('f045c147-758e-4cc8-b4fd-633488e263e2', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '7d407456-ff3b-44ff-b8a6-f555987206a1', + 'sessao', 'realizado', '2026-02-23T15:00:00', '2026-02-23T15:50:00', 'online', 'b5c62afc-75c2-4dd3-a35a-037d7e1d4609', '2026-02-23'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('b097f0ac-67fd-4c6e-8cab-6417772a24ff', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '7d407456-ff3b-44ff-b8a6-f555987206a1', + 'sessao', 'realizado', '2026-02-25T15:00:00', '2026-02-25T15:50:00', 'online', 'b5c62afc-75c2-4dd3-a35a-037d7e1d4609', '2026-02-25'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('c0256c42-c125-4d17-ac8d-e210b50ca56f', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '7d407456-ff3b-44ff-b8a6-f555987206a1', + 'sessao', 'realizado', '2026-03-02T15:00:00', '2026-03-02T15:50:00', 'online', 'b5c62afc-75c2-4dd3-a35a-037d7e1d4609', '2026-03-02'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('d43bd403-ac9a-4e3d-a00d-91b2fdaa8b84', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '7d407456-ff3b-44ff-b8a6-f555987206a1', + 'sessao', 'realizado', '2026-03-04T15:00:00', '2026-03-04T15:50:00', 'online', 'b5c62afc-75c2-4dd3-a35a-037d7e1d4609', '2026-03-04'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('8515afad-90a0-4a7f-936a-9b6977759bf6', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '7d407456-ff3b-44ff-b8a6-f555987206a1', + 'sessao', 'faltou', '2026-03-09T15:00:00', '2026-03-09T15:50:00', 'online', 'b5c62afc-75c2-4dd3-a35a-037d7e1d4609', '2026-03-09'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('a8f0bdb6-9502-49e5-8c2b-a00822113847', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '86fcfccb-6230-42fa-a111-987d707fd4be', + 'sessao', 'realizado', '2026-02-11T16:00:00', '2026-02-11T16:50:00', 'online', '6cd1c566-eee0-4bf4-b68b-c5d9ad24714c', '2026-02-11'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('041a0295-4986-43ba-9ef1-49eb962a64e1', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '86fcfccb-6230-42fa-a111-987d707fd4be', + 'sessao', 'faltou', '2026-02-18T16:00:00', '2026-02-18T16:50:00', 'online', '6cd1c566-eee0-4bf4-b68b-c5d9ad24714c', '2026-02-18'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('074d85af-d24e-4de6-8c90-0073f1411a0b', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '86fcfccb-6230-42fa-a111-987d707fd4be', + 'sessao', 'faltou', '2026-02-25T16:00:00', '2026-02-25T16:50:00', 'online', '6cd1c566-eee0-4bf4-b68b-c5d9ad24714c', '2026-02-25'); +INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date) + VALUES ('a07e5625-6c44-4c05-9607-e60cea9ab226', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', '86fcfccb-6230-42fa-a111-987d707fd4be', + 'sessao', 'realizado', '2026-03-04T16:00:00', '2026-03-04T16:50:00', 'online', '6cd1c566-eee0-4bf4-b68b-c5d9ad24714c', '2026-03-04'); + +-- ─── 8. Agendador Público — solicitações pendentes ───────────────────────── + +INSERT INTO agendador_solicitacoes (id, owner_id, tenant_id, paciente_nome, paciente_sobrenome, paciente_email, paciente_celular, tipo, modalidade, data_solicitada, hora_solicitada, status) + VALUES ('891b1bd8-05a6-4aac-8346-8aa99d889ebf', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', 'Marcos', 'Costa', 'marcos.costa12@yahoo.com.br', '(51) 91799-2922', + 'primeira', 'presencial', '2026-03-24', '09:00', 'recusado'); +INSERT INTO agendador_solicitacoes (id, owner_id, tenant_id, paciente_nome, paciente_sobrenome, paciente_email, paciente_celular, tipo, modalidade, data_solicitada, hora_solicitada, status) + VALUES ('e80d1e72-dbdd-48c3-be6f-117d2f5f4267', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', 'Carla', 'Carvalho', 'carla.carvalho82@hotmail.com', '(91) 92340-8703', + 'reagendar', 'presencial', '2026-03-23', '09:00', 'pendente'); +INSERT INTO agendador_solicitacoes (id, owner_id, tenant_id, paciente_nome, paciente_sobrenome, paciente_email, paciente_celular, tipo, modalidade, data_solicitada, hora_solicitada, status) + VALUES ('db89a451-74ab-4b43-ad16-91b69172fff5', 'aaaaaaaa-0002-0002-0002-000000000002', 'bbbbbbbb-0002-0002-0002-000000000002', 'Sérgio', 'Martins', 'sergio.martins82@gmail.com', '(11) 93735-0761', + 'reagendar', 'presencial', '2026-03-16', '08:00', 'pendente'); + +COMMIT; + +-- Restaura comportamento normal dos triggers +SET session_replication_role = DEFAULT; + +-- ─── Fim do seed ──────────────────────────────────────────────────────────── \ No newline at end of file diff --git a/migrations/agenda_eventos_price.sql b/migrations/agenda_eventos_price.sql new file mode 100644 index 0000000..800cf48 --- /dev/null +++ b/migrations/agenda_eventos_price.sql @@ -0,0 +1,8 @@ +-- migrations/agenda_eventos_price.sql +-- Adiciona coluna price à agenda_eventos para registrar o valor da sessão + +ALTER TABLE agenda_eventos + ADD COLUMN IF NOT EXISTS price numeric(10,2); + +COMMENT ON COLUMN agenda_eventos.price IS + 'Valor da sessão em BRL. Preenchido automaticamente pela tabela professional_pricing do profissional.'; diff --git a/migrations/agendador_check_email.sql b/migrations/agendador_check_email.sql new file mode 100644 index 0000000..0de3715 --- /dev/null +++ b/migrations/agendador_check_email.sql @@ -0,0 +1,36 @@ +-- ═══════════════════════════════════════════════════════════════════════════ +-- agendador_check_email +-- Verifica se um e-mail já possui solicitação anterior para este agendador +-- SECURITY DEFINER → anon pode chamar sem burlar RLS diretamente +-- Execute no Supabase SQL Editor +-- ═══════════════════════════════════════════════════════════════════════════ + +CREATE OR REPLACE FUNCTION public.agendador_check_email( + p_slug text, + p_email text +) +RETURNS boolean +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_owner_id uuid; +BEGIN + SELECT c.owner_id INTO v_owner_id + FROM public.agendador_configuracoes c + WHERE c.link_slug = p_slug AND c.ativo = true + LIMIT 1; + + IF v_owner_id IS NULL THEN RETURN false; END IF; + + RETURN EXISTS ( + SELECT 1 FROM public.agendador_solicitacoes s + WHERE s.owner_id = v_owner_id + AND lower(s.paciente_email) = lower(trim(p_email)) + LIMIT 1 + ); +END; +$$; + +GRANT EXECUTE ON FUNCTION public.agendador_check_email(text, text) TO anon, authenticated; diff --git a/migrations/agendador_features.sql b/migrations/agendador_features.sql new file mode 100644 index 0000000..6e1701b --- /dev/null +++ b/migrations/agendador_features.sql @@ -0,0 +1,62 @@ +-- ═══════════════════════════════════════════════════════════════════════════ +-- Feature keys do Agendador Online +-- Execute no Supabase SQL Editor +-- ═══════════════════════════════════════════════════════════════════════════ + +-- ── 1. Inserir as features ────────────────────────────────────────────────── +INSERT INTO public.features (key, name, descricao) +VALUES + ( + 'agendador.online', + 'Agendador Online', + 'Permite que pacientes solicitem agendamentos via link público. Inclui aprovação manual ou automática, controle de horários e notificações.' + ), + ( + 'agendador.link_personalizado', + 'Link Personalizado do Agendador', + 'Permite que o profissional escolha um slug de URL próprio para o agendador (ex: /agendar/dra-ana-silva) em vez de um link gerado automaticamente.' + ) +ON CONFLICT (key) DO UPDATE + SET name = EXCLUDED.name, + descricao = EXCLUDED.descricao; + +-- ── 2. Vincular aos planos ────────────────────────────────────────────────── +-- ATENÇÃO: ajuste os filtros de plan key/name conforme seus planos reais. +-- Exemplo: agendador.online disponível para planos PRO e acima. +-- agendador.link_personalizado apenas para planos Elite/Superior. + +-- agendador.online → todos os planos com target 'therapist' ou 'clinic' +-- (Adapte o WHERE conforme necessário) +INSERT INTO public.plan_features (plan_id, feature_id, enabled) +SELECT + p.id, + f.id, + true +FROM public.plans p +CROSS JOIN public.features f +WHERE f.key = 'agendador.online' + AND p.is_active = true + -- Comente a linha abaixo para liberar para TODOS os planos: + -- AND p.key IN ('pro', 'elite', 'clinic_pro', 'clinic_elite') +ON CONFLICT DO NOTHING; + +-- agendador.link_personalizado → apenas planos superiores +-- Deixe comentado e adicione manualmente quando definir os planos: +-- INSERT INTO public.plan_features (plan_id, feature_id, enabled) +-- SELECT p.id, f.id, true +-- FROM public.plans p +-- CROSS JOIN public.features f +-- WHERE f.key = 'agendador.link_personalizado' +-- AND p.key IN ('elite', 'clinic_elite', 'pro_plus') +-- ON CONFLICT DO NOTHING; + +-- ── 3. Verificação ───────────────────────────────────────────────────────── +SELECT + f.key, + f.name, + COUNT(pf.plan_id) AS planos_vinculados +FROM public.features f +LEFT JOIN public.plan_features pf ON pf.feature_id = f.id AND pf.enabled = true +WHERE f.key IN ('agendador.online', 'agendador.link_personalizado') +GROUP BY f.key, f.name +ORDER BY f.key; diff --git a/migrations/agendador_fix_slots.sql b/migrations/agendador_fix_slots.sql new file mode 100644 index 0000000..e2d4e6e --- /dev/null +++ b/migrations/agendador_fix_slots.sql @@ -0,0 +1,221 @@ +-- ═══════════════════════════════════════════════════════════════════════════ +-- FIX: agendador_slots_disponiveis + agendador_dias_disponiveis +-- Usa agenda_online_slots como fonte de slots +-- Cruzamento com: agenda_eventos, recurrence_rules/exceptions, agendador_solicitacoes +-- Execute no Supabase SQL Editor +-- ═══════════════════════════════════════════════════════════════════════════ + +CREATE OR REPLACE FUNCTION public.agendador_slots_disponiveis( + p_slug text, + p_data date +) +RETURNS TABLE (hora time, disponivel boolean) +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_owner_id uuid; + v_duracao int; + v_antecedencia int; + v_agora timestamptz; + v_db_dow int; + v_slot time; + v_slot_fim time; + v_slot_ts timestamptz; + v_ocupado boolean; + -- loop de recorrências + v_rule RECORD; + v_rule_start_dow int; + v_first_occ date; + v_day_diff int; + v_ex_type text; +BEGIN + SELECT c.owner_id, c.duracao_sessao_min, c.antecedencia_minima_horas + INTO v_owner_id, v_duracao, v_antecedencia + FROM public.agendador_configuracoes c + WHERE c.link_slug = p_slug AND c.ativo = true + LIMIT 1; + + IF v_owner_id IS NULL THEN RETURN; END IF; + + v_agora := now(); + v_db_dow := extract(dow from p_data::timestamp)::int; + + FOR v_slot IN + SELECT s.time + FROM public.agenda_online_slots s + WHERE s.owner_id = v_owner_id + AND s.weekday = v_db_dow + AND s.enabled = true + ORDER BY s.time + LOOP + v_slot_fim := v_slot + (v_duracao || ' minutes')::interval; + v_ocupado := false; + + -- ── Antecedência mínima ────────────────────────────────────────────────── + v_slot_ts := (p_data::text || ' ' || v_slot::text)::timestamp + AT TIME ZONE 'America/Sao_Paulo'; + IF v_slot_ts < v_agora + (v_antecedencia || ' hours')::interval THEN + v_ocupado := true; + END IF; + + -- ── Eventos avulsos internos (agenda_eventos) ──────────────────────────── + IF NOT v_ocupado THEN + SELECT EXISTS ( + SELECT 1 FROM public.agenda_eventos e + WHERE e.owner_id = v_owner_id + AND e.status::text NOT IN ('cancelado', 'faltou') + AND (e.inicio_em AT TIME ZONE 'America/Sao_Paulo')::date = p_data + AND (e.inicio_em AT TIME ZONE 'America/Sao_Paulo')::time < v_slot_fim + AND (e.fim_em AT TIME ZONE 'America/Sao_Paulo')::time > v_slot + ) INTO v_ocupado; + END IF; + + -- ── Recorrências ativas (recurrence_rules) ─────────────────────────────── + -- Loop explícito para evitar erros de tipo no cálculo do ciclo semanal + IF NOT v_ocupado THEN + FOR v_rule IN + SELECT + r.id, + r.start_date::date AS start_date, + r.end_date::date AS end_date, + r.start_time::time AS start_time, + r.end_time::time AS end_time, + COALESCE(r.interval, 1)::int AS interval + FROM public.recurrence_rules r + WHERE r.owner_id = v_owner_id + AND r.status = 'ativo' + AND p_data >= r.start_date::date + AND (r.end_date IS NULL OR p_data <= r.end_date::date) + AND v_db_dow = ANY(r.weekdays) + AND r.start_time::time < v_slot_fim + AND r.end_time::time > v_slot + LOOP + -- Calcula a primeira ocorrência do dia-da-semana a partir do start_date + v_rule_start_dow := extract(dow from v_rule.start_date)::int; + v_first_occ := v_rule.start_date + + (((v_db_dow - v_rule_start_dow + 7) % 7))::int; + v_day_diff := (p_data - v_first_occ)::int; + + -- Ocorrência válida: diff >= 0 e divisível pelo ciclo semanal + IF v_day_diff >= 0 AND v_day_diff % (7 * v_rule.interval) = 0 THEN + + -- Verifica se há exceção para esta data + v_ex_type := NULL; + SELECT ex.type INTO v_ex_type + FROM public.recurrence_exceptions ex + WHERE ex.recurrence_id = v_rule.id + AND ex.original_date = p_data + LIMIT 1; + + -- Sem exceção, ou exceção que não cancela → bloqueia o slot + IF v_ex_type IS NULL OR v_ex_type NOT IN ( + 'cancel_session', 'patient_missed', + 'therapist_canceled', 'holiday_block', + 'reschedule_session' + ) THEN + v_ocupado := true; + EXIT; -- já basta uma regra que conflite + END IF; + + END IF; + END LOOP; + END IF; + + -- ── Recorrências remarcadas para este dia (reschedule → new_date = p_data) ─ + IF NOT v_ocupado THEN + SELECT EXISTS ( + SELECT 1 + FROM public.recurrence_exceptions ex + JOIN public.recurrence_rules r ON r.id = ex.recurrence_id + WHERE r.owner_id = v_owner_id + AND r.status = 'ativo' + AND ex.type = 'reschedule_session' + AND ex.new_date = p_data + AND COALESCE(ex.new_start_time, r.start_time)::time < v_slot_fim + AND COALESCE(ex.new_end_time, r.end_time)::time > v_slot + ) INTO v_ocupado; + END IF; + + -- ── Solicitações públicas pendentes ────────────────────────────────────── + IF NOT v_ocupado THEN + SELECT EXISTS ( + SELECT 1 FROM public.agendador_solicitacoes sol + WHERE sol.owner_id = v_owner_id + AND sol.status = 'pendente' + AND sol.data_solicitada = p_data + AND sol.hora_solicitada = v_slot + AND (sol.reservado_ate IS NULL OR sol.reservado_ate > v_agora) + ) INTO v_ocupado; + END IF; + + hora := v_slot; + disponivel := NOT v_ocupado; + RETURN NEXT; + END LOOP; +END; +$$; + +GRANT EXECUTE ON FUNCTION public.agendador_slots_disponiveis(text, date) TO anon, authenticated; + + +-- ── agendador_dias_disponiveis ─────────────────────────────────────────────── +CREATE OR REPLACE FUNCTION public.agendador_dias_disponiveis( + p_slug text, + p_ano int, + p_mes int +) +RETURNS TABLE (data date, tem_slots boolean) +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_owner_id uuid; + v_antecedencia int; + v_agora timestamptz; + v_data date; + v_data_inicio date; + v_data_fim date; + v_db_dow int; + v_tem_slot boolean; +BEGIN + SELECT c.owner_id, c.antecedencia_minima_horas + INTO v_owner_id, v_antecedencia + FROM public.agendador_configuracoes c + WHERE c.link_slug = p_slug AND c.ativo = true + LIMIT 1; + + IF v_owner_id IS NULL THEN RETURN; END IF; + + v_agora := now(); + v_data_inicio := make_date(p_ano, p_mes, 1); + v_data_fim := (v_data_inicio + interval '1 month' - interval '1 day')::date; + + v_data := v_data_inicio; + WHILE v_data <= v_data_fim LOOP + v_db_dow := extract(dow from v_data::timestamp)::int; + + SELECT EXISTS ( + SELECT 1 FROM public.agenda_online_slots s + WHERE s.owner_id = v_owner_id + AND s.weekday = v_db_dow + AND s.enabled = true + AND (v_data::text || ' ' || s.time::text)::timestamp + AT TIME ZONE 'America/Sao_Paulo' + >= v_agora + (v_antecedencia || ' hours')::interval + ) INTO v_tem_slot; + + IF v_tem_slot THEN + data := v_data; + tem_slots := true; + RETURN NEXT; + END IF; + + v_data := v_data + 1; + END LOOP; +END; +$$; + +GRANT EXECUTE ON FUNCTION public.agendador_dias_disponiveis(text, int, int) TO anon, authenticated; diff --git a/migrations/agendador_online.sql b/migrations/agendador_online.sql new file mode 100644 index 0000000..bc9390e --- /dev/null +++ b/migrations/agendador_online.sql @@ -0,0 +1,170 @@ +-- ═══════════════════════════════════════════════════════════════════════════ +-- Agendador Online — tabelas de configuração e solicitações +-- ═══════════════════════════════════════════════════════════════════════════ + +-- ── 1. agendador_configuracoes ────────────────────────────────────────────── +CREATE TABLE IF NOT EXISTS "public"."agendador_configuracoes" ( + "owner_id" "uuid" NOT NULL, + "tenant_id" "uuid", + + -- PRO / Ativação + "ativo" boolean DEFAULT false NOT NULL, + "link_slug" "text", + + -- Identidade Visual + "imagem_fundo_url" "text", + "imagem_header_url" "text", + "logomarca_url" "text", + "cor_primaria" "text" DEFAULT '#4b6bff', + + -- Perfil Público + "nome_exibicao" "text", + "endereco" "text", + "botao_como_chegar_ativo" boolean DEFAULT true NOT NULL, + "maps_url" "text", + + -- Fluxo de Agendamento + "modo_aprovacao" "text" DEFAULT 'aprovacao' NOT NULL, + "modalidade" "text" DEFAULT 'presencial' NOT NULL, + "tipos_habilitados" "jsonb" DEFAULT '["primeira","retorno"]'::jsonb NOT NULL, + "duracao_sessao_min" integer DEFAULT 50 NOT NULL, + "antecedencia_minima_horas" integer DEFAULT 24 NOT NULL, + "prazo_resposta_horas" integer DEFAULT 2 NOT NULL, + "reserva_horas" integer DEFAULT 2 NOT NULL, + + -- Pagamento + "pagamento_obrigatorio" boolean DEFAULT false NOT NULL, + "pix_chave" "text", + "pix_countdown_minutos" integer DEFAULT 20 NOT NULL, + + -- Triagem & Conformidade + "triagem_motivo" boolean DEFAULT true NOT NULL, + "triagem_como_conheceu" boolean DEFAULT false NOT NULL, + "verificacao_email" boolean DEFAULT false NOT NULL, + "exigir_aceite_lgpd" boolean DEFAULT true NOT NULL, + + -- Textos + "mensagem_boas_vindas" "text", + "texto_como_se_preparar" "text", + "texto_termos_lgpd" "text", + + -- Timestamps + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + "updated_at" timestamp with time zone DEFAULT now() NOT NULL, + + CONSTRAINT "agendador_configuracoes_pkey" PRIMARY KEY ("owner_id"), + CONSTRAINT "agendador_configuracoes_owner_fk" + FOREIGN KEY ("owner_id") REFERENCES "auth"."users"("id") ON DELETE CASCADE, + CONSTRAINT "agendador_configuracoes_tenant_fk" + FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE CASCADE, + CONSTRAINT "agendador_configuracoes_modo_check" + CHECK ("modo_aprovacao" = ANY (ARRAY['automatico','aprovacao'])), + CONSTRAINT "agendador_configuracoes_modalidade_check" + CHECK ("modalidade" = ANY (ARRAY['presencial','online','ambos'])), + CONSTRAINT "agendador_configuracoes_duracao_check" + CHECK ("duracao_sessao_min" >= 10 AND "duracao_sessao_min" <= 240), + CONSTRAINT "agendador_configuracoes_antecedencia_check" + CHECK ("antecedencia_minima_horas" >= 0 AND "antecedencia_minima_horas" <= 720), + CONSTRAINT "agendador_configuracoes_reserva_check" + CHECK ("reserva_horas" >= 1 AND "reserva_horas" <= 48), + CONSTRAINT "agendador_configuracoes_pix_countdown_check" + CHECK ("pix_countdown_minutos" >= 5 AND "pix_countdown_minutos" <= 120), + CONSTRAINT "agendador_configuracoes_prazo_check" + CHECK ("prazo_resposta_horas" >= 1 AND "prazo_resposta_horas" <= 72) +); + +ALTER TABLE "public"."agendador_configuracoes" ENABLE ROW LEVEL SECURITY; + +DROP POLICY IF EXISTS "agendador_cfg_select" ON "public"."agendador_configuracoes"; +CREATE POLICY "agendador_cfg_select" ON "public"."agendador_configuracoes" + FOR SELECT USING (auth.uid() = owner_id); + +DROP POLICY IF EXISTS "agendador_cfg_write" ON "public"."agendador_configuracoes"; +CREATE POLICY "agendador_cfg_write" ON "public"."agendador_configuracoes" + USING (auth.uid() = owner_id) + WITH CHECK (auth.uid() = owner_id); + +CREATE INDEX IF NOT EXISTS "agendador_cfg_tenant_idx" + ON "public"."agendador_configuracoes" ("tenant_id"); + +-- ── 2. agendador_solicitacoes ─────────────────────────────────────────────── +CREATE TABLE IF NOT EXISTS "public"."agendador_solicitacoes" ( + "id" "uuid" DEFAULT gen_random_uuid() NOT NULL, + "owner_id" "uuid" NOT NULL, + "tenant_id" "uuid", + + -- Dados do paciente + "paciente_nome" "text" NOT NULL, + "paciente_sobrenome" "text", + "paciente_email" "text" NOT NULL, + "paciente_celular" "text", + "paciente_cpf" "text", + + -- Agendamento solicitado + "tipo" "text" NOT NULL, + "modalidade" "text" NOT NULL, + "data_solicitada" date NOT NULL, + "hora_solicitada" time NOT NULL, + + -- Reserva temporária + "reservado_ate" timestamp with time zone, + + -- Triagem + "motivo" "text", + "como_conheceu" "text", + + -- Pagamento + "pix_status" "text" DEFAULT 'pendente', + "pix_pago_em" timestamp with time zone, + + -- Status geral + "status" "text" DEFAULT 'pendente' NOT NULL, + "recusado_motivo" "text", + + -- Autorização + "autorizado_em" timestamp with time zone, + "autorizado_por" "uuid", + + -- Vínculos internos + "user_id" "uuid", + "patient_id" "uuid", + "evento_id" "uuid", + + -- Timestamps + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + "updated_at" timestamp with time zone DEFAULT now() NOT NULL, + + CONSTRAINT "agendador_solicitacoes_pkey" PRIMARY KEY ("id"), + CONSTRAINT "agendador_sol_owner_fk" + FOREIGN KEY ("owner_id") REFERENCES "auth"."users"("id") ON DELETE CASCADE, + CONSTRAINT "agendador_sol_tenant_fk" + FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE CASCADE, + CONSTRAINT "agendador_sol_status_check" + CHECK ("status" = ANY (ARRAY['pendente','autorizado','recusado','expirado'])), + CONSTRAINT "agendador_sol_tipo_check" + CHECK ("tipo" = ANY (ARRAY['primeira','retorno','reagendar'])), + CONSTRAINT "agendador_sol_modalidade_check" + CHECK ("modalidade" = ANY (ARRAY['presencial','online'])), + CONSTRAINT "agendador_sol_pix_check" + CHECK ("pix_status" IS NULL OR "pix_status" = ANY (ARRAY['pendente','pago','expirado'])) +); + +ALTER TABLE "public"."agendador_solicitacoes" ENABLE ROW LEVEL SECURITY; + +DROP POLICY IF EXISTS "agendador_sol_owner_select" ON "public"."agendador_solicitacoes"; +CREATE POLICY "agendador_sol_owner_select" ON "public"."agendador_solicitacoes" + FOR SELECT USING (auth.uid() = owner_id); + +DROP POLICY IF EXISTS "agendador_sol_owner_write" ON "public"."agendador_solicitacoes"; +CREATE POLICY "agendador_sol_owner_write" ON "public"."agendador_solicitacoes" + USING (auth.uid() = owner_id) + WITH CHECK (auth.uid() = owner_id); + +CREATE INDEX IF NOT EXISTS "agendador_sol_owner_idx" + ON "public"."agendador_solicitacoes" ("owner_id", "status"); + +CREATE INDEX IF NOT EXISTS "agendador_sol_tenant_idx" + ON "public"."agendador_solicitacoes" ("tenant_id"); + +CREATE INDEX IF NOT EXISTS "agendador_sol_data_idx" + ON "public"."agendador_solicitacoes" ("data_solicitada", "hora_solicitada"); diff --git a/migrations/agendador_pagamento_modo.sql b/migrations/agendador_pagamento_modo.sql new file mode 100644 index 0000000..683caa0 --- /dev/null +++ b/migrations/agendador_pagamento_modo.sql @@ -0,0 +1,20 @@ +-- migrations/agendador_pagamento_modo.sql +-- Adiciona suporte a modo de pagamento no agendador online +-- Execute no Supabase SQL Editor + +ALTER TABLE agendador_configuracoes + ADD COLUMN IF NOT EXISTS pagamento_modo text NOT NULL DEFAULT 'sem_pagamento', + ADD COLUMN IF NOT EXISTS pagamento_metodos_visiveis text[] NOT NULL DEFAULT '{}'; + +-- Migração de dados existentes: +-- quem tinha pagamento_obrigatorio = true → pix_antecipado +UPDATE agendador_configuracoes + SET pagamento_modo = 'pix_antecipado' + WHERE pagamento_obrigatorio = true + AND pagamento_modo = 'sem_pagamento'; + +COMMENT ON COLUMN agendador_configuracoes.pagamento_modo IS + 'sem_pagamento | pagar_na_hora | pix_antecipado'; + +COMMENT ON COLUMN agendador_configuracoes.pagamento_metodos_visiveis IS + 'Métodos exibidos ao paciente quando pagamento_modo = pagar_na_hora. Ex: {pix, deposito, dinheiro, cartao, convenio}'; diff --git a/migrations/agendador_publico.sql b/migrations/agendador_publico.sql new file mode 100644 index 0000000..4ca29d4 --- /dev/null +++ b/migrations/agendador_publico.sql @@ -0,0 +1,219 @@ +-- ═══════════════════════════════════════════════════════════════════════════ +-- Agendador Online — acesso público (anon) + função de slots disponíveis +-- ═══════════════════════════════════════════════════════════════════════════ + +-- ── 1. Geração automática de slug ────────────────────────────────────────── +-- Cria slug único de 8 chars quando o profissional ativa sem link_personalizado +CREATE OR REPLACE FUNCTION public.agendador_gerar_slug() +RETURNS trigger LANGUAGE plpgsql AS $$ +DECLARE + v_slug text; + v_exists boolean; +BEGIN + -- só gera se ativou e não tem slug ainda + IF NEW.ativo = true AND (NEW.link_slug IS NULL OR NEW.link_slug = '') THEN + LOOP + v_slug := lower(substring(replace(gen_random_uuid()::text, '-', ''), 1, 8)); + SELECT EXISTS ( + SELECT 1 FROM public.agendador_configuracoes + WHERE link_slug = v_slug AND owner_id <> NEW.owner_id + ) INTO v_exists; + EXIT WHEN NOT v_exists; + END LOOP; + NEW.link_slug := v_slug; + END IF; + RETURN NEW; +END; +$$; + +DROP TRIGGER IF EXISTS agendador_slug_trigger ON public.agendador_configuracoes; +CREATE TRIGGER agendador_slug_trigger + BEFORE INSERT OR UPDATE ON public.agendador_configuracoes + FOR EACH ROW EXECUTE FUNCTION public.agendador_gerar_slug(); + +-- ── 2. Políticas públicas (anon) ──────────────────────────────────────────── + +-- Leitura pública da config pelo slug (só ativo) +DROP POLICY IF EXISTS "agendador_cfg_public_read" ON public.agendador_configuracoes; +CREATE POLICY "agendador_cfg_public_read" ON public.agendador_configuracoes + FOR SELECT TO anon + USING (ativo = true AND link_slug IS NOT NULL); + +-- Inserção pública de solicitações (qualquer pessoa pode solicitar) +DROP POLICY IF EXISTS "agendador_sol_public_insert" ON public.agendador_solicitacoes; +CREATE POLICY "agendador_sol_public_insert" ON public.agendador_solicitacoes + FOR INSERT TO anon + WITH CHECK (true); + +-- Leitura da própria solicitação (pelo paciente logado) +DROP POLICY IF EXISTS "agendador_sol_patient_read" ON public.agendador_solicitacoes; +CREATE POLICY "agendador_sol_patient_read" ON public.agendador_solicitacoes + FOR SELECT TO authenticated + USING (auth.uid() = user_id OR auth.uid() = owner_id); + +-- ── 3. Função: retorna slots disponíveis para uma data ────────────────────── +-- Roda como SECURITY DEFINER (acessa agenda_regras e agenda_eventos sem RLS) +CREATE OR REPLACE FUNCTION public.agendador_slots_disponiveis( + p_slug text, + p_data date +) +RETURNS TABLE (hora time, disponivel boolean) +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_owner_id uuid; + v_duracao int; + v_reserva int; + v_antecedencia int; + v_dia_semana int; -- 0=dom..6=sab (JS) → convertemos + v_db_dow int; -- 0=dom..6=sab no Postgres (extract dow) + v_inicio time; + v_fim time; + v_slot time; + v_slot_fim time; + v_agora timestamptz; +BEGIN + -- carrega config do agendador + SELECT + c.owner_id, + c.duracao_sessao_min, + c.reserva_horas, + c.antecedencia_minima_horas + INTO v_owner_id, v_duracao, v_reserva, v_antecedencia + FROM public.agendador_configuracoes c + WHERE c.link_slug = p_slug AND c.ativo = true + LIMIT 1; + + IF v_owner_id IS NULL THEN + RETURN; + END IF; + + v_agora := now(); + v_db_dow := extract(dow from p_data::timestamp)::int; -- 0=dom..6=sab + + -- regra semanal para o dia da semana + SELECT hora_inicio, hora_fim + INTO v_inicio, v_fim + FROM public.agenda_regras_semanais + WHERE owner_id = v_owner_id + AND dia_semana = v_db_dow + AND ativo = true + LIMIT 1; + + IF v_inicio IS NULL THEN + RETURN; -- profissional não atende nesse dia + END IF; + + -- itera slots de v_duracao em v_duracao dentro da jornada + v_slot := v_inicio; + WHILE v_slot + (v_duracao || ' minutes')::interval <= v_fim LOOP + v_slot_fim := v_slot + (v_duracao || ' minutes')::interval; + + -- bloco temporário para verificar conflitos + DECLARE + v_ocupado boolean := false; + v_slot_ts timestamptz; + BEGIN + -- antecedência mínima (compara em horário de Brasília) + v_slot_ts := (p_data::text || ' ' || v_slot::text)::timestamp AT TIME ZONE 'America/Sao_Paulo'; + + IF v_slot_ts < v_agora + (v_antecedencia || ' hours')::interval THEN + v_ocupado := true; + END IF; + + -- conflito com eventos existentes na agenda + IF NOT v_ocupado THEN + SELECT EXISTS ( + SELECT 1 FROM public.agenda_eventos + WHERE owner_id = v_owner_id + AND status::text NOT IN ('cancelado', 'faltou') + AND inicio_em AT TIME ZONE 'America/Sao_Paulo' >= p_data::timestamp + AND inicio_em AT TIME ZONE 'America/Sao_Paulo' < p_data::timestamp + interval '1 day' + AND (inicio_em AT TIME ZONE 'America/Sao_Paulo')::time < v_slot_fim + AND (fim_em AT TIME ZONE 'America/Sao_Paulo')::time > v_slot + ) INTO v_ocupado; + END IF; + + -- conflito com solicitações pendentes (reservadas) + IF NOT v_ocupado THEN + SELECT EXISTS ( + SELECT 1 FROM public.agendador_solicitacoes + WHERE owner_id = v_owner_id + AND status = 'pendente' + AND data_solicitada = p_data + AND hora_solicitada = v_slot + AND (reservado_ate IS NULL OR reservado_ate > v_agora) + ) INTO v_ocupado; + END IF; + + hora := v_slot; + disponivel := NOT v_ocupado; + RETURN NEXT; + END; + + v_slot := v_slot + (v_duracao || ' minutes')::interval; + END LOOP; +END; +$$; + +GRANT EXECUTE ON FUNCTION public.agendador_slots_disponiveis(text, date) TO anon, authenticated; + +-- ── 4. Função: retorna dias com disponibilidade no mês ───────────────────── +CREATE OR REPLACE FUNCTION public.agendador_dias_disponiveis( + p_slug text, + p_ano int, + p_mes int -- 1-12 +) +RETURNS TABLE (data date, tem_slots boolean) +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_owner_id uuid; + v_antecedencia int; + v_data date; + v_data_inicio date; + v_data_fim date; + v_agora timestamptz; + v_db_dow int; + v_tem_regra boolean; +BEGIN + SELECT c.owner_id, c.antecedencia_minima_horas + INTO v_owner_id, v_antecedencia + FROM public.agendador_configuracoes c + WHERE c.link_slug = p_slug AND c.ativo = true + LIMIT 1; + + IF v_owner_id IS NULL THEN RETURN; END IF; + + v_agora := now(); + v_data_inicio := make_date(p_ano, p_mes, 1); + v_data_fim := (v_data_inicio + interval '1 month' - interval '1 day')::date; + + v_data := v_data_inicio; + WHILE v_data <= v_data_fim LOOP + -- não oferece dias no passado ou dentro da antecedência mínima + IF v_data::timestamptz + '23:59:59'::interval > v_agora + (v_antecedencia || ' hours')::interval THEN + v_db_dow := extract(dow from v_data::timestamp)::int; + + SELECT EXISTS ( + SELECT 1 FROM public.agenda_regras_semanais + WHERE owner_id = v_owner_id AND dia_semana = v_db_dow AND ativo = true + ) INTO v_tem_regra; + + IF v_tem_regra THEN + data := v_data; + tem_slots := true; + RETURN NEXT; + END IF; + END IF; + + v_data := v_data + 1; + END LOOP; +END; +$$; + +GRANT EXECUTE ON FUNCTION public.agendador_dias_disponiveis(text, int, int) TO anon, authenticated; diff --git a/migrations/agendador_status_convertido.sql b/migrations/agendador_status_convertido.sql new file mode 100644 index 0000000..cddb978 --- /dev/null +++ b/migrations/agendador_status_convertido.sql @@ -0,0 +1,19 @@ +-- ═══════════════════════════════════════════════════════════════════════════ +-- FIX: adiciona status 'convertido' na constraint de agendador_solicitacoes +-- e adiciona coluna motivo_recusa (alias amigável de recusado_motivo) +-- Execute no Supabase SQL Editor +-- ═══════════════════════════════════════════════════════════════════════════ + +-- 1. Remove o CHECK existente e recria com os novos valores +ALTER TABLE public.agendador_solicitacoes + DROP CONSTRAINT IF EXISTS "agendador_sol_status_check"; + +ALTER TABLE public.agendador_solicitacoes + ADD CONSTRAINT "agendador_sol_status_check" + CHECK (status = ANY (ARRAY[ + 'pendente', + 'autorizado', + 'recusado', + 'expirado', + 'convertido' + ])); diff --git a/migrations/agendador_storage.sql b/migrations/agendador_storage.sql new file mode 100644 index 0000000..6d82893 --- /dev/null +++ b/migrations/agendador_storage.sql @@ -0,0 +1,56 @@ +-- ═══════════════════════════════════════════════════════════════════════════ +-- Storage bucket para imagens do Agendador Online +-- Execute no Supabase SQL Editor +-- ═══════════════════════════════════════════════════════════════════════════ + +-- ── 1. Criar o bucket ────────────────────────────────────────────────────── +INSERT INTO storage.buckets (id, name, public, file_size_limit, allowed_mime_types) +VALUES ( + 'agendador', + 'agendador', + true, -- público (URLs diretas sem assinar) + 5242880, -- 5 MB + ARRAY['image/jpeg','image/png','image/webp','image/gif'] +) +ON CONFLICT (id) DO UPDATE + SET public = true, + file_size_limit = 5242880, + allowed_mime_types = ARRAY['image/jpeg','image/png','image/webp','image/gif']; + +-- ── 2. Políticas ─────────────────────────────────────────────────────────── + +-- Leitura pública (anon e authenticated) +DROP POLICY IF EXISTS "agendador_storage_public_read" ON storage.objects; +CREATE POLICY "agendador_storage_public_read" + ON storage.objects FOR SELECT + USING (bucket_id = 'agendador'); + +-- Upload: apenas o dono da pasta (owner_id é o primeiro segmento do path) +DROP POLICY IF EXISTS "agendador_storage_owner_insert" ON storage.objects; +CREATE POLICY "agendador_storage_owner_insert" + ON storage.objects FOR INSERT + TO authenticated + WITH CHECK ( + bucket_id = 'agendador' + AND (storage.foldername(name))[1] = auth.uid()::text + ); + +-- Update/upsert pelo dono +DROP POLICY IF EXISTS "agendador_storage_owner_update" ON storage.objects; +CREATE POLICY "agendador_storage_owner_update" + ON storage.objects FOR UPDATE + TO authenticated + USING ( + bucket_id = 'agendador' + AND (storage.foldername(name))[1] = auth.uid()::text + ); + +-- Delete pelo dono +DROP POLICY IF EXISTS "agendador_storage_owner_delete" ON storage.objects; +CREATE POLICY "agendador_storage_owner_delete" + ON storage.objects FOR DELETE + TO authenticated + USING ( + bucket_id = 'agendador' + AND (storage.foldername(name))[1] = auth.uid()::text + ); diff --git a/migrations/payment_settings.sql b/migrations/payment_settings.sql new file mode 100644 index 0000000..b8ee28e --- /dev/null +++ b/migrations/payment_settings.sql @@ -0,0 +1,71 @@ +-- migrations/payment_settings.sql +-- Tabela de configurações de formas de pagamento por terapeuta/owner +-- Execute no Supabase SQL Editor + +CREATE TABLE IF NOT EXISTS payment_settings ( + id uuid DEFAULT gen_random_uuid() PRIMARY KEY, + owner_id uuid NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE, + tenant_id uuid REFERENCES tenants(id) ON DELETE CASCADE, + + -- Pix + pix_ativo boolean NOT NULL DEFAULT false, + pix_tipo text NOT NULL DEFAULT 'cpf', -- cpf | cnpj | email | celular | aleatoria + pix_chave text NOT NULL DEFAULT '', + pix_nome_titular text NOT NULL DEFAULT '', + + -- Depósito / TED + deposito_ativo boolean NOT NULL DEFAULT false, + deposito_banco text NOT NULL DEFAULT '', + deposito_agencia text NOT NULL DEFAULT '', + deposito_conta text NOT NULL DEFAULT '', + deposito_tipo_conta text NOT NULL DEFAULT 'corrente', -- corrente | poupanca + deposito_titular text NOT NULL DEFAULT '', + deposito_cpf_cnpj text NOT NULL DEFAULT '', + + -- Dinheiro (espécie) + dinheiro_ativo boolean NOT NULL DEFAULT false, + + -- Cartão (maquininha presencial) + cartao_ativo boolean NOT NULL DEFAULT false, + cartao_instrucao text NOT NULL DEFAULT '', + + -- Plano de saúde / Convênio + convenio_ativo boolean NOT NULL DEFAULT false, + convenio_lista text NOT NULL DEFAULT '', -- texto livre com convênios aceitos + + -- Observações gerais exibidas ao paciente + observacoes_pagamento text NOT NULL DEFAULT '', + + created_at timestamptz DEFAULT now(), + updated_at timestamptz DEFAULT now(), + + CONSTRAINT payment_settings_owner_id_key UNIQUE (owner_id) +); + +-- Índice por tenant +CREATE INDEX IF NOT EXISTS payment_settings_tenant_id_idx ON payment_settings(tenant_id); + +-- RLS +ALTER TABLE payment_settings ENABLE ROW LEVEL SECURITY; + +-- Owner lê e escreve os próprios dados +DROP POLICY IF EXISTS "payment_settings: owner full access" ON payment_settings; +CREATE POLICY "payment_settings: owner full access" + ON payment_settings + FOR ALL + USING (owner_id = auth.uid()) + WITH CHECK (owner_id = auth.uid()); + +-- updated_at automático +CREATE OR REPLACE FUNCTION update_payment_settings_updated_at() +RETURNS TRIGGER LANGUAGE plpgsql AS $$ +BEGIN + NEW.updated_at = now(); + RETURN NEW; +END; +$$; + +DROP TRIGGER IF EXISTS trg_payment_settings_updated_at ON payment_settings; +CREATE TRIGGER trg_payment_settings_updated_at + BEFORE UPDATE ON payment_settings + FOR EACH ROW EXECUTE FUNCTION update_payment_settings_updated_at(); diff --git a/migrations/professional_pricing.sql b/migrations/professional_pricing.sql new file mode 100644 index 0000000..2892900 --- /dev/null +++ b/migrations/professional_pricing.sql @@ -0,0 +1,61 @@ +-- migrations/professional_pricing.sql +-- Fase 1: Precificação — tabela de preços padrão por profissional +-- Execute no Supabase SQL Editor + +-- ───────────────────────────────────────────────────────────── +-- 1. Campo price em agenda_eventos +-- ───────────────────────────────────────────────────────────── +ALTER TABLE agenda_eventos + ADD COLUMN IF NOT EXISTS price numeric(10,2); + +-- ───────────────────────────────────────────────────────────── +-- 2. Tabela de preços por profissional +-- Chave: owner_id + determined_commitment_id (NULL = padrão) +-- ───────────────────────────────────────────────────────────── +CREATE TABLE IF NOT EXISTS professional_pricing ( + id uuid DEFAULT gen_random_uuid() PRIMARY KEY, + owner_id uuid NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE, + tenant_id uuid NOT NULL, + determined_commitment_id uuid REFERENCES determined_commitments(id) ON DELETE SET NULL, + -- NULL = preço padrão (fallback quando não há match por tipo) + price numeric(10,2) NOT NULL, + notes text, + created_at timestamptz DEFAULT now(), + updated_at timestamptz DEFAULT now(), + + CONSTRAINT professional_pricing_owner_commitment_key + UNIQUE (owner_id, determined_commitment_id) +); + +-- Índice por tenant (listagens do admin) +CREATE INDEX IF NOT EXISTS professional_pricing_tenant_idx + ON professional_pricing (tenant_id); + +-- ───────────────────────────────────────────────────────────── +-- 3. RLS +-- ───────────────────────────────────────────────────────────── +ALTER TABLE professional_pricing ENABLE ROW LEVEL SECURITY; + +-- Terapeuta lê e escreve seus próprios preços +DROP POLICY IF EXISTS "professional_pricing: owner full access" ON professional_pricing; +CREATE POLICY "professional_pricing: owner full access" + ON professional_pricing + FOR ALL + USING (owner_id = auth.uid()) + WITH CHECK (owner_id = auth.uid()); + +-- ───────────────────────────────────────────────────────────── +-- 4. updated_at automático +-- ───────────────────────────────────────────────────────────── +CREATE OR REPLACE FUNCTION update_professional_pricing_updated_at() +RETURNS TRIGGER LANGUAGE plpgsql AS $$ +BEGIN + NEW.updated_at = now(); + RETURN NEW; +END; +$$; + +DROP TRIGGER IF EXISTS trg_professional_pricing_updated_at ON professional_pricing; +CREATE TRIGGER trg_professional_pricing_updated_at + BEFORE UPDATE ON professional_pricing + FOR EACH ROW EXECUTE FUNCTION update_professional_pricing_updated_at(); diff --git a/migrations/recurrence_rules_price.sql b/migrations/recurrence_rules_price.sql new file mode 100644 index 0000000..a84164a --- /dev/null +++ b/migrations/recurrence_rules_price.sql @@ -0,0 +1,6 @@ +-- migrations/recurrence_rules_price.sql +-- Adiciona campo price em recurrence_rules para herança nas ocorrências virtuais +-- Execute no Supabase SQL Editor + +ALTER TABLE recurrence_rules + ADD COLUMN IF NOT EXISTS price numeric(10,2); diff --git a/migrations/remove_session_start_offset.sql b/migrations/remove_session_start_offset.sql new file mode 100644 index 0000000..1ddddef --- /dev/null +++ b/migrations/remove_session_start_offset.sql @@ -0,0 +1,6 @@ +-- Migration: remove session_start_offset_min from agenda_configuracoes +-- This field is replaced by hora_inicio in agenda_regras_semanais (work schedule per day) +-- The first session slot is now derived directly from hora_inicio of the work rule. + +ALTER TABLE public.agenda_configuracoes + DROP COLUMN IF EXISTS session_start_offset_min; diff --git a/migrations/support_sessions.sql b/migrations/support_sessions.sql new file mode 100644 index 0000000..ea75cf7 --- /dev/null +++ b/migrations/support_sessions.sql @@ -0,0 +1,235 @@ +-- ═══════════════════════════════════════════════════════════════════════════ +-- Support Sessions — Sessões de suporte técnico SaaS +-- ═══════════════════════════════════════════════════════════════════════════ +-- Permite que admins SaaS gerem tokens de acesso temporário para debug +-- de agendas de terapeutas, sem expor debug para usuários comuns. +-- +-- SEGURANÇA: +-- - RLS: só saas_admin pode criar/listar sessões +-- - Token é opaco (gen_random_uuid) — não adivinhável +-- - expires_at com TTL máximo de 60 minutos +-- - validate_support_session() retorna apenas true/false + tenant_id +-- (não expõe dados do admin) +-- ═══════════════════════════════════════════════════════════════════════════ + +-- ── Tabela ────────────────────────────────────────────────────────────────── + +CREATE TABLE IF NOT EXISTS "public"."support_sessions" ( + "id" uuid DEFAULT gen_random_uuid() NOT NULL, + "tenant_id" uuid NOT NULL, + "admin_id" uuid NOT NULL, + "token" text NOT NULL DEFAULT (replace(gen_random_uuid()::text, '-', '') || replace(gen_random_uuid()::text, '-', '')), + "expires_at" timestamp with time zone NOT NULL + DEFAULT (now() + interval '60 minutes'), + "created_at" timestamp with time zone NOT NULL DEFAULT now(), + + CONSTRAINT "support_sessions_pkey" PRIMARY KEY ("id"), + + CONSTRAINT "support_sessions_tenant_fk" + FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE CASCADE, + + CONSTRAINT "support_sessions_admin_fk" + FOREIGN KEY ("admin_id") REFERENCES "auth"."users"("id") ON DELETE CASCADE, + + CONSTRAINT "support_sessions_token_unique" UNIQUE ("token") +); + +-- ── Índices ────────────────────────────────────────────────────────────────── + +CREATE INDEX IF NOT EXISTS "support_sessions_token_idx" + ON "public"."support_sessions" ("token"); + +CREATE INDEX IF NOT EXISTS "support_sessions_tenant_idx" + ON "public"."support_sessions" ("tenant_id"); + +CREATE INDEX IF NOT EXISTS "support_sessions_expires_idx" + ON "public"."support_sessions" ("expires_at"); + +-- ── RLS ────────────────────────────────────────────────────────────────────── + +ALTER TABLE "public"."support_sessions" ENABLE ROW LEVEL SECURITY; + +-- Somente saas_admin pode ver suas próprias sessões de suporte +DROP POLICY IF EXISTS "support_sessions_saas_select" ON "public"."support_sessions"; +CREATE POLICY "support_sessions_saas_select" + ON "public"."support_sessions" + FOR SELECT + USING ( + auth.uid() = admin_id + AND EXISTS ( + SELECT 1 FROM public.profiles + WHERE id = auth.uid() + AND role = 'saas_admin' + ) + ); + +-- Somente saas_admin pode criar sessões de suporte +DROP POLICY IF EXISTS "support_sessions_saas_insert" ON "public"."support_sessions"; +CREATE POLICY "support_sessions_saas_insert" + ON "public"."support_sessions" + FOR INSERT + WITH CHECK ( + auth.uid() = admin_id + AND EXISTS ( + SELECT 1 FROM public.profiles + WHERE id = auth.uid() + AND role = 'saas_admin' + ) + ); + +-- Somente saas_admin pode deletar suas próprias sessões +DROP POLICY IF EXISTS "support_sessions_saas_delete" ON "public"."support_sessions"; +CREATE POLICY "support_sessions_saas_delete" + ON "public"."support_sessions" + FOR DELETE + USING ( + auth.uid() = admin_id + AND EXISTS ( + SELECT 1 FROM public.profiles + WHERE id = auth.uid() + AND role = 'saas_admin' + ) + ); + +-- ── RPC: create_support_session ─────────────────────────────────────────────── +-- Cria uma sessão de suporte para um tenant. +-- Apenas saas_admin pode chamar. TTL: 60 minutos (configurável via p_ttl_minutes). +-- Retorna: token, expires_at + +DROP FUNCTION IF EXISTS public.create_support_session(uuid, integer); +CREATE OR REPLACE FUNCTION public.create_support_session( + p_tenant_id uuid, + p_ttl_minutes integer DEFAULT 60 +) +RETURNS json +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_admin_id uuid; + v_role text; + v_token text; + v_expires timestamp with time zone; + v_session support_sessions; +BEGIN + -- Verifica autenticação + v_admin_id := auth.uid(); + IF v_admin_id IS NULL THEN + RAISE EXCEPTION 'Não autenticado.' USING ERRCODE = 'P0001'; + END IF; + + -- Verifica role saas_admin + SELECT role INTO v_role + FROM public.profiles + WHERE id = v_admin_id; + + IF v_role <> 'saas_admin' THEN + RAISE EXCEPTION 'Acesso negado. Somente saas_admin pode criar sessões de suporte.' + USING ERRCODE = 'P0002'; + END IF; + + -- Valida TTL (1 a 120 minutos) + IF p_ttl_minutes < 1 OR p_ttl_minutes > 120 THEN + RAISE EXCEPTION 'TTL inválido. Use entre 1 e 120 minutos.' + USING ERRCODE = 'P0003'; + END IF; + + -- Valida tenant + IF NOT EXISTS (SELECT 1 FROM public.tenants WHERE id = p_tenant_id) THEN + RAISE EXCEPTION 'Tenant não encontrado.' + USING ERRCODE = 'P0004'; + END IF; + + -- Gera token único (64 chars hex, sem pgcrypto) + v_token := replace(gen_random_uuid()::text, '-', '') || replace(gen_random_uuid()::text, '-', ''); + v_expires := now() + (p_ttl_minutes || ' minutes')::interval; + + -- Insere sessão + INSERT INTO public.support_sessions (tenant_id, admin_id, token, expires_at) + VALUES (p_tenant_id, v_admin_id, v_token, v_expires) + RETURNING * INTO v_session; + + RETURN json_build_object( + 'token', v_session.token, + 'expires_at', v_session.expires_at, + 'session_id', v_session.id + ); +END; +$$; + +-- ── RPC: validate_support_session ──────────────────────────────────────────── +-- Valida um token de suporte. Não requer autenticação (chamada pública). +-- Retorna: { valid: bool, tenant_id: uuid|null } +-- NUNCA retorna admin_id ou dados internos. + +DROP FUNCTION IF EXISTS public.validate_support_session(text); +CREATE OR REPLACE FUNCTION public.validate_support_session( + p_token text +) +RETURNS json +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_session support_sessions; +BEGIN + IF p_token IS NULL OR length(trim(p_token)) < 32 THEN + RETURN json_build_object('valid', false, 'tenant_id', null); + END IF; + + SELECT * INTO v_session + FROM public.support_sessions + WHERE token = p_token + AND expires_at > now() + LIMIT 1; + + IF NOT FOUND THEN + RETURN json_build_object('valid', false, 'tenant_id', null); + END IF; + + RETURN json_build_object( + 'valid', true, + 'tenant_id', v_session.tenant_id + ); +END; +$$; + +-- ── RPC: revoke_support_session ─────────────────────────────────────────────── +-- Revoga um token manualmente. Apenas o admin que criou pode revogar. + +DROP FUNCTION IF EXISTS public.revoke_support_session(text); +CREATE OR REPLACE FUNCTION public.revoke_support_session( + p_token text +) +RETURNS boolean +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_admin_id uuid; + v_role text; +BEGIN + v_admin_id := auth.uid(); + IF v_admin_id IS NULL THEN + RAISE EXCEPTION 'Não autenticado.' USING ERRCODE = 'P0001'; + END IF; + + SELECT role INTO v_role FROM public.profiles WHERE id = v_admin_id; + IF v_role <> 'saas_admin' THEN + RAISE EXCEPTION 'Acesso negado.' USING ERRCODE = 'P0002'; + END IF; + + DELETE FROM public.support_sessions + WHERE token = p_token + AND admin_id = v_admin_id; + + RETURN FOUND; +END; +$$; + +-- ── Cleanup automático (opcional) ──────────────────────────────────────────── +-- Sessões expiradas podem ser limpas periodicamente via pg_cron ou edge function. +-- DELETE FROM public.support_sessions WHERE expires_at < now(); diff --git a/migrations/unify_patient_id.sql b/migrations/unify_patient_id.sql new file mode 100644 index 0000000..4f58658 --- /dev/null +++ b/migrations/unify_patient_id.sql @@ -0,0 +1,34 @@ +-- ═══════════════════════════════════════════════════════════════════════════ +-- Unifica paciente_id → patient_id em agenda_eventos +-- ═══════════════════════════════════════════════════════════════════════════ +-- Contexto: +-- Campo legado `paciente_id` (texto, sem FK) coexiste com `patient_id` +-- (uuid, com FK → patients.id). Eventos antigos têm `paciente_id` preenchido +-- mas `patient_id = null`. Esta migration corrige isso e remove a coluna legada. +-- +-- SEGURANÇA: +-- Execute em transação. Verifique os counts antes do COMMIT. +-- ═══════════════════════════════════════════════════════════════════════════ + +BEGIN; + +-- 1. Copia paciente_id → patient_id onde patient_id ainda é null +-- paciente_id já é uuid no banco — sem necessidade de cast ou validação de regex +UPDATE public.agenda_eventos + SET patient_id = paciente_id + WHERE patient_id IS NULL + AND paciente_id IS NOT NULL; + +-- 2. Verificação: deve retornar 0 +SELECT COUNT(*) AS "orfaos_restantes" + FROM public.agenda_eventos + WHERE patient_id IS NULL AND paciente_id IS NOT NULL; + +-- 3. Remove a coluna legada +ALTER TABLE public.agenda_eventos DROP COLUMN IF EXISTS paciente_id; + +-- 4. Remove FK e coluna legada de terapeuta_id se existir equivalente +-- (opcional — remova o comentário se quiser limpar terapeuta_id também) +-- ALTER TABLE public.agenda_eventos DROP COLUMN IF EXISTS terapeuta_id; + +COMMIT; diff --git a/package-lock.json b/package-lock.json index 390382c..3ea8c71 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "sakai-vue", + "name": "agenciapsi", "version": "5.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "sakai-vue", + "name": "agenciapsi", "version": "5.0.0", "dependencies": { "@fullcalendar/core": "^6.1.20", @@ -21,6 +21,7 @@ "pinia": "^3.0.4", "primeicons": "^7.0.0", "primevue": "^4.5.4", + "quill": "^2.0.3", "tailwindcss-primeui": "^0.6.0", "vue": "^3.4.34", "vue-router": "^4.4.0" @@ -30,6 +31,7 @@ "@rushstack/eslint-patch": "^1.8.0", "@tailwindcss/vite": "^4.1.17", "@vitejs/plugin-vue": "^5.0.5", + "@vitest/ui": "^4.0.18", "@vue/eslint-config-prettier": "^9.0.0", "autoprefixer": "^10.4.24", "eslint": "^8.57.0", @@ -39,7 +41,8 @@ "sass": "^1.55.0", "tailwindcss": "^4.1.18", "unplugin-vue-components": "^0.27.3", - "vite": "^5.3.1" + "vite": "^5.3.1", + "vitest": "^4.0.18" } }, "node_modules/@antfu/utils": { @@ -365,6 +368,22 @@ "node": ">=12" } }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/netbsd-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", @@ -381,6 +400,22 @@ "node": ">=12" } }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/openbsd-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", @@ -397,6 +432,22 @@ "node": ">=12" } }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/sunos-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", @@ -1032,6 +1083,12 @@ "url": "https://opencollective.com/pkgr" } }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true + }, "node_modules/@primeuix/styled": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/@primeuix/styled/-/styled-0.7.4.tgz", @@ -1468,6 +1525,12 @@ "integrity": "sha512-ojSshQPKwVvSMR8yT2L/QtUkV5SXi/IfDiJ4/8d6UbTPjiHVmxZzUAzGD8Tzks1b9+qQkZa0isUOvYObedITaw==", "dev": true }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true + }, "node_modules/@supabase/auth-js": { "version": "2.95.3", "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.95.3.tgz", @@ -1799,6 +1862,22 @@ "vite": "^5.2.0 || ^6 || ^7" } }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1845,6 +1924,105 @@ "vue": "^3.2.25" } }, + "node_modules/@vitest/expect": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", + "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", + "dev": true, + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "chai": "^6.2.1", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", + "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", + "dev": true, + "dependencies": { + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", + "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", + "dev": true, + "dependencies": { + "@vitest/utils": "4.0.18", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", + "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", + "dev": true, + "dependencies": { + "@vitest/pretty-format": "4.0.18", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", + "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", + "dev": true, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/ui": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-4.0.18.tgz", + "integrity": "sha512-CGJ25bc8fRi8Lod/3GHSvXRKi7nBo3kxh0ApW4yCjmrWmRmlT53B5E08XRSZRliygG0aVNxLrBEqPYdz/KcCtQ==", + "dev": true, + "dependencies": { + "@vitest/utils": "4.0.18", + "fflate": "^0.8.2", + "flatted": "^3.3.3", + "pathe": "^2.0.3", + "sirv": "^3.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "4.0.18" + } + }, + "node_modules/@vitest/utils": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", + "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", + "dev": true, + "dependencies": { + "@vitest/pretty-format": "4.0.18", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/@vue/compiler-core": { "version": "3.5.28", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.28.tgz", @@ -2069,6 +2247,15 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/autoprefixer": { "version": "10.4.24", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.24.tgz", @@ -2230,6 +2417,15 @@ } ] }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "engines": { + "node": ">=18" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -2415,6 +2611,12 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true + }, "node_modules/esbuild": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", @@ -2686,6 +2888,20 @@ "node": ">=0.10.0" } }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==" + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2695,8 +2911,7 @@ "node_modules/fast-diff": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==" }, "node_modules/fast-glob": { "version": "3.3.3", @@ -2747,6 +2962,29 @@ "reusify": "^1.0.4" } }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "dev": true + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -3394,6 +3632,22 @@ "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "dev": true }, + "node_modules/lodash-es": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", + "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==" + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead." + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -3471,6 +3725,15 @@ "ufo": "^1.6.1" } }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -3534,6 +3797,16 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ] + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3590,6 +3863,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parchment": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/parchment/-/parchment-3.0.0.tgz", + "integrity": "sha512-HUrJFQ/StvgmXRcQ1ftY6VEZUq3jA2t9ncFN4F84J/vN0/FPpQF+8FKXb3l6fLces6q0uOHj6NJn+2xvZnxO6A==" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -3836,6 +4114,33 @@ } ] }, + "node_modules/quill": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/quill/-/quill-2.0.3.tgz", + "integrity": "sha512-xEYQBqfYx/sfb33VJiKnSJp8ehloavImQ2A6564GAbqG55PGw1dAWUn1MUbQB62t0azawUS2CZZhWCjO8gRvTw==", + "dependencies": { + "eventemitter3": "^5.0.1", + "lodash-es": "^4.17.21", + "parchment": "^3.0.0", + "quill-delta": "^5.1.0" + }, + "engines": { + "npm": ">=8.2.3" + } + }, + "node_modules/quill-delta": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz", + "integrity": "sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==", + "dependencies": { + "fast-diff": "^1.3.0", + "lodash.clonedeep": "^4.5.0", + "lodash.isequal": "^4.5.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/readdirp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", @@ -4009,6 +4314,26 @@ "node": ">=8" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true + }, + "node_modules/sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", + "dev": true, + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -4025,6 +4350,18 @@ "node": ">=0.10.0" } }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -4119,6 +4456,46 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true + }, + "node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", + "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -4131,6 +4508,15 @@ "node": ">=8.0" } }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -4409,6 +4795,601 @@ } } }, + "node_modules/vitest": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", + "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", + "dev": true, + "dependencies": { + "@vitest/expect": "4.0.18", + "@vitest/mocker": "4.0.18", + "@vitest/pretty-format": "4.0.18", + "@vitest/runner": "4.0.18", + "@vitest/snapshot": "4.0.18", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "es-module-lexer": "^1.7.0", + "expect-type": "^1.2.2", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^3.10.0", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3", + "vite": "^6.0.0 || ^7.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.0.18", + "@vitest/browser-preview": "4.0.18", + "@vitest/browser-webdriverio": "4.0.18", + "@vitest/ui": "4.0.18", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@vitest/mocker": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", + "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", + "dev": true, + "dependencies": { + "@vitest/spy": "4.0.18", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/vitest/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/vitest/node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, "node_modules/vue": { "version": "3.5.28", "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.28.tgz", @@ -4488,6 +5469,22 @@ "node": ">= 8" } }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -4698,6 +5695,13 @@ "dev": true, "optional": true }, + "@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "dev": true, + "optional": true + }, "@esbuild/netbsd-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", @@ -4705,6 +5709,13 @@ "dev": true, "optional": true }, + "@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "dev": true, + "optional": true + }, "@esbuild/openbsd-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", @@ -4712,6 +5723,13 @@ "dev": true, "optional": true }, + "@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "dev": true, + "optional": true + }, "@esbuild/sunos-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", @@ -5058,6 +6076,12 @@ "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", "dev": true }, + "@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true + }, "@primeuix/styled": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/@primeuix/styled/-/styled-0.7.4.tgz", @@ -5312,6 +6336,12 @@ "integrity": "sha512-ojSshQPKwVvSMR8yT2L/QtUkV5SXi/IfDiJ4/8d6UbTPjiHVmxZzUAzGD8Tzks1b9+qQkZa0isUOvYObedITaw==", "dev": true }, + "@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true + }, "@supabase/auth-js": { "version": "2.95.3", "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.95.3.tgz", @@ -5506,6 +6536,22 @@ "tailwindcss": "4.1.18" } }, + "@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "requires": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true + }, "@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -5546,6 +6592,81 @@ "dev": true, "requires": {} }, + "@vitest/expect": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", + "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", + "dev": true, + "requires": { + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "chai": "^6.2.1", + "tinyrainbow": "^3.0.3" + } + }, + "@vitest/pretty-format": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", + "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", + "dev": true, + "requires": { + "tinyrainbow": "^3.0.3" + } + }, + "@vitest/runner": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", + "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", + "dev": true, + "requires": { + "@vitest/utils": "4.0.18", + "pathe": "^2.0.3" + } + }, + "@vitest/snapshot": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", + "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", + "dev": true, + "requires": { + "@vitest/pretty-format": "4.0.18", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + } + }, + "@vitest/spy": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", + "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", + "dev": true + }, + "@vitest/ui": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-4.0.18.tgz", + "integrity": "sha512-CGJ25bc8fRi8Lod/3GHSvXRKi7nBo3kxh0ApW4yCjmrWmRmlT53B5E08XRSZRliygG0aVNxLrBEqPYdz/KcCtQ==", + "dev": true, + "requires": { + "@vitest/utils": "4.0.18", + "fflate": "^0.8.2", + "flatted": "^3.3.3", + "pathe": "^2.0.3", + "sirv": "^3.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3" + } + }, + "@vitest/utils": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", + "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", + "dev": true, + "requires": { + "@vitest/pretty-format": "4.0.18", + "tinyrainbow": "^3.0.3" + } + }, "@vue/compiler-core": { "version": "3.5.28", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.28.tgz", @@ -5735,6 +6856,12 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true + }, "autoprefixer": { "version": "10.4.24", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.24.tgz", @@ -5821,6 +6948,12 @@ "integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==", "dev": true }, + "chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true + }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -5953,6 +7086,12 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==" }, + "es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true + }, "esbuild": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", @@ -6137,6 +7276,17 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, + "eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==" + }, + "expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -6146,8 +7296,7 @@ "fast-diff": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==" }, "fast-glob": { "version": "3.3.3", @@ -6194,6 +7343,19 @@ "reusify": "^1.0.4" } }, + "fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "requires": {} + }, + "fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "dev": true + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -6583,6 +7745,21 @@ "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "dev": true }, + "lodash-es": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", + "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==" + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -6647,6 +7824,12 @@ "ufo": "^1.6.1" } }, + "mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true + }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -6692,6 +7875,12 @@ "boolbase": "^1.0.0" } }, + "obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -6733,6 +7922,11 @@ "p-limit": "^3.0.2" } }, + "parchment": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/parchment/-/parchment-3.0.0.tgz", + "integrity": "sha512-HUrJFQ/StvgmXRcQ1ftY6VEZUq3jA2t9ncFN4F84J/vN0/FPpQF+8FKXb3l6fLces6q0uOHj6NJn+2xvZnxO6A==" + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -6892,6 +8086,27 @@ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, + "quill": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/quill/-/quill-2.0.3.tgz", + "integrity": "sha512-xEYQBqfYx/sfb33VJiKnSJp8ehloavImQ2A6564GAbqG55PGw1dAWUn1MUbQB62t0azawUS2CZZhWCjO8gRvTw==", + "requires": { + "eventemitter3": "^5.0.1", + "lodash-es": "^4.17.21", + "parchment": "^3.0.0", + "quill-delta": "^5.1.0" + } + }, + "quill-delta": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz", + "integrity": "sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==", + "requires": { + "fast-diff": "^1.3.0", + "lodash.clonedeep": "^4.5.0", + "lodash.isequal": "^4.5.0" + } + }, "readdirp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", @@ -7001,6 +8216,23 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true + }, + "sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", + "dev": true, + "requires": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + } + }, "source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -7011,6 +8243,18 @@ "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==" }, + "stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true + }, + "std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -7075,6 +8319,34 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true + }, + "tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "dev": true + }, + "tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "requires": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + } + }, + "tinyrainbow": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", + "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "dev": true + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -7084,6 +8356,12 @@ "is-number": "^7.0.0" } }, + "totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true + }, "tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -7240,6 +8518,266 @@ "rollup": "^4.20.0" } }, + "vitest": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", + "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", + "dev": true, + "requires": { + "@vitest/expect": "4.0.18", + "@vitest/mocker": "4.0.18", + "@vitest/pretty-format": "4.0.18", + "@vitest/runner": "4.0.18", + "@vitest/snapshot": "4.0.18", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "es-module-lexer": "^1.7.0", + "expect-type": "^1.2.2", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^3.10.0", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3", + "vite": "^6.0.0 || ^7.0.0", + "why-is-node-running": "^2.3.0" + }, + "dependencies": { + "@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "dev": true, + "optional": true + }, + "@vitest/mocker": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", + "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", + "dev": true, + "requires": { + "@vitest/spy": "4.0.18", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + } + }, + "esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "requires": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "requires": { + "@types/estree": "^1.0.0" + } + }, + "vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "requires": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "fsevents": "~2.3.3", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + } + } + } + }, "vue": { "version": "3.5.28", "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.28.tgz", @@ -7290,6 +8828,16 @@ "isexe": "^2.0.0" } }, + "why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "requires": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + } + }, "word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", diff --git a/package.json b/package.json index a947a66..430c5fb 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,16 @@ { - "name": "sakai-vue", + "name": "agenciapsi", "version": "5.0.0", + "type": "module", "scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview", - "lint": "eslint --fix . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore" + "lint": "eslint --fix . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore", + "test": "vitest run", + "test:watch": "vitest", + "test:ui": "vitest --ui", + "simulate": "node scripts/simulation/simulateUsage.js" }, "dependencies": { "@fullcalendar/core": "^6.1.20", @@ -21,6 +26,7 @@ "pinia": "^3.0.4", "primeicons": "^7.0.0", "primevue": "^4.5.4", + "quill": "^2.0.3", "tailwindcss-primeui": "^0.6.0", "vue": "^3.4.34", "vue-router": "^4.4.0" @@ -30,6 +36,7 @@ "@rushstack/eslint-patch": "^1.8.0", "@tailwindcss/vite": "^4.1.17", "@vitejs/plugin-vue": "^5.0.5", + "@vitest/ui": "^4.0.18", "@vue/eslint-config-prettier": "^9.0.0", "autoprefixer": "^10.4.24", "eslint": "^8.57.0", @@ -39,6 +46,7 @@ "sass": "^1.55.0", "tailwindcss": "^4.1.18", "unplugin-vue-components": "^0.27.3", - "vite": "^5.3.1" + "vite": "^5.3.1", + "vitest": "^4.0.18" } } diff --git a/scripts/simulation/simulateUsage.js b/scripts/simulation/simulateUsage.js new file mode 100644 index 0000000..b99a9de --- /dev/null +++ b/scripts/simulation/simulateUsage.js @@ -0,0 +1,555 @@ +/** + * simulateUsage.js + * + * Gera dois arquivos SQL: + * logs/simulation-seed.sql → insere dados de simulação + * logs/simulation-cleanup.sql → remove os dados inseridos + * + * e um relatório legível: + * logs/simulation-report.txt + * logs/simulation-log.txt + * + * COMO USAR: + * 1. Preencha scripts/simulation/simulation.config.js com seu OWNER_ID e TENANT_ID + * 2. npm run simulate + * 3. Abra o Supabase SQL Editor e rode simulation-seed.sql + * 4. Teste o sistema + * 5. Quando terminar, rode simulation-cleanup.sql para limpar + */ + +import fs from 'fs' +import path from 'path' +import { config } from './simulation.config.js' +import { logInfo, logWarning, logError, getLog } from './simulationLogger.js' + +// ─── Validação ──────────────────────────────────────────────────────────────── + +if (config.OWNER_ID === 'SEU-OWNER-UUID-AQUI' || config.TENANT_ID === 'SEU-TENANT-UUID-AQUI') { + console.error('\n❌ ERRO: Preencha OWNER_ID e TENANT_ID em scripts/simulation/simulation.config.js\n') + process.exit(1) +} + +// ─── Dados brasileiros falsos ───────────────────────────────────────────────── + +const NOMES = [ + ['Ana', 'Beatriz', 'Carla', 'Daniela', 'Fernanda', 'Gabriela', 'Helena', 'Isabela', + 'Juliana', 'Karen', 'Laura', 'Mariana', 'Natália', 'Olivia', 'Patrícia'], + ['Carlos', 'Daniel', 'Eduardo', 'Felipe', 'Gustavo', 'Henrique', 'Igor', 'João', + 'Lucas', 'Marcos', 'Nelson', 'Otávio', 'Paulo', 'Rafael', 'Sérgio'], +] + +const SOBRENOMES = [ + 'Silva', 'Santos', 'Oliveira', 'Souza', 'Lima', 'Ferreira', 'Rodrigues', + 'Almeida', 'Costa', 'Gomes', 'Martins', 'Pereira', 'Carvalho', 'Rocha', 'Nunes', +] + +const MODALIDADES = ['presencial', 'online', 'presencial', 'presencial'] // ponderado + +// ─── Utilitários ───────────────────────────────────────────────────────────── + +let _rng = 1 + +function rng () { + // LCG determinístico para gerar sequência reproduzível + _rng = (_rng * 1664525 + 1013904223) & 0xffffffff + return Math.abs(_rng) / 0x80000000 +} + +function pick (arr) { return arr[Math.floor(rng() * arr.length)] } + +function uuid () { + // gera UUID v4-like determinístico baseado no nosso rng + const h = () => Math.floor(rng() * 0x10000).toString(16).padStart(4, '0') + return `${h()}${h()}-${h()}-4${h().slice(1)}-${(8 + Math.floor(rng() * 4)).toString(16)}${h().slice(1)}-${h()}${h()}${h()}` +} + +function addDays (date, n) { + const d = new Date(date) + d.setDate(d.getDate() + n) + return d +} + +function toISO (date) { + return date.toISOString().split('T')[0] +} + +function toISODateTime (date, hh, mm) { + return `${toISO(date)}T${String(hh).padStart(2,'0')}:${String(mm).padStart(2,'0')}:00` +} + +function sqlStr (v) { + if (v === null || v === undefined) return 'NULL' + return `'${String(v).replace(/'/g, "''")}'` +} + +function weekdayName (n) { + return ['Dom','Seg','Ter','Qua','Qui','Sex','Sáb'][n] +} + +// ─── Gerador de nomes únicos ────────────────────────────────────────────────── + +const usedNames = new Set() + +function fakeName () { + let attempts = 0 + while (attempts < 50) { + const gender = rng() > 0.5 ? 0 : 1 + const nome = pick(NOMES[gender]) + const sobrenome = pick(SOBRENOMES) + const full = `${nome} ${sobrenome}` + if (!usedNames.has(full)) { + usedNames.add(full) + return full + } + attempts++ + } + return `Paciente ${usedNames.size + 1}` +} + +function fakeCpf () { + const n = () => Math.floor(rng() * 9) + 1 + return `${n()}${n()}${n()}${n()}${n()}${n()}${n()}${n()}${n()}${n()}${n()}` +} + +function fakePhone () { + const ddd = [11,21,31,41,51,61,71,81,91][Math.floor(rng() * 9)] + const num = Math.floor(rng() * 900000000) + 900000000 + return `(${ddd}) 9${String(num).slice(1,5)}-${String(num).slice(5,9)}` +} + +function fakeEmail (nome) { + const slug = nome.toLowerCase() + .replace(/\s+/g, '.') + .normalize('NFD').replace(/[\u0300-\u036f]/g, '') + const num = Math.floor(rng() * 99) + 1 + const domains = ['gmail.com','hotmail.com','outlook.com','yahoo.com.br'] + return `${slug}${num}@${pick(domains)}` +} + +// ─── Blocos SQL ─────────────────────────────────────────────────────────────── + +const seedLines = [] +const cleanupIds = { + patients: [], + agendaEventos: [], + recurrenceRules: [], + recurrenceExceptions: [], + agendadorSolicitacoes: [], + agendaConfiguracoes: [], + agendaRegrasSemanais: [], +} + +function emit (line) { seedLines.push(line) } + +// ─── Construção da simulação ────────────────────────────────────────────────── + +const TODAY = new Date() +TODAY.setHours(0, 0, 0, 0) +const PAST_START = addDays(TODAY, -config.DAYS_BACK) +const FUTURE_END = addDays(TODAY, config.SIMULATION_DAYS) + +const ownerId = config.OWNER_ID +const tenantId = config.TENANT_ID + +logInfo('Iniciando simulação...') +logInfo(`OWNER_ID: ${ownerId}`) +logInfo(`TENANT_ID: ${tenantId}`) +logInfo(`Período: ${toISO(PAST_START)} → ${toISO(FUTURE_END)}`) + +// ─── 1. Pacientes ───────────────────────────────────────────────────────────── + +emit('-- ============================================================') +emit('-- SIMULAÇÃO AgenciaPsi — gerado por npm run simulate') +emit(`-- Data: ${new Date().toLocaleString('pt-BR')}`) +emit('-- ============================================================') +emit('') +emit('-- Desabilita triggers para permitir inserts de simulação') +emit('SET session_replication_role = replica;') +emit('') +emit('BEGIN;') +emit('') +emit('-- ─── 1. Pacientes ───────────────────────────────────────────────────────────') +emit('') + +const patients = [] + +for (let i = 0; i < config.PATIENTS_COUNT; i++) { + const id = uuid() + const nome = fakeName() + const parts = nome.split(' ') + const email = fakeEmail(nome) + const tel = fakePhone() + const cpf = fakeCpf() + + patients.push({ id, nome_completo: nome, email, telefone: tel }) + cleanupIds.patients.push(id) + + emit(`INSERT INTO patients (id, tenant_id, owner_id, responsible_member_id, nome_completo, email_principal, telefone, cpf, patient_scope, status)`) + emit(` VALUES (${sqlStr(id)}, ${sqlStr(tenantId)}, ${sqlStr(ownerId)},`) + emit(` (SELECT id FROM tenant_members WHERE user_id = ${sqlStr(ownerId)} AND tenant_id = ${sqlStr(tenantId)} LIMIT 1),`) + emit(` ${sqlStr(nome)}, ${sqlStr(email)}, ${sqlStr(tel)}, ${sqlStr(cpf)}, 'clinic', 'Ativo');`) +} + +logInfo(`✔ ${patients.length} pacientes criados`) +emit('') + +// ─── 2. Configurações de agenda ─────────────────────────────────────────────── + +emit('-- ─── 2. Configurações de agenda ─────────────────────────────────────────────') +emit('') + +const pausas = [ + { weekday: 1, start: '12:00', end: '13:00', label: 'Almoço' }, + { weekday: 2, start: '12:00', end: '13:00', label: 'Almoço' }, + { weekday: 3, start: '12:00', end: '13:00', label: 'Almoço' }, + { weekday: 4, start: '12:00', end: '13:00', label: 'Almoço' }, + { weekday: 5, start: '12:00', end: '13:00', label: 'Almoço' }, +] + +emit(`INSERT INTO agenda_configuracoes (owner_id, tenant_id, session_duration_min, session_break_min, pausas_semanais, online_ativo, setup_clinica_concluido)`) +emit(` VALUES (${sqlStr(ownerId)}, ${sqlStr(tenantId)},`) +emit(` ${config.SESSION_DURATION_MIN}, 10, '${JSON.stringify(pausas)}'::jsonb, true, true)`) +emit(` ON CONFLICT (owner_id) DO NOTHING;`) +emit('') + +logInfo('✔ agenda_configuracoes inserida') + +// ─── 3. Regras semanais de disponibilidade ──────────────────────────────────── + +emit('-- ─── 3. Regras semanais ─────────────────────────────────────────────────────') +emit('') + +const workDays = [1, 2, 3, 4, 5] // seg–sex +for (const dia of workDays) { + const rid = uuid() + cleanupIds.agendaRegrasSemanais.push(rid) + emit(`INSERT INTO agenda_regras_semanais (id, owner_id, tenant_id, dia_semana, hora_inicio, hora_fim, ativo)`) + emit(` VALUES (${sqlStr(rid)}, ${sqlStr(ownerId)}, ${sqlStr(tenantId)}, ${dia}, '08:00', '18:00', true);`) +} + +logInfo(`✔ ${workDays.length} regras semanais inseridas`) +emit('') + +// ─── 4. Eventos avulsos (passado) ───────────────────────────────────────────── + +emit('-- ─── 4. Eventos avulsos (passado) ──────────────────────────────────────────') +emit('') + +const avulsoCount = 3 +const avulsoPatients = patients.slice(0, avulsoCount) +let avulsosCreated = 0 + +// Avulsos usam 13h para não conflitar com séries (9h–12h e 14h–17h) +for (const pat of avulsoPatients) { + const daysAgo = Math.floor(rng() * config.DAYS_BACK) + 1 + const date = addDays(TODAY, -daysAgo) + if (date.getDay() === 0 || date.getDay() === 6) continue // pular fds + + const hour = 13 + const startDT = toISODateTime(date, hour, 0) + const endDT = toISODateTime(date, hour, 50) + const evId = uuid() + const modal = pick(MODALIDADES) + const statuses = ['realizado', 'faltou', 'agendado'] + const status = pick(statuses) + + cleanupIds.agendaEventos.push(evId) + + emit(`INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, titulo)`) + emit(` VALUES (${sqlStr(evId)}, ${sqlStr(ownerId)}, ${sqlStr(tenantId)}, ${sqlStr(pat.id)},`) + emit(` 'sessao', ${sqlStr(status)}, ${sqlStr(startDT)}, ${sqlStr(endDT)}, ${sqlStr(modal)}, 'Sessão avulsa');`) + + avulsosCreated++ +} + +logInfo(`✔ ${avulsosCreated} eventos avulsos criados`) +emit('') + +// ─── 5. Séries de recorrência ───────────────────────────────────────────────── + +emit('-- ─── 5. Séries de recorrência ───────────────────────────────────────────────') +emit('') + +const ruleStartDate = addDays(TODAY, -config.DAYS_BACK) +const ruleEndDate = addDays(TODAY, config.SIMULATION_DAYS) + +// Distribui pacientes pelas séries (cicla se menos pacientes que séries) +const seriesPatients = patients.slice(0, config.RECURRENCE_RULES_COUNT) +const types = ['weekly', 'weekly', 'weekly', 'biweekly', 'custom_weekdays', 'weekly'] +const wdays = [[1], [2], [4], [1], [1,3], [3]] +// Cada série tem seu próprio horário para evitar sobreposição +const ruleHours = [9, 10, 11, 14, 15, 16] + +const recurrenceRules = [] + +for (let i = 0; i < config.RECURRENCE_RULES_COUNT; i++) { + const pat = seriesPatients[i % seriesPatients.length] + const type = types[i] || 'weekly' + const weekdays = wdays[i] || [1] + const modal = pick(MODALIDADES) + const ruleId = uuid() + const hour = ruleHours[i] || (9 + i) + const startTime = `${String(hour).padStart(2,'0')}:00` + const endTime = `${String(hour).padStart(2,'0')}:50` + const weekdaysArr = `ARRAY[${weekdays.join(',')}]::smallint[]` + + recurrenceRules.push({ id: ruleId, patient: pat, type, weekdays, start_date: ruleStartDate, modal, hour }) + cleanupIds.recurrenceRules.push(ruleId) + + emit(`INSERT INTO recurrence_rules (id, owner_id, tenant_id, patient_id, type, weekdays, interval, start_date, end_date, status, start_time, end_time, modalidade)`) + emit(` VALUES (${sqlStr(ruleId)}, ${sqlStr(ownerId)}, ${sqlStr(tenantId)}, ${sqlStr(pat.id)},`) + emit(` ${sqlStr(type)}, ${weekdaysArr}, 1, ${sqlStr(toISO(ruleStartDate))}, ${sqlStr(toISO(ruleEndDate))},`) + emit(` 'ativo', ${sqlStr(startTime)}, ${sqlStr(endTime)}, ${sqlStr(modal)});`) +} + +logInfo(`✔ ${recurrenceRules.length} regras de recorrência criadas`) +emit('') + +// ─── 6. Exceções de recorrência (passado) ──────────────────────────────────── + +emit('-- ─── 6. Exceções de recorrência ────────────────────────────────────────────') +emit('') + +let excFaltou = 0, excRemarcado = 0, excCancelado = 0 + +for (const rr of recurrenceRules) { + // Gera datas das ocorrências passadas + const occs = [] + let cur = new Date(rr.start_date) + // avançar para o primeiro dia correto + while (cur <= TODAY) { + const dow = cur.getDay() + if (rr.weekdays.includes(dow)) { + if (cur < TODAY) occs.push(new Date(cur)) + } + cur = addDays(cur, 1) + } + + for (const occDate of occs) { + const r = rng() + const dateStr = toISO(occDate) + + if (r < config.RATE_FALTOU) { + const excId = uuid() + cleanupIds.recurrenceExceptions.push(excId) + emit(`INSERT INTO recurrence_exceptions (id, recurrence_id, tenant_id, original_date, type, new_date)`) + emit(` VALUES (${sqlStr(excId)}, ${sqlStr(rr.id)}, ${sqlStr(tenantId)}, ${sqlStr(dateStr)}, 'patient_missed', NULL);`) + excFaltou++ + } else if (r < config.RATE_FALTOU + config.RATE_REMARCADO) { + const offset = Math.floor(rng() * 4) + 1 + const newDate = addDays(occDate, offset) + // não remarcar para fds + if (newDate.getDay() === 0 || newDate.getDay() === 6) continue + const excId = uuid() + cleanupIds.recurrenceExceptions.push(excId) + emit(`INSERT INTO recurrence_exceptions (id, recurrence_id, tenant_id, original_date, type, new_date)`) + emit(` VALUES (${sqlStr(excId)}, ${sqlStr(rr.id)}, ${sqlStr(tenantId)}, ${sqlStr(dateStr)}, 'reschedule_session', ${sqlStr(toISO(newDate))});`) + excRemarcado++ + } else if (r < config.RATE_FALTOU + config.RATE_REMARCADO + config.RATE_CANCELADO) { + const excId = uuid() + cleanupIds.recurrenceExceptions.push(excId) + emit(`INSERT INTO recurrence_exceptions (id, recurrence_id, tenant_id, original_date, type, new_date)`) + emit(` VALUES (${sqlStr(excId)}, ${sqlStr(rr.id)}, ${sqlStr(tenantId)}, ${sqlStr(dateStr)}, 'cancel_session', NULL);`) + excCancelado++ + } + } +} + +logInfo(`✔ Exceções: ${excFaltou} faltou, ${excRemarcado} remarcado, ${excCancelado} cancelado`) +emit('') + +// ─── 7. Sessões reais para ocorrências passadas (realizado/faltou) ──────────── + +emit('-- ─── 7. Sessões reais (passado — realizado/faltou) ────────────────────────') +emit('') + +let realSessionsCreated = 0 + +for (const rr of recurrenceRules) { + let cur2 = new Date(rr.start_date) + while (cur2 < TODAY) { + const dow = cur2.getDay() + if (rr.weekdays.includes(dow)) { + const dateStr = toISO(cur2) + const evId = uuid() + const hh = String(rr.hour).padStart(2, '0') + const startDT = `${dateStr}T${hh}:00:00` + const endDT = `${dateStr}T${hh}:50:00` + // status baseado nas exceções: se há exceção faltou → faltou, else → realizado + // simplificado: 80% realizado, 20% faltou para sessões passadas + const status = rng() < 0.8 ? 'realizado' : 'faltou' + + cleanupIds.agendaEventos.push(evId) + + emit(`INSERT INTO agenda_eventos (id, owner_id, tenant_id, patient_id, tipo, status, inicio_em, fim_em, modalidade, recurrence_id, recurrence_date)`) + emit(` VALUES (${sqlStr(evId)}, ${sqlStr(ownerId)}, ${sqlStr(tenantId)}, ${sqlStr(rr.patient.id)},`) + emit(` 'sessao', ${sqlStr(status)}, ${sqlStr(startDT)}, ${sqlStr(endDT)}, ${sqlStr(rr.modal)}, ${sqlStr(rr.id)}, ${sqlStr(dateStr)});`) + + realSessionsCreated++ + } + cur2 = addDays(cur2, 1) + } +} + +logInfo(`✔ ${realSessionsCreated} sessões reais (passado) criadas`) +emit('') + +// ─── 8. Solicitações do Agendador Público ───────────────────────────────────── + +emit('-- ─── 8. Agendador Público — solicitações pendentes ─────────────────────────') +emit('') + +const agendadorStatuses = ['pendente', 'pendente', 'pendente', 'autorizado', 'recusado'] + +for (let i = 0; i < config.AGENDADOR_REQUESTS_COUNT; i++) { + const nome = fakeName() + const parts2 = nome.split(' ') + const primeiro = parts2[0] + const sobrenome = parts2.slice(1).join(' ') + const email = fakeEmail(nome) + const cel = fakePhone() + const daysAhead = Math.floor(rng() * 14) + 1 + const reqDate = addDays(TODAY, daysAhead) + if (reqDate.getDay() === 0 || reqDate.getDay() === 6) continue + const hour = config.WORK_HOUR_START + Math.floor(rng() * 6) + const hora = `${String(hour).padStart(2,'0')}:00` + const modal = pick(MODALIDADES) + const status = pick(agendadorStatuses) + const solId = uuid() + + cleanupIds.agendadorSolicitacoes.push(solId) + + emit(`INSERT INTO agendador_solicitacoes (id, owner_id, tenant_id, paciente_nome, paciente_sobrenome, paciente_email, paciente_celular, tipo, modalidade, data_solicitada, hora_solicitada, status)`) + emit(` VALUES (${sqlStr(solId)}, ${sqlStr(ownerId)}, ${sqlStr(tenantId)}, ${sqlStr(primeiro)}, ${sqlStr(sobrenome)}, ${sqlStr(email)}, ${sqlStr(cel)},`) + emit(` ${sqlStr(pick(['primeira', 'retorno', 'reagendar']))}, ${sqlStr(modal)}, ${sqlStr(toISO(reqDate))}, ${sqlStr(hora)}, ${sqlStr(status)});`) +} + +logInfo(`✔ ${config.AGENDADOR_REQUESTS_COUNT} solicitações do agendador criadas`) +emit('') + +// ─── 9. Fechar transação ────────────────────────────────────────────────────── + +emit('COMMIT;') +emit('') +emit('-- Restaura comportamento normal dos triggers') +emit('SET session_replication_role = DEFAULT;') +emit('') +emit('-- ─── Fim do seed ────────────────────────────────────────────────────────────') + +// ─── Gerar SQL de cleanup ──────────────────────────────────────────────────── + +function buildCleanupSQL () { + const lines = [] + lines.push('-- ============================================================') + lines.push('-- CLEANUP — remove dados da simulação AgenciaPsi') + lines.push(`-- Data: ${new Date().toLocaleString('pt-BR')}`) + lines.push('-- ============================================================') + lines.push('') + lines.push('SET session_replication_role = replica;') + lines.push('') + lines.push('BEGIN;') + lines.push('') + + function delBlock (table, ids) { + if (ids.length === 0) return + const quoted = ids.map(id => `'${id}'`).join(', ') + lines.push(`DELETE FROM ${table} WHERE id IN (${quoted});`) + } + + delBlock('recurrence_exceptions', cleanupIds.recurrenceExceptions) + lines.push('') + delBlock('agenda_eventos', cleanupIds.agendaEventos) + lines.push('') + delBlock('recurrence_rules', cleanupIds.recurrenceRules) + lines.push('') + delBlock('agendador_solicitacoes', cleanupIds.agendadorSolicitacoes) + lines.push('') + delBlock('agenda_regras_semanais', cleanupIds.agendaRegrasSemanais) + lines.push('') + // agenda_configuracoes: PK é owner_id, não id + lines.push(`-- Descomente se quiser remover também as configurações de agenda:`) + lines.push(`-- DELETE FROM agenda_configuracoes WHERE owner_id = ${sqlStr(ownerId)};`) + lines.push('') + delBlock('patients', cleanupIds.patients) + lines.push('') + lines.push('COMMIT;') + lines.push('') + lines.push('SET session_replication_role = DEFAULT;') + lines.push('') + lines.push('-- ─── Fim do cleanup ─────────────────────────────────────────────────────────') + + return lines.join('\n') +} + +// ─── Relatório ──────────────────────────────────────────────────────────────── + +function buildReport () { + const lines = [] + lines.push('============================================================') + lines.push(' RELATÓRIO DE SIMULAÇÃO — AgenciaPsi') + lines.push(` Gerado em: ${new Date().toLocaleString('pt-BR')}`) + lines.push('============================================================') + lines.push('') + lines.push(`OWNER_ID: ${ownerId}`) + lines.push(`TENANT_ID: ${tenantId}`) + lines.push('') + lines.push('─── Dados gerados ─────────────────────────────────────────') + lines.push(` Pacientes: ${patients.length}`) + lines.push(` Séries de recorrência: ${recurrenceRules.length}`) + lines.push(` Sessões reais (passado): ${realSessionsCreated}`) + lines.push(` Eventos avulsos: ${avulsosCreated}`) + lines.push(` Exceções — faltou: ${excFaltou}`) + lines.push(` Exceções — remarcado: ${excRemarcado}`) + lines.push(` Exceções — cancelado: ${excCancelado}`) + lines.push(` Solicitações agendador: ${config.AGENDADOR_REQUESTS_COUNT}`) + lines.push('') + lines.push('─── Pacientes criados ─────────────────────────────────────') + for (const p of patients) { + lines.push(` [${p.id}] ${p.nome_completo} — ${p.email}`) + } + lines.push('') + lines.push('─── Séries de recorrência ─────────────────────────────────') + for (const r of recurrenceRules) { + const dias = r.weekdays.map(d => weekdayName(d)).join(', ') + lines.push(` [${r.id}]`) + lines.push(` Paciente: ${r.patient.nome_completo}`) + lines.push(` Tipo: ${r.type} | Dias: ${dias}`) + lines.push(` Período: ${toISO(r.start_date)} → ${toISO(FUTURE_END)}`) + } + lines.push('') + lines.push('─── Como testar ───────────────────────────────────────────') + lines.push(' 1. Abra o Supabase SQL Editor') + lines.push(' 2. Cole e rode: logs/simulation-seed.sql') + lines.push(' 3. Acesse a agenda — os eventos devem aparecer') + lines.push(' 4. Acesse Pacientes — pacientes simulados aparecem na lista') + lines.push(' 5. Acesse Agendamentos Recebidos — solicitações pendentes') + lines.push(' 6. Quando terminar, rode: logs/simulation-cleanup.sql') + lines.push('') + lines.push('============================================================') + + return lines.join('\n') +} + +// ─── Salvar arquivos ───────────────────────────────────────────────────────── + +const outDir = path.resolve(config.OUTPUT_DIR) +if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true }) + +const seedPath = path.join(outDir, 'simulation-seed.sql') +const cleanupPath = path.join(outDir, 'simulation-cleanup.sql') +const reportPath = path.join(outDir, 'simulation-report.txt') +const logPath = path.join(outDir, 'simulation-log.txt') + +fs.writeFileSync(seedPath, seedLines.join('\n'), 'utf-8') +fs.writeFileSync(cleanupPath, buildCleanupSQL(), 'utf-8') +fs.writeFileSync(reportPath, buildReport(), 'utf-8') + +logInfo(`✔ Seed SQL: ${seedPath}`) +logInfo(`✔ Cleanup SQL: ${cleanupPath}`) +logInfo(`✔ Relatório: ${reportPath}`) + +fs.writeFileSync(logPath, getLog(), 'utf-8') + +console.log('\n✅ Simulação concluída. Arquivos em logs/') +console.log(' → Rode simulation-seed.sql no Supabase SQL Editor para inserir os dados') +console.log(' → Rode simulation-cleanup.sql quando quiser remover\n') diff --git a/scripts/simulation/simulation.config.js b/scripts/simulation/simulation.config.js new file mode 100644 index 0000000..0111941 --- /dev/null +++ b/scripts/simulation/simulation.config.js @@ -0,0 +1,43 @@ +/** + * simulation.config.js + * + * Preencha OWNER_ID e TENANT_ID com os valores reais do seu usuário. + * Para encontrar esses valores: + * - OWNER_ID: SELECT id FROM auth.users WHERE email = 'seu@email.com'; + * - TENANT_ID: SELECT id FROM tenants WHERE name ILIKE '%nome da clínica%'; + * + * Depois rode: npm run simulate + * Os arquivos serão gerados em logs/ + */ + +export const config = { + // ─── OBRIGATÓRIO — preencha com seus valores reais ────────────────────────── + OWNER_ID: 'aaaaaaaa-0002-0002-0002-000000000002', + TENANT_ID: 'bbbbbbbb-0002-0002-0002-000000000002', + + // ─── Configurações de simulação ────────────────────────────────────────────── + SIMULATION_DAYS: 90, // quantos dias para o futuro gerar sessões + DAYS_BACK: 30, // quantos dias no passado (sessões já realizadas) + + // ─── Parâmetros dos pacientes ──────────────────────────────────────────────── + PATIENTS_COUNT: 8, // quantos pacientes criar (patient_scope = 'clinic') + + // ─── Parâmetros das séries de recorrência ──────────────────────────────────── + RECURRENCE_RULES_COUNT: 6, // quantas séries semanais criar + + // ─── Taxas de exceção (0.0 a 1.0) ──────────────────────────────────────────── + RATE_FALTOU: 0.10, // 10% das sessões passadas → faltou + RATE_REMARCADO: 0.08, // 8% → remarcado para outro dia + RATE_CANCELADO: 0.05, // 5% → cancelado + + // ─── Agendador público ──────────────────────────────────────────────────────── + AGENDADOR_REQUESTS_COUNT: 5, // solicitações pendentes no agendador público + + // ─── Horário de trabalho ───────────────────────────────────────────────────── + WORK_HOUR_START: 8, // 08:00 + WORK_HOUR_END: 18, // 18:00 + SESSION_DURATION_MIN: 50, // duração padrão em minutos + + // ─── Saída ──────────────────────────────────────────────────────────────────── + OUTPUT_DIR: 'logs', +} diff --git a/scripts/simulation/simulationLogger.js b/scripts/simulation/simulationLogger.js new file mode 100644 index 0000000..8e4ddb7 --- /dev/null +++ b/scripts/simulation/simulationLogger.js @@ -0,0 +1,33 @@ +/** + * simulationLogger.js + * + * Logger simples que imprime no console e acumula linhas para salvar em arquivo. + */ + +const lines = [] + +function timestamp () { + return new Date().toISOString().replace('T', ' ').substring(0, 19) +} + +export function logInfo (msg) { + const line = `[INFO] ${timestamp()} ${msg}` + console.log(line) + lines.push(line) +} + +export function logWarning (msg) { + const line = `[WARN] ${timestamp()} ${msg}` + console.warn(line) + lines.push(line) +} + +export function logError (msg) { + const line = `[ERROR] ${timestamp()} ${msg}` + console.error(line) + lines.push(line) +} + +export function getLog () { + return lines.join('\n') +} diff --git a/src/App.vue b/src/App.vue index 2fe97d3..8359708 100644 --- a/src/App.vue +++ b/src/App.vue @@ -4,6 +4,8 @@ import { useRoute } from 'vue-router' import { supabase } from '@/lib/supabase/client' import { useTenantStore } from '@/stores/tenantStore' import { useEntitlementsStore } from '@/stores/entitlementsStore' +import AjudaDrawer from '@/components/AjudaDrawer.vue' +import { fetchDocsForPath } from '@/composables/useAjuda' const route = useRoute() const tenantStore = useTenantStore() @@ -114,6 +116,9 @@ onMounted(async () => { // snapshot inicial await debugSnapshot('mounted') + + // Carrega docs de ajuda para a rota inicial + fetchDocsForPath(route.path) }) // snapshot a cada navegação (isso é o que vai te salvar) @@ -121,10 +126,17 @@ watch( () => route.fullPath, async (to, from) => { await debugSnapshot(`route change: ${from} -> ${to}`) + // Atualiza docs de ajuda ao navegar + fetchDocsForPath(route.path) } ) \ No newline at end of file diff --git a/src/assets/demo/code.scss b/src/assets/demo/code.scss deleted file mode 100644 index d0d2e9a..0000000 --- a/src/assets/demo/code.scss +++ /dev/null @@ -1,17 +0,0 @@ -pre.app-code { - background-color: var(--code-background); - margin: 0 0 1rem 0; - padding: 0; - border-radius: var(--content-border-radius); - overflow: auto; - - code { - color: var(--code-color); - padding: 1rem; - margin: 0; - line-height: 1.5; - display: block; - font-weight: semibold; - font-family: monaco, Consolas, monospace; - } -} diff --git a/src/assets/demo/demo.scss b/src/assets/demo/demo.scss deleted file mode 100644 index 9d8993f..0000000 --- a/src/assets/demo/demo.scss +++ /dev/null @@ -1,2 +0,0 @@ -@use './code.scss'; -@use './flags/flags.css'; diff --git a/src/assets/demo/flags/flags.css b/src/assets/demo/flags/flags.css deleted file mode 100644 index fe887e3..0000000 --- a/src/assets/demo/flags/flags.css +++ /dev/null @@ -1 +0,0 @@ -span.flag{width:44px;height:30px;display:inline-block;}img.flag{width:30px}.flag{background:url(https://primefaces.org/cdn/primevue/images/flag/flags_responsive.png) no-repeat;background-size:100%;vertical-align: middle;}.flag-ad{background-position:0 .413223%}.flag-ae{background-position:0 .826446%}.flag-af{background-position:0 1.239669%}.flag-ag{background-position:0 1.652893%}.flag-ai{background-position:0 2.066116%}.flag-al{background-position:0 2.479339%}.flag-am{background-position:0 2.892562%}.flag-an{background-position:0 3.305785%}.flag-ao{background-position:0 3.719008%}.flag-aq{background-position:0 4.132231%}.flag-ar{background-position:0 4.545455%}.flag-as{background-position:0 4.958678%}.flag-at{background-position:0 5.371901%}.flag-au{background-position:0 5.785124%}.flag-aw{background-position:0 6.198347%}.flag-az{background-position:0 6.61157%}.flag-ba{background-position:0 7.024793%}.flag-bb{background-position:0 7.438017%}.flag-bd{background-position:0 7.85124%}.flag-be{background-position:0 8.264463%}.flag-bf{background-position:0 8.677686%}.flag-bg{background-position:0 9.090909%}.flag-bh{background-position:0 9.504132%}.flag-bi{background-position:0 9.917355%}.flag-bj{background-position:0 10.330579%}.flag-bm{background-position:0 10.743802%}.flag-bn{background-position:0 11.157025%}.flag-bo{background-position:0 11.570248%}.flag-br{background-position:0 11.983471%}.flag-bs{background-position:0 12.396694%}.flag-bt{background-position:0 12.809917%}.flag-bv{background-position:0 13.22314%}.flag-bw{background-position:0 13.636364%}.flag-by{background-position:0 14.049587%}.flag-bz{background-position:0 14.46281%}.flag-ca{background-position:0 14.876033%}.flag-cc{background-position:0 15.289256%}.flag-cd{background-position:0 15.702479%}.flag-cf{background-position:0 16.115702%}.flag-cg{background-position:0 16.528926%}.flag-ch{background-position:0 16.942149%}.flag-ci{background-position:0 17.355372%}.flag-ck{background-position:0 17.768595%}.flag-cl{background-position:0 18.181818%}.flag-cm{background-position:0 18.595041%}.flag-cn{background-position:0 19.008264%}.flag-co{background-position:0 19.421488%}.flag-cr{background-position:0 19.834711%}.flag-cu{background-position:0 20.247934%}.flag-cv{background-position:0 20.661157%}.flag-cx{background-position:0 21.07438%}.flag-cy{background-position:0 21.487603%}.flag-cz{background-position:0 21.900826%}.flag-de{background-position:0 22.31405%}.flag-dj{background-position:0 22.727273%}.flag-dk{background-position:0 23.140496%}.flag-dm{background-position:0 23.553719%}.flag-do{background-position:0 23.966942%}.flag-dz{background-position:0 24.380165%}.flag-ec{background-position:0 24.793388%}.flag-ee{background-position:0 25.206612%}.flag-eg{background-position:0 25.619835%}.flag-eh{background-position:0 26.033058%}.flag-er{background-position:0 26.446281%}.flag-es{background-position:0 26.859504%}.flag-et{background-position:0 27.272727%}.flag-fi{background-position:0 27.68595%}.flag-fj{background-position:0 28.099174%}.flag-fk{background-position:0 28.512397%}.flag-fm{background-position:0 28.92562%}.flag-fo{background-position:0 29.338843%}.flag-fr{background-position:0 29.752066%}.flag-ga{background-position:0 30.165289%}.flag-gd{background-position:0 30.578512%}.flag-ge{background-position:0 30.991736%}.flag-gf{background-position:0 31.404959%}.flag-gh{background-position:0 31.818182%}.flag-gi{background-position:0 32.231405%}.flag-gl{background-position:0 32.644628%}.flag-gm{background-position:0 33.057851%}.flag-gn{background-position:0 33.471074%}.flag-gp{background-position:0 33.884298%}.flag-gq{background-position:0 34.297521%}.flag-gr{background-position:0 34.710744%}.flag-gs{background-position:0 35.123967%}.flag-gt{background-position:0 35.53719%}.flag-gu{background-position:0 35.950413%}.flag-gw{background-position:0 36.363636%}.flag-gy{background-position:0 36.77686%}.flag-hk{background-position:0 37.190083%}.flag-hm{background-position:0 37.603306%}.flag-hn{background-position:0 38.016529%}.flag-hr{background-position:0 38.429752%}.flag-ht{background-position:0 38.842975%}.flag-hu{background-position:0 39.256198%}.flag-id{background-position:0 39.669421%}.flag-ie{background-position:0 40.082645%}.flag-il{background-position:0 40.495868%}.flag-in{background-position:0 40.909091%}.flag-io{background-position:0 41.322314%}.flag-iq{background-position:0 41.735537%}.flag-ir{background-position:0 42.14876%}.flag-is{background-position:0 42.561983%}.flag-it{background-position:0 42.975207%}.flag-jm{background-position:0 43.38843%}.flag-jo{background-position:0 43.801653%}.flag-jp{background-position:0 44.214876%}.flag-ke{background-position:0 44.628099%}.flag-kg{background-position:0 45.041322%}.flag-kh{background-position:0 45.454545%}.flag-ki{background-position:0 45.867769%}.flag-km{background-position:0 46.280992%}.flag-kn{background-position:0 46.694215%}.flag-kp{background-position:0 47.107438%}.flag-kr{background-position:0 47.520661%}.flag-kw{background-position:0 47.933884%}.flag-ky{background-position:0 48.347107%}.flag-kz{background-position:0 48.760331%}.flag-la{background-position:0 49.173554%}.flag-lb{background-position:0 49.586777%}.flag-lc{background-position:0 50%}.flag-li{background-position:0 50.413223%}.flag-lk{background-position:0 50.826446%}.flag-lr{background-position:0 51.239669%}.flag-ls{background-position:0 51.652893%}.flag-lt{background-position:0 52.066116%}.flag-lu{background-position:0 52.479339%}.flag-lv{background-position:0 52.892562%}.flag-ly{background-position:0 53.305785%}.flag-ma{background-position:0 53.719008%}.flag-mc{background-position:0 54.132231%}.flag-md{background-position:0 54.545455%}.flag-me{background-position:0 54.958678%}.flag-mg{background-position:0 55.371901%}.flag-mh{background-position:0 55.785124%}.flag-mk{background-position:0 56.198347%}.flag-ml{background-position:0 56.61157%}.flag-mm{background-position:0 57.024793%}.flag-mn{background-position:0 57.438017%}.flag-mo{background-position:0 57.85124%}.flag-mp{background-position:0 58.264463%}.flag-mq{background-position:0 58.677686%}.flag-mr{background-position:0 59.090909%}.flag-ms{background-position:0 59.504132%}.flag-mt{background-position:0 59.917355%}.flag-mu{background-position:0 60.330579%}.flag-mv{background-position:0 60.743802%}.flag-mw{background-position:0 61.157025%}.flag-mx{background-position:0 61.570248%}.flag-my{background-position:0 61.983471%}.flag-mz{background-position:0 62.396694%}.flag-na{background-position:0 62.809917%}.flag-nc{background-position:0 63.22314%}.flag-ne{background-position:0 63.636364%}.flag-nf{background-position:0 64.049587%}.flag-ng{background-position:0 64.46281%}.flag-ni{background-position:0 64.876033%}.flag-nl{background-position:0 65.289256%}.flag-no{background-position:0 65.702479%}.flag-np{background-position:0 66.115702%}.flag-nr{background-position:0 66.528926%}.flag-nu{background-position:0 66.942149%}.flag-nz{background-position:0 67.355372%}.flag-om{background-position:0 67.768595%}.flag-pa{background-position:0 68.181818%}.flag-pe{background-position:0 68.595041%}.flag-pf{background-position:0 69.008264%}.flag-pg{background-position:0 69.421488%}.flag-ph{background-position:0 69.834711%}.flag-pk{background-position:0 70.247934%}.flag-pl{background-position:0 70.661157%}.flag-pm{background-position:0 71.07438%}.flag-pn{background-position:0 71.487603%}.flag-pr{background-position:0 71.900826%}.flag-pt{background-position:0 72.31405%}.flag-pw{background-position:0 72.727273%}.flag-py{background-position:0 73.140496%}.flag-qa{background-position:0 73.553719%}.flag-re{background-position:0 73.966942%}.flag-ro{background-position:0 74.380165%}.flag-rs{background-position:0 74.793388%}.flag-ru{background-position:0 75.206612%}.flag-rw{background-position:0 75.619835%}.flag-sa{background-position:0 76.033058%}.flag-sb{background-position:0 76.446281%}.flag-sc{background-position:0 76.859504%}.flag-sd{background-position:0 77.272727%}.flag-se{background-position:0 77.68595%}.flag-sg{background-position:0 78.099174%}.flag-sh{background-position:0 78.512397%}.flag-si{background-position:0 78.92562%}.flag-sj{background-position:0 79.338843%}.flag-sk{background-position:0 79.752066%}.flag-sl{background-position:0 80.165289%}.flag-sm{background-position:0 80.578512%}.flag-sn{background-position:0 80.991736%}.flag-so{background-position:0 81.404959%}.flag-sr{background-position:0 81.818182%}.flag-ss{background-position:0 82.231405%}.flag-st{background-position:0 82.644628%}.flag-sv{background-position:0 83.057851%}.flag-sy{background-position:0 83.471074%}.flag-sz{background-position:0 83.884298%}.flag-tc{background-position:0 84.297521%}.flag-td{background-position:0 84.710744%}.flag-tf{background-position:0 85.123967%}.flag-tg{background-position:0 85.53719%}.flag-th{background-position:0 85.950413%}.flag-tj{background-position:0 86.363636%}.flag-tk{background-position:0 86.77686%}.flag-tl{background-position:0 87.190083%}.flag-tm{background-position:0 87.603306%}.flag-tn{background-position:0 88.016529%}.flag-to{background-position:0 88.429752%}.flag-tp{background-position:0 88.842975%}.flag-tr{background-position:0 89.256198%}.flag-tt{background-position:0 89.669421%}.flag-tv{background-position:0 90.082645%}.flag-tw{background-position:0 90.495868%}.flag-ty{background-position:0 90.909091%}.flag-tz{background-position:0 91.322314%}.flag-ua{background-position:0 91.735537%}.flag-ug{background-position:0 92.14876%}.flag-gb,.flag-uk{background-position:0 92.561983%}.flag-um{background-position:0 92.975207%}.flag-us{background-position:0 93.38843%}.flag-uy{background-position:0 93.801653%}.flag-uz{background-position:0 94.214876%}.flag-va{background-position:0 94.628099%}.flag-vc{background-position:0 95.041322%}.flag-ve{background-position:0 95.454545%}.flag-vg{background-position:0 95.867769%}.flag-vi{background-position:0 96.280992%}.flag-vn{background-position:0 96.694215%}.flag-vu{background-position:0 97.107438%}.flag-wf{background-position:0 97.520661%}.flag-ws{background-position:0 97.933884%}.flag-ye{background-position:0 98.347107%}.flag-za{background-position:0 98.760331%}.flag-zm{background-position:0 99.173554%}.flag-zr{background-position:0 99.586777%}.flag-zw{background-position:0 100%} diff --git a/src/assets/styles.scss b/src/assets/styles.scss index 04a4158..72ce665 100644 --- a/src/assets/styles.scss +++ b/src/assets/styles.scss @@ -1,4 +1,3 @@ /* You can add global styles to this file, and also import other style files */ @use 'primeicons/primeicons.css'; @use '@/assets/layout/layout.scss'; -@use '@/assets/demo/demo.scss'; diff --git a/src/components/AjudaDrawer.vue b/src/components/AjudaDrawer.vue new file mode 100644 index 0000000..f0324e1 --- /dev/null +++ b/src/components/AjudaDrawer.vue @@ -0,0 +1,716 @@ + + + + +