restructure: flatten workspace nesting, move devcontainer to root

- backend/workspaces/backend/ → backend/
- backend/workspaces/frontend/ → frontend/
- backend/.devcontainer/ + .vscode/ → repo root (where VS Code expects them)
- loose scripts/SQL files → scripts/
- replace nested git repo with single repo at project root
- update docker-compose.yml build context and devcontainer.json path
- add root .gitignore

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-03-15 11:47:58 +01:00
parent 7e725090fe
commit e63adb964d
155 changed files with 650 additions and 29 deletions

View File

@@ -0,0 +1,49 @@
import { error, redirect } from '@sveltejs/kit';
import { env } from '$env/dynamic/private';
export async function load({ params, fetch }) {
const { id } = params;
const baseUrl = 'http://localhost:8080';
try {
// Parallel Dokument und Personen laden
const [docRes, personsRes] = await Promise.all([
fetch(`${baseUrl}/api/documents/${id}`),
fetch(`${baseUrl}/api/persons`)
]);
if (!docRes.ok) throw error(docRes.status, 'Dokument nicht gefunden');
if (!personsRes.ok) throw error(personsRes.status, 'Personen konnten nicht geladen werden');
return {
document: await docRes.json(),
persons: await personsRes.json()
};
} catch (e) {
console.error(e);
throw error(500, 'Ladefehler');
}
}
export const actions = {
default: async ({ request, params, fetch }) => {
const baseUrl = env.API_INTERNAL_URL || 'http://localhost:8080';
const formData = await request.formData();
// Sende den FormData Request direkt an das Spring Backend weiter
// (Spring kann Multipart verarbeiten)
const res = await fetch(`${baseUrl}/api/documents/${params.id}`, {
method: "PUT",
body: formData
});
if (!res.ok) {
return { success: false, message: 'Speichern fehlgeschlagen' };
}
throw redirect(303, `/documents/${params.id}`);
}
};

View File

@@ -0,0 +1,190 @@
<script lang="ts">
import { enhance } from '$app/forms';
import TagInput from '$lib/components/TagInput.svelte';
export let data;
export let form; // Rückgabe der Action (Fehler etc.)
let { document: doc, persons } = data;
let tags = doc.tags ? doc.tags.map(t => t.name) : [];
</script>
<div class="max-w-4xl mx-auto p-6 bg-white shadow mt-10 rounded-lg">
<h1 class="text-2xl font-bold mb-6">Dokument bearbeiten</h1>
{#if form?.message}
<div class="bg-red-100 text-red-700 p-3 rounded mb-4">{form.message}</div>
{/if}
<form method="POST" enctype="multipart/form-data" use:enhance class="space-y-6">
<!-- Datei Austausch -->
<div class="bg-blue-50 p-4 rounded border border-blue-100">
<label for="file-upload" class="block text-sm font-medium text-gray-700 mb-2"
>Datei ersetzen (optional)</label
>
<div class="flex items-center gap-4">
<span class="text-xs text-gray-500">Aktuell: {doc.originalFilename}</span>
<!-- ID hinzugefügt -->
<input
id="file-upload"
type="file"
name="file"
class="block w-full text-sm text-gray-500
file:mr-4 file:py-2 file:px-4
file:rounded-full file:border-0
file:text-sm file:font-semibold
file:bg-blue-50 file:text-blue-700
hover:file:bg-blue-100"
/>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Titel -->
<div>
<label for="title" class="block text-sm font-medium text-gray-700">Titel</label>
<!-- ID hinzugefügt -->
<input
id="title"
type="text"
name="title"
value={doc.title || ''}
required
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
/>
</div>
<div>
<label for="documentLocation" class="block text-sm font-medium text-gray-700"
>Dokumentenort</label
>
<!-- ID hinzugefügt -->
<input
id="documentLocation"
type="text"
name="documentLocation"
value={doc.documentLocation || ''}
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
/>
</div>
<!-- Datum -->
<div>
<label for="documentDate" class="block text-sm font-medium text-gray-700">Datum</label>
<!-- ID hinzugefügt -->
<input
id="documentDate"
type="text"
name="documentDate"
value={doc.documentDate || ''}
placeholder="YYYY-MM-DD"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
/>
</div>
<!-- Ort -->
<div>
<label for="location" class="block text-sm font-medium text-gray-700">Ort</label>
<!-- ID hinzugefügt -->
<input
id="location"
type="text"
name="location"
value={doc.location || ''}
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
/>
</div>
</div>
<!-- Sender -->
<div>
<label for="senderId" class="block text-sm font-medium text-gray-700">Absender</label>
<!-- ID hinzugefügt -->
<select
id="senderId"
name="senderId"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
>
<option value="">-- Unbekannt --</option>
{#each persons as person}
<option value={person.id} selected={doc.sender?.id === person.id}>
{person.firstName}
{person.lastName}
</option>
{/each}
</select>
</div>
<!-- Empfänger (Multi-Select) -->
<div>
<label for="receiverIds" class="block text-sm font-medium text-gray-700"
>Empfänger (Strg+Klick für mehrere)</label
>
<!-- ID hinzugefügt -->
<select
id="receiverIds"
name="receiverIds"
multiple
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm h-32"
>
{#each persons as person}
<option value={person.id} selected={doc.receivers?.some((r) => r.id === person.id)}>
{person.firstName}
{person.lastName}
</option>
{/each}
</select>
</div>
<div>
<label class="block text-sm font-bold text-brand-navy uppercase tracking-widest mb-2">
Schlagworte
</label>
<TagInput bind:tags />
<input type="hidden" name="tags" value={tags.join(',')} />
</div>
<!-- Inhalt -->
<div>
<label for="summary" class="block text-sm font-medium text-gray-700">Inhalt</label>
<!-- ID hinzugefügt -->
<textarea
id="summary"
name="summary"
rows="2"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm font-serif"
>{doc.summary || ''}</textarea
>
</div>
<!-- Transkription -->
<div>
<label for="transcription" class="block text-sm font-medium text-gray-700"
>Transkription</label
>
<!-- ID hinzugefügt -->
<textarea
id="transcription"
name="transcription"
rows="10"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm font-serif"
>{doc.transcription || ''}</textarea
>
</div>
<!-- Buttons -->
<div class="flex justify-end gap-4">
<a
href="/documents/{doc.id}"
class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50"
>
Abbrechen
</a>
<button
type="submit"
class="px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700"
>
Speichern
</button>
</div>
</form>
</div>