V 1.0.0 (front/backend) Erste lauffähige Version

This commit is contained in:
rxf
2025-11-23 12:14:58 +01:00
commit 3a6af1caca
20 changed files with 1085 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
services:
mongodb:
image: mongo:latest
container_name: mongodb
restart: unless-stopped
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: ${MONGO_ROOT_USER}
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWD}
volumes:
- mongodb_data:/data/db
- mongodb_config:/data/configdb
volumes:
mongodb_data:
mongodb_config:

24
backend/package.json Normal file
View File

@@ -0,0 +1,24 @@
{
"name": "backend",
"type": "module",
"version": "1.0.0",
"vdate": "2025-11-23 11:00 UTC",
"description": "",
"main": "index.js",
"scripts": {
"start": "node src/server.js",
"dev": "nodemon src/server.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"cors": "^2.8.5",
"dotenv": "^17.2.3",
"express": "^5.1.0",
"mongodb": "^7.0.0"
},
"devDependencies": {
"nodemon": "^3.1.11"
}
}

40
backend/src/db/db.js Normal file
View File

@@ -0,0 +1,40 @@
// src/db/db.js
import 'dotenv/config'; // Importiert und lädt Umgebungsvariablen
import { MongoClient } from 'mongodb';
// MongoDB Verbindungs-URI aus der .env-Datei
const uri = process.env.MONGO_URI;
let db;
/**
* Stellt die Verbindung zur MongoDB her.
* @returns {db} Die verbundene Datenbankinstanz.
*/
export async function connectToDb() {
try {
const client = new MongoClient(uri, {
});
await client.connect();
// Die Datenbankinstanz speichern
db = client.db();
console.log(`✅ Erfolgreich mit MongoDB verbunden.`);
return db;
} catch (error) {
console.error("❌ Fehler bei der Verbindung zur MongoDB:", error);
process.exit(1);
}
}
/**
* Gibt die gespeicherte Datenbankinstanz zurück.
* @returns {db} Die Datenbankinstanz.
*/
export function getDb() {
return db;
}

154
backend/src/server.js Normal file
View File

@@ -0,0 +1,154 @@
// src/server.js
import 'dotenv/config';
import express from 'express';
import cors from 'cors';
import { connectToDb, getDb } from './db/db.js';
import { ObjectId } from 'mongodb'; // Wichtig für die Arbeit mit MongoDB IDs
// Initialisiert Express
const app = express();
const PORT = process.env.PORT || 3001;
// Middleware konfigurieren - CORS muss vor allen Routen kommen
app.use((req, res, next) => {
console.log(`📥 ${req.method} ${req.path} from ${req.get('origin') || 'unknown origin'}`);
res.header('Access-Control-Allow-Origin', 'http://localhost:5173');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
res.header('Access-Control-Allow-Credentials', 'true');
// Handle preflight requests
if (req.method === 'OPTIONS') {
console.log('✅ Preflight request handled');
return res.sendStatus(200);
}
next();
});
app.use(express.json());
// -----------------------------------------------------
// API ROUTEN
// -----------------------------------------------------
// 1. READ: Alle Termine abrufen (GET /api/appointments)
app.get('/api/appointments', async (req, res) => {
try {
const db = getDb();
// Finde alle Dokumente in der Collection 'appointments'
const appointments = await db.collection('appointments')
.find({})
// Optional: Nach Termindatum sortieren (aufsteigend)
.sort({ termin: 1 })
.toArray();
// Sende die Daten zurück an das Frontend
res.json(appointments);
} catch (error) {
console.error("Fehler beim Abrufen der Termine:", error);
res.status(500).json({ message: "Interner Serverfehler beim Abrufen der Daten." });
}
});
// 2. CREATE: Neuen Termin erstellen (POST /api/appointments)
app.post('/api/appointments', async (req, res) => {
try {
const db = getDb();
const appointmentData = req.body; // Die Daten kommen vom React-Formular
// Validiere, dass der Termin ein gültiges Datum hat (Optional, aber gut)
if (!appointmentData.arztName || !appointmentData.termin) {
return res.status(400).json({ message: "Arztname und Termin sind erforderlich." });
}
// Mongo generiert die _id automatisch.
const result = await db.collection('appointments').insertOne(appointmentData);
// Der eingefügte Termin, inklusive der von Mongo erstellten _id
const newAppointment = { _id: result.insertedId, ...appointmentData };
// Sende den neu erstellten Termin zurück an das Frontend (Status 201 Created)
res.status(201).json(newAppointment);
} catch (error) {
console.error("Fehler beim Erstellen des Termins:", error);
res.status(500).json({ message: "Interner Serverfehler beim Speichern der Daten." });
}
});
// 3. UPDATE: Termin aktualisieren (PUT /api/appointments/:id)
app.put('/api/appointments/:id', async (req, res) => {
try {
const db = getDb();
const { id } = req.params;
const updatedFields = req.body; // Enthält alle Felder (oder nur die geänderten)
// Die _id des Dokuments muss ein gültiges ObjectId-Objekt sein
const filter = { _id: new ObjectId(id) };
// Entferne das _id Feld aus den aktualisierten Daten, um Fehler zu vermeiden
delete updatedFields._id;
// Führe die Aktualisierung durch
const result = await db.collection('appointments').updateOne(
filter,
{ $set: updatedFields }
);
if (result.matchedCount === 0) {
return res.status(404).json({ message: "Termin nicht gefunden." });
}
// Hole das aktualisierte Dokument, um es zurückzusenden (optional, aber nützlich)
const updatedAppointment = await db.collection('appointments').findOne(filter);
res.json(updatedAppointment);
} catch (error) {
console.error(`Fehler beim Aktualisieren des Termins ${req.params.id}:`, error);
// Gib einen 400 Bad Request zurück, falls die ID ungültig ist (z.B. falsches Format)
res.status(400).json({ message: "Ungültige ID oder Serverfehler." });
}
});
// 4. DELETE: Termin löschen (DELETE /api/appointments/:id)
app.delete('/api/appointments/:id', async (req, res) => {
try {
const db = getDb();
const { id } = req.params;
const filter = { _id: new ObjectId(id) };
const result = await db.collection('appointments').deleteOne(filter);
if (result.deletedCount === 0) {
return res.status(404).json({ message: "Termin nicht gefunden." });
}
// Sende Status 204 (No Content), um den erfolgreichen Löschvorgang zu signalisieren
res.status(204).send();
} catch (error) {
console.error(`Fehler beim Löschen des Termins ${req.params.id}:`, error);
res.status(400).json({ message: "Ungültige ID oder Serverfehler." });
}
});
// -----------------------------------------------------
// Server Start Logik
// -----------------------------------------------------
async function startServer() {
try {
await connectToDb();
app.listen(PORT, () => {
console.log(`🚀 Server läuft auf Port ${PORT}`);
});
} catch (error) {
console.error("Fehler beim Starten des Servers:", error);
}
}
startServer();