425 lines
12 KiB
Markdown
425 lines
12 KiB
Markdown
# Technische Dokumentation
|
|
|
|
[← Zurück zur Hauptseite](../README.md)
|
|
|
|
## Technologie-Stack
|
|
|
|
- **Backend**: PHP 8.4
|
|
- **Framework**: Symfony 7.3
|
|
- **Datenbank**: MariaDB 11.7
|
|
- **ORM**: Doctrine 3.0
|
|
- **API**: API Platform 4.2
|
|
- **Template Engine**: Twig 3.22
|
|
- **Webserver**: Apache 2.4 mit mod_rewrite
|
|
- **Container**: Docker & Docker Compose
|
|
- **Frontend**: jQuery 3.7.1, separates CSS/JS
|
|
|
|
## Architektur
|
|
|
|
### Schichtenmodell
|
|
|
|
```
|
|
┌─────────────────────────────────────┐
|
|
│ Presentation Layer │
|
|
│ (Twig Templates, CSS, JavaScript) │
|
|
└─────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────┐
|
|
│ Controller Layer │
|
|
│ (HomeController, AuthController, │
|
|
│ ImmobilienSaveController) │
|
|
└─────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────┐
|
|
│ Service Layer │
|
|
│ (Security, Validation, Business │
|
|
│ Logic) │
|
|
└─────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────┐
|
|
│ Persistence Layer │
|
|
│ (Doctrine ORM, Repositories) │
|
|
└─────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────┐
|
|
│ Database Layer │
|
|
│ (MariaDB) │
|
|
└─────────────────────────────────────┘
|
|
```
|
|
|
|
### Komponenten
|
|
|
|
#### Frontend
|
|
- **Templates:** `templates/` (Twig)
|
|
- **CSS:** `public/css/` (calculator.css, auth.css)
|
|
- **JavaScript:** `public/js/` (calculator.js mit jQuery)
|
|
|
|
#### Backend
|
|
- **Controller:** `src/Controller/` (Request Handling)
|
|
- **Entity:** `src/Entity/` (Datenmodelle)
|
|
- **Repository:** `src/Repository/` (Datenbank-Queries)
|
|
- **Security:** `src/Security/` (Authentifizierung)
|
|
- **Enum:** `src/Enum/` (PHP Enums)
|
|
|
|
## Datenbank-Schema
|
|
|
|
### Entity-Relationship-Diagram
|
|
|
|
```
|
|
┌──────────────┐ ┌────────────────┐
|
|
│ User │ 1 * │ Immobilie │
|
|
│──────────────│◄────────│────────────────│
|
|
│ id │ │ id │
|
|
│ name │ │ verwalter_id │
|
|
│ email │ │ adresse │
|
|
│ password │ │ wohnflaeche │
|
|
│ role │ │ nutzflaeche │
|
|
│ api_key │ │ zimmer │
|
|
│ created_at │ │ kaufpreis │
|
|
└──────────────┘ │ typ │
|
|
│ ... │
|
|
└────────────────┘
|
|
│
|
|
┌──────────────┴──────────────┐
|
|
│ │
|
|
▼ ▼
|
|
┌───────────────┐ ┌─────────────────┐
|
|
│ Bundesland │ │ Heizungstyp │
|
|
│───────────────│ │─────────────────│
|
|
│ id │ │ id │
|
|
│ name │ │ name │
|
|
│ grunderwerbst.│ └─────────────────┘
|
|
└───────────────┘
|
|
```
|
|
|
|
### Tabellen-Details
|
|
|
|
#### User-Tabelle
|
|
|
|
| Feld | Typ | Constraints | Beschreibung |
|
|
|------|-----|-------------|--------------|
|
|
| id | INT | PK, AUTO_INCREMENT | Eindeutige ID |
|
|
| name | VARCHAR(255) | NOT NULL | Benutzername |
|
|
| email | VARCHAR(255) | NOT NULL, UNIQUE | E-Mail-Adresse |
|
|
| password | VARCHAR(255) | NULL | Bcrypt-Hash des Passworts |
|
|
| role | VARCHAR(255) | NOT NULL | Benutzerrolle (Enum) |
|
|
| api_key | VARCHAR(64) | NOT NULL, UNIQUE | SHA256 API-Key |
|
|
| created_at | DATETIME | NOT NULL | Erstellungsdatum |
|
|
|
|
**Benutzerrollen (Enum):**
|
|
- `user` - Normaler Benutzer
|
|
- `admin` - Administrator
|
|
- `moderator` - Moderator
|
|
- `technical` - Technischer User
|
|
|
|
#### Bundesland-Tabelle
|
|
|
|
| Feld | Typ | Constraints | Beschreibung |
|
|
|------|-----|-------------|--------------|
|
|
| id | INT | PK, AUTO_INCREMENT | Eindeutige ID |
|
|
| name | VARCHAR(100) | NOT NULL, UNIQUE | Name des Bundeslandes |
|
|
| grunderwerbsteuer | DECIMAL(4,2) | NOT NULL | Steuersatz in % |
|
|
|
|
**Vorbefüllt mit 16 deutschen Bundesländern**
|
|
|
|
#### Heizungstyp-Tabelle
|
|
|
|
| Feld | Typ | Constraints | Beschreibung |
|
|
|------|-----|-------------|--------------|
|
|
| id | INT | PK, AUTO_INCREMENT | Eindeutige ID |
|
|
| name | VARCHAR(100) | NOT NULL, UNIQUE | Name des Heizungstyps |
|
|
|
|
**Vorbefüllt mit:** Ölheizung, Gasheizung, Wärmepumpe, Pelletheizung
|
|
|
|
#### Immobilien-Tabelle
|
|
|
|
| Feld | Typ | Constraints | Beschreibung |
|
|
|------|-----|-------------|--------------|
|
|
| id | INT | PK, AUTO_INCREMENT | Eindeutige ID |
|
|
| verwalter_id | INT | FK → users.id, NOT NULL | Besitzer der Immobilie |
|
|
| bundesland_id | INT | FK → bundeslaender.id, NULL | Bundesland |
|
|
| heizungstyp_id | INT | FK → heizungstypen.id, NULL | Heizungstyp |
|
|
| adresse | VARCHAR(255) | NOT NULL | Vollständige Adresse |
|
|
| wohnflaeche | INT | NOT NULL | Wohnfläche in m² |
|
|
| nutzflaeche | INT | NOT NULL | Nutzfläche in m² |
|
|
| garage | BOOLEAN | NOT NULL, DEFAULT false | Garage vorhanden? |
|
|
| zimmer | INT | NOT NULL | Anzahl Zimmer |
|
|
| baujahr | INT | NULL | Baujahr (1800-2100) |
|
|
| typ | VARCHAR(255) | NOT NULL | Immobilientyp (Enum) |
|
|
| beschreibung | TEXT | NULL | Freitextbeschreibung |
|
|
| etage | INT | NULL | Stockwerk (0-10) |
|
|
| kaufpreis | INT | NULL | Kaufpreis in Euro |
|
|
| abschreibungszeit | INT | NULL | Abschreibungszeit in Jahren |
|
|
| created_at | DATETIME | NOT NULL | Erstellungsdatum |
|
|
| updated_at | DATETIME | NOT NULL | Letzte Änderung |
|
|
|
|
**Immobilientyp (Enum):**
|
|
- `wohnung` - Wohnung
|
|
- `haus` - Haus
|
|
- `grundstueck` - Grundstück
|
|
- `gewerbe` - Gewerbe
|
|
- `buero` - Büro
|
|
|
|
### Indizes
|
|
|
|
```sql
|
|
-- User
|
|
CREATE UNIQUE INDEX UNIQ_1483A5E9E7927C74 ON users (email);
|
|
CREATE UNIQUE INDEX UNIQ_1483A5E9C912ED9D ON users (api_key);
|
|
|
|
-- Bundesland
|
|
CREATE UNIQUE INDEX UNIQ_DF7DFAB25E237E06 ON bundeslaender (name);
|
|
|
|
-- Heizungstyp
|
|
CREATE UNIQUE INDEX UNIQ_6161C2A65E237E06 ON heizungstypen (name);
|
|
|
|
-- Immobilie
|
|
CREATE INDEX IDX_2C789D3E5F66D3 ON immobilien (verwalter_id);
|
|
CREATE INDEX IDX_2C789DC1B4DB52 ON immobilien (heizungstyp_id);
|
|
CREATE INDEX IDX_2C789DB74FDBEB ON immobilien (bundesland_id);
|
|
```
|
|
|
|
## Konfiguration
|
|
|
|
### Umgebungsvariablen (.env)
|
|
|
|
```env
|
|
# Symfony
|
|
APP_ENV=dev # Umgebung: dev | prod | test
|
|
APP_SECRET=<32-zeichen-hex> # Symfony Secret für Verschlüsselung
|
|
|
|
# Datenbank
|
|
DATABASE_URL="mysql://immorechner_user:immorechner_pass@db:3306/immorechner?serverVersion=mariadb-11.7.1&charset=utf8mb4"
|
|
|
|
# Routing
|
|
DEFAULT_URI=http://localhost
|
|
|
|
# CORS (für API)
|
|
CORS_ALLOW_ORIGIN='^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$'
|
|
```
|
|
|
|
### Services (config/services.yaml)
|
|
|
|
```yaml
|
|
services:
|
|
_defaults:
|
|
autowire: true
|
|
autoconfigure: true
|
|
|
|
App\:
|
|
resource: '../src/'
|
|
exclude:
|
|
- '../src/Entity/'
|
|
- '../src/Repository/'
|
|
- '../src/Kernel.php'
|
|
|
|
App\Controller\:
|
|
resource: '../src/Controller/'
|
|
tags: ['controller.service_arguments']
|
|
|
|
App\Repository\:
|
|
resource: '../src/Repository/'
|
|
```
|
|
|
|
### Security (config/packages/security.yaml)
|
|
|
|
```yaml
|
|
security:
|
|
password_hashers:
|
|
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
|
|
|
|
providers:
|
|
app_user_provider:
|
|
entity:
|
|
class: App\Entity\User
|
|
property: email
|
|
|
|
firewalls:
|
|
# API mit API-Key
|
|
api:
|
|
pattern: ^/api
|
|
stateless: true
|
|
custom_authenticators:
|
|
- App\Security\ApiKeyAuthenticator
|
|
|
|
# Frontend mit Form-Login
|
|
main:
|
|
lazy: true
|
|
provider: app_user_provider
|
|
form_login:
|
|
login_path: app_login
|
|
check_path: app_login
|
|
default_target_path: app_home
|
|
logout:
|
|
path: app_logout
|
|
target: app_home
|
|
```
|
|
|
|
### API Platform (config/packages/api_platform.yaml)
|
|
|
|
```yaml
|
|
api_platform:
|
|
title: 'Immorechner API'
|
|
version: 1.0.0
|
|
mapping:
|
|
paths: ['%kernel.project_dir%/src/Entity']
|
|
defaults:
|
|
stateless: true
|
|
formats:
|
|
jsonld: ['application/ld+json']
|
|
json: ['application/json']
|
|
```
|
|
|
|
## Docker-Konfiguration
|
|
|
|
### docker-compose.yml
|
|
|
|
```yaml
|
|
services:
|
|
web:
|
|
build: .
|
|
container_name: immorechner_web
|
|
ports:
|
|
- "8080:80"
|
|
volumes:
|
|
- .:/var/www/html
|
|
depends_on:
|
|
- db
|
|
|
|
db:
|
|
image: mariadb:latest
|
|
container_name: immorechner_db
|
|
environment:
|
|
MYSQL_ROOT_PASSWORD: root
|
|
MYSQL_DATABASE: immorechner
|
|
MYSQL_USER: immorechner_user
|
|
MYSQL_PASSWORD: immorechner_pass
|
|
ports:
|
|
- "3306:3306"
|
|
volumes:
|
|
- db_data:/var/lib/mysql
|
|
|
|
phpmyadmin:
|
|
image: phpmyadmin:latest
|
|
container_name: immorechner_phpmyadmin
|
|
ports:
|
|
- "8081:80"
|
|
environment:
|
|
PMA_HOST: db
|
|
PMA_USER: root
|
|
PMA_PASSWORD: root
|
|
```
|
|
|
|
### Dockerfile
|
|
|
|
```dockerfile
|
|
FROM php:8.4-apache
|
|
|
|
# Install dependencies
|
|
RUN apt-get update && apt-get install -y \
|
|
libpng-dev libonig-dev libxml2-dev libicu-dev \
|
|
libzip-dev git curl unzip
|
|
|
|
# Install PHP extensions
|
|
RUN docker-php-ext-install pdo_mysql mbstring exif \
|
|
pcntl bcmath gd zip intl opcache
|
|
|
|
# Enable Apache modules
|
|
RUN a2enmod rewrite headers
|
|
|
|
# Copy Composer
|
|
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
|
|
|
|
# Set working directory
|
|
WORKDIR /var/www/html
|
|
|
|
# Copy application
|
|
COPY . /var/www/html
|
|
|
|
# Set permissions
|
|
RUN chown -R www-data:www-data /var/www/html
|
|
```
|
|
|
|
## Performance-Optimierungen
|
|
|
|
### Opcache (Produktion)
|
|
|
|
In Produktion ist Opcache aktiviert:
|
|
|
|
```ini
|
|
opcache.enable=1
|
|
opcache.memory_consumption=256
|
|
opcache.max_accelerated_files=20000
|
|
opcache.validate_timestamps=0
|
|
```
|
|
|
|
### Doctrine Query Cache
|
|
|
|
Doctrine nutzt automatisch Query-Cache in Produktion.
|
|
|
|
### Asset Compilation
|
|
|
|
Assets werden bei Deployment kompiliert:
|
|
|
|
```bash
|
|
php bin/console assets:install public --symlink --relative
|
|
```
|
|
|
|
## Sicherheit
|
|
|
|
### CSRF-Schutz
|
|
|
|
Alle Forms verwenden CSRF-Tokens:
|
|
|
|
```twig
|
|
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
|
|
```
|
|
|
|
### Passwort-Hashing
|
|
|
|
Passwörter werden mit bcrypt gehasht:
|
|
|
|
```php
|
|
$hashedPassword = $passwordHasher->hashPassword($user, $password);
|
|
```
|
|
|
|
### API-Key-Generierung
|
|
|
|
API-Keys sind SHA256-Hashes:
|
|
|
|
```php
|
|
return hash('sha256', random_bytes(32).microtime(true));
|
|
```
|
|
|
|
### SQL-Injection-Schutz
|
|
|
|
Doctrine ORM verhindert SQL-Injection durch Prepared Statements.
|
|
|
|
### XSS-Schutz
|
|
|
|
Twig escaped automatisch alle Ausgaben.
|
|
|
|
## Migrations
|
|
|
|
Migrationen werden mit Doctrine Migrations verwaltet:
|
|
|
|
```bash
|
|
# Neue Migration erstellen
|
|
php bin/console doctrine:migrations:diff
|
|
|
|
# Migrationen ausführen
|
|
php bin/console doctrine:migrations:migrate
|
|
|
|
# Migration-Status anzeigen
|
|
php bin/console doctrine:migrations:status
|
|
```
|
|
|
|
---
|
|
|
|
**Siehe auch:**
|
|
- [Installation](installation.md) - Setup-Anleitung
|
|
- [Development](development.md) - Entwickler-Workflow
|
|
- [Docker](docker.md) - Container-Management
|
|
|
|
[← Zurück zur Hauptseite](../README.md)
|