# DÜSK - Düsseldorfer Schülerinventar **DÜSK** ist eine professionelle Desktop- und Mobile-Anwendung zur Erfassung und Auswertung von Selbst- und Fremdeinschätzungen von Schülerkompetenzen. Die Anwendung kommuniziert mit einer PHP-API und ist sowohl als Swift/iOS-App als auch als Java/Swing-Desktop-Version verfügbar. ## 📋 Inhaltsverzeichnis - [Überblick](#-überblick) - [Features](#-features) - [Technologie-Stack](#-technologie-stack) - [API-Dokumentation](#-api-dokumentation) - [Datenbankstruktur](#-datenbankstruktur) - [Installation](#-installation) - [Projektstruktur](#-projektstruktur) - [Berechnungslogik](#-berechnungslogik) - [Konfiguration](#-konfiguration) - [Fehlerbehandlung](#-fehlerbehandlung) - [Entwicklung](#-entwicklung) - [Lizenz](#-lizenz) --- ## 🎯 Überblick DÜSK (Düsseldorfer Schülerinventar) ist ein diagnostisches Instrument zur Erfassung von Schülerkompetenzen in sechs Bereichen: 1. **Arbeitsverhalten** - Zuverlässigkeit, Arbeitstempo, Planung 2. **Lernverhalten** - Selbstständigkeit, Belastbarkeit, Konzentration 3. **Sozialverhalten** - Teamfähigkeit, Hilfsbereitschaft, Kommunikation 4. **Fachkompetenz** - Schreiben, Lesen, Mathematik, Naturwissenschaften 5. **Personale Kompetenz** - Kreativität, Problemlösung, Abstraktion 6. **Methodenkompetenz** - Präsentation, PC-Kenntnisse, fächerübergreifendes Denken Die Anwendung ermöglicht den Vergleich von Selbst- (SE) und Fremdeinschätzung (FE) mit Normtabellen für Hauptschulen (HS) und Förderschulen (FS). --- ## ✨ Features ### Kernfunktionen - ✅ **Login/Logout** mit Session-Verwaltung - ✅ **CRUD-Operationen** für Schülerprofile - ✅ **36 Items** pro Einschätzung (4-stufige Likert-Skala) - ✅ **Automatische Kompetenzberechnung** aus 72 Items - ✅ **Normwertvergleich** (HS/FS Normtabellen) - ✅ **Profilansicht** mit Tabellen, Diagrammen und Interpretation ### Erweiterte Funktionen - 📊 **Zeitreihenanalyse** für Gruppenentwicklung - 📈 **Vergleichsdiagramme** (SE vs. FE) - 📐 **Korrelationsberechnung** (Pearson) - 📑 **Exportfunktion** (PDF/CSV/Text) - 🔍 **Such- und Filterfunktionen** - 📁 **Gruppenverwaltung** (CRUD) - 🌙 **Dark Mode Support** - 💾 **Offline-Cache** (Core Data) --- ## 🛠 Technologie-Stack ### Swift/iOS Version | Komponente | Technologie | Version | |------------|-------------|---------| | Sprache | Swift | 5.7+ | | UI-Framework | SwiftUI | - | | Netzwerk | URLSession (async/await) | - | | Diagramme | Swift Charts | iOS 16+ | | Persistenz | Core Data (optional) | - | | Mindest-iOS | iOS 16.0 | - | | Mindest-macOS | macOS 13.0 | - | ### Server (PHP API) | Komponente | Technologie | |------------|-------------| | Backend | PHP 7.4+ | | Datenbank | MySQL 5.7+ | | Webserver | Apache/Nginx | | Format | JSON | --- ## 📡 API-Dokumentation Die REST-API ist unter `https://paul-koop.org/api/` verfügbar. ### Authentifizierung #### POST `/api_login.php` ```json // Request { "username": "gast", "password": "gast" } // Response (Success) { "success": true, "userID": "12345", "session": "abc123def456" } // Response (Error) { "success": false, "error": "Invalid credentials" } ``` ### Profile-Endpunkte Alle Profile-Endpunkte benötigen die Header: - `X-User-ID`: Benutzer-ID aus Login - `X-Session`: Session-Token aus Login #### GET `/api_profiles.php` **Response**: Array aller Profile ```json [ { "profilID": "1", "name": "Max Mustermann", "gruppename": "Klasse 8a", "gruppeID": "5", "item1": 4, "item2": 3, ..., "item36": 2, "feitem1": 3, "feitem2": 4, ..., "feitem36": 3 } ] ``` #### GET `/api_profiles.php?id={profileId}` **Response**: Einzelnes Profil #### POST `/api_profiles.php` **Request Body**: Vollständiges Profil-Objekt **Response**: 200 OK bei Erfolg #### PUT `/api_profiles.php` **Request Body**: Aktualisiertes Profil-Objekt **Response**: 200 OK bei Erfolg #### DELETE `/api_profiles.php?id={profileId}` **Response**: 200 OK bei Erfolg ### Gruppen-Endpunkte #### GET `/api_groups.php` **Response**: ```json [ {"gruppeID": 1, "name": "Klasse 8a"}, {"gruppeID": 2, "name": "Klasse 8b"} ] ``` #### POST `/api_groups.php` **Request Body**: `{"name": "Neue Gruppe"}` **Response**: 200 OK bei Erfolg #### DELETE `/api_groups.php?id={groupId}` **Response**: 200 OK bei Erfolg --- ## 🗄 Datenbankstruktur ### Tabelle: `profiles` | Feld | Typ | Beschreibung | |------|-----|---------------| | `profilID` | INT AUTO_INCREMENT | Primärschlüssel | | `userID` | INT | Fremdschlüssel zu users | | `name` | VARCHAR(255) | Profilname | | `gruppeID` | INT | Fremdschlüssel zu groups | | `created_at` | TIMESTAMP | Erstellungsdatum | | `updated_at` | TIMESTAMP | Letzte Änderung | | `item1` - `item36` | TINYINT | SE-Items (1-4) | | `feitem1` - `feitem36` | TINYINT | FE-Items (1-4) | ### Tabelle: `groups` | Feld | Typ | Beschreibung | |------|-----|---------------| | `gruppeID` | INT AUTO_INCREMENT | Primärschlüssel | | `userID` | INT | Fremdschlüssel zu users | | `name` | VARCHAR(255) | Gruppenname | | `created_at` | TIMESTAMP | Erstellungsdatum | ### Tabelle: `users` | Feld | Typ | Beschreibung | |------|-----|---------------| | `userID` | INT AUTO_INCREMENT | Primärschlüssel | | `username` | VARCHAR(50) | Benutzername (unique) | | `password_hash` | VARCHAR(255) | Gehashter Passwort | | `session_token` | VARCHAR(255) | Aktueller Session-Token | | `created_at` | TIMESTAMP | Registrierungsdatum | ### SQL-Schema ```sql -- Users Tabelle CREATE TABLE users ( userID INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) UNIQUE NOT NULL, password_hash VARCHAR(255) NOT NULL, session_token VARCHAR(255), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- Groups Tabelle CREATE TABLE groups ( gruppeID INT AUTO_INCREMENT PRIMARY KEY, userID INT NOT NULL, name VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (userID) REFERENCES users(userID) ON DELETE CASCADE, UNIQUE KEY unique_group_per_user (userID, name) ); -- Profiles Tabelle CREATE TABLE profiles ( profilID INT AUTO_INCREMENT PRIMARY KEY, userID INT NOT NULL, name VARCHAR(255) NOT NULL, gruppeID INT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 36 SE-Items item1 TINYINT DEFAULT 2, item2 TINYINT DEFAULT 2, ..., item36 TINYINT DEFAULT 2, -- 36 FE-Items feitem1 TINYINT DEFAULT 2, feitem2 TINYINT DEFAULT 2, ..., feitem36 TINYINT DEFAULT 2, FOREIGN KEY (userID) REFERENCES users(userID) ON DELETE CASCADE, FOREIGN KEY (gruppeID) REFERENCES groups(gruppeID) ON DELETE SET NULL ); ``` --- ## 💻 Installation ### Swift (iOS/macOS) Version ```bash # Repository klonen git clone https://github.com/yourusername/duesk-swift.git cd duesk-swift # Xcode-Projekt öffnen open Duesk.xcodeproj # Build und Run (⌘R) ``` **Oder mit Swift Package Manager:** ```bash swift build swift run ``` ### Server (PHP API) Setup ```bash # 1. Dateien auf Webserver kopieren scp -r api/* user@server:/var/www/html/api/ # 2. Datenbank einrichten mysql -u root -p < database/schema.sql # 3. Konfiguration anpassen cp config.sample.php config.php vim config.php # 4. Verzeichnisberechtigungen setzen chmod 755 /var/www/html/api/ chmod 644 /var/www/html/api/*.php ``` --- ## 📁 Projektstruktur ### Swift Version ``` duesk-swift/ ├── Duesk.xcodeproj/ # Xcode Projektdatei ├── Duesk/ │ ├── App/ │ │ ├── DueskApp.swift # App-Einstiegspunkt │ │ └── Info.plist # App-Konfiguration │ ├── Models/ │ │ ├── LoginResponse.swift # API Response Model │ │ ├── Profile.swift # Profil Datenmodell │ │ ├── Group.swift # Gruppen Datenmodell │ │ └── Norms.swift # Normtabellen & Konstanten │ ├── Views/ │ │ ├── LoginView.swift # Login-Screen │ │ ├── MainView.swift # Hauptansicht mit Sidebar │ │ ├── ProfileDetailView.swift # Profildetails mit Charts │ │ ├── ProfileEditView.swift # Profil bearbeiten/erstellen │ │ ├── GroupManagerView.swift # Gruppenverwaltung │ │ └── TimeSeriesView.swift # Zeitreihenanalyse │ ├── ViewModels/ │ │ ├── LoginViewModel.swift │ │ ├── ProfileListViewModel.swift │ │ ├── ProfileDetailViewModel.swift │ │ ├── ProfileEditViewModel.swift │ │ ├── GroupManagerViewModel.swift │ │ └── TimeSeriesViewModel.swift │ ├── Services/ │ │ ├── APIService.swift # Netzwerk-API Calls │ │ ├── SessionManager.swift # Session & Auth │ │ └── Calculator.swift # Berechnungslogik │ └── Assets.xcassets/ # App Icons & Assets └── README.md ``` ### Server API Struktur ``` /var/www/html/api/ ├── api_login.php # Login-Endpunkt ├── api_profiles.php # Profile CRUD ├── api_groups.php # Gruppen CRUD ├── config.php # Datenbankkonfiguration ├── database/ │ ├── schema.sql # DB-Schema │ └── seed.sql # Testdaten ├── includes/ │ ├── db_connection.php # DB-Verbindungsklasse │ └── auth.php # Authentifizierungs-Middleware └── .htaccess # Apache Rewrite Rules ``` --- ## 🧮 Berechnungslogik ### Item-zu-Kompetenz-Zuordnung ```swift // Kompetenz 1: Arbeitsverhalten (Items 1-10) let kompetenz1 = items[0...9] // Kompetenz 2: Lernverhalten (Items 11-20) let kompetenz2 = items[10...19] // Kompetenz 3: Sozialverhalten (Items 21-28 + 9-10) let kompetenz3 = items[20...27] + [items[8], items[9]] // Kompetenz 4: Fachkompetenz (Items 29-36) let kompetenz4 = items[28...35] // Kompetenz 5: Personale Kompetenz let kompetenz5 = [items[0], items[1], items[5], items[6], items[7], items[8], items[9], items[11], items[12], items[13], items[14]] // Kompetenz 6: Methodenkompetenz let kompetenz6 = [items[2], items[3], items[4], items[8], items[9], items[10], items[16], items[17]] ``` ### Profilwertberechnung ```swift func calculateProfileValue(rawSum: Int, normTable: [Double]) -> Int { // 1 = weit unterdurchschnittlich // 2 = unterdurchschnittlich // 3 = durchschnittlich // 4 = überdurchschnittlich // 5 = weit überdurchschnittlich for (index, threshold) in normTable.enumerated() { if Double(rawSum) < threshold { return index + 1 } } return 5 } ``` ### Korrelationsberechnung (Pearson) ```swift func pearsonCorrelation(x: [Double], y: [Double]) -> Double { let n = Double(x.count) let sumX = x.reduce(0, +) let sumY = y.reduce(0, +) let sumXY = zip(x, y).map(*).reduce(0, +) let sumX2 = x.map { $0 * $0 }.reduce(0, +) let sumY2 = y.map { $0 * $0 }.reduce(0, +) let numerator = sumXY - (sumX * sumY / n) let denominator = sqrt((sumX2 - (sumX * sumX / n)) * (sumY2 - (sumY * sumY / n))) return denominator == 0 ? 0 : numerator / denominator } ``` ### Normtabellen (Auszug) | Kompetenz | HS SE (Perzentile) | HS FE (Perzentile) | |-----------|-------------------|-------------------| | Arbeitsverhalten | 21.3, 25.3, 29.3, 33.3, 37.3 | 12.7, 18.2, 23.7, 29.2, 34.7 | | Lernverhalten | 20.9, 24.9, 29.0, 33.1, 37.2 | 13.3, 18.4, 23.5, 28.6, 33.7 | | Sozialverhalten | 17.9, 21.4, 24.8, 28.2, 31.7 | 10.8, 15.4, 20.1, 24.7, 29.4 | | Fachkompetenz | 14.0, 17.7, 21.4, 25.2, 28.9 | 14.2, 15.3, 16.4, 17.5, 18.5 | | Personale Kompetenz | 24.6, 28.6, 33.0, 37.5, 42.0 | 14.1, 20.2, 26.3, 32.4, 38.5 | | Methodenkompetenz | 15.5, 19.0, 22.4, 25.8, 29.3 | 10.5, 14.5, 18.5, 22.5, 26.5 | --- ## ⚙️ Konfiguration ### API Base URL ändern **Swift:** ```swift // APIService.swift private let baseURL = "https://your-server.com/api/" ``` **PHP (Server):** ```php // config.php define('DB_HOST', 'localhost'); define('DB_NAME', 'duesk'); define('DB_USER', 'username'); define('DB_PASS', 'password'); define('API_SECRET', 'your-secret-key'); ``` ### Umgebungsvariablen ```bash # Entwicklung export API_URL="https://dev.paul-koop.org/api/" export DEBUG_MODE=true # Produktion export API_URL="https://paul-koop.org/api/" export DEBUG_MODE=false ``` --- ## 🐛 Fehlerbehandlung ### HTTP-Statuscodes | Code | Bedeutung | Behandlung | |------|-----------|------------| | 200 | Erfolg | Daten verarbeiten | | 400 | Bad Request | Validierungsfehler prüfen | | 401 | Unauthorized | Neu anmelden | | 403 | Forbidden | Berechtigung prüfen | | 404 | Not Found | Ressource existiert nicht | | 500 | Server Error | Erneut versuchen, Support kontaktieren | ### Typische Fehler und Lösungen ```swift // Netzwerkfehler do { let profiles = try await APIService.shared.getProfiles() } catch let error as URLError { switch error.code { case .notConnectedToInternet: showAlert("Keine Internetverbindung") case .timedOut: showAlert("Verbindung zeitüberschritten") default: showAlert("Netzwerkfehler: \(error.localizedDescription)") } } ``` --- ## 👨‍💻 Entwicklung ### Voraussetzungen **Swift Entwicklung:** - macOS 12.0+ - Xcode 14.0+ - Swift 5.7+ ### Tests ausführen ```bash # Swift Tests cd duesk-swift swift test ### Build für Produktion ```bash # iOS App (IPA) xcodebuild -scheme Duesk -configuration Release archive # macOS App (APP) xcodebuild -scheme Duesk -configuration Release build # Java JAR mvn clean package ```