Backend Go 1.23+ : - API REST + WebSocket (chi, gorilla/websocket) - Authentification PAM via SSH + JWT RS256 - Chiffrement AES-256-GCM pour secrets SQLite - Pool SSH, client Proxmox REST, hub WebSocket pub/sub - Système de modules compilés à initialisation conditionnelle - Audit log, migrations SQLite versionnées Frontend Vue 3 + Vite + TypeScript : - Thème Neumorphism sombre/clair (CSS custom properties) - Wizard d'installation, Dashboard drag-drop, Terminal xterm.js - Toutes les vues CORE + stubs modules optionnels - i18n EN/FR (vue-i18n v11) Infrastructure : - Docker multi-stage (Go → alpine, Node → nginx) - docker-compose.yml, .gitattributes, LICENSE MIT, README Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
128 lines
3.4 KiB
TypeScript
128 lines
3.4 KiB
TypeScript
// Configuration du routeur Vue — gère la navigation et la protection des routes.
|
|
import { createRouter, createWebHistory } from 'vue-router'
|
|
import { useAuthStore } from '@/stores/auth.store'
|
|
|
|
const router = createRouter({
|
|
history: createWebHistory(),
|
|
routes: [
|
|
// Page d'installation (premier lancement)
|
|
{
|
|
path: '/install',
|
|
name: 'install',
|
|
component: () => import('@/views/Install.vue'),
|
|
meta: { public: true, hideLayout: true },
|
|
},
|
|
|
|
// Authentification
|
|
{
|
|
path: '/login',
|
|
name: 'login',
|
|
component: () => import('@/views/Login.vue'),
|
|
meta: { public: true, hideLayout: true },
|
|
},
|
|
|
|
// Application principale (protégée)
|
|
{
|
|
path: '/',
|
|
component: () => import('@/components/Layout.vue'),
|
|
meta: { requiresAuth: true },
|
|
children: [
|
|
{
|
|
path: '',
|
|
name: 'dashboard',
|
|
component: () => import('@/views/Dashboard.vue'),
|
|
},
|
|
{
|
|
path: 'proxmox',
|
|
name: 'proxmox',
|
|
component: () => import('@/views/Proxmox.vue'),
|
|
},
|
|
{
|
|
path: 'updates',
|
|
name: 'updates',
|
|
component: () => import('@/views/Updates.vue'),
|
|
},
|
|
{
|
|
path: 'files',
|
|
name: 'files',
|
|
component: () => import('@/views/Files.vue'),
|
|
meta: { module: 'files' },
|
|
},
|
|
{
|
|
path: 'terminal',
|
|
name: 'terminal',
|
|
component: () => import('@/views/Terminal.vue'),
|
|
meta: { module: 'terminal' },
|
|
},
|
|
{
|
|
path: 'logs',
|
|
name: 'logs',
|
|
component: () => import('@/views/Logs.vue'),
|
|
meta: { module: 'logs' },
|
|
},
|
|
{
|
|
path: 'services',
|
|
name: 'services',
|
|
component: () => import('@/views/Services.vue'),
|
|
meta: { module: 'services' },
|
|
},
|
|
{
|
|
path: 'settings',
|
|
name: 'settings',
|
|
component: () => import('@/views/Settings.vue'),
|
|
},
|
|
{
|
|
path: 'modules',
|
|
name: 'modules',
|
|
component: () => import('@/views/Modules.vue'),
|
|
meta: { requiresAdmin: true },
|
|
},
|
|
],
|
|
},
|
|
|
|
// Redirection 404
|
|
{
|
|
path: '/:pathMatch(.*)*',
|
|
redirect: '/',
|
|
},
|
|
],
|
|
})
|
|
|
|
// Guard de navigation : vérification authentification et installation
|
|
router.beforeEach(async (to) => {
|
|
const authStore = useAuthStore()
|
|
|
|
// Vérifier si l'application est installée (appel API au premier chargement)
|
|
if (!authStore.installChecked) {
|
|
await authStore.checkInstallation()
|
|
}
|
|
|
|
// Rediriger vers l'installation si pas encore configuré
|
|
if (!authStore.isInstalled && to.name !== 'install') {
|
|
return { name: 'install' }
|
|
}
|
|
|
|
// Si installé et route d'install → rediriger vers le dashboard
|
|
if (authStore.isInstalled && to.name === 'install') {
|
|
return { name: 'dashboard' }
|
|
}
|
|
|
|
// Routes publiques — passer directement
|
|
if (to.meta.public) return true
|
|
|
|
// Routes protégées — vérifier l'authentification
|
|
if (to.meta.requiresAuth || to.matched.some(r => r.meta.requiresAuth)) {
|
|
if (!authStore.isAuthenticated) {
|
|
return { name: 'login', query: { redirect: to.fullPath } }
|
|
}
|
|
}
|
|
|
|
// Routes admin uniquement
|
|
if (to.meta.requiresAdmin && !authStore.user?.is_admin) {
|
|
return { name: 'dashboard' }
|
|
}
|
|
|
|
return true
|
|
})
|
|
|
|
export default router
|