Compare commits

...

2 Commits

5 changed files with 101 additions and 12 deletions
+51
View File
@@ -0,0 +1,51 @@
# Migração do TrackSteelAPP para a Marcos-VPS
Este plano descreve o processo passo a passo para migrar completamente a infraestrutura (Banco de Dados Supabase, Logto, e o Front-End) da Hostinger para a nova VPS (marcos-vps), além de replicar o repositório atual para o GitHub.
> [!IMPORTANT]
> A migração foi desenhada para NÃO afetar ou modificar qualquer componente rodando atualmente na VPS da Hostinger, garantindo que a aplicação atual continue funcionando sem instabilidades durante o processo.
## Open Questions
Antes de iniciarmos a execução do plano, preciso de algumas confirmações:
1. **Banco de Dados (Supabase)**: O Coolify da Hostinger roda um Supabase completo (com meta, db, rest, etc). Você gostaria de replicar o Supabase inteiro na marcos-vps via Coolify, ou apenas o container do PostgreSQL (supabase-db)? (O recomendado é replicar a stack inteira para manter 100% de compatibilidade se você usa os recursos do Supabase).
2. **Novo Repositório no GitHub**: Farei um git clone --mirror do Gitea e um git push --mirror para o novo GitHub, preservando todo o histórico. Devo configurar a marcos-vps para fazer os deployments a partir do novo repositório no GitHub?
## Proposed Changes
### 1. Migração de Repositório (Gitea -> GitHub)
- Fazer clone completo (mirror) do repositório atual do Gitea.
- Adicionar o remote do GitHub (https://github.com/admbrainsteel/TracksteelApp.git) usando o token fornecido.
- Enviar todo o histórico (push --mirror) para o GitHub.
- Alterar o remote do repositório local na VPS para o GitHub (ou mantê-lo duplo para a Hostinger).
### 2. Migração de Banco de Dados e Logto (Hostinger -> marcos-vps)
**Extração (Hostinger):**
- Fazer dump completo dos dados do PostgreSQL (supabase-db) utilizando pg_dumpall ou pg_dump.
- Fazer dump do banco de dados do Logto (container postgres-ea4tt75aeibqtu19hjqqw12f).
- Coletar as variáveis de ambiente, chaves e senhas dos containers no Coolify atual.
**Provisionamento (marcos-vps):**
- Acessar a marcos-vps (Tailscale IP: 100.97.2.16).
- Através da CLI do Coolify ou API, recriar os serviços: Supabase Stack e Logto.
- Ajustar as variáveis de ambiente para utilizar a nova URL.
**Restauração (marcos-vps):**
- Importar os dados do Supabase.
- Importar os dados do Logto.
### 3. Deploy do TrackSteelAPP na marcos-vps
- Criar a aplicação TrackSteelAPP no Coolify da marcos-vps.
- Conectar ao repositório do GitHub (com os tokens).
- Configurar o mapeamento de portas da aplicação no Coolify da marcos-vps para expor a porta na máquina host como 8750, atendendo ao requisito do túnel Cloudflare (http://localhost:8750).
- Atualizar o arquivo `.env` para apontar para os novos serviços locais (Logto e Supabase da marcos-vps).
## Verification Plan
### Automated Tests
- Testar conectividade SSH e acesso a banco de dados em ambos os servidores para garantir a integridade dos backups antes de aplicar.
### Manual Verification
- Ao final, solicitarei que você acesse a nova URL https://ts.brainsteel.com.br pelo navegador para validar se a aplicação carrega, o login pelo Logto funciona e os dados antigos do banco de dados estão perfeitamente sincronizados.
+4 -4
View File
@@ -46,14 +46,14 @@ export function UserInfo() {
useEffect(() => { useEffect(() => {
async function fetchUserProfile() { async function fetchUserProfile() {
if (!user) return; if (!user) return;
const { data, error } = await supabase const { data: profileArr, error } = await supabase
.from('profiles') .from('profiles')
.select('full_name, email, profile_image_url') .select('full_name, email, profile_image_url')
.eq('id', user.id) .eq('id', user.id)
.maybeSingle(); .limit(1);
if (!error && data) { if (!error && profileArr && profileArr.length > 0) {
setProfile(data); setProfile(profileArr[0]);
} else { } else {
setProfile({ setProfile({
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
+4 -3
View File
@@ -209,16 +209,17 @@ export function useInterfaceResources() {
.from('profiles') .from('profiles')
.select('privilege_id') .select('privilege_id')
.eq('id', userId) .eq('id', userId)
.maybeSingle(); .limit(1);
if (profileError) throw profileError; if (profileError) throw profileError;
if (!profile?.privilege_id) return []; const priv = profile && profile.length > 0 ? profile[0].privilege_id : null;
if (!priv) return [];
const { data, error } = await supabase const { data, error } = await supabase
.from('privilege_interface_resources') .from('privilege_interface_resources')
.select('resource_key') .select('resource_key')
.eq('privilege_id', profile.privilege_id); .eq('privilege_id', priv);
if (error) throw error; if (error) throw error;
+7 -5
View File
@@ -67,19 +67,20 @@ export function useUserResourcePermissions(resourceKey: string) {
// Enriquecer com dados do usuário // Enriquecer com dados do usuário
const enrichedData = await Promise.all( const enrichedData = await Promise.all(
(data || []).map(async (permission) => { (data || []).map(async (permission) => {
const { data: profileData } = await supabase const { data: profileDataArr } = await supabase
.from('profiles') .from('profiles')
.select('email, full_name') .select('email, full_name')
.eq('id', permission.user_id) .eq('id', permission.user_id)
.maybeSingle(); .limit(1);
const profileData = profileDataArr && profileDataArr.length > 0 ? profileDataArr[0] : null;
return { return {
user_id: permission.user_id, user_id: permission.user_id,
resource_key: permission.resource_key, resource_key: permission.resource_key,
permission_level: permission.permission as PermissionLevel, permission_level: permission.permission as PermissionLevel,
created_at: permission.created_at, created_at: permission.created_at,
updated_at: permission.updated_at, updated_at: permission.updated_at,
profiles: profileData profiles: profileData as any
} as UserInterfacePermission; } as UserInterfacePermission;
}) })
); );
@@ -167,12 +168,13 @@ export function useUserResourcePermissions(resourceKey: string) {
} }
// Verify user exists // Verify user exists
const { data: userExists, error: userError } = await supabase const { data: userExistsArr, error: userError } = await supabase
.from('profiles') .from('profiles')
.select('id, email') .select('id, email')
.eq('id', userId) .eq('id', userId)
.maybeSingle(); .limit(1);
const userExists = userExistsArr && userExistsArr.length > 0 ? userExistsArr[0] : null;
if (userError || !userExists) { if (userError || !userExists) {
console.error('User not found:', { userId, userError }); console.error('User not found:', { userId, userError });
toast.error('Usuário não encontrado'); toast.error('Usuário não encontrado');
Executable
+35
View File
@@ -0,0 +1,35 @@
#!/bin/bash
# ---------------------------------------------------------
# TRACKSTEEL APP: DEPLOY E SINCRONIZAÇÃO
# ---------------------------------------------------------
CYAN='\033[0;36m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
echo -e "\n${CYAN}🚀 Iniciando Ciclo Automático de Deploy TrackSteelAPP...${NC}"
echo -e "${YELLOW}📝 Sincronizando código...${NC}"
git add .
if git diff-index --quiet HEAD --; then
echo -e "${GREEN}✨ Nenhuma nova alteração para comitar.${NC}"
else
TIMESTAMP=$(date +"%d/%m/%Y %H:%M:%S")
MSG="${1:-🚀 Auto-deploy: TrackSteelAPP atualizado em $TIMESTAMP}"
echo -e "${CYAN}📤 Criando novo commit: $MSG${NC}"
git commit -m "$MSG"
fi
echo -e "${CYAN}📤 Sincronizando com o repositório remoto (git push)...${NC}"
git push
echo -e "${YELLOW}🔄 Disparando Deploy via API Oficial no Coolify...${NC}"
COOLIFY_TOKEN="19|ZJKUbBgyeNGcKrVkMI5gJ1uMHDC39d9VIShHL473a60d9882"
TRACKSTEEL_UUID="i8o44gggg00o88ccc8oo48kk"
curl -s -X GET "https://painel.reifonas.cloud/api/v1/deploy?uuid=${TRACKSTEEL_UUID}&force=false" \
-H "Authorization: Bearer $COOLIFY_TOKEN"
echo -e "\n${GREEN}🚀 Deploy oficial via API engatilhado com sucesso!${NC}"
echo -e "${GREEN}🏁 Ciclo concluído com sucesso.${NC}\n"