Plano de Arquitetura e Estruturação do Login
Este documento propõe uma reorganização do projeto e detalha como componentizar e estruturar o fluxo de autenticação (login/register/logout) seguindo boas práticas React modernas, separação de responsabilidades e pensando em escalabilidade.
Objetivos
- Organizar o código por feature/modules para facilitar manutenção e escalabilidade.
- Separar UI, services, state/context e rotas.
- Criar um fluxo de autenticação testável, seguro (conceitualmente) e fácil de migrar para backend.
- Fornecer passos práticos de migração e snippets de exemplo.
Proposta de estrutura de pastas (feature-based)
- src/
- app/
- routes.jsx # rotas principais e composição de providers
- App.jsx
- features/
- auth/
- components/ # componentes de UI específicos (SignInForm, SignUpForm)
- SignInForm.jsx
- SignUpForm.jsx
- AuthLayout.jsx
- hooks/
- useAuth.js # hooks que delegam para context/service
- services/
- authService.js # login/logout/init (API wrapper)
- context/
- AuthProvider.jsx # contexto com login/logout/isAuthenticated
- pages/
- tests/
- donations/
- components/
- services/
- context/
- pages/
- shared/
- api/
- apiClient.js # axios/fetch centralizado com interceptors
- ui/
- utils/
- docs/
- index.css
- main.jsx
Notas:
features/auth isola toda a lógica e UI de autenticação.
shared/api/apiClient.js centraliza configuração HTTP, interceptors (ex.: anexar token).
Contratos e responsabilidades
- UI (components): render + callbacks (onSubmit), nenhuma chamada direta a
localStorage/fetch.
- Service (authService): responsável por chamadas HTTP (ou mock/localStorage em protótipo), armazenamento de token e configuração do cliente HTTP.
- Context / Provider (AuthProvider): mantém estado
user, loading, error e expõe login, logout e register para a UI.
- Routes: apenas composição de páginas. Rotas privadas são protegidas por um wrapper
RequireAuth.
Fluxo de autenticação proposto
- Usuário submete credenciais no
SignInForm (apenas UI).
SignInForm chama const { login } = useAuth() e passa credentials.
useAuth delega para authService.login (service fará POST /auth/login).
authService recebe token + user, salva token (preferencialmente cookie httpOnly; se não houver backend, salvar localStorage em protótipo), configura apiClient com header Authorization.
AuthProvider atualiza user e isAuthenticated.
RequireAuth redireciona para /login caso não autenticado.
Snippets essenciais (exemplos)
src/shared/api/apiClient.js
import axios from 'axios';
const api = axios.create({ baseURL: process.env.REACT_APP_API_URL || '/' });
export default api;
src/features/auth/services/authService.js (interface exemplo)
import api from '../../../shared/api/apiClient';
export async function login({ email, password }) {
// Em produção: POST /auth/login
const { data } = await api.post('/auth/login', { email, password });
const { token, user } = data;
localStorage.setItem('token', token); // protótipo
api.defaults.headers.common.Authorization = `Bearer ${token}`;
return user;
}
export function logout() {
localStorage.removeItem('token');
delete api.defaults.headers.common.Authorization;
}
export function initAuth() {
const token = localStorage.getItem('token');
if (token) api.defaults.headers.common.Authorization = `Bearer ${token}`;
}
src/features/auth/context/AuthProvider.jsx
import React, { createContext, useContext, useState, useEffect } from 'react';
import * as authService from '../services/authService';
const AuthContext = createContext();
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
authService.initAuth();
// opcional: chamar /me para validar token
setLoading(false);
}, []);
const login = async (creds) => {
const user = await authService.login(creds);
setUser(user);
return user;
};
const logout = () => {
authService.logout();
setUser(null);
};
return (
<AuthContext.Provider value={{ user, login, logout, loading }}>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => useContext(AuthContext);
RequireAuth para rotas privadas
import { Navigate } from 'react-router-dom';
import { useAuth } from './context/AuthProvider';
export default function RequireAuth({ children }) {
const { user, loading } = useAuth();
if (loading) return <div>Loading...</div>;
return user ? children : <Navigate to="/login" replace />;
}
- Como
SignInForm deve ficar (apenas esqueleto)
import React, { useState } from 'react';
import { useAuth } from '../context/AuthProvider';
import { useNavigate } from 'react-router-dom';
export default function SignInForm() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const { login } = useAuth();
const navigate = useNavigate();
const handleSubmit = async (e) => {
e.preventDefault();
try {
await login({ email, password });
navigate('/donations');
} catch (err) {
// mostrar erro
}
};
return (
<form onSubmit={handleSubmit}>
{/* inputs */}
</form>
);
}
Migração prática (passos prioritários)
- Criar
shared/api/apiClient.js e garantir que é usado por serviços existentes (futuro: adicionar interceptors para 401).
- Implementar
features/auth/services/authService.js com interface login/logout/init. Em protótipo, esse file pode usar localStorage para compatibilidade.
- Implementar
features/auth/context/AuthProvider.jsx e envolver a árvore em main.jsx (substituir o UserProvider).
- Refatorar
SignInForm e SignUpForm para chamar useAuth().login/register ao invés de manipular localStorage.
- Adicionar
RequireAuth e proteger rotas (ex.: /donations, /DonationsEdit).
- Substituir
<a href> por Link de react-router-dom em Header para navegação sem reload.
- Auditar locais que usam
localStorage e movê-los para services/context.
Checklist de segurança e qualidade
Prioridade / estimativa rápida
- Baixo esforço (0.5-1 dia): criar
apiClient, authService protótipo, AuthProvider básico, refatorar SignInForm.
- Médio (1-2 dias): adicionar RequireAuth, refatorar
Header e navegação, mover outras chamadas localStorage para services.
- Alto (2-4 dias): integrar com backend real, trocar armazenamento para cookies httpOnly, refresh tokens.
Conclusão
Seguindo este plano a aplicação ficará modular, com responsabilidades claras e pronta para crescer: adicionar roles, refresh tokens, e testes será muito mais simples. Se quiser, implemento a primeira iteração: authService, AuthProvider e a refatoração de SignInForm/SignUpForm com patches no repositório.
Plano de Arquitetura e Estruturação do Login
Este documento propõe uma reorganização do projeto e detalha como componentizar e estruturar o fluxo de autenticação (login/register/logout) seguindo boas práticas React modernas, separação de responsabilidades e pensando em escalabilidade.
Objetivos
Proposta de estrutura de pastas (feature-based)
Notas:
features/authisola toda a lógica e UI de autenticação.shared/api/apiClient.jscentraliza configuração HTTP, interceptors (ex.: anexar token).Contratos e responsabilidades
localStorage/fetch.user,loading,errore expõelogin,logouteregisterpara a UI.RequireAuth.Fluxo de autenticação proposto
SignInForm(apenas UI).SignInFormchamaconst { login } = useAuth()e passacredentials.useAuthdelega paraauthService.login(service fará POST /auth/login).authServicerecebe token + user, salva token (preferencialmente cookie httpOnly; se não houver backend, salvar localStorage em protótipo), configuraapiClientcom header Authorization.AuthProvideratualizausereisAuthenticated.RequireAuthredireciona para/logincaso não autenticado.Snippets essenciais (exemplos)
src/shared/api/apiClient.jssrc/features/auth/services/authService.js(interface exemplo)src/features/auth/context/AuthProvider.jsxRequireAuthpara rotas privadasSignInFormdeve ficar (apenas esqueleto)Migração prática (passos prioritários)
shared/api/apiClient.jse garantir que é usado por serviços existentes (futuro: adicionar interceptors para 401).features/auth/services/authService.jscom interfacelogin/logout/init. Em protótipo, esse file pode usarlocalStoragepara compatibilidade.features/auth/context/AuthProvider.jsxe envolver a árvore emmain.jsx(substituir oUserProvider).SignInFormeSignUpFormpara chamaruseAuth().login/registerao invés de manipularlocalStorage.RequireAuthe proteger rotas (ex.:/donations,/DonationsEdit).<a href>porLinkdereact-router-domemHeaderpara navegação sem reload.localStoragee movê-los paraservices/context.Checklist de segurança e qualidade
httpOnlyquando houver backend.authServiceeAuthProvidercom testes unitários.Prioridade / estimativa rápida
apiClient,authServiceprotótipo,AuthProviderbásico, refatorarSignInForm.Headere navegação, mover outras chamadaslocalStoragepara services.Conclusão
Seguindo este plano a aplicação ficará modular, com responsabilidades claras e pronta para crescer: adicionar roles, refresh tokens, e testes será muito mais simples. Se quiser, implemento a primeira iteração:
authService,AuthProvidere a refatoração deSignInForm/SignUpFormcom patches no repositório.