Aller au contenu principal

Frontend Architecture

The frontend architecture embraces the server-centric security principle where the UI is completely "security agnostic" - it simply displays whatever data the server returns after filtering.

Component Organization​

apps/frontend/src/
├── components/
│ ├── common/ # Shared UI components
│ ├── clients/ # Client management components
│ ├── reclamations/ # Tax claim components
│ └── documents/ # Document management
├── services/ # API communication layer
│ ├── api.ts # Base API client with JWT
│ ├── clientService.ts # Client API calls
│ └── reclamationService.ts # Tax claim API calls
├── contexts/ # React contexts
│ ├── AuthContext.tsx # JWT authentication (no security logic)
│ └── ApiContext.tsx # API client context
├── hooks/ # Custom React hooks
│ ├── useAuth.ts # Authentication state
│ └── useClients.ts # Client data fetching
└── utils/ # Utilities
└── constants.ts

API Client Setup​

// services/api.ts - Simple API client that adds JWT to requests
import axios, { AxiosInstance } from "axios";

class ApiClient {
private client: AxiosInstance;

constructor() {
this.client = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL,
});

// Automatically add JWT token to all requests
this.client.interceptors.request.use(async (config) => {
try {
const token = localStorage.getItem("jwt_token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
} catch (error) {
console.error("Failed to get access token:", error);
}
return config;
});

// Handle authorization errors globally
this.client.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
window.location.href = "/login";
} else if (error.response?.status === 403) {
throw new Error("You do not have permission to access this resource");
}
throw error;
},
);
}
}