Appiyon Architectural Laws β
Version: 3.0 Last Updated: 2025-10-24 Framework: Symfony 7.3 + Doctrine ORM Purpose: Die fundamentalen architektonischen Gesetze von Appiyon fΓΌr KI-Agenten und Entwickler
ποΈ Die 6 Layer β
Infrastructure β Admin-System (separater Guard, KEINE Principals)
β
Shared β Enums, Traits, Identity (teams, principals, users, CRM)
β
Foundation β Basis-Bausteine (Tenant, User, Media, Communication)
β
Core β Primitive Data Models (Country, Language, Category)
β
Domain β Business Logic (App, Developer, Review)
β
Dev β Framework-Integration (Controllers, Commands, EventSubscribers)π΄ Critical Laws (NIEMALS brechen) β
Law 1: Layer Dependencies β
Layers dΓΌrfen nur tiefere Layers importieren
β
Domain β Core β Foundation β Shared β Infrastructure
β Core β Domain
β Foundation β Core
β Shared β FoundationBeispiele:
// β
RICHTIG - Domain importiert Core
namespace App\Appi\Domain\App\UseCase;
use App\Appi\Core\Category\Entity\Category;
// β FALSCH - Core importiert Domain
namespace App\Appi\Core\Category\UseCase;
use App\Appi\Domain\App\Entity\App; // VERBOTEN!Grund: Verhindert zirkulΓ€re AbhΓ€ngigkeiten und hΓ€lt die Architektur sauber.
Law 2: Event-Only Cross-Domain Communication β
Domains kommunizieren NUR via Events
// β FALSCH - Direkter Domain-zu-Domain Call
namespace App\Appi\Domain\Finance;
use App\Appi\Domain\Automotive\Service\RepairService;
class InvoiceService {
public function __construct(
private RepairService $repairService // VERBOTEN!
) {}
}
// β
RICHTIG - Via Events
namespace App\Appi\Domain\Finance;
class InvoiceListener {
#[AsEventListener]
public function onRepairCompleted(RepairCompletedEvent $event): void {
// Erstelle Rechnung basierend auf Event
}
}Innerhalb EINES Domain-Moduls: Synchrone Calls erlaubt
Grund: Domains bleiben entkoppelt und kΓΆnnen unabhΓ€ngig entwickelt werden.
Law 3: Infrastructure Layer Isolation β
Infrastructure = Separates Admin-System
// β
RICHTIG - Infrastructure mit eigener admins-Tabelle
namespace App\Appi\Infrastructure\Admin\Entity;
#[ORM\Entity]
#[ORM\Table(name: 'admins')]
class Admin {
// Eigene Tabelle, KEIN Principal
}
// β FALSCH - Admin als Principal
class Admin {
#[ORM\OneToOne(targetEntity: Principal::class)]
private Principal $principal; // NEIN!
}Infrastructure-Layer:
- β
Hat eigene
adminsTabelle - β Hat eigenen Authentication Guard
- β Zugriff auf GLOBALE Infrastruktur
- β NIEMALS Zugriff auf Mandanten-Daten
- β KEINE Verwendung von Principal-System
Grund: Admins verwalten Infrastruktur, nicht Mandanten-Daten.
Law 4: Shared Layer = Identity + Utilities β
Shared enthΓ€lt universelle Komponenten
Shared Layer enthΓ€lt:
- β Identity-System: teams, principals, users, crm_entries
- β Enums: PrincipalType, EntityStatus, LocationType, CommunicationType
- β Traits: AuditableTrait, SoftDeleteTrait
- β Contracts: Interfaces fΓΌr alle Layer
- β Exceptions: DomainException, ApplicationException
- β Events: BaseDomainEvent, AuditableInterface
- β Audit-System: AuditLog Entity
Grund: Shared stellt fundamentale Bausteine fΓΌr alle Layer bereit.
Law 5: Principal-Based Identity β
Principal = Universelle IdentitΓ€t (in Shared Layer)
#[ORM\Entity]
#[ORM\Table(name: 'principals')]
class Principal {
#[ORM\Column(type: 'string')]
private string $principalType; // 'person' or 'organization'
}
#[ORM\Entity]
#[ORM\Table(name: 'users')]
class User {
#[ORM\Id]
private int $principalId; // Primary Key = Principal ID
}
#[ORM\Entity]
#[ORM\Table(name: 'crm_entries')]
class CrmEntry {
private int $principalId;
private int $teamId;
private int $roleTypeId; // customer, supplier, employee, developer
}
// β FALSCH - Separate Tables
#[ORM\Entity]
class Customer { } // NEIN! Nutze CrmEntryGrund: Eine Person/Organisation = Ein Principal mit vielen Rollen.
Law 6: No team_id in Foundation/Core/Domain β
team_id existiert NUR in Dev Layer
// β FALSCH - team_id in Core
namespace App\Appi\Core\Category\Entity;
class Category {
private int $teamId; // VERBOTEN!
}
// β
RICHTIG - Core ohne team_id
namespace App\Appi\Core\Category\Entity;
class Category {
// Universell, KEIN team_id
}
// β
RICHTIG - Dev mit team_id
namespace App\Appi\Dev\Catalog\Entity;
class Item {
private int $teamId; // OK in Dev!
private int $categoryId; // Referenz zu Core
}Ausnahme: Shared/Identity (verwaltet Teams)
Grund: Foundation/Core/Domain sind universell. Kontext kommt in Dev.
Law 7: Authentication in Shared, Authorization in Dev β
Auth-System ist zweigeteilt
// β
Authentication in Shared
namespace App\Appi\Shared\Identity\UseCase;
class AuthenticateUserHandler { }
// β
Authorization in Dev
namespace App\Appi\Dev\Http\Controller;
class ItemController {
public function create() {
$this->denyAccessUnlessGranted('ITEM_CREATE');
}
}
// β FALSCH - auth() in Core
namespace App\Appi\Core\Category\UseCase;
class CreateCategoryHandler {
public function handle() {
$user = $this->security->getUser(); // VERBOTEN!
}
}Grund: Business Logic bleibt testbar und kontext-frei.
Law 8: Enums statt Lookup-Tables β
Enums in Shared, keine ID-basierten Lookups
// β
RICHTIG - Enum nutzen
use App\Appi\Shared\Enums\PrincipalType;
#[ORM\Entity]
class Principal {
#[ORM\Column(type: 'string', enumType: PrincipalType::class)]
private PrincipalType $principalType;
}
// Migration mit CHECK Constraint
CREATE TABLE principals (
principal_type VARCHAR(50),
CONSTRAINT chk_type CHECK (principal_type IN ('person', 'organization'))
);
// β FALSCH - Lookup-Table
CREATE TABLE principal_types (id SERIAL, name VARCHAR);VerfΓΌgbare Enums: PrincipalType, EntityStatus, LocationType, OperationalStatus, CommunicationType
Grund: Enums sind typsicher, kein JOIN-Overhead, klare Validation.
Law 9: CQRS Pattern with Commands & Handlers β
Use Cases folgen Command/Handler Pattern
// β
Command (DTO)
final readonly class CreateAdminCommand {
public function __construct(
public string $name,
public string $email,
public string $password
) {}
}
// β
Handler
final readonly class CreateAdminHandler {
public function handle(CreateAdminCommand $command): Admin {
// 1. Validation
// 2. Business Rules
// 3. Create Entity
// 4. Persist
// 5. Dispatch Event
}
}
// β FALSCH - Business Logic im ControllerGrund: Klare Trennung von Input, Business Logic, Output.
Law 10: Doctrine statt Active Record β
Entities sind reine Datenstrukturen
// β
RICHTIG - Doctrine Entity
#[ORM\Entity]
class Admin {
private ?int $id = null;
private string $name;
public function getName(): string { return $this->name; }
}
// β
Business Logic in Handlers
class CreateAdminHandler {
public function handle() {
$admin = new Admin();
$this->repository->save($admin);
}
}
// β FALSCH - Active Record (Laravel)
class Admin extends Model {
public static function create() { } // NO!
public function save() { } // NO!
}Grund: Doctrine Pattern. Entities = Daten, Repositories = Persistence.
Law 11: Repository Interfaces + Doctrine Implementation β
Repositories immer als Interface definieren
// β
Contract
interface AdminRepositoryInterface {
public function save(Admin $admin): void;
public function findById(int $id): ?Admin;
}
// β
Implementation
class AdminRepository implements AdminRepositoryInterface {
// Doctrine-spezifische Implementation
}
// β
Services nutzen Interface
class CreateAdminHandler {
public function __construct(
private AdminRepositoryInterface $repository
) {}
}Grund: Testbarkeit, Austauschbarkeit, klare Contracts.
Law 12: Events mit AuditableInterface β
Wichtige Domain Events implementieren AuditableInterface
final class AdminCreatedEvent implements AuditableInterface {
public function getEventName(): string {
return 'admin.created';
}
public function getAuditableType(): string {
return Admin::class;
}
public function getAuditData(): array {
return ['name' => $this->admin->getName()];
}
}Naming: {entity}.{action} (admin.created, user.authenticated)
Grund: Automatisches Audit-Logging fΓΌr alle wichtigen Events.
π Quick Reference β
| Feature | Infrastructure | Shared | Foundation | Core | Domain | Dev |
|---|---|---|---|---|---|---|
| Imports | - | Infra | Shared | Found | Core | Domain |
| team_id | β | CrmEntry | β | β | β | β |
| Enums | β | β | uses | uses | uses | uses |
| Auth | Own Guard | β | β | β | β | β (authz) |
| APIs | β | β | β | β | β | β |
| Controllers | β | β | β | β | β | β |
Diese Laws sind die Grundlage fΓΌr Code-Generierung. Bei Unsicherheit: Frage nach!