Files
immorechner/docs/technical.md
2025-11-09 11:27:21 +01:00

12 KiB

Technische Dokumentation

← Zurück zur Hauptseite

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

-- 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)

# 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)

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)

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)

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

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

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:

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:

php bin/console assets:install public --symlink --relative

Sicherheit

CSRF-Schutz

Alle Forms verwenden CSRF-Tokens:

<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">

Passwort-Hashing

Passwörter werden mit bcrypt gehasht:

$hashedPassword = $passwordHasher->hashPassword($user, $password);

API-Key-Generierung

API-Keys sind SHA256-Hashes:

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:

# 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:

← Zurück zur Hauptseite