docs: add README, LICENSE, .env.example
README in German with universal framing (class, study group, cohort) rather than INFO1-specific wording. MIT license. Update package.json with description, keywords, repository URL, proper license field, start script. Add .env.example documenting required environment variables.
This commit is contained in:
@@ -0,0 +1,11 @@
|
|||||||
|
# Required
|
||||||
|
JWT_SECRET=
|
||||||
|
|
||||||
|
# Mail (required for email verification and password reset)
|
||||||
|
RESEND_API_KEY=
|
||||||
|
MAIL_FROM=noreply@yourdomain.example
|
||||||
|
MAIL_FROM_NAME=Class Portal
|
||||||
|
|
||||||
|
# App
|
||||||
|
APP_URL=https://yourdomain.example
|
||||||
|
NODE_ENV=production
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 lulinretrograde
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
# INFO1
|
||||||
|
|
||||||
|
Ein selbst gehostetes Dashboard für eine Klasse, Lerngruppe oder kleine Kohorte. Ein Ort für Stundenplan, Hausaufgaben, Noten, Fehlzeiten, gemeinsamen Kalender, Klassenchat und Ende zu Ende verschlüsselte Direktnachrichten.
|
||||||
|
|
||||||
|
Bewusst unspektakulär aufgebaut: Node.js, Express, SQLite, vanilla JavaScript. Kein Buildschritt, kein Framework Lock in, läuft auf einem 1 GB VPS.
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
## Worum geht es
|
||||||
|
|
||||||
|
Die meisten Schul- und Lernplattformen sind schwergewichtig, kommerziell oder an eine bestimmte Institution gebunden. INFO1 ist das Gegenteil: eine einzige App, die jede Gruppe für sich selbst hosten kann, mit voller Kontrolle über die eigenen Daten und ohne Anbieter dazwischen.
|
||||||
|
|
||||||
|
Das Projekt nimmt Datenschutz ernst (Direktnachrichten werden im Browser verschlüsselt, der Server sieht nie Klartext), bleibt im Umfang ehrlich (für ein paar hundert aktive Nutzer, nicht für tausende) und ist so geschrieben, dass eine Person den Code an einem Nachmittag vollständig lesen kann.
|
||||||
|
|
||||||
|
## Funktionen
|
||||||
|
|
||||||
|
**Persönliches Dashboard**
|
||||||
|
- Stundenplan, Hausaufgabenverwaltung, Notenbuch mit automatischen Durchschnitten
|
||||||
|
- Fehlzeitenprotokoll, persönliche Todos, Countdowns, anpassbare Schnelllinks
|
||||||
|
- Dateiablage pro Nutzer mit Speicherkontingent
|
||||||
|
|
||||||
|
**Geteilte Klassenebene**
|
||||||
|
- Klassenkalender für Prüfungen, Ferien, Ereignisse (ohne Login einsehbar)
|
||||||
|
- Klassenchat mit Rate Limiting und sanfter Moderation
|
||||||
|
- Ende zu Ende verschlüsselte Gruppennachrichten (ECDH P-256 und AES-GCM, Schlüssel verlassen nie den Browser)
|
||||||
|
|
||||||
|
**Lehrerwerkzeuge**
|
||||||
|
- Fachbezogene Ankündigungen, Materialupload, Klausurplanung
|
||||||
|
- Direktes Setzen von Noten für einzelne Schüler
|
||||||
|
- Freigabeprozess: neue Lehrerkonten landen in einer Warteschlange für einen Admin
|
||||||
|
|
||||||
|
**Adminkonsole**
|
||||||
|
- Nutzerverwaltung (sperren, entsperren, befördern, zurückstufen, löschen)
|
||||||
|
- Manuelles Freischalten der E-Mail-Verifizierung, Rollenänderung, Auditlog
|
||||||
|
- Triage von Supporttickets mit Thread-Antworten
|
||||||
|
- Speicher- und Nutzungsstatistiken pro Nutzer
|
||||||
|
|
||||||
|
**Auth und Kontosicherheit**
|
||||||
|
- E-Mail-Verifizierung bei der Registrierung über [Resend](https://resend.com)
|
||||||
|
- Passwort-Reset per Mail mit einmalig verwendbaren Tokens (1 Stunde gültig)
|
||||||
|
- TOTP-Zweifaktor-Authentifizierung mit QR-Code
|
||||||
|
- Passwort-Hashing mit bcrypt (Kosten 12), JWT in HttpOnly-Cookie
|
||||||
|
- Rate Limiting auf allen sensiblen Endpoints
|
||||||
|
|
||||||
|
## Technologie
|
||||||
|
|
||||||
|
| Schicht | Wahl |
|
||||||
|
|---------|------|
|
||||||
|
| Laufzeit | Node.js 20, Express 5 |
|
||||||
|
| Datenbank | SQLite über `better-sqlite3` (synchron, in-process) |
|
||||||
|
| Auth | JWT im HttpOnly-Cookie, bcrypt, otplib für TOTP |
|
||||||
|
| Mail | Resend (austauschbar gegen jeden SMTP-Anbieter) |
|
||||||
|
| Frontend | Vanilla JavaScript, kein Bundler, kein Framework |
|
||||||
|
| Security | Helmet, CSP, express-rate-limit |
|
||||||
|
|
||||||
|
Gesamtgröße: rund 3 KLOC Servercode und eine Handvoll eigenständige HTML-Dateien.
|
||||||
|
|
||||||
|
## Schnellstart
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/lulinretrograde/ifb-schulapp.git info1
|
||||||
|
cd info1
|
||||||
|
npm install
|
||||||
|
cp .env.example .env # dann bearbeiten
|
||||||
|
node index.js
|
||||||
|
```
|
||||||
|
|
||||||
|
Die App bindet an `127.0.0.1:3010`. Für öffentliche Deployments einen Reverse Proxy davorschalten (Caddy, nginx, Cloudflare Tunnel).
|
||||||
|
|
||||||
|
## Konfiguration
|
||||||
|
|
||||||
|
Alle Einstellungen laufen über Umgebungsvariablen. Vollständige Liste in `.env.example`.
|
||||||
|
|
||||||
|
```dotenv
|
||||||
|
JWT_SECRET= # Pflicht, 32+ zufällige Bytes
|
||||||
|
RESEND_API_KEY= # Pflicht für Verifizierungs- und Reset-Mails
|
||||||
|
MAIL_FROM=noreply@deinedomain.example
|
||||||
|
MAIL_FROM_NAME=Klassenportal
|
||||||
|
APP_URL=https://deinedomain.example
|
||||||
|
NODE_ENV=production
|
||||||
|
```
|
||||||
|
|
||||||
|
### E-Mail-Domain-Beschränkung
|
||||||
|
|
||||||
|
Die Registrierung ist standardmäßig auf eine einzige E-Mail-Domain beschränkt, via Regex in `src/routes.js`. `IFB_EMAIL_RE` anpassen oder entfernen, um die Beschränkung zu lockern, oder durch eine eigene Allowlist ersetzen.
|
||||||
|
|
||||||
|
### Datenbank
|
||||||
|
|
||||||
|
SQLite-Datei liegt unter `./data.db` und wird beim ersten Start erzeugt. Migrationen sind idempotent und stehen am Ende von `src/db.js`. Für ein Backup die Datei zur Laufzeit kopieren (SQLite erlaubt parallele Lesezugriffe während des Kopierens).
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
Minimale systemd-Unit:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[Unit]
|
||||||
|
Description=INFO1
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=www
|
||||||
|
WorkingDirectory=/opt/info1
|
||||||
|
ExecStart=/usr/bin/node index.js
|
||||||
|
Restart=always
|
||||||
|
Environment=NODE_ENV=production
|
||||||
|
EnvironmentFile=/opt/info1/.env
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
```
|
||||||
|
|
||||||
|
TLS am Reverse Proxy terminieren und `NODE_ENV=production` setzen, damit das Auth-Cookie das `Secure`-Flag bekommt.
|
||||||
|
|
||||||
|
## Sicherheit
|
||||||
|
|
||||||
|
- Die App startet nicht, wenn `JWT_SECRET` nicht gesetzt ist.
|
||||||
|
- Direktnachrichten werden im Browser verschlüsselt, bevor sie hochgeladen werden. Der Server speichert ausschließlich opaken Chiffretext und kann auch mit Datenbankzugriff den Inhalt nicht lesen.
|
||||||
|
- Alle schreibenden Endpoints sind Rate limitiert. Die Limits sind für kleine Gruppen abgestimmt und sollten für größere Deployments nachgezogen werden.
|
||||||
|
- Adminaktionen landen in `admin_logs` mit Akteur, Ziel und einem JSON-Detail-Blob.
|
||||||
|
|
||||||
|
Verantwortungsvolle Offenlegung von Schwachstellen: Issue mit Kurzbeschreibung öffnen, Details per Mail nachreichen.
|
||||||
|
|
||||||
|
## Projektstruktur
|
||||||
|
|
||||||
|
```
|
||||||
|
index.js Express-Bootstrap, Static Serving, Routenmontage
|
||||||
|
src/
|
||||||
|
db.js SQLite-Singleton, Schema, Migrationen
|
||||||
|
auth.js JWT-Hilfsfunktionen, requireAuth-Middleware
|
||||||
|
routes.js Auth-Endpoints, Admin, Tickets, Chat, Klassenkalender
|
||||||
|
teacher.js Lehrer-Endpoints und Material-Upload
|
||||||
|
files.js Dateiablage pro Nutzer mit Quota
|
||||||
|
mailer.js Resend-Wrapper und Mail-Templates
|
||||||
|
public/
|
||||||
|
index.html Öffentliche Startseite
|
||||||
|
login.html Login, Registrierung, Passwort-Reset
|
||||||
|
app.html Hauptdashboard nach Login
|
||||||
|
admin.html Adminkonsole
|
||||||
|
reset-password.html Zielseite für Passwort-Reset-Links
|
||||||
|
datenschutz.html Datenschutzerklärung
|
||||||
|
e2ee.js Kryptoprimitiven für Ende zu Ende Verschlüsselung
|
||||||
|
```
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Aktiv entwickelt für eine einzelne Kohorte. Im produktiven Einsatz bei einer kleinen Gruppe von Lernenden und Lehrenden. Die APIs sind nicht versioniert und können sich zwischen Commits ändern.
|
||||||
|
|
||||||
|
## Lizenz
|
||||||
|
|
||||||
|
MIT. Siehe [LICENSE](./LICENSE).
|
||||||
+10
-6
@@ -1,14 +1,18 @@
|
|||||||
{
|
{
|
||||||
"name": "info1",
|
"name": "info1",
|
||||||
"version": "1.0.0",
|
"version": "0.1.0",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"start": "node index.js"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": ["dashboard", "education", "class", "self-hosted", "e2ee", "express", "sqlite"],
|
||||||
"author": "",
|
"author": "lulinretrograde",
|
||||||
"license": "ISC",
|
"license": "MIT",
|
||||||
"description": "",
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/lulinretrograde/ifb-schulapp.git"
|
||||||
|
},
|
||||||
|
"description": "Self-hosted class dashboard: timetable, homework, grades, shared calendar, class chat, and end-to-end encrypted direct messages. Built on Node.js, Express, SQLite, vanilla JS.",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bcryptjs": "^3.0.3",
|
"bcryptjs": "^3.0.3",
|
||||||
"better-sqlite3": "^12.9.0",
|
"better-sqlite3": "^12.9.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user