From 34f18638821b5b9a44b61914fa3ba4fe348b267f Mon Sep 17 00:00:00 2001
From: 0qln <0qln@proton.me>
Date: Tue, 25 Aug 2026 19:04:44 +0200
Subject: [PATCH] initial scaffold: structure, build setup, chapter stubs,
diagrams
---
.biber.conf | 4 +
.envrc | 3 +
.gitignore | 4 +
.latexmkrc | 4 +
README.md | 58 +++++
appendix/appendix-code.tex | 10 +
appendix/appendix-diagrams.tex | 1 +
appendix/appendix-screenshots.tex | 1 +
appendix/appendix-tables.tex | 2 +
appendix/appendix.tex | 17 ++
chapters/closure/evaluation.tex | 4 +
chapters/closure/outlook.tex | 6 +
chapters/closure/reflection.tex | 5 +
chapters/closure/target-comparison.tex | 4 +
chapters/company/econ-localization.tex | 1 +
chapters/company/products-and-services.tex | 1 +
chapters/company/worksimple.tex | 1 +
chapters/conception/authorization.tex | 13 ++
chapters/conception/document-types.tex | 7 +
chapters/conception/lookup-decision.tex | 13 ++
chapters/conception/lookup-research.tex | 8 +
chapters/conception/s3-layout.tex | 14 ++
chapters/conception/ui-concept.tex | 5 +
chapters/execution/architecture.tex | 12 +
chapters/execution/document-explorer.tex | 5 +
chapters/execution/downloads.tex | 13 ++
chapters/execution/filter-pagination.tex | 6 +
chapters/execution/folder-management.tex | 8 +
chapters/execution/pdf-preview.tex | 6 +
chapters/execution/race-conditions.tex | 15 ++
chapters/execution/s3-client.tex | 5 +
chapters/execution/search.tex | 6 +
chapters/execution/type-icons.tex | 5 +
chapters/execution/url-files.tex | 5 +
chapters/overview/initial-situation.tex | 5 +
chapters/overview/participants.tex | 4 +
chapters/overview/project-description.tex | 4 +
chapters/overview/project-scope.tex | 7 +
chapters/overview/system-landscape.tex | 12 +
chapters/overview/target-situation.tex | 4 +
chapters/planning/backlog.tex | 14 ++
chapters/planning/feature-analysis.tex | 7 +
chapters/planning/infrastructure.tex | 15 ++
chapters/planning/onboarding.tex | 5 +
chapters/planning/requirements.tex | 5 +
chapters/planning/schedule.tex | 4 +
chapters/qa/acceptance-testing.tex | 5 +
chapters/qa/code-reviews.tex | 7 +
chapters/qa/releases.tex | 5 +
chapters/qa/test-strategy.tex | 4 +
chapters/qa/unit-tests.tex | 6 +
figures/diagrams/ado-workflow.mmd | 10 +
figures/diagrams/auth-sequence.mmd | 18 ++
figures/diagrams/gantt-plan.mmd | 18 ++
figures/diagrams/lookup-flow.mmd | 10 +
figures/diagrams/module-components.mmd | 29 +++
figures/diagrams/race-condition-a.mmd | 15 ++
figures/diagrams/s3-layout.mmd | 9 +
figures/diagrams/system-context.mmd | 18 ++
figures/diagrams/timeline-infra.mmd | 10 +
figures/diagrams/zip-stream.mmd | 15 ++
figures/itc/IT-Center_Dortmund_Logo.svg.png | Bin 0 -> 5245 bytes
frontmatter/abstract.tex | 4 +
frontmatter/acknowledgments.tex | 4 +
frontmatter/usage-of-ai.tex | 10 +
main.tex | 102 ++++++++
pidi-thesis.cls | 246 ++++++++++++++++++++
references.bib | 92 ++++++++
shell.nix | 47 ++++
69 files changed, 1042 insertions(+)
create mode 100644 .biber.conf
create mode 100644 .envrc
create mode 100644 .gitignore
create mode 100644 .latexmkrc
create mode 100644 README.md
create mode 100644 appendix/appendix-code.tex
create mode 100644 appendix/appendix-diagrams.tex
create mode 100644 appendix/appendix-screenshots.tex
create mode 100644 appendix/appendix-tables.tex
create mode 100644 appendix/appendix.tex
create mode 100644 chapters/closure/evaluation.tex
create mode 100644 chapters/closure/outlook.tex
create mode 100644 chapters/closure/reflection.tex
create mode 100644 chapters/closure/target-comparison.tex
create mode 100644 chapters/company/econ-localization.tex
create mode 100644 chapters/company/products-and-services.tex
create mode 100644 chapters/company/worksimple.tex
create mode 100644 chapters/conception/authorization.tex
create mode 100644 chapters/conception/document-types.tex
create mode 100644 chapters/conception/lookup-decision.tex
create mode 100644 chapters/conception/lookup-research.tex
create mode 100644 chapters/conception/s3-layout.tex
create mode 100644 chapters/conception/ui-concept.tex
create mode 100644 chapters/execution/architecture.tex
create mode 100644 chapters/execution/document-explorer.tex
create mode 100644 chapters/execution/downloads.tex
create mode 100644 chapters/execution/filter-pagination.tex
create mode 100644 chapters/execution/folder-management.tex
create mode 100644 chapters/execution/pdf-preview.tex
create mode 100644 chapters/execution/race-conditions.tex
create mode 100644 chapters/execution/s3-client.tex
create mode 100644 chapters/execution/search.tex
create mode 100644 chapters/execution/type-icons.tex
create mode 100644 chapters/execution/url-files.tex
create mode 100644 chapters/overview/initial-situation.tex
create mode 100644 chapters/overview/participants.tex
create mode 100644 chapters/overview/project-description.tex
create mode 100644 chapters/overview/project-scope.tex
create mode 100644 chapters/overview/system-landscape.tex
create mode 100644 chapters/overview/target-situation.tex
create mode 100644 chapters/planning/backlog.tex
create mode 100644 chapters/planning/feature-analysis.tex
create mode 100644 chapters/planning/infrastructure.tex
create mode 100644 chapters/planning/onboarding.tex
create mode 100644 chapters/planning/requirements.tex
create mode 100644 chapters/planning/schedule.tex
create mode 100644 chapters/qa/acceptance-testing.tex
create mode 100644 chapters/qa/code-reviews.tex
create mode 100644 chapters/qa/releases.tex
create mode 100644 chapters/qa/test-strategy.tex
create mode 100644 chapters/qa/unit-tests.tex
create mode 100644 figures/diagrams/ado-workflow.mmd
create mode 100644 figures/diagrams/auth-sequence.mmd
create mode 100644 figures/diagrams/gantt-plan.mmd
create mode 100644 figures/diagrams/lookup-flow.mmd
create mode 100644 figures/diagrams/module-components.mmd
create mode 100644 figures/diagrams/race-condition-a.mmd
create mode 100644 figures/diagrams/s3-layout.mmd
create mode 100644 figures/diagrams/system-context.mmd
create mode 100644 figures/diagrams/timeline-infra.mmd
create mode 100644 figures/diagrams/zip-stream.mmd
create mode 100644 figures/itc/IT-Center_Dortmund_Logo.svg.png
create mode 100644 frontmatter/abstract.tex
create mode 100644 frontmatter/acknowledgments.tex
create mode 100644 frontmatter/usage-of-ai.tex
create mode 100644 main.tex
create mode 100644 pidi-thesis.cls
create mode 100644 references.bib
create mode 100644 shell.nix
diff --git a/.biber.conf b/.biber.conf
new file mode 100644
index 0000000..0680dba
--- /dev/null
+++ b/.biber.conf
@@ -0,0 +1,4 @@
+
+ out
+ out
+
diff --git a/.envrc b/.envrc
new file mode 100644
index 0000000..d84c52c
--- /dev/null
+++ b/.envrc
@@ -0,0 +1,3 @@
+use nix
+
+export VIMTEX_OUTPUT_DIRECTORY="out"
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..faf7b4f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+out
+latexout
+latex.out
+.direnv
diff --git a/.latexmkrc b/.latexmkrc
new file mode 100644
index 0000000..a6cf24a
--- /dev/null
+++ b/.latexmkrc
@@ -0,0 +1,4 @@
+$pdf_mode = 4; # lualatex
+$bibtex_use = 2; # biber
+$out_dir = out;
+$clean_ext .= ' %R.run.xml %R.bbl %R.bcf %R-blx.bib';
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..a0f513b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,58 @@
+# PidI Thesis LaTeX Template
+
+This template follows the specs:
+- A4, margins: left/top **3 cm**, right/bottom **2.5 cm**.
+- Page numbers bottom-center.
+- Font: **Times Newer Roman 12 pt** (`times` class option, default).
+- Line spacing **1.3**, justified text, paragraph spacing **6 pt**, emphasis **bold**.
+- `\emph{}` is mapped to bold.
+
+## File name for submission
+
+` PidI 3 .pdf`
+
+## Build
+
+```sh
+direnv allow # einmalig — setzt Nix-Umgebung auf
+latexmk # baut das PDF (LuaLaTeX + Biber, Ausgabe nach out/)
+latexmk -c # aufräumen
+```
+
+Requires the Nix shell (`shell.nix`) — provides TeX Live, `latexmk`, `mermaid-cli`,
+and Times Newer Roman (fonts are installed into `~/.local/share/fonts/` by the shell hook).
+
+`minted` code listings require shell escape; `latexmk` handles this automatically via
+`$pdf_mode = 4`.
+
+## Rendering Mermaid diagrams
+
+```sh
+# render a single diagram
+mmdc -i figures/diagrams/system-context.mmd -o figures/diagrams/system-context.pdf
+
+# render all diagrams at once
+for f in figures/diagrams/*.mmd; do
+ mmdc -i "$f" -o "${f%.mmd}.pdf"
+done
+```
+
+Render before calling `latexmk` whenever a `.mmd` file changes. The generated `.pdf`
+files are gitignored via `out` (only `out/` is ignored, so diagrams in `figures/` are
+**not** ignored — commit them).
+
+## Structure
+
+```
+main.tex entry point: metadata + \input all chapters
+pidi-thesis.cls enforces the complete layout
+frontmatter/ usage-of-ai, abstract, acknowledgments
+chapters//*.tex one file per \section
+appendix/ appendix.tex bundles tables/diagrams/screenshots/code
+figures/code/ code excerpts as real files (no inline code in appendix)
+figures/diagrams/ *.mmd source + rendered *.pdf
+figures/screenshots/ screenshots
+figures/worksimple/ company logos
+figures/itc/ ITC logo
+references.bib biblatex/biber sources
+```
diff --git a/appendix/appendix-code.tex b/appendix/appendix-code.tex
new file mode 100644
index 0000000..7ffae9b
--- /dev/null
+++ b/appendix/appendix-code.tex
@@ -0,0 +1,10 @@
+% TODO: Code-Ausschnitte — je in center-Umgebung mit \captionof{listing}{...} + \inputminted
+
+% Reihenfolge gemäß Kapiteln:
+% s3-settings-registration.cs, s3-documents-client.cs,
+% documents-page-model.cs, document-view-model.cs, documents-table-body.cshtml,
+% document-type-mapping.cs, document-types.resx,
+% document-search.cs, pagination-continuation-token.cs,
+% zip-download-action.cs, presigned-url.cs, url-file-parsing.cs,
+% org-slug.cs, resolve-customer-prefix.cs, rename-customer-folder.cs,
+% authorization-policy.cs, documents-service-tests.cs
diff --git a/appendix/appendix-diagrams.tex b/appendix/appendix-diagrams.tex
new file mode 100644
index 0000000..15ab173
--- /dev/null
+++ b/appendix/appendix-diagrams.tex
@@ -0,0 +1 @@
+% TODO: eingebundene Diagramme (falls nicht inline in Kapiteln)
diff --git a/appendix/appendix-screenshots.tex b/appendix/appendix-screenshots.tex
new file mode 100644
index 0000000..bbfe415
--- /dev/null
+++ b/appendix/appendix-screenshots.tex
@@ -0,0 +1 @@
+% TODO: Screenshots der fertigen Documents-Seite (Liste, Filter, Suche, PDF-Modal, ZIP-Auswahl)
diff --git a/appendix/appendix-tables.tex b/appendix/appendix-tables.tex
new file mode 100644
index 0000000..7ecd1db
--- /dev/null
+++ b/appendix/appendix-tables.tex
@@ -0,0 +1,2 @@
+% TODO: Zeitplan Soll/Ist, Backlog (PBI-Tabelle), PR-Übersicht,
+% Anforderungsmatrix, Dokumententypen↔Ordner↔Icon, Lookup-Trade-offs, Beteiligte
diff --git a/appendix/appendix.tex b/appendix/appendix.tex
new file mode 100644
index 0000000..acd38d0
--- /dev/null
+++ b/appendix/appendix.tex
@@ -0,0 +1,17 @@
+\section{Tabellen}
+\input{appendix/appendix-tables}
+
+\clearpage
+
+\section{Diagramme}
+\input{appendix/appendix-diagrams}
+
+\clearpage
+
+\section{Screenshots}
+\input{appendix/appendix-screenshots}
+
+\clearpage
+
+\section{Code-Ausschnitte}
+\input{appendix/appendix-code}
diff --git a/chapters/closure/evaluation.tex b/chapters/closure/evaluation.tex
new file mode 100644
index 0000000..8405f56
--- /dev/null
+++ b/chapters/closure/evaluation.tex
@@ -0,0 +1,4 @@
+\section{Zielerreichung}
+\label{sec:evaluation}
+
+% TODO
diff --git a/chapters/closure/outlook.tex b/chapters/closure/outlook.tex
new file mode 100644
index 0000000..8a442e7
--- /dev/null
+++ b/chapters/closure/outlook.tex
@@ -0,0 +1,6 @@
+\section{Ausblick}
+\label{sec:outlook}
+
+% TODO: PBI 10070 (Race Conditions), Search Integration (von AU noch nicht verfügbar),
+% Dashboard-Kacheln (Security Assessments, zuletzt hinzugefügte Dokumente),
+% Abrechnungsdaten
diff --git a/chapters/closure/reflection.tex b/chapters/closure/reflection.tex
new file mode 100644
index 0000000..3708ef0
--- /dev/null
+++ b/chapters/closure/reflection.tex
@@ -0,0 +1,5 @@
+\section{Reflexion}
+\label{sec:reflection}
+
+% TODO: Lessons Learned — S3-Lookup-Entscheidung, Race Conditions als offenes Thema,
+% Infrastruktur-Vorlauf unterschätzt (AU-Kommunikation 2026-07-22 bis 2026-08-07)
diff --git a/chapters/closure/target-comparison.tex b/chapters/closure/target-comparison.tex
new file mode 100644
index 0000000..562cb9f
--- /dev/null
+++ b/chapters/closure/target-comparison.tex
@@ -0,0 +1,4 @@
+\section{Soll-Ist-Vergleich}
+\label{sec:target-comparison}
+
+% TODO: Tabelle Soll-Ist (Zeitplan, Features)
diff --git a/chapters/company/econ-localization.tex b/chapters/company/econ-localization.tex
new file mode 100644
index 0000000..a66c6f9
--- /dev/null
+++ b/chapters/company/econ-localization.tex
@@ -0,0 +1 @@
+% TODO: Kapitel aus PidI 2 übernehmen und auf PidI 3 aktualisieren
diff --git a/chapters/company/products-and-services.tex b/chapters/company/products-and-services.tex
new file mode 100644
index 0000000..a66c6f9
--- /dev/null
+++ b/chapters/company/products-and-services.tex
@@ -0,0 +1 @@
+% TODO: Kapitel aus PidI 2 übernehmen und auf PidI 3 aktualisieren
diff --git a/chapters/company/worksimple.tex b/chapters/company/worksimple.tex
new file mode 100644
index 0000000..a66c6f9
--- /dev/null
+++ b/chapters/company/worksimple.tex
@@ -0,0 +1 @@
+% TODO: Kapitel aus PidI 2 übernehmen und auf PidI 3 aktualisieren
diff --git a/chapters/conception/authorization.tex b/chapters/conception/authorization.tex
new file mode 100644
index 0000000..63b7423
--- /dev/null
+++ b/chapters/conception/authorization.tex
@@ -0,0 +1,13 @@
+\section{Autorisierungskonzept}
+\label{sec:authorization}
+
+% TODO: App-Rolle Documents.Read (Entra ID), Claim efecte:company_id
+% Menüpunkt nur sichtbar mit Rolle, Direktzugriff ohne Rolle → 403 (nicht 404)
+% Sequence-Diagramm auth-sequence.pdf
+
+% \begin{figure}[H]
+% \centering
+% \includegraphics[width=0.9\textwidth]{figures/diagrams/auth-sequence.pdf}
+% \caption{Autorisierungsablauf}
+% \label{fig:auth-sequence}
+% \end{figure}
diff --git a/chapters/conception/document-types.tex b/chapters/conception/document-types.tex
new file mode 100644
index 0000000..919bc8c
--- /dev/null
+++ b/chapters/conception/document-types.tex
@@ -0,0 +1,7 @@
+\section{Dokumententypen und Icons}
+\label{sec:document-types}
+
+% TODO: 7 Typen hardcoded in Houston (PBI 9560/9549):
+% Service-Protokoll, Abnahme Dokumente, SLA-Reports, Monitoring Reports,
+% Security Assessments, Abrechnungsdaten, Vertragsunterlagen
+% Typzuordnung über Unterordnername, Tabelle im Anhang
diff --git a/chapters/conception/lookup-decision.tex b/chapters/conception/lookup-decision.tex
new file mode 100644
index 0000000..29cd0e7
--- /dev/null
+++ b/chapters/conception/lookup-decision.tex
@@ -0,0 +1,13 @@
+\section{Architekturentscheidung: O(1)-Fast-Path}
+\label{sec:lookup-decision}
+
+% TODO: PBI 10018 — metadatenbasierter Fast-Path
+% ResolveCustomerPrefixAsync: Fast-Path → Kollisions-Fast-Path → O(n)-Fallback + Self-Healing-Rename
+% Houston als führende Instanz für Ordnerbenennung
+
+% \begin{figure}[H]
+% \centering
+% \includegraphics[width=\textwidth]{figures/diagrams/lookup-flow.pdf}
+% \caption{Ablauf \texttt{ResolveCustomerPrefixAsync}}
+% \label{fig:lookup-flow}
+% \end{figure}
diff --git a/chapters/conception/lookup-research.tex b/chapters/conception/lookup-research.tex
new file mode 100644
index 0000000..4317894
--- /dev/null
+++ b/chapters/conception/lookup-research.tex
@@ -0,0 +1,8 @@
+\section{Problem: Lookup des Kundenordners}
+\label{sec:lookup-research}
+
+% TODO: PBI 9857 — S3 kann nicht nach Metadaten-Tags suchen → lineares Scannen aller Top-Level-Prefixes
+% Trade-off-Matrix der 6 Varianten (In-Memory Cache, Claim, Efecte-Feld, S3 SelectObject, Search Integration, Prefix im Namen)
+% \cite{aws-s3-select}, \cite{storagegrid-search-integration}
+
+% Tabelle~\ref{tab:lookup-tradeoffs} im Anhang
diff --git a/chapters/conception/s3-layout.tex b/chapters/conception/s3-layout.tex
new file mode 100644
index 0000000..a2f09a5
--- /dev/null
+++ b/chapters/conception/s3-layout.tex
@@ -0,0 +1,14 @@
+\section{Ablagekonzept im S3-Speicher}
+\label{sec:s3-layout}
+
+% TODO: Ordnerbaum (Feature 484):
+% Bucket → Kundenordner [meta: efecte_org-id] → Typordner/ → Dokumente
+% Typ = Unterordner, nicht Metadatum an der Datei
+% Leere Ordner werden nicht angezeigt
+
+% \begin{figure}[H]
+% \centering
+% \includegraphics[width=0.75\textwidth]{figures/diagrams/s3-layout.pdf}
+% \caption{S3-Ablagestruktur}
+% \label{fig:s3-layout}
+% \end{figure}
diff --git a/chapters/conception/ui-concept.tex b/chapters/conception/ui-concept.tex
new file mode 100644
index 0000000..7ecdd93
--- /dev/null
+++ b/chapters/conception/ui-concept.tex
@@ -0,0 +1,5 @@
+\section{UI-Konzept und Clickdummy}
+\label{sec:ui-concept}
+
+% TODO: Hanna Ebner, Branch Clickdummy_Dokumente (2026-07-22)
+% Listenansicht, Typfilter oben als Buttons, flexible Tabellenspalten
diff --git a/chapters/execution/architecture.tex b/chapters/execution/architecture.tex
new file mode 100644
index 0000000..a673dad
--- /dev/null
+++ b/chapters/execution/architecture.tex
@@ -0,0 +1,12 @@
+\section{Architektur des Documents-Moduls}
+\label{sec:architecture}
+
+% TODO: Razor Page DocumentsPage.cshtml → DocumentsService → S3DocumentsClient
+% Klassendiagramm module-components.pdf
+
+% \begin{figure}[H]
+% \centering
+% \includegraphics[width=0.9\textwidth]{figures/diagrams/module-components.pdf}
+% \caption{Komponentenstruktur des Documents-Moduls}
+% \label{fig:module-components}
+% \end{figure}
diff --git a/chapters/execution/document-explorer.tex b/chapters/execution/document-explorer.tex
new file mode 100644
index 0000000..b1ecd74
--- /dev/null
+++ b/chapters/execution/document-explorer.tex
@@ -0,0 +1,5 @@
+\section{Document Explorer}
+\label{sec:document-explorer}
+
+% TODO: PBI 9295 — /documents Seite, ListObjectsV2, Empty State, Fehlerbehandlung
+% Abbildung~\ref{fig:documents-page-model}, \ref{fig:document-view-model}, \ref{fig:documents-table-body}
diff --git a/chapters/execution/downloads.tex b/chapters/execution/downloads.tex
new file mode 100644
index 0000000..509c561
--- /dev/null
+++ b/chapters/execution/downloads.tex
@@ -0,0 +1,13 @@
+\section{Dokumenten-Downloads}
+\label{sec:downloads}
+
+% TODO: PBI 9299 (Einzeldownload), PBI 9296 (ZIP-Download)
+% Streaming: S3 GetObject → ZipArchive → HTTP Response Stream
+% Abbildung~\ref{fig:zip-download-action}
+
+% \begin{figure}[H]
+% \centering
+% \includegraphics[width=0.9\textwidth]{figures/diagrams/zip-stream.pdf}
+% \caption{ZIP-Download-Ablauf}
+% \label{fig:zip-stream}
+% \end{figure}
diff --git a/chapters/execution/filter-pagination.tex b/chapters/execution/filter-pagination.tex
new file mode 100644
index 0000000..e4f2550
--- /dev/null
+++ b/chapters/execution/filter-pagination.tex
@@ -0,0 +1,6 @@
+\section{Typfilter und Paginierung}
+\label{sec:filter-pagination}
+
+% TODO: PBI 9749 (Typfilter), PBI 9731 (Pagination)
+% ContinuationToken statt Offset-Pagination
+% Abbildung~\ref{fig:pagination-continuation-token}
diff --git a/chapters/execution/folder-management.tex b/chapters/execution/folder-management.tex
new file mode 100644
index 0000000..213c6fb
--- /dev/null
+++ b/chapters/execution/folder-management.tex
@@ -0,0 +1,8 @@
+\section{Ordnerstruktur und Kundenordner-Lookup}
+\label{sec:folder-management}
+
+% TODO: PBI 9560 (Ordneranlage beim ersten Seitenaufruf), PBI 10018 (O(1)-Lookup)
+% OrgSlug: deterministische, S3-konforme Normalisierung des Efecte-Namens (Umlaute bleiben erhalten)
+% IBM-Naming-Constraints: \cite{ibm-s3-naming}
+% ResolveCustomerPrefixAsync, Self-Healing-Rename
+% Abbildung~\ref{fig:org-slug}, \ref{fig:resolve-customer-prefix}, \ref{fig:rename-customer-folder}
diff --git a/chapters/execution/pdf-preview.tex b/chapters/execution/pdf-preview.tex
new file mode 100644
index 0000000..4b38385
--- /dev/null
+++ b/chapters/execution/pdf-preview.tex
@@ -0,0 +1,6 @@
+\section{PDF-Modal-Vorschau und Share-Link-Previews}
+\label{sec:pdf-preview}
+
+% TODO: PBI 9300 (PDF-Modal), PBI 9294 (Share-Link-Previews)
+% Pre-Signed URLs, zeitlich begrenzte Gültigkeit
+% Abbildung~\ref{fig:presigned-url}
diff --git a/chapters/execution/race-conditions.tex b/chapters/execution/race-conditions.tex
new file mode 100644
index 0000000..071c8fd
--- /dev/null
+++ b/chapters/execution/race-conditions.tex
@@ -0,0 +1,15 @@
+\section{Bekannte Grenze: Race Conditions im Lookup}
+\label{sec:race-conditions}
+
+% TODO: PBI 10070 — Houston läuft in mehreren Instanzen, In-Memory-Lock reicht nicht
+% Szenario A: Datenverlust beim parallelen Rename (Rollback löscht Dokumente des Gewinners)
+% Szenario B: Mandantenvermischung beim gleichzeitigen Anlegen gleicher Efecte-Namen
+% Lösungsansätze: Rollback-Absicherung, Conditional Writes, verteiltes Lock, prozessuale Migration
+% Timebox: 4–6 Stunden (Stephan Janßen)
+
+% \begin{figure}[H]
+% \centering
+% \includegraphics[width=0.9\textwidth]{figures/diagrams/race-condition-a.pdf}
+% \caption{Race Condition Szenario A: Datenverlust beim parallelen Rename}
+% \label{fig:race-condition-a}
+% \end{figure}
diff --git a/chapters/execution/s3-client.tex b/chapters/execution/s3-client.tex
new file mode 100644
index 0000000..ff7f07e
--- /dev/null
+++ b/chapters/execution/s3-client.tex
@@ -0,0 +1,5 @@
+\section{Anbindung des S3-Speichers}
+\label{sec:s3-client}
+
+% TODO: AWS SDK für .NET, IAmazonS3, keyed services in Program.cs, S3Settings (DEV/TEST/PROD Buckets)
+% Abbildung~\ref{fig:s3-settings-registration}, \ref{fig:s3-documents-client}
diff --git a/chapters/execution/search.tex b/chapters/execution/search.tex
new file mode 100644
index 0000000..31c6927
--- /dev/null
+++ b/chapters/execution/search.tex
@@ -0,0 +1,6 @@
+\section{Serverseitige Suche}
+\label{sec:search}
+
+% TODO: PBI 9298 — Suchleiste, titelbasiert, Teiltreffer, serverseitiges Filtern
+% S3-API bietet keine direkte Filterung → Houston-seitiger Filter
+% Abbildung~\ref{fig:document-search}
diff --git a/chapters/execution/type-icons.tex b/chapters/execution/type-icons.tex
new file mode 100644
index 0000000..a0a17e2
--- /dev/null
+++ b/chapters/execution/type-icons.tex
@@ -0,0 +1,5 @@
+\section{Dokumenttypen und Icons}
+\label{sec:type-icons}
+
+% TODO: PBI 9549 — Typ-Mapping aus Unterordner, .resx-Lokalisierung
+% Abbildung~\ref{fig:document-type-mapping}, \ref{fig:document-types-resx}
diff --git a/chapters/execution/url-files.tex b/chapters/execution/url-files.tex
new file mode 100644
index 0000000..2d3ca93
--- /dev/null
+++ b/chapters/execution/url-files.tex
@@ -0,0 +1,5 @@
+\section{Support für URL-Dateien}
+\label{sec:url-files}
+
+% TODO: PBI 9301 — .url-Dateien parsen, Verlinkung beliebiger URLs (Teams, SharePoint)
+% Abbildung~\ref{fig:url-file-parsing}
diff --git a/chapters/overview/initial-situation.tex b/chapters/overview/initial-situation.tex
new file mode 100644
index 0000000..eda7156
--- /dev/null
+++ b/chapters/overview/initial-situation.tex
@@ -0,0 +1,5 @@
+\section{Ausgangssituation}
+\label{sec:initial-situation}
+
+% TODO: Feature 484 lag 2,5 Jahre im Backlog (Nicole Kimmel, 2023-11-02).
+% Bisher kein zentraler Dokumentenzugang für Kunden.
diff --git a/chapters/overview/participants.tex b/chapters/overview/participants.tex
new file mode 100644
index 0000000..3fd5465
--- /dev/null
+++ b/chapters/overview/participants.tex
@@ -0,0 +1,4 @@
+\section{Beteiligte und Rollen}
+\label{sec:participants}
+
+% TODO: Tabelle aus note-1787657238720 (Beteiligte)
diff --git a/chapters/overview/project-description.tex b/chapters/overview/project-description.tex
new file mode 100644
index 0000000..5f6ef68
--- /dev/null
+++ b/chapters/overview/project-description.tex
@@ -0,0 +1,4 @@
+\section{Projektbeschreibung}
+\label{sec:project-description}
+
+% TODO
diff --git a/chapters/overview/project-scope.tex b/chapters/overview/project-scope.tex
new file mode 100644
index 0000000..eee8da3
--- /dev/null
+++ b/chapters/overview/project-scope.tex
@@ -0,0 +1,7 @@
+\section{Projektabgrenzung}
+\label{sec:project-scope}
+
+% TODO: Out of Scope aus Feature 484:
+% - Kunde kann Dokumente nicht bearbeiten
+% - Keine neuen Ordner intern wild anlegen
+% - Filestash ist externes Admin-UI (kein Houston-Eigenbau)
diff --git a/chapters/overview/system-landscape.tex b/chapters/overview/system-landscape.tex
new file mode 100644
index 0000000..5f8a746
--- /dev/null
+++ b/chapters/overview/system-landscape.tex
@@ -0,0 +1,12 @@
+\section{Systemlandschaft}
+\label{sec:system-landscape}
+
+% TODO: Houston (ASP.NET Core, Razor Pages) — Efecte — Microsoft Entra ID — S3/StorageGRID — Filestash
+
+% Diagramm:
+% \begin{figure}[H]
+% \centering
+% \includegraphics[width=0.9\textwidth]{figures/diagrams/system-context.pdf}
+% \caption{Systemkontext}
+% \label{fig:system-context}
+% \end{figure}
diff --git a/chapters/overview/target-situation.tex b/chapters/overview/target-situation.tex
new file mode 100644
index 0000000..4b60f7e
--- /dev/null
+++ b/chapters/overview/target-situation.tex
@@ -0,0 +1,4 @@
+\section{Zielsituation}
+\label{sec:target-situation}
+
+% TODO: Feature 484 Rev 38 — Dokumentenbereich in Houston, 7 Dokumententypen, S3-Ablage, Filestash als Admin-UI
diff --git a/chapters/planning/backlog.tex b/chapters/planning/backlog.tex
new file mode 100644
index 0000000..b6ecaeb
--- /dev/null
+++ b/chapters/planning/backlog.tex
@@ -0,0 +1,14 @@
+\section{Backlog-Schnitt und Schätzung}
+\label{sec:backlog}
+
+% TODO: 14 PBIs + 1 Bug unter Feature 484
+% Prozess: DoR, DoD, Approval-Team, Sprints 15–17.2026
+% Siehe Tabelle~\ref{tab:backlog} im Anhang
+
+% Gantt:
+% \begin{figure}[H]
+% \centering
+% \includegraphics[width=\textwidth]{figures/diagrams/gantt-plan.pdf}
+% \caption{Zeitplanung über Sprints 15–17.2026}
+% \label{fig:gantt}
+% \end{figure}
diff --git a/chapters/planning/feature-analysis.tex b/chapters/planning/feature-analysis.tex
new file mode 100644
index 0000000..2e4b1d6
--- /dev/null
+++ b/chapters/planning/feature-analysis.tex
@@ -0,0 +1,7 @@
+\section{Feature-Analyse}
+\label{sec:feature-analysis}
+
+% TODO: 18.06.2026 — 4 Rückfragen von Linus an Thomas, Antworten im selben Ticket (Feature 484 Rev 17–32)
+% - Autorisierung via Metadatum: ja
+% - Filestash als externe Website (kein Custom-UI): ja
+% - ...
diff --git a/chapters/planning/infrastructure.tex b/chapters/planning/infrastructure.tex
new file mode 100644
index 0000000..8958388
--- /dev/null
+++ b/chapters/planning/infrastructure.tex
@@ -0,0 +1,15 @@
+\section{Infrastrukturbeschaffung}
+\label{sec:infrastructure}
+
+% TODO: Service Requests an Maschinenraum (2026-07-22), Provisionierung durch Advanced Unibyte,
+% 3 Buckets (DEV/TEST/PROD), Credentials in Passbolt (2026-07-27)
+% Anfrage S3 Select (2026-07-30), Aktivierung durch AU (2026-08-07)
+% Search Integration: von AU nicht bereitgestellt (2026-08-17)
+
+% Timeline-Diagramm:
+% \begin{figure}[H]
+% \centering
+% \includegraphics[width=\textwidth]{figures/diagrams/timeline-infra.pdf}
+% \caption{Chronologie der Infrastrukturbeschaffung}
+% \label{fig:timeline-infra}
+% \end{figure}
diff --git a/chapters/planning/onboarding.tex b/chapters/planning/onboarding.tex
new file mode 100644
index 0000000..8c85a3b
--- /dev/null
+++ b/chapters/planning/onboarding.tex
@@ -0,0 +1,5 @@
+\section{Einarbeitung}
+\label{sec:onboarding}
+
+% TODO: S3-API, AWS SDK für .NET, StorageGRID-Dokumentation
+% Quellen: note-1785344962361 (S3-Recherche mit Timo), note-1785413874041
diff --git a/chapters/planning/requirements.tex b/chapters/planning/requirements.tex
new file mode 100644
index 0000000..d701af1
--- /dev/null
+++ b/chapters/planning/requirements.tex
@@ -0,0 +1,5 @@
+\section{Anforderungserhebung}
+\label{sec:requirements}
+
+% TODO: Funktionale und nichtfunktionale Anforderungen aus den PBI-ACs
+% Tabelle: Anforderungsmatrix (funktional / nichtfunktional → PBI)
diff --git a/chapters/planning/schedule.tex b/chapters/planning/schedule.tex
new file mode 100644
index 0000000..29c7bd6
--- /dev/null
+++ b/chapters/planning/schedule.tex
@@ -0,0 +1,4 @@
+\section{Zeit- und Aufwandsplanung}
+\label{sec:schedule}
+
+% TODO: Sprints 15–17.2026, Aufwandsschätzungen (Story Points), 24 Manntage / 192 h gesamt
diff --git a/chapters/qa/acceptance-testing.tex b/chapters/qa/acceptance-testing.tex
new file mode 100644
index 0000000..561ff1d
--- /dev/null
+++ b/chapters/qa/acceptance-testing.tex
@@ -0,0 +1,5 @@
+\section{Abnahmetest}
+\label{sec:acceptance-testing}
+
+% TODO: Maria-Lena Andersz — Sichtbarkeitsproblem des Menüpunkts (2026-08-13)
+% Rollenzuweisung klären, Bug 10134 (Suchfunktion), finale Abnahme 2026-08-24/25
diff --git a/chapters/qa/code-reviews.tex b/chapters/qa/code-reviews.tex
new file mode 100644
index 0000000..b0680af
--- /dev/null
+++ b/chapters/qa/code-reviews.tex
@@ -0,0 +1,7 @@
+\section{Code-Reviews}
+\label{sec:code-reviews}
+
+% TODO: 11 PRs (2154–2196), Reviewer: Timo Walter, Sarah Hinzmann, Robin Noack
+% Reviewfunde: zentrale Auth über Program.cs, keyed Settings, 403 statt 404,
+% Slug-Naming-Constraints (IBM-Doku), Fehlerbehandlung statt stiller leerer Seite
+% Tabelle~\ref{tab:pull-requests} im Anhang
diff --git a/chapters/qa/releases.tex b/chapters/qa/releases.tex
new file mode 100644
index 0000000..7674c5f
--- /dev/null
+++ b/chapters/qa/releases.tex
@@ -0,0 +1,5 @@
+\section{Releases}
+\label{sec:releases}
+
+% TODO: DEV / TEST / PROD je eigener Bucket, Rollenvergabe vor Release
+% PR 2196 noch aktiv bei Dokumentationsabgabe
diff --git a/chapters/qa/test-strategy.tex b/chapters/qa/test-strategy.tex
new file mode 100644
index 0000000..2bc2dc9
--- /dev/null
+++ b/chapters/qa/test-strategy.tex
@@ -0,0 +1,4 @@
+\section{Teststrategie}
+\label{sec:test-strategy}
+
+% TODO: Unit-Tests mit gemocktem IAmazonS3, Abnahmetests durch Maria-Lena Andersz
diff --git a/chapters/qa/unit-tests.tex b/chapters/qa/unit-tests.tex
new file mode 100644
index 0000000..f2075a1
--- /dev/null
+++ b/chapters/qa/unit-tests.tex
@@ -0,0 +1,6 @@
+\section{Unit-Tests}
+\label{sec:unit-tests}
+
+% TODO: DocumentsServiceTests — gemocktes IAmazonS3
+% Pfade: Fast-Path, Fallback, Rename, Create, Kollision, Fehlerfall
+% Abbildung~\ref{fig:documents-service-tests}
diff --git a/figures/diagrams/ado-workflow.mmd b/figures/diagrams/ado-workflow.mmd
new file mode 100644
index 0000000..fef3165
--- /dev/null
+++ b/figures/diagrams/ado-workflow.mmd
@@ -0,0 +1,10 @@
+stateDiagram-v2
+ [*] --> New
+ New --> ToApprove : Linus reicht PBI ein
+ ToApprove --> Approved : Approval-Team
+ Approved --> Committed : Sprint-Planung
+ Committed --> DevCompleted : PR gemerged
+ DevCompleted --> TestCompleted : Abnahme bestanden
+ TestCompleted --> [*]
+ ToApprove --> Removed : Verworfen
+ Removed --> New : Wiederhergestellt
diff --git a/figures/diagrams/auth-sequence.mmd b/figures/diagrams/auth-sequence.mmd
new file mode 100644
index 0000000..a7d7dde
--- /dev/null
+++ b/figures/diagrams/auth-sequence.mmd
@@ -0,0 +1,18 @@
+sequenceDiagram
+ participant B as Browser
+ participant H as Houston
+ participant AAD as Entra ID
+ participant S3 as S3-Speicher
+
+ B->>H: GET /documents
+ H->>H: Prüfe Claim Documents.Read
+ alt Keine Rolle
+ H-->>B: 403 Forbidden
+ else Rolle vorhanden
+ H->>H: Lese efecte:company_id aus Claim
+ H->>S3: ResolveCustomerPrefixAsync(orgId)
+ S3-->>H: Kundenordner-Prefix
+ H->>S3: ListObjectsV2(prefix)
+ S3-->>H: Objektliste
+ H-->>B: Documents-Seite
+ end
diff --git a/figures/diagrams/gantt-plan.mmd b/figures/diagrams/gantt-plan.mmd
new file mode 100644
index 0000000..076517d
--- /dev/null
+++ b/figures/diagrams/gantt-plan.mmd
@@ -0,0 +1,18 @@
+gantt
+ title Zeitplanung PidI 3 (Sprints 15–17.2026)
+ dateFormat YYYY-MM-DD
+ section Planung
+ Feature-Analyse :done, 2026-06-18, 1d
+ Anforderungen & Backlog :done, 2026-07-07, 5d
+ section Sprint 15.2026
+ Document Explorer :done, 2026-07-27, 5d
+ Icons & Suche :done, 2026-08-01, 12d
+ Downloads & PDF-Modal :done, 2026-08-15, 7d
+ section Sprint 16.2026
+ Typfilter & Pagination :done, 2026-08-18, 4d
+ Ordner-Lookup :active, 2026-08-17, 8d
+ section Sprint 17.2026
+ Race Conditions (10070) :2026-08-26, 5d
+ section Qualitätssicherung
+ Abnahmetest :done, 2026-08-13, 12d
+ Release :2026-08-26, 3d
diff --git a/figures/diagrams/lookup-flow.mmd b/figures/diagrams/lookup-flow.mmd
new file mode 100644
index 0000000..a2dd7ae
--- /dev/null
+++ b/figures/diagrams/lookup-flow.mmd
@@ -0,0 +1,10 @@
+flowchart TD
+ A[ResolveCustomerPrefixAsync\norgId, orgName] --> B{Fast-Path:\nGetObjectMetadata\nslug-name/}
+ B -->|Gefunden & ID passt| Z[✓ Fertig\n1 Request]
+ B -->|Nicht gefunden oder\nID passt nicht| C{Kollisions-Fast-Path:\nslug-name orgId /}
+ C -->|Gefunden| Z2[✓ Fertig\n2 Requests]
+ C -->|Nicht gefunden| D[Fallback: O-n\nListObjectsV2 alle\nTop-Level-Prefixes]
+ D -->|Ordner mit\npAssender ID gefunden| E[Rename auf\nkanonischen Namen]
+ E --> Z3[✓ Fertig\nnächster Lookup O-1]
+ D -->|Kein Ordner| F[Anlegen: Ordner +\nUnterstruktur 9560]
+ F --> Z4[✓ Fertig\nSeite leer]
diff --git a/figures/diagrams/module-components.mmd b/figures/diagrams/module-components.mmd
new file mode 100644
index 0000000..22f65b0
--- /dev/null
+++ b/figures/diagrams/module-components.mmd
@@ -0,0 +1,29 @@
+classDiagram
+ class DocumentsPage {
+ +OnGetAsync()
+ +OnGetDownloadAsync()
+ +OnGetZipAsync()
+ }
+ class DocumentsService {
+ +ListDocumentsAsync(orgId, search, type, token)
+ +GetDownloadUrlAsync(orgId, key)
+ +GetZipStreamAsync(orgId, keys)
+ +ResolveCustomerPrefixAsync(orgId, orgName)
+ }
+ class S3DocumentsClient {
+ -IAmazonS3 _s3
+ +ListObjectsAsync(prefix, delimiter, token)
+ +GetObjectMetadataAsync(key)
+ +GetPresignedUrlAsync(key)
+ }
+ class OrgSlug {
+ +Slugify(name) string
+ }
+ class S3Settings {
+ +BucketName string
+ +ServiceUrl string
+ }
+ DocumentsPage --> DocumentsService
+ DocumentsService --> S3DocumentsClient
+ DocumentsService --> OrgSlug
+ S3DocumentsClient --> S3Settings
diff --git a/figures/diagrams/race-condition-a.mmd b/figures/diagrams/race-condition-a.mmd
new file mode 100644
index 0000000..301570c
--- /dev/null
+++ b/figures/diagrams/race-condition-a.mmd
@@ -0,0 +1,15 @@
+sequenceDiagram
+ participant A as Request A
+ participant S3 as S3-Speicher
+ participant B as Request B
+
+ Note over A,B: Ordner AltName/ mit 200 Objekten, Zielname: Kunde GmbH/
+ A->>S3: CanClaim(Kunde GmbH) → Missing → true
+ B->>S3: CanClaim(Kunde GmbH) → Missing → true
+ A->>S3: Kopiere 200 Objekte nach Kunde GmbH/
+ B->>S3: Kopiere Objekte #1–60 nach Kunde GmbH/
+ A->>S3: DeleteObjects(AltName/*) ✓
+ B->>S3: Kopie #61 → NoSuchKey ✗
+ B->>S3: catch: DeleteObjects(copiedKeys #1–60)
+ Note over S3: 60 Objekte aus Kunde GmbH/ gelöscht!
+ Note over S3: AltName/ existiert nicht mehr → Datenverlust
diff --git a/figures/diagrams/s3-layout.mmd b/figures/diagrams/s3-layout.mmd
new file mode 100644
index 0000000..47ec228
--- /dev/null
+++ b/figures/diagrams/s3-layout.mmd
@@ -0,0 +1,9 @@
+flowchart TD
+ B[(S3-Bucket\ndocuments-houston-prod)]
+ B --> KA["Kunde A/\n[meta: efecte_org-id=42]"]
+ B --> KB["Kunde B/\n[meta: efecte_org-id=77]"]
+ KA --> D1[doc1.pdf\nuntyped]
+ KA --> T1["Service-Protokoll/"]
+ KA --> T2["Vertragsunterlagen/"]
+ T1 --> D2[bericht-2026-07.pdf]
+ T2 --> D3[SLA-2026.pdf]
diff --git a/figures/diagrams/system-context.mmd b/figures/diagrams/system-context.mmd
new file mode 100644
index 0000000..095c3d8
--- /dev/null
+++ b/figures/diagrams/system-context.mmd
@@ -0,0 +1,18 @@
+flowchart LR
+ subgraph Kunde
+ K[Kundenportal\nHouston]
+ end
+ subgraph WorkSimple
+ H[Houston\nASP.NET Core]
+ F[Filestash\nS3-Browser]
+ end
+ subgraph Infrastruktur
+ E[Efecte\nCMDB]
+ S3[(S3-Speicher\nStorageGRID)]
+ AAD[Microsoft\nEntra ID]
+ end
+ K -->|HTTPS| H
+ H -->|REST| E
+ H -->|AWS SDK| S3
+ H -->|OpenID Connect| AAD
+ F -->|S3-API| S3
diff --git a/figures/diagrams/timeline-infra.mmd b/figures/diagrams/timeline-infra.mmd
new file mode 100644
index 0000000..234d839
--- /dev/null
+++ b/figures/diagrams/timeline-infra.mmd
@@ -0,0 +1,10 @@
+%%{init: {'theme': 'base'}}%%
+timeline
+ title Infrastrukturbeschaffung S3-Speicher
+ 2026-07-22 : Service Request erstellt (Maschinenraum)
+ 2026-07-23 : Request Alexander Wagner zugewiesen
+ 2026-07-27 : 3 Buckets durch AU erstellt, Credentials in Passbolt
+ 2026-07-30 : Anfrage S3 Select + Search Integration
+ 2026-08-04 : Lennart Meinert kontaktiert AU
+ 2026-08-07 : S3 Select für alle 3 Buckets aktiviert
+ 2026-08-17 : Search Integration von AU abgelehnt
diff --git a/figures/diagrams/zip-stream.mmd b/figures/diagrams/zip-stream.mmd
new file mode 100644
index 0000000..6b0af7a
--- /dev/null
+++ b/figures/diagrams/zip-stream.mmd
@@ -0,0 +1,15 @@
+sequenceDiagram
+ participant B as Browser
+ participant P as PageModel
+ participant S as DocumentsService
+ participant S3 as S3-Speicher
+
+ B->>P: POST /documents?handler=Zip&keys=[...]
+ P->>S: GetZipStreamAsync(orgId, keys)
+ loop je Dokument
+ S->>S3: GetObjectAsync(key)
+ S3-->>S: Stream
+ S->>S: ZipArchive.CreateEntry + CopyToAsync
+ end
+ S-->>P: ZipStream
+ P-->>B: application/zip (streaming)
diff --git a/figures/itc/IT-Center_Dortmund_Logo.svg.png b/figures/itc/IT-Center_Dortmund_Logo.svg.png
new file mode 100644
index 0000000000000000000000000000000000000000..98efa2e169fb9a4b172d95e1253dd053bc1c73f4
GIT binary patch
literal 5245
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
literal 0
HcmV?d00001
diff --git a/frontmatter/abstract.tex b/frontmatter/abstract.tex
new file mode 100644
index 0000000..a8f3ea8
--- /dev/null
+++ b/frontmatter/abstract.tex
@@ -0,0 +1,4 @@
+% \chapter*{Kurzfassung}
+% \addcontentsline{toc}{chapter}{Kurzfassung}
+% TODO
+% \clearpage
diff --git a/frontmatter/acknowledgments.tex b/frontmatter/acknowledgments.tex
new file mode 100644
index 0000000..291bc1b
--- /dev/null
+++ b/frontmatter/acknowledgments.tex
@@ -0,0 +1,4 @@
+% \chapter*{Danksagung}
+% \addcontentsline{toc}{chapter}{Danksagung}
+% TODO
+% \clearpage
diff --git a/frontmatter/usage-of-ai.tex b/frontmatter/usage-of-ai.tex
new file mode 100644
index 0000000..7df3ae2
--- /dev/null
+++ b/frontmatter/usage-of-ai.tex
@@ -0,0 +1,10 @@
+\chapter*{Nutzung von KI}
+\addcontentsline{toc}{chapter}{Nutzung von KI}
+
+Bei der Erstellung dieser Dokumentation wurde KI ausschließlich für die folgenden Bereiche verwendet:
+\begin{itemize}
+ \item Erlernen von \LaTeX-Syntax und Suche von entsprechenden \LaTeX-Packages für diese Dokumentation
+ \item Formatierung und Umformulierung von Inhalt, der vom Autor verfasst wurde, in den Kapiteln \ref{chap:company}, \ref{chap:overview}, \ref{chap:planning}, \ref{chap:conception}, \ref{chap:execution}, \ref{chap:qa} und \ref{chap:closure}
+\end{itemize}
+
+\clearpage
diff --git a/main.tex b/main.tex
new file mode 100644
index 0000000..95ba8b4
--- /dev/null
+++ b/main.tex
@@ -0,0 +1,102 @@
+\documentclass[times]{pidi-thesis}
+
+% --- Bibliography
+\usepackage[backend=biber,style=authoryear,sorting=nyt]{biblatex}
+\addbibresource{references.bib}
+
+% Language
+\selectlanguage{ngerman}
+
+% --- Metadata
+\setthesismeta
+ {Houston Dokumente: Kundendokumente aus S3}
+ {Houston Dokumente}
+ {Linus Nagel}
+ {2024008}
+ {Bachelor of Science - IT und Software Systeme}
+ {ITC Dortmund}
+ {Informatik}
+ {WorkSimple GmbH}
+ {Sarah Hinzmann}
+
+\setdates
+{TODO -- TODO}
+{TODO}
+
+\begin{document}
+
+\renewcommand{\companylogo}{figures/worksimple/Logo_Normal.png}
+\renewcommand{\unilogo}{figures/itc/IT-Center_Dortmund_Logo.svg.png}
+\renewcommand{\headerlogo}{figures/worksimple/Icon.png}
+\frontmatterpages
+
+\chapter{Vorstellung des Unternehmens}
+\label{chap:company}
+\input{chapters/company/worksimple}
+\input{chapters/company/products-and-services}
+\input{chapters/company/econ-localization}
+
+\chapter{Projektüberblick}
+\label{chap:overview}
+\input{chapters/overview/project-description}
+\input{chapters/overview/initial-situation}
+\input{chapters/overview/system-landscape}
+\input{chapters/overview/target-situation}
+\input{chapters/overview/project-scope}
+\input{chapters/overview/participants}
+
+\chapter{Planung und Vorbereitung}
+\label{chap:planning}
+\input{chapters/planning/onboarding}
+\input{chapters/planning/feature-analysis}
+\input{chapters/planning/requirements}
+\input{chapters/planning/backlog}
+\input{chapters/planning/schedule}
+\input{chapters/planning/infrastructure}
+
+\chapter{Konzeption}
+\label{chap:conception}
+\input{chapters/conception/s3-layout}
+\input{chapters/conception/authorization}
+\input{chapters/conception/document-types}
+\input{chapters/conception/ui-concept}
+\input{chapters/conception/lookup-research}
+\input{chapters/conception/lookup-decision}
+
+\chapter{Umsetzung}
+\label{chap:execution}
+\input{chapters/execution/architecture}
+\input{chapters/execution/s3-client}
+\input{chapters/execution/document-explorer}
+\input{chapters/execution/type-icons}
+\input{chapters/execution/search}
+\input{chapters/execution/filter-pagination}
+\input{chapters/execution/downloads}
+\input{chapters/execution/pdf-preview}
+\input{chapters/execution/url-files}
+\input{chapters/execution/folder-management}
+\input{chapters/execution/race-conditions}
+
+\chapter{Qualitätssicherung und Auslieferung}
+\label{chap:qa}
+\input{chapters/qa/test-strategy}
+\input{chapters/qa/unit-tests}
+\input{chapters/qa/code-reviews}
+\input{chapters/qa/acceptance-testing}
+\input{chapters/qa/releases}
+
+\chapter{Projektabschluss}
+\label{chap:closure}
+\input{chapters/closure/target-comparison}
+\input{chapters/closure/evaluation}
+\input{chapters/closure/reflection}
+\input{chapters/closure/outlook}
+
+\appendix
+
+\chapter{Anhang}
+\input{appendix/appendix}
+
+\printrefs
+
+\end{document}
diff --git a/pidi-thesis.cls b/pidi-thesis.cls
new file mode 100644
index 0000000..3ca30bb
--- /dev/null
+++ b/pidi-thesis.cls
@@ -0,0 +1,246 @@
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesClass{pidi-thesis}[2025/09/03 v1.0 PidI Thesis Class]
+
+\newif\if@times
+\newif\if@calibri
+\newif\if@arial
+\@timestrue % default
+
+\DeclareOption{times}{\@timestrue \@arialfalse \@calibrifalse}
+\DeclareOption{calibri}{\@calibritrue \@arialfalse \@timesfalse}
+\DeclareOption{arial}{\@arialtrue \@calibrifalse \@timesfalse}
+
+% pass through unknown options to base class if needed
+\DeclareOption*{\PassOptionsToClass{\CurrentOption}{report}}
+\ProcessOptions\relax
+
+% size depends on font choice: Times (12pt) vs sans (11pt)
+\if@times
+\LoadClass[12pt,a4paper]{report}
+\else
+\LoadClass[11pt,a4paper]{report}
+\fi
+
+% --- Packages
+\RequirePackage[a4paper,left=3cm,right=2.5cm,top=3cm,bottom=2.5cm,headsep=1cm,footskip=10mm,includehead,includefoot]{geometry}
+\RequirePackage{float}
+\RequirePackage{iftex}
+\RequirePackage{microtype}
+\RequirePackage{setspace}
+\RequirePackage{graphicx}
+\RequirePackage{booktabs}
+\RequirePackage{tabularx}
+\RequirePackage{caption}
+\RequirePackage{titlesec}
+\RequirePackage{enumitem}
+\RequirePackage{fancyhdr}
+\RequirePackage{hyperref}
+\RequirePackage{xcolor}
+\RequirePackage[ngerman,english]{babel}
+\RequirePackage{csquotes}
+\RequirePackage{transparent}
+\RequirePackage[absolute,overlay]{textpos}
+\RequirePackage{changepage}
+\RequirePackage{listings}
+\RequirePackage{minted}
+\RequirePackage{pdfpages}
+\RequirePackage{longtable}
+\RequirePackage[htt]{hyphenat}
+
+% Code highlighting
+\usemintedstyle{default}
+
+% Fonts: sans (Arial/Calibri) in 11pt, or Times New Roman 12pt
+\ifPDFTeX
+\if@times
+\RequirePackage{newtxtext}
+\else
+\RequirePackage[scaled=0.95]{helvet}
+\renewcommand{\familydefault}{\sfdefault}
+\fi
+\else
+\RequirePackage{fontspec}
+\if@times
+\setmainfont{TimesNewerRoman-Regular.otf}[
+BoldFont = TimesNewerRoman-Bold.otf,
+ItalicFont = TimesNewerRoman-Italic.otf,
+BoldItalicFont = TimesNewerRoman-BoldItalic.otf
+]
+\else
+\if@calibri
+\setmainfont{Calibri}
+\else
+\setmainfont{Arial}
+\fi
+\fi
+\fi
+
+% Line spacing
+\setstretch{1.3}
+
+% Paragraph spacing
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{6pt}
+
+% Headings: bold + clear visual hierarchy
+\titleformat{\chapter}{\bfseries\LARGE}{\thechapter\quad}{0pt}{}
+\titlespacing*{\chapter}{0pt}{*2}{*1}
+\titleformat{\section}{\bfseries\Large}{\thesection\quad}{0pt}{}
+\titlespacing*{\section}{0pt}{*1.5}{*0.8}
+\titleformat{\subsection}{\bfseries\large}{\thesubsection\quad}{0pt}{}
+\titlespacing*{\subsection}{0pt}{*1.2}{*0.6}
+
+% Emphasis should be bold as per spec
+\renewcommand{\emph}[1]{\textbf{#1}}
+
+% Captions a bit tighter
+\captionsetup{font=small,labelfont=bf}
+
+% Lists tighter by default
+\setlist{itemsep=3pt plus 1pt, topsep=6pt}
+
+% Header & footer: page number bottom-center; optional header with short title
+\pagestyle{fancy}
+\fancyhf{} % clear
+\fancyfoot[C]{\thepage}
+\renewcommand{\headrulewidth}{0pt}
+\renewcommand{\footrulewidth}{0pt}
+
+% Redefine 'plain' style to ensure chapter starting pages also use bottom-center numbering
+\fancypagestyle{plain}{
+ \fancyhf{}
+ \fancyfoot[C]{\thepage}
+ \renewcommand{\headrulewidth}{0pt}
+ \renewcommand{\footrulewidth}{0pt}
+}
+
+% Optional header content command; placed 1cm above text via headsep=1cm
+\newcommand{\shorthead}{}
+\fancyhead[L]{\shorthead}
+
+\newcommand{\headerlogo}{}
+\fancyhead[R]{\IfFileExists{\headerlogo}{\includegraphics[height=1em]{\headerlogo}}{}}
+
+\renewcommand{\headrulewidth}{0.4pt}
+
+% Hyperref setup
+\hypersetup{
+pdftitle={},
+pdfauthor={},
+colorlinks=true,
+linkcolor=[rgb]{0.0,0.2,0.6},
+citecolor=[rgb]{0.0,0.2,0.6},
+urlcolor=[rgb]{0.0,0.2,0.6}
+}
+
+% --- Meta fields
+\newcommand{\thesistitle}{}
+\newcommand{\thesisshorttitle}{}
+\newcommand{\authorname}{}
+\newcommand{\matrikel}{}
+\newcommand{\degree}{}
+\newcommand{\institution}{}
+\newcommand{\faculty}{}
+\newcommand{\course}{Praktikum in der Industrie (PidI 3)}
+\newcommand{\company}{}
+\newcommand{\advisor}{}
+\newcommand{\daterange}{}
+\newcommand{\submissiondate}{}
+
+\newcommand{\setthesismeta}[9]{%
+\renewcommand{\thesistitle}{#1}%
+\renewcommand{\thesisshorttitle}{#2}%
+\renewcommand{\authorname}{#3}%
+\renewcommand{\matrikel}{#4}%
+\renewcommand{\degree}{#5}%
+\renewcommand{\institution}{#6}%
+\renewcommand{\faculty}{#7}%
+\renewcommand{\company}{#8}%
+\renewcommand{\advisor}{#9}%
+}
+
+\newcommand{\setdates}[2]{%
+\renewcommand{\daterange}{#1}%
+\renewcommand{\submissiondate}{#2}%
+}
+
+% Update header and pdf meta when title/author set
+\AtBeginDocument{%
+\renewcommand{\shorthead}{\thesisshorttitle}%
+\hypersetup{pdftitle=\thesistitle, pdfauthor=\authorname}%
+}
+
+% Title page per spec, clean & simple
+\newcommand{\companylogo}{}
+\newcommand{\unilogo}{}
+\newcommand{\maketitlepage}{%
+\begin{titlepage}
+
+\newcommand{\hlogo}{1.5cm}
+
+\centering
+
+{\bfseries\LARGE \thesistitle\par}
+\vspace{2em}
+{\Large \course\par}
+\vspace{2em}
+{\large \textbf{Autor/in:} \authorname \\
+\textbf{Matrikelnummer:} \matrikel \par}
+\vspace{1em}
+{\large \textbf{Studiengang/Abschluss:} \degree \par}
+\vspace{1em}
+{\large \textbf{Hochschule:} \institution \\
+\textbf{Fakultät/Bereich:} \faculty \par}
+\vspace{1em}
+{\large \textbf{Partnerunternehmen:} \company \\
+\textbf{Betreuer/in im Unternehmen:} \advisor \par}
+
+\vspace{2em}
+\includegraphics[height=\hlogo]{\companylogo}
+\hfill
+\includegraphics[height=\hlogo]{\unilogo}
+\vfill
+{\large \textbf{Tätigkeitszeitraum:} \daterange \par}
+\vspace{0.5em}
+{\large \textbf{Abgabedatum:} \submissiondate \par}
+
+\addcontentsline{toc}{chapter}{Titelseite}
+\end{titlepage}
+}
+
+% Confirmation page (Bescheinigung)
+\newcommand{\confirmationpage}{%
+\chapter*{Bescheinigung}
+Hiermit wird bestätigt, dass \textbf{\authorname} das Praktikum \textbf{\course} im Partnerunternehmen \textbf{\company} im Zeitraum \textbf{\daterange} selbständig durchgeführt hat. Es wurden mindestens \textbf{24 Manntage} an dem Projekt gearbeitet. Der Einsatz von KI beschränkt sich maximal auf die erlaubten Zwecke.
+
+\vspace{4em}
+\begin{tabularx}{\textwidth}{X X}
+\hrulefill & \hrulefill \\
+Ort, Datum & Unterschrift Betreuer/in \\
+\end{tabularx}
+
+\addcontentsline{toc}{chapter}{Bescheinigung}
+\clearpage
+}
+
+% Abstract & declarations convenience
+\newcommand{\frontmatterpages}{%
+\pagenumbering{roman}
+\maketitlepage
+\renewcommand*\contentsname{Inhaltsangabe}
+\tableofcontents
+\addcontentsline{toc}{chapter}{Inhaltsangabe}
+\confirmationpage
+\input{frontmatter/usage-of-ai}
+\input{frontmatter/abstract}
+\input{frontmatter/acknowledgments}
+\clearpage
+\pagenumbering{arabic}
+}
+
+% Bibliography (biblatex expected)
+\newcommand{\printrefs}{%
+\clearpage
+\addcontentsline{toc}{chapter}{Literaturverzeichnis}
+\printbibliography
+}
diff --git a/references.bib b/references.bib
new file mode 100644
index 0000000..c55a17a
--- /dev/null
+++ b/references.bib
@@ -0,0 +1,92 @@
+@comment{Quellen für PidI 3 — Houston Dokumente}
+
+@online{aws-s3-select,
+ author = {{Amazon Web Services}},
+ title = {Selecting content from objects},
+ url = {https://docs.aws.amazon.com/AmazonS3/latest/userguide/selecting-content-from-objects.html},
+ urldate = {2026-08-25}
+}
+
+@online{aws-listobjectsv2,
+ author = {{Amazon Web Services}},
+ title = {ListObjectsV2},
+ url = {https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html},
+ urldate = {2026-08-25}
+}
+
+@online{aws-s3-naming,
+ author = {{Amazon Web Services}},
+ title = {Object key naming guidelines},
+ url = {https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html},
+ urldate = {2026-08-25}
+}
+
+@online{aws-conditional-writes,
+ author = {{Amazon Web Services}},
+ title = {Conditional requests for Amazon S3},
+ url = {https://docs.aws.amazon.com/AmazonS3/latest/userguide/conditional-requests.html},
+ urldate = {2026-08-25}
+}
+
+@online{aws-presigned-urls,
+ author = {{Amazon Web Services}},
+ title = {Sharing objects with presigned URLs},
+ url = {https://docs.aws.amazon.com/AmazonS3/latest/userguide/ShareObjectPreSignedURL.html},
+ urldate = {2026-08-25}
+}
+
+@online{storagegrid-s3-select,
+ author = {{NetApp}},
+ title = {Use S3 Select Object Content},
+ url = {https://docs.netapp.com/us-en/storagegrid/s3/select-object-content.html},
+ urldate = {2026-08-25}
+}
+
+@online{storagegrid-search-integration,
+ author = {{NetApp}},
+ title = {Use the StorageGRID search integration service},
+ url = {https://docs.netapp.com/us-en/storagegrid-enable/product-feature-guides/storagegrid-search-integration-service.html},
+ urldate = {2026-08-25}
+}
+
+@online{ibm-s3-naming,
+ author = {{IBM}},
+ title = {Naming constraints for object storage},
+ url = {https://www.ibm.com/docs/en/ahts/4.4.x?topic=reference-naming-constraints},
+ urldate = {2026-08-25}
+}
+
+@online{filestash-s3,
+ author = {{Mickael Kerjean}},
+ title = {Filestash — S3 Browser},
+ url = {https://www.filestash.app/s3-browser.html},
+ urldate = {2026-08-25}
+}
+
+@online{dotnet-keyed-di,
+ author = {{Microsoft}},
+ title = {Keyed services in .NET dependency injection},
+ url = {https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection#keyed-services},
+ urldate = {2026-08-25}
+}
+
+@online{dotnet-zip,
+ author = {{Microsoft}},
+ title = {ZipArchive Class},
+ url = {https://learn.microsoft.com/en-us/dotnet/api/system.io.compression.ziparchive},
+ urldate = {2026-08-25}
+}
+
+@online{entra-app-roles,
+ author = {{Microsoft}},
+ title = {Add app roles to your application and receive them in the token},
+ url = {https://learn.microsoft.com/en-us/entra/identity-platform/howto-add-app-roles-in-apps},
+ urldate = {2026-08-25}
+}
+
+@online{razor-pages,
+ author = {{Microsoft}},
+ title = {Introduction to Razor Pages in ASP.NET Core},
+ url = {https://learn.microsoft.com/en-us/aspnet/core/razor-pages/},
+ urldate = {2026-08-25}
+}
diff --git a/shell.nix b/shell.nix
new file mode 100644
index 0000000..2b506e3
--- /dev/null
+++ b/shell.nix
@@ -0,0 +1,47 @@
+with import {}; let
+ fonts = [
+ times-newer-roman
+ ];
+ # This is not reccocgnised by latexmk, so we will have to put our
+ # font files in ~/.local/share/fonts
+ # fontsConf = makeFontsConf {
+ # fontDirectories = fonts;
+ # };
+ # export FONTCONFIG_FILE="${fontsConf}"
+in
+ mkShell {
+ nativeBuildInputs = fonts;
+ packages = [
+ latexrun
+ mermaid-cli
+ times-newer-roman
+ (texlive.withPackages (ps:
+ with ps; [
+ transparent
+ times
+ hyphenat
+ changepage
+ biblatex
+ listings
+ minted
+ upquote
+ biber
+ fontaxes
+ newtxtt
+ newtx
+ newtxsf
+ csquotes
+ enumitem
+ titlesec
+ latexmk
+ scheme-medium
+ textpos
+ ]))
+ ];
+ shellHook = ''
+ # install fonts
+ DEST=~/.local/share/fonts/TimesNewerRoman
+ mkdir -p $DEST
+ cp -r ${toString times-newer-roman}/share/fonts/opentype "$DEST"
+ '';
+ }