# Projektstruktur: `public/` als Document-Root

> **Status:** umgesetzt. Der Webserver liefert **`public/`** aus; alles andere
> liegt eine Ebene höher und ist damit nicht über den Browser erreichbar.

## Warum

Zuvor war das gesamte Repo der Document-Root — jede Datei (auch `.env`,
`bootstrap.php`, `config/`, `app/`, `vendor/`) lag prinzipiell im Web-Zugriff und
war nur per `.htaccess`-Regeln gesperrt. Standard und robuster ist ein eigener
Document-Root `public/`, der **nur** die öffentlichen Einstiegspunkte und Assets
enthält. Sensible Dateien liegen dann physisch ausserhalb des Web-Zugriffs — ein
Konfigurationsfehler in der `.htaccess` kann sie nicht mehr preisgeben.

## Was liegt wo

**In `public/` (Document-Root, öffentlich):**

- Einstiegs-Seiten: `index.php`, `detail/`, `dokumente/`, `settings/`,
  `search/`, `news/`, `login/`, `maintenance.php`
- View-Bausteine: `bpTable.php`, `termineSidebar.php`, `partials/`
- Assets: `assets/`, `css/`, `library/`, `favicon.ico`, `robots.txt`, `script.js`
- Nutzerdateien: `uploads/`, `archives/` (siehe unten)
- `php.ini`, `.htaccess`
- **Drei Shims:** `bootstrap.php`, `db.php`, `header.php` — je eine Zeile, die an
  die echte Datei eine Ebene höher delegiert (siehe unten).

**Über `public/` (nicht über den Browser erreichbar):**

- **Echte Infrastruktur:** `bootstrap.php`, `db.php`, `header.php`
- Konfiguration & Code: `config/`, `app/`, `vendor/`
- Daten & Werkzeuge: `db/` (Schema), `docs/`, `tests/`, `cron/`
- Geheimnisse: `.env`
- Projekt-Metadaten: `composer.*`, `package*.json`, `.gitignore`, `README.md`,
  `CHANGELOG.md`, `.ddev/`

## Die Shim-Lösung

Die Seiten binden Infrastruktur relativ zum Webroot ein, z.B.
`require_once __DIR__ . '/../header.php'`. Da `public/` jetzt der Webroot ist,
zeigt das auf `public/header.php`. Dort liegt ein **Shim**:

```php
<?php
require_once __DIR__ . '/../header.php';   // echte Datei, ausserhalb public/
```

So musste **kein einziger Include in den ~30 Seiten geändert werden**, und die
echte `bootstrap.php`/`db.php`/`header.php` liegt trotzdem sauber ausserhalb des
Document-Roots — zusammen mit `config/`, `app/`, `vendor/`, `.env`. Die echten
Dateien referenzieren einander und `vendor/`/`config/`/`.env` unverändert per
`__DIR__` (alle im selben Verzeichnis, dem Repo-Root).

## uploads/ und archives/

Diese liegen **bewusst in `public/`**, nicht darüber: Die Datei-URLs zeigen in
den Document-Root (`BASE_URL/uploads/<id>.<ext>`), und der Zugriff wird **nicht**
über die Verzeichnis-Lage geschützt, sondern über den Token-Mechanismus —
`public/uploads/.htaccess` schreibt jeden Zugriff auf `download.php` um, das die
dokumentgebundene Kurzsignatur (`App\Security\DownloadToken`) prüft. Die
Config-Pfade zeigen entsprechend auf `public/uploads` bzw. `public/archives`
(`config/app.php`, überschreibbar per `.env`: `UPLOAD_DIR`/`ARCHIVE_DIR`).

## Deployment auf Produktion — WICHTIG

Der Webserver-Document-Root **muss** auf `.../public` gesetzt werden:

- **ddev (lokal):** `.ddev/config.yaml` → `docroot: "public"` (erledigt).
- **Produktion (cPanel/Hoster):** die Domain auf das `public/`-Unterverzeichnis
  zeigen lassen.

> **Ohne korrekten Document-Root funktioniert die App nicht — und schlimmer:
> Läge der Root weiterhin auf dem Repo-Stamm, wären `.env` & Code wieder
> erreichbar.** Kann der Hoster keinen Unterordner als Docroot setzen, ist diese
> Struktur so nicht nutzbar; dann bräuchte es einen alternativen Weg (z.B.
> Symlink oder ein Deploy, das nur `public/` als Web-Wurzel ausrollt und den Rest
> daneben legt). Vor dem Prod-Deploy klären.

Die `.htaccess` in `public/` behält ihre Sperr-Regeln (Force-SSL, `.env`/
Dotfile-/Code-Verzeichnis-Sperren) als zusätzliche Absicherung — greifen tut vor
allem schon der Document-Root selbst.
