12 KiB
12 KiB
Technische Dokumentation
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 |
| 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 Benutzeradmin- Administratormoderator- Moderatortechnical- 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- Wohnunghaus- Hausgrundstueck- Grundstückgewerbe- Gewerbebuero- 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:
- Installation - Setup-Anleitung
- Development - Entwickler-Workflow
- Docker - Container-Management