first commit
This commit is contained in:
12
.env.example
Normal file
12
.env.example
Normal file
@@ -0,0 +1,12 @@
|
||||
# Database Connection
|
||||
DATABASE_URL="postgres://postgres:"
|
||||
|
||||
# Security
|
||||
JWT_SECRET="change_this_to_a_secure_secret"
|
||||
|
||||
# SMTP Configuration
|
||||
SMTP_HOST="smtp.example.com"
|
||||
SMTP_PORT=587
|
||||
SMTP_USER="user@example.com"
|
||||
SMTP_PASS="password"
|
||||
SMTP_FROM="noreply@smartes-klassenzimmer.de"
|
||||
@@ -9,17 +9,10 @@ async function bootstrap() {
|
||||
|
||||
// CORS Konfiguration
|
||||
app.enableCors({
|
||||
origin: [
|
||||
'http://localhost:5173', // Vite Dev Server
|
||||
'http://127.0.0.1:5173', // Vite Dev Server (Alternative)
|
||||
'http://localhost:5500',
|
||||
'http://127.0.0.1:5500',
|
||||
'http://localhost',
|
||||
'*'
|
||||
],
|
||||
origin: true,
|
||||
credentials: true,
|
||||
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
|
||||
allowedHeaders: ['Content-Type', 'Authorization'],
|
||||
allowedHeaders: ['Content-Type', 'Authorization', 'Accept'],
|
||||
});
|
||||
|
||||
// Globales Präfix für alle Routes
|
||||
@@ -37,6 +30,6 @@ async function bootstrap() {
|
||||
}),
|
||||
);
|
||||
|
||||
await app.listen(process.env.PORT ?? 3000);
|
||||
await app.listen(process.env.PORT ?? 3000, '0.0.0.0');
|
||||
}
|
||||
bootstrap();
|
||||
|
||||
@@ -2,7 +2,7 @@ import { browser } from '$app/environment';
|
||||
|
||||
// API Client für Backend-Kommunikation
|
||||
const API_BASE_URL = browser
|
||||
? (import.meta.env.VITE_API_BASE_URL || 'http://localhost:3000/api')
|
||||
? (import.meta.env.VITE_API_BASE_URL || `http://${window.location.hostname}:3000/api`)
|
||||
: (import.meta.env.VITE_INTERNAL_API_URL || 'http://backend:3000/api');
|
||||
|
||||
interface ApiResponse<T> {
|
||||
|
||||
@@ -28,7 +28,7 @@ class ClassroomStore {
|
||||
if (this.socket?.connected) return;
|
||||
if (!authStore.user) return;
|
||||
|
||||
this.socket = io('http://localhost:3000/api/classroom', {
|
||||
this.socket = io(`http://${window.location.hostname}:3000/api/classroom`, {
|
||||
withCredentials: true,
|
||||
transports: ['websocket'],
|
||||
});
|
||||
|
||||
@@ -39,8 +39,9 @@ class WhiteboardStore {
|
||||
this.whiteboardId = whiteboardId;
|
||||
this.userId = userId;
|
||||
|
||||
// WebSocket-Verbindung herstellen
|
||||
this.socket = io('http://localhost:3000/whiteboard', {
|
||||
if (this.socket) return;
|
||||
|
||||
this.socket = io(`http://${window.location.hostname}:3000/whiteboard`, {
|
||||
withCredentials: true,
|
||||
transports: ['websocket', 'polling']
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import type { LayoutLoad } from './$types';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
// Routen die NICHT authentifiziert sein müssen
|
||||
const PUBLIC_ROUTES = ['/', '/login', '/register'];
|
||||
@@ -10,9 +11,13 @@ export const load: LayoutLoad = async ({ url, fetch }) => {
|
||||
return {};
|
||||
}
|
||||
|
||||
const apiBase = browser
|
||||
? `http://${window.location.hostname}:3000/api`
|
||||
: 'http://localhost:3000/api';
|
||||
|
||||
// Versuche den User zu laden
|
||||
try {
|
||||
const response = await fetch('http://localhost:3000/api/auth/me', {
|
||||
const response = await fetch(`${apiBase}/auth/me`, {
|
||||
credentials: 'include'
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { env } from '$env/dynamic/private';
|
||||
import type { RequestHandler } from './$types';
|
||||
|
||||
// Fallback, falls die Variable nicht gesetzt ist (für lokale Entwicklung ohne Docker)
|
||||
const TARGET_URL = env.VITE_INTERNAL_API_URL || 'http://localhost:3000/api';
|
||||
|
||||
const proxy: RequestHandler = async ({ request, params, url }) => {
|
||||
// Der Pfad hinter /api/ (z.B. "auth/me")
|
||||
const path = params.path;
|
||||
const query = url.search;
|
||||
|
||||
// Ziel-URL zusammenbauen
|
||||
const targetUrl = `${TARGET_URL}/${path}${query}`;
|
||||
|
||||
try {
|
||||
// Request-Body und Header kopieren
|
||||
const headers = new Headers(request.headers);
|
||||
// Host-Header entfernen, damit das Backend nicht verwirrt ist
|
||||
headers.delete('host');
|
||||
headers.delete('connection');
|
||||
|
||||
// Den ursprünglichen Request klonen und an das Ziel senden
|
||||
const response = await fetch(targetUrl, {
|
||||
method: request.method,
|
||||
headers,
|
||||
body: request.body,
|
||||
// Wichtig für Cookies/Auth, falls nötig
|
||||
// duplex: 'half' // Node 18+ fetch requirement für streams, falls verwendet
|
||||
// @ts-ignore - sveltekit fetch wrapper handles this usually, but native fetch might need it
|
||||
} as RequestInit);
|
||||
|
||||
// Die Antwort vom Backend an den Client zurückgeben
|
||||
return new Response(response.body, {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
headers: response.headers
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Proxy Error:', err);
|
||||
return new Response(JSON.stringify({ error: 'Proxy Error', details: String(err) }), {
|
||||
status: 502,
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const GET: RequestHandler = proxy;
|
||||
export const POST: RequestHandler = proxy;
|
||||
export const PUT: RequestHandler = proxy;
|
||||
export const DELETE: RequestHandler = proxy;
|
||||
export const PATCH: RequestHandler = proxy;
|
||||
@@ -59,6 +59,9 @@
|
||||
let showMembersModal = $state(false);
|
||||
let allUsers = $state<User[]>([]);
|
||||
let selectedUserIds = $state<number[]>([]);
|
||||
|
||||
// Dynamic Base URL
|
||||
const baseUrl = `http://${window.location.hostname}:3000`;
|
||||
|
||||
$effect(() => {
|
||||
if (!authStore.isLoading) {
|
||||
@@ -82,7 +85,7 @@
|
||||
|
||||
async function loadGroups() {
|
||||
try {
|
||||
const response = await fetch('http://localhost:3000/api/live/groups/my', {
|
||||
const response = await fetch(`${baseUrl}/api/live/groups/my`, {
|
||||
credentials: 'include'
|
||||
});
|
||||
|
||||
@@ -110,7 +113,7 @@
|
||||
|
||||
try {
|
||||
// Nachrichten-Historie laden
|
||||
const response = await fetch(`http://localhost:3000/api/live/groups/${group.id}/messages`, {
|
||||
const response = await fetch(`${baseUrl}/api/live/groups/${group.id}/messages`, {
|
||||
credentials: 'include'
|
||||
});
|
||||
|
||||
@@ -151,7 +154,7 @@
|
||||
console.log('User authenticated:', authStore.isAuthenticated);
|
||||
|
||||
// Socket.io Verbindung - das httpOnly Cookie wird automatisch mitgesendet
|
||||
socket = io('http://localhost:3000/api/live', {
|
||||
socket = io(`${baseUrl}/api/live`, {
|
||||
withCredentials: true,
|
||||
transports: ['websocket', 'polling']
|
||||
});
|
||||
@@ -233,7 +236,7 @@
|
||||
payload.description = newGroupDescription.trim();
|
||||
}
|
||||
|
||||
const response = await fetch('http://localhost:3000/api/live/groups', {
|
||||
const response = await fetch(`${baseUrl}/api/live/groups`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
@@ -262,7 +265,7 @@
|
||||
if (!confirm('Möchten Sie diese Gruppe wirklich löschen?')) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(`http://localhost:3000/api/live/groups/${groupId}`, {
|
||||
const response = await fetch(`${baseUrl}/api/live/groups/${groupId}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include'
|
||||
});
|
||||
@@ -305,7 +308,7 @@
|
||||
|
||||
async function loadAllUsers() {
|
||||
try {
|
||||
const response = await fetch('http://localhost:3000/api/users', {
|
||||
const response = await fetch(`${baseUrl}/api/users`, {
|
||||
credentials: 'include'
|
||||
});
|
||||
|
||||
@@ -328,7 +331,7 @@
|
||||
if (!currentGroup || selectedUserIds.length === 0) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(`http://localhost:3000/api/live/groups/${currentGroup.id}/members`, {
|
||||
const response = await fetch(`${baseUrl}/api/live/groups/${currentGroup.id}/members`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
@@ -360,7 +363,7 @@
|
||||
if (!confirm('Möchten Sie dieses Mitglied wirklich entfernen?')) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(`http://localhost:3000/api/live/groups/${currentGroup.id}/members/${userId}`, {
|
||||
const response = await fetch(`${baseUrl}/api/live/groups/${currentGroup.id}/members/${userId}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include'
|
||||
});
|
||||
|
||||
@@ -2,5 +2,23 @@ import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit()]
|
||||
plugins: [sveltekit()],
|
||||
server: {
|
||||
host: 'localhost',
|
||||
port: 5173,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://10.77.48.43:3000',
|
||||
changeOrigin: true,
|
||||
configure: (proxy, _options) => {
|
||||
proxy.on('proxyReq', (proxyReq, req, _res) => {
|
||||
if (req.headers.cookie) {
|
||||
proxyReq.setHeader('Cookie', req.headers.cookie);
|
||||
}
|
||||
console.log('[Backend Proxy]', req.method, req.url, '→ Cookies:', !!req.headers.cookie);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user