Initial commit: LMS microservices scaffold

- Gradle multi-module: libs/{common-http,security-jwt,markdown,test-support},
  services/{identity,academic,progress,gateway}, web (Thymeleaf+htmx)
- identity-service: JWT auth (RSA), accounts, students, groups, enrollment,
  import from XLSX/CSV, credentials export, password reset
- academic-service: lab import from JSON/zip (markdown + YAML + variants),
  levels, API
- progress-service: schema for student levels and variant assignments
- gateway: Spring Cloud Gateway, JWT validation, route propagation
- web: Server-side UI with flex/footer layout, light/dark theme toggle,
  admin dashboard, groups CRUD, student portal placeholder
- docker-compose: PostgreSQL 18
- Tests: identity smoke test with Testcontainers
This commit is contained in:
2026-09-10 19:46:13 +03:00
commit 2cee104633
125 changed files with 4752 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
*, *::before, *::after { box-sizing: border-box; }
html { height: 100%; }
:root {
--c-bg: #f8fafc;
--c-surface: #ffffff;
--c-text: #0f172a;
--c-text-muted: #64748b;
--c-text-link: #6366f1;
--c-text-link-hover: #4f46e5;
--c-border: #e2e8f0;
--c-accent: #6366f1;
--c-badge-ok-bg: #dcfce7;
--c-badge-ok-text: #166534;
--c-badge-warn-bg: #fef3c7;
--c-badge-warn-text: #92400e;
}
[data-theme="dark"] {
--c-bg: #0f1115;
--c-surface: #171a21;
--c-text: #e7e9ee;
--c-text-muted: #9aa3b2;
--c-text-link: #6ea8fe;
--c-text-link-hover: #8bb9fe;
--c-border: #262b36;
--c-accent: #6ea8fe;
--c-badge-ok-bg: rgba(16, 185, 129, 0.15);
--c-badge-ok-text: #6ee7b7;
--c-badge-warn-bg: rgba(251, 191, 36, 0.15);
--c-badge-warn-text: #fcd34d;
}
body {
margin: 0;
background: var(--c-bg);
color: var(--c-text);
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
line-height: 1.5;
}
a { color: var(--c-text-link); }
a:hover { color: var(--c-text-link-hover); }
.btn {
display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem;
border-radius: 0.5rem; padding: 0.5rem 1rem; font-size: 0.875rem; font-weight: 500;
border: none; cursor: pointer; transition: opacity 0.15s;
}
.btn:active { opacity: 0.8; }
.btn-primary { background: var(--c-accent); color: white; }
.btn-primary:hover { opacity: 0.9; }
.btn-secondary {
background: var(--c-surface); color: var(--c-text);
box-shadow: inset 0 0 0 1px var(--c-border);
}
.btn-secondary:hover { background: var(--c-border); }
.input {
width: 100%; border-radius: 0.5rem; background: var(--c-bg); color: var(--c-text);
padding: 0.5rem 0.75rem; font-size: 0.875rem; border: 1px solid var(--c-border);
outline: none;
}
.input:focus { border-color: var(--c-accent); box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2); }
.input::placeholder { color: var(--c-text-muted); }
.label { display: block; margin-bottom: 0.25rem; font-size: 0.875rem; font-weight: 500; }
.card {
border-radius: 0.75rem; background: var(--c-surface); border: 1px solid var(--c-border);
}
.badge { display: inline-flex; align-items: center; border-radius: 9999px; padding: 0.125rem 0.625rem; font-size: 0.75rem; font-weight: 500; }
.badge-ok { background: var(--c-badge-ok-bg); color: var(--c-badge-ok-text); }
.badge-warn { background: var(--c-badge-warn-bg); color: var(--c-badge-warn-text); }
table { width: 100%; font-size: 0.875rem; border-collapse: collapse; }
th { text-align: left; font-weight: 500; color: var(--c-text-muted); padding: 0.75rem 1.5rem; border-bottom: 1px solid var(--c-border); }
td { padding: 0.75rem 1.5rem; border-bottom: 1px solid var(--c-border); }
tr:last-child td { border-bottom: none; }

File diff suppressed because one or more lines are too long