feat : init project Coltura (CRM/ERP)

Symfony 8 + API Platform 4 + Nuxt 4 monorepo.
Backend: User entity, JWT auth, fixtures.
Frontend: login, dashboard, auth middleware, i18n, @malio/layer-ui.
Docker: dev (ports 8083/3003/5436) + prod multi-stage.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Matthieu
2026-04-07 10:56:57 +02:00
commit 4c9040c923
70 changed files with 2464 additions and 0 deletions

71
frontend/stores/auth.ts Normal file
View File

@@ -0,0 +1,71 @@
import { defineStore } from 'pinia'
import type { UserData } from '~/services/dto/user-data'
import { getCurrentUser, login, logout } from '~/services/auth'
export const useAuthStore = defineStore('auth', {
state: () => ({
user: null as UserData | null,
isLoading: false,
checked: false
}),
getters: {
isAuthenticated: (state) => Boolean(state.user)
},
actions: {
clearSession() {
this.user = null
this.checked = true
this.isLoading = false
},
async ensureSession() {
if (this.checked) {
return this.user
}
this.checked = true
try {
const me = await getCurrentUser()
this.user = me
return me
} catch {
this.user = null
return null
}
},
async login(username: string, password: string) {
this.isLoading = true
try {
await login(username, password)
const me = await getCurrentUser()
this.user = me
this.checked = true
return me
} finally {
this.isLoading = false
}
},
async logout() {
this.isLoading = true
try {
await logout()
} catch {
// Ignore logout errors so we can still clear local auth state.
} finally {
this.user = null
this.checked = true
this.isLoading = false
}
},
async refreshUser() {
try {
const me = await getCurrentUser()
this.user = me
} catch {
// Silently fail — user session might have expired
}
}
}
})

19
frontend/stores/ui.ts Normal file
View File

@@ -0,0 +1,19 @@
import { defineStore } from 'pinia'
export const useUiStore = defineStore('ui', {
state: () => ({
sidebarCollapsed: false,
sidebarOpen: false,
}),
actions: {
toggleSidebar() {
this.sidebarCollapsed = !this.sidebarCollapsed
},
openMobileSidebar() {
this.sidebarOpen = true
},
closeMobileSidebar() {
this.sidebarOpen = false
},
},
})