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