Guia de Referência do Desenvolvedor
Um documento vivo que descreve os principais padrões de arquitetura e configurações deste projeto.
Padrão para Operações no Servidor (Server Actions)
Para garantir segurança e centralização, todas as operações que precisam ser executadas no servidor seguem um padrão de 3 etapas.
Passo 1: A Server Action
A lógica principal é definida em uma função `async` exportada de um arquivo `actions.ts`. Este arquivo **deve** começar com a diretiva `"use server"`.
// Em src/app/some-route/actions.ts
'use server';
import { getFirestoreAdmin } from '@/firebase/admin';
export async function ourServerAction(formData: FormData) {
const data = formData.get('someData');
try {
const firestoreAdmin = await getFirestoreAdmin();
// ...sua lógica segura aqui...
return { success: true, message: 'Operação concluída!' };
} catch (error) {
return { success: false, error: 'Falha na operação.' };
}
}Passo 2: Acesso aos Serviços do Firebase Admin
O arquivo `src/firebase/admin.ts` centraliza a inicialização do Firebase Admin SDK. Ele garante que a inicialização ocorra apenas uma vez (padrão singleton) e fornece funções `async` para obter as instâncias dos serviços.
// Em src/firebase/admin.ts
let firestoreAdmin: Firestore;
function initializeAdminApp() {
// ...lógica de inicialização...
}
export async function getFirestoreAdmin() {
if (!firestoreAdmin) {
initializeAdminApp();
}
return firestoreAdmin;
}Passo 3: Chamada a partir do Componente Cliente
O componente de cliente importa a `Server Action` e a chama diretamente. O hook `useTransition` é usado para gerenciar estados de carregamento e fornecer feedback ao usuário sem bloquear a interface.
// Em um componente cliente, ex: src/app/some-route/page.tsx
'use client';
import { useState, useTransition } from 'react';
import { ourServerAction } from './actions';
export default function MyPage() {
const [isPending, startTransition] = useTransition();
const handleAction = () => {
const formData = new FormData();
formData.append('someData', 'valor');
startTransition(async () => {
const result = await ourServerAction(formData);
if (result.success) {
// Exibir toast de sucesso
} else {
// Exibir toast de erro
}
});
};
return (
<button onClick={handleAction} disabled={isPending}>
{isPending ? 'Executando...' : 'Executar Ação no Servidor'}
</button>
);
}