feat: Setup projet Classeo avec infrastructure Docker et architecture DDD

Configure l'environnement de développement complet avec Docker Compose,
structure DDD 4 Bounded Contexts, et pipeline CI/CD GitHub Actions.

Corrections compatibilité CI:
- Symfony 8 nécessite monolog-bundle ^4.0 (la v3.x ne supporte que jusqu'à Symfony 7)
- ESLint v9 nécessite flat config (eslint.config.js) - le format .eslintrc.cjs est obsolète
This commit is contained in:
2026-01-30 09:55:58 +01:00
parent ddefa927c7
commit 6da5996340
125 changed files with 10032 additions and 0 deletions

62
frontend/src/app.css Normal file
View File

@@ -0,0 +1,62 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--primary: 221.2 83.2% 53.3%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--ring: 221.2 83.2% 53.3%;
--radius: 0.5rem;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%;
--popover: 222.2 84% 4.9%;
--popover-foreground: 210 40% 98%;
--card: 222.2 84% 4.9%;
--card-foreground: 210 40% 98%;
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;
--primary: 217.2 91.2% 59.8%;
--primary-foreground: 222.2 47.4% 11.2%;
--secondary: 217.2 32.6% 17.5%;
--secondary-foreground: 210 40% 98%;
--accent: 217.2 32.6% 17.5%;
--accent-foreground: 210 40% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%;
--ring: 224.3 76.3% 48%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
font-feature-settings:
'rlig' 1,
'calt' 1;
}
}

16
frontend/src/app.html Normal file
View File

@@ -0,0 +1,16 @@
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#3b82f6" />
<meta name="description" content="Classeo - Application de gestion scolaire" />
<link rel="manifest" href="%sveltekit.assets%/manifest.webmanifest" />
<link rel="apple-touch-icon" href="%sveltekit.assets%/apple-touch-icon.png" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>

View File

@@ -0,0 +1,2 @@
// place files you want to import through the `$lib` alias in this folder.
export * from './types';

View File

@@ -0,0 +1,35 @@
// API response types
export interface ApiError {
code: string;
message: string;
violations?: Array<{
propertyPath: string;
message: string;
}>;
}
export interface PaginatedResponse<T> {
data: T[];
meta: {
total: number;
page: number;
itemsPerPage: number;
lastPage: number;
};
}
export interface HydraCollection<T> {
'@context': string;
'@id': string;
'@type': string;
'hydra:totalItems': number;
'hydra:member': T[];
'hydra:view'?: {
'@id': string;
'@type': string;
'hydra:first'?: string;
'hydra:last'?: string;
'hydra:next'?: string;
'hydra:previous'?: string;
};
}

View File

@@ -0,0 +1,2 @@
export * from './shared';
export * from './api';

View File

@@ -0,0 +1,27 @@
// Branded types for type safety
export type TenantId = string & { readonly brand: unique symbol };
export type UserId = string & { readonly brand: unique symbol };
export type NoteId = string & { readonly brand: unique symbol };
export type ClasseId = string & { readonly brand: unique symbol };
export type EleveId = string & { readonly brand: unique symbol };
// Helper functions for branded types
export function createTenantId(id: string): TenantId {
return id as TenantId;
}
export function createUserId(id: string): UserId {
return id as UserId;
}
export function createNoteId(id: string): NoteId {
return id as NoteId;
}
export function createClasseId(id: string): ClasseId {
return id as ClasseId;
}
export function createEleveId(id: string): EleveId {
return id as EleveId;
}

View File

@@ -0,0 +1,23 @@
<script lang="ts">
import '../app.css';
import { browser } from '$app/environment';
import { QueryClient, QueryClientProvider } from '@tanstack/svelte-query';
let { children } = $props();
const queryClient = $state(
new QueryClient({
defaultOptions: {
queries: {
enabled: browser,
staleTime: 1000 * 60 * 5, // 5 minutes
retry: 1
}
}
})
);
</script>
<QueryClientProvider client={queryClient}>
{@render children()}
</QueryClientProvider>

View File

@@ -0,0 +1,28 @@
<script lang="ts">
let count = $state(0);
function increment() {
count++;
}
</script>
<svelte:head>
<title>Classeo</title>
</svelte:head>
<main class="flex min-h-screen flex-col items-center justify-center bg-gray-50">
<div class="text-center">
<h1 class="mb-4 text-4xl font-bold text-primary">Bienvenue sur Classeo</h1>
<p class="mb-8 text-gray-600">Application de gestion scolaire</p>
<div class="rounded-lg bg-white p-8 shadow-md">
<p class="mb-4 text-2xl font-semibold text-gray-800">Compteur: {count}</p>
<button
onclick={increment}
class="rounded-md bg-primary px-6 py-2 text-primary-foreground transition-colors hover:bg-primary/90"
>
Incrementer
</button>
</div>
</div>
</main>