feat: production deployment - full update with providers, admin, glossaries, pricing, tests

Major changes across backend, frontend, infrastructure:
- Provider system with model selection (Google, DeepL, OpenAI, Ollama, Google Cloud)
- Admin panel: user management, pricing, settings
- Glossary system with CSV import/export
- Subscription and tier quota management
- Security hardening (rate limiting, API key auth, path traversal fixes)
- Docker compose for dev, prod, and IONOS deployment
- Alembic migrations for new tables
- Frontend: dashboard, pricing page, landing page, i18n (en/fr)
- Test suite and verification scripts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Sepehr Ramezani
2026-04-25 15:01:47 +02:00
parent 2ba4fedfc8
commit 26bd096a06
1178 changed files with 136435 additions and 3047 deletions

View File

@@ -17,6 +17,18 @@ export default function AdminLayout({
const { settings, setAdminToken } = useTranslationStore();
const [isChecking, setIsChecking] = useState(true);
const [isValid, setIsValid] = useState(false);
/** Sans ça, au premier rendu après un chargement complet le token nest pas encore lu depuis localStorage → fausse absence de token → redirection /admin/login (bug sur F5 ou URL directe). */
const [persistHydrated, setPersistHydrated] = useState(false);
useEffect(() => {
const unsub = useTranslationStore.persist.onFinishHydration(() => {
setPersistHydrated(true);
});
if (useTranslationStore.persist.hasHydrated()) {
setPersistHydrated(true);
}
return unsub;
}, []);
const verifyToken = useCallback(async (token: string): Promise<boolean> => {
try {
@@ -39,6 +51,10 @@ export default function AdminLayout({
return;
}
if (!persistHydrated) {
return;
}
const adminToken = settings.adminToken;
if (!adminToken) {
router.push(`/admin/login?redirect=${encodeURIComponent(pathname)}`);
@@ -54,7 +70,7 @@ export default function AdminLayout({
setIsValid(true);
setIsChecking(false);
});
}, [settings.adminToken, pathname, router, verifyToken, setAdminToken]);
}, [settings.adminToken, pathname, router, verifyToken, setAdminToken, persistHydrated]);
if (isChecking && pathname !== "/admin/login") {
return (