Skip to content

fix: folder structure #6

@ErycMJ

Description

@ErycMJ

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/
          • LoginPage.jsx
        • tests/
      • donations/
        • components/
        • services/
        • context/
        • pages/
    • shared/
      • api/
        • apiClient.js # axios/fetch centralizado com interceptors
      • ui/
        • Button.jsx
        • Input.jsx
      • 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

  1. Usuário submete credenciais no SignInForm (apenas UI).
  2. SignInForm chama const { login } = useAuth() e passa credentials.
  3. useAuth delega para authService.login (service fará POST /auth/login).
  4. authService recebe token + user, salva token (preferencialmente cookie httpOnly; se não houver backend, salvar localStorage em protótipo), configura apiClient com header Authorization.
  5. AuthProvider atualiza user e isAuthenticated.
  6. RequireAuth redireciona para /login caso não autenticado.

Snippets essenciais (exemplos)

  1. src/shared/api/apiClient.js
import axios from 'axios';
const api = axios.create({ baseURL: process.env.REACT_APP_API_URL || '/' });
export default api;
  1. 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}`;
}
  1. 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);
  1. 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 />;
}
  1. 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)

  1. Criar shared/api/apiClient.js e garantir que é usado por serviços existentes (futuro: adicionar interceptors para 401).
  2. Implementar features/auth/services/authService.js com interface login/logout/init. Em protótipo, esse file pode usar localStorage para compatibilidade.
  3. Implementar features/auth/context/AuthProvider.jsx e envolver a árvore em main.jsx (substituir o UserProvider).
  4. Refatorar SignInForm e SignUpForm para chamar useAuth().login/register ao invés de manipular localStorage.
  5. Adicionar RequireAuth e proteger rotas (ex.: /donations, /DonationsEdit).
  6. Substituir <a href> por Link de react-router-dom em Header para navegação sem reload.
  7. Auditar locais que usam localStorage e movê-los para services/context.

Checklist de segurança e qualidade

  • Remover armazenamento de senhas em texto (migrar para backend com hashing).
  • Tratar tokens em cookies httpOnly quando houver backend.
  • Validar inputs no frontend e tratar erros do servidor no service.
  • Cobrir authService e AuthProvider com testes unitários.
  • Adicionar lint/format e regras (ESLint/Prettier) se ainda não existir.

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.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions