A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.
This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).
Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
134 lines
4.8 KiB
Go
134 lines
4.8 KiB
Go
package main
|
|
|
|
import (
|
|
"log"
|
|
|
|
"github.com/breakpilot/school-service/internal/config"
|
|
"github.com/breakpilot/school-service/internal/database"
|
|
"github.com/breakpilot/school-service/internal/handlers"
|
|
"github.com/breakpilot/school-service/internal/middleware"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func main() {
|
|
// Load configuration
|
|
cfg, err := config.Load()
|
|
if err != nil {
|
|
log.Fatalf("Failed to load configuration: %v", err)
|
|
}
|
|
|
|
// Set Gin mode based on environment
|
|
if cfg.Environment == "production" {
|
|
gin.SetMode(gin.ReleaseMode)
|
|
}
|
|
|
|
// Connect to database
|
|
db, err := database.Connect(cfg.DatabaseURL)
|
|
if err != nil {
|
|
log.Fatalf("Failed to connect to database: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
// Run migrations
|
|
if err := database.Migrate(db); err != nil {
|
|
log.Fatalf("Failed to run migrations: %v", err)
|
|
}
|
|
|
|
// Create handler
|
|
handler := handlers.NewHandler(db.Pool, cfg.LLMGatewayURL)
|
|
|
|
// Create router
|
|
router := gin.New()
|
|
router.Use(gin.Recovery())
|
|
router.Use(middleware.RequestLogger())
|
|
router.Use(middleware.CORS())
|
|
router.Use(middleware.RateLimiter())
|
|
|
|
// Health endpoint (no auth required)
|
|
router.GET("/health", handler.Health)
|
|
|
|
// API routes (auth required)
|
|
api := router.Group("/api/v1/school")
|
|
api.Use(middleware.AuthMiddleware(cfg.JWTSecret))
|
|
{
|
|
// School Years
|
|
api.GET("/years", handler.GetSchoolYears)
|
|
api.POST("/years", handler.CreateSchoolYear)
|
|
|
|
// Classes
|
|
api.GET("/classes", handler.GetClasses)
|
|
api.POST("/classes", handler.CreateClass)
|
|
api.GET("/classes/:id", handler.GetClass)
|
|
api.DELETE("/classes/:id", handler.DeleteClass)
|
|
|
|
// Students (nested under classes)
|
|
api.GET("/classes/:id/students", handler.GetStudents)
|
|
api.POST("/classes/:id/students", handler.CreateStudent)
|
|
api.POST("/classes/:id/students/import", handler.ImportStudents)
|
|
api.DELETE("/classes/:id/students/:studentId", handler.DeleteStudent)
|
|
|
|
// Subjects
|
|
api.GET("/subjects", handler.GetSubjects)
|
|
api.POST("/subjects", handler.CreateSubject)
|
|
api.DELETE("/subjects/:id", handler.DeleteSubject)
|
|
|
|
// Exams
|
|
api.GET("/exams", handler.GetExams)
|
|
api.POST("/exams", handler.CreateExam)
|
|
api.GET("/exams/:id", handler.GetExam)
|
|
api.PUT("/exams/:id", handler.UpdateExam)
|
|
api.DELETE("/exams/:id", handler.DeleteExam)
|
|
api.POST("/exams/:id/generate-variant", handler.GenerateExamVariant)
|
|
api.GET("/exams/:id/results", handler.GetExamResults)
|
|
api.POST("/exams/:id/results", handler.SaveExamResults)
|
|
api.PUT("/exams/:id/results/:studentId/approve", handler.ApproveExamResult)
|
|
api.GET("/exams/:id/needs-rewrite", handler.GetStudentsNeedingRewrite)
|
|
|
|
// Grades
|
|
api.GET("/grades/:classId", handler.GetClassGrades)
|
|
api.GET("/grades/student/:studentId", handler.GetStudentGrades)
|
|
api.PUT("/grades/:studentId/:subjectId/oral", handler.UpdateOralGrade)
|
|
api.POST("/grades/calculate", handler.CalculateFinalGrades)
|
|
api.POST("/grades/transfer", handler.TransferApprovedGrades)
|
|
api.PUT("/grades/:studentId/:subjectId/lock", handler.LockFinalGrade)
|
|
api.PUT("/grades/:studentId/:subjectId/weights", handler.UpdateGradeWeights)
|
|
|
|
// Statistics
|
|
api.GET("/statistics/:classId", handler.GetClassStatistics)
|
|
api.GET("/statistics/:classId/subject/:subjectId", handler.GetSubjectStatistics)
|
|
api.GET("/statistics/student/:studentId", handler.GetStudentStatistics)
|
|
api.GET("/statistics/:classId/notenspiegel", handler.GetNotenspiegel)
|
|
|
|
// Attendance
|
|
api.GET("/attendance/:classId", handler.GetClassAttendance)
|
|
api.GET("/attendance/student/:studentId", handler.GetStudentAttendance)
|
|
api.POST("/attendance", handler.CreateAttendance)
|
|
api.POST("/attendance/:classId/bulk", handler.BulkCreateAttendance)
|
|
api.DELETE("/attendance/:id", handler.DeleteAttendance)
|
|
|
|
// Gradebook Entries
|
|
api.GET("/gradebook/:classId", handler.GetGradebookEntries)
|
|
api.GET("/gradebook/student/:studentId", handler.GetStudentEntries)
|
|
api.POST("/gradebook", handler.CreateGradebookEntry)
|
|
api.DELETE("/gradebook/:id", handler.DeleteGradebookEntry)
|
|
|
|
// Certificates
|
|
api.GET("/certificates/templates", handler.GetCertificateTemplates)
|
|
api.GET("/certificates/class/:classId", handler.GetClassCertificates)
|
|
api.GET("/certificates/feedback/:studentId", handler.GenerateGradeFeedback)
|
|
api.POST("/certificates/generate", handler.GenerateCertificate)
|
|
api.POST("/certificates/generate-bulk", handler.BulkGenerateCertificates)
|
|
api.GET("/certificates/detail/:id", handler.GetCertificate)
|
|
api.PUT("/certificates/detail/:id", handler.UpdateCertificate)
|
|
api.PUT("/certificates/detail/:id/finalize", handler.FinalizeCertificate)
|
|
api.GET("/certificates/detail/:id/pdf", handler.GetCertificatePDF)
|
|
api.DELETE("/certificates/detail/:id", handler.DeleteCertificate)
|
|
}
|
|
|
|
// Start server
|
|
log.Printf("School Service starting on port %s", cfg.Port)
|
|
if err := router.Run(":" + cfg.Port); err != nil {
|
|
log.Fatalf("Failed to start server: %v", err)
|
|
}
|
|
}
|