Inhalt
Aktueller Ordner:
duesseldorfer-schuelerinventar-swift-client
📖 Readme-Datei automatisch erkannt
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
- Features
- Technologie-Stack
- API-Dokumentation
- Datenbankstruktur
- Installation
- Projektstruktur
- Berechnungslogik
- Konfiguration
- Fehlerbehandlung
- Entwicklung
- 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.phpResponse: 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.phpRequest Body: Vollständiges Profil-Objekt
Response: 200 OK bei Erfolg
#### PUT
/api_profiles.phpRequest 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.phpResponse:
`json[
{"gruppeID": 1, "name": "Klasse 8a"},
{"gruppeID": 2, "name": "Klasse 8b"}
]
`#### POST
/api_groups.phpRequest 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
`bashRepository 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:
`bashswift build
swift run
`Server (PHP API) Setup
`bash1. 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
`swiftfunc 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)
`swiftfunc 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
`bashEntwicklung
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
`bashSwift Tests
cd duesk-swift
swift test
Build für Produktion
`bashiOS App (IPA)
xcodebuild -scheme Duesk -configuration Release archive
macOS App (APP)
xcodebuild -scheme Duesk -configuration Release build
Java JAR
mvn clean package
`