docs: consolidate documentation into organized structure

- Move 12 markdown files from root to docs/ subdirectories
- Organize documentation by category:
  • docs/troubleshooting/ (1 file)  - Technical troubleshooting guides
  • docs/deployment/      (4 files) - Deployment and security documentation
  • docs/guides/          (3 files) - Feature-specific guides
  • docs/planning/        (4 files) - Planning and improvement proposals

Root directory cleanup:
- Reduced from 16 to 4 markdown files in root
- Only essential project files remain:
  • CLAUDE.md (AI instructions)
  • README.md (Main project readme)
  • CLEANUP_PLAN.md (Current cleanup plan)
  • SRC_STRUCTURE_IMPROVEMENTS.md (Structure improvements)

This improves:
 Documentation discoverability
 Logical organization by purpose
 Clean root directory
 Better maintainability
This commit is contained in:
2025-10-05 11:05:04 +02:00
parent 887847dde6
commit 5050c7d73a
36686 changed files with 196456 additions and 12398919 deletions

View File

@@ -0,0 +1,79 @@
<?php
declare(strict_types=1);
namespace App\Application\Admin\ValueObjects;
final readonly class AdminLayoutData
{
public function __construct(
public string $title,
public NavigationMenu $navigationMenu,
public BreadcrumbCollection $breadcrumbs,
public string $currentPath,
public ?string $metaDescription = null,
public ?string $pageClass = null
) {
}
public static function fromArray(array $data): self
{
return new self(
title: $data['title'] ?? 'Admin',
navigationMenu: NavigationMenu::fromArray($data['navigation_menu'] ?? []),
breadcrumbs: BreadcrumbCollection::fromArray($data['breadcrumbs_data'] ?? []),
currentPath: $data['current_path'] ?? '/',
metaDescription: $data['meta_description'] ?? null,
pageClass: $data['page_class'] ?? null
);
}
public function toArray(): array
{
return [
'title' => $this->title,
'page_title' => $this->title,
'navigation_menu' => $this->navigationMenu->toArray(),
'breadcrumbs_data' => $this->breadcrumbs->toArray(),
'current_path' => $this->currentPath,
'meta_description' => $this->metaDescription,
'page_class' => $this->pageClass,
];
}
public function withTitle(string $title): self
{
return new self(
title: $title,
navigationMenu: $this->navigationMenu,
breadcrumbs: $this->breadcrumbs,
currentPath: $this->currentPath,
metaDescription: $this->metaDescription,
pageClass: $this->pageClass
);
}
public function withNavigationMenu(NavigationMenu $navigationMenu): self
{
return new self(
title: $this->title,
navigationMenu: $navigationMenu,
breadcrumbs: $this->breadcrumbs,
currentPath: $this->currentPath,
metaDescription: $this->metaDescription,
pageClass: $this->pageClass
);
}
public function withBreadcrumbs(BreadcrumbCollection $breadcrumbs): self
{
return new self(
title: $this->title,
navigationMenu: $this->navigationMenu,
breadcrumbs: $breadcrumbs,
currentPath: $this->currentPath,
metaDescription: $this->metaDescription,
pageClass: $this->pageClass
);
}
}

View File

@@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
namespace App\Application\Admin\ValueObjects;
final readonly class Breadcrumb
{
public function __construct(
public string $name,
public ?string $url = null,
public bool $isActive = false
) {
}
public static function fromArray(array $data): self
{
return new self(
name: $data['name'] ?? '',
url: $data['url'] ?? null,
isActive: $data['is_active'] ?? false
);
}
public function toArray(): array
{
return [
'name' => $this->name,
'url' => $this->url,
'is_active' => $this->isActive,
];
}
public function withActiveState(bool $isActive): self
{
return new self(
name: $this->name,
url: $this->url,
isActive: $isActive
);
}
public function isClickable(): bool
{
return $this->url !== null && ! $this->isActive;
}
}

View File

@@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace App\Application\Admin\ValueObjects;
final readonly class BreadcrumbCollection
{
/** @param array<Breadcrumb> $breadcrumbs */
public function __construct(
public array $breadcrumbs
) {
}
public static function fromArray(array $data): self
{
$breadcrumbs = [];
foreach ($data as $breadcrumbData) {
$breadcrumbs[] = Breadcrumb::fromArray($breadcrumbData);
}
return new self($breadcrumbs);
}
public function toArray(): array
{
return array_map(
fn (Breadcrumb $breadcrumb) => $breadcrumb->toArray(),
$this->breadcrumbs
);
}
public function add(Breadcrumb $breadcrumb): self
{
return new self([...$this->breadcrumbs, $breadcrumb]);
}
public function isEmpty(): bool
{
return empty($this->breadcrumbs);
}
public function count(): int
{
return count($this->breadcrumbs);
}
public function getLast(): ?Breadcrumb
{
if (empty($this->breadcrumbs)) {
return null;
}
return end($this->breadcrumbs);
}
}

View File

@@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
namespace App\Application\Admin\ValueObjects;
final readonly class NavigationItem
{
public function __construct(
public string $name,
public string $url,
public ?string $icon = null,
public bool $isActive = false
) {
}
public static function fromArray(array $data): self
{
return new self(
name: $data['name'] ?? '',
url: $data['url'] ?? '',
icon: $data['icon'] ?? null,
isActive: $data['is_active'] ?? false
);
}
public function toArray(): array
{
return [
'name' => $this->name,
'url' => $this->url,
'icon' => $this->icon,
'is_active' => $this->isActive,
];
}
public function withActiveState(bool $isActive): self
{
return new self(
name: $this->name,
url: $this->url,
icon: $this->icon,
isActive: $isActive
);
}
public function isActive(string $currentPath): bool
{
return $this->url === $currentPath || str_starts_with($currentPath, $this->url);
}
}

View File

@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace App\Application\Admin\ValueObjects;
final readonly class NavigationMenu
{
/** @param array<NavigationSection> $sections */
public function __construct(
public array $sections
) {
}
public static function fromArray(array $data): self
{
$sections = [];
foreach ($data as $sectionData) {
$sections[] = NavigationSection::fromArray($sectionData);
}
return new self($sections);
}
public function toArray(): array
{
return array_map(
fn (NavigationSection $section) => $section->toArray(),
$this->sections
);
}
public function addSection(NavigationSection $section): self
{
return new self([...$this->sections, $section]);
}
public function findSectionByName(string $name): ?NavigationSection
{
foreach ($this->sections as $section) {
if ($section->name === $name) {
return $section;
}
}
return null;
}
}

View File

@@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
namespace App\Application\Admin\ValueObjects;
final readonly class NavigationSection
{
/** @param array<NavigationItem> $items */
public function __construct(
public string $name,
public array $items,
public ?string $icon = null
) {
}
public static function fromArray(array $data): self
{
$items = [];
foreach ($data['items'] ?? [] as $itemData) {
$items[] = NavigationItem::fromArray($itemData);
}
return new self(
name: $data['section'] ?? $data['name'] ?? '',
items: $items,
icon: $data['icon'] ?? null
);
}
public function toArray(): array
{
return [
'section' => $this->name,
'name' => $this->name,
'items' => array_map(
fn (NavigationItem $item) => $item->toArray(),
$this->items
),
'icon' => $this->icon,
];
}
public function addItem(NavigationItem $item): self
{
return new self(
name: $this->name,
items: [...$this->items, $item],
icon: $this->icon
);
}
public function hasActiveItem(string $currentPath): bool
{
foreach ($this->items as $item) {
if ($item->isActive($currentPath)) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
namespace App\Application\Admin\ValueObjects;
final readonly class RouteCollection implements \IteratorAggregate, \Countable
{
/**
* @param list<array<string, mixed>> $routes
*/
public function __construct(
private array $routes = []
) {
}
/**
* @param list<array<string, mixed>> $routes
*/
public static function fromArray(array $routes): self
{
return new self($routes);
}
public function count(): int
{
return count($this->routes);
}
public function isEmpty(): bool
{
return empty($this->routes);
}
/**
* @return list<array<string, mixed>>
*/
public function toArray(): array
{
return $this->routes;
}
public function filterByMethod(string $method): self
{
$filtered = array_filter($this->routes, function (array $route) use ($method) {
return ($route['method'] ?? 'GET') === $method;
});
return new self(array_values($filtered));
}
public function filterByPattern(string $pattern): self
{
$filtered = array_filter($this->routes, function (array $route) use ($pattern) {
return isset($route['path']) && str_contains($route['path'], $pattern);
});
return new self(array_values($filtered));
}
/**
* @return \ArrayIterator<int, array<string, mixed>>
*/
public function getIterator(): \ArrayIterator
{
return new \ArrayIterator($this->routes);
}
}