Итерация 1: каркас Slim 4 приложения

- Slim 4 + php-di контейнер с маршрутизацией
- Docker Compose: app (PHP 8.3-FPM) + web (nginx) + db (MariaDB)
- Phinx миграция: таблица users (uuid, username, password_hash)
- Auth: login/logout с сессиями
- Setup: создание первого пользователя
- Dashboard с layout (Bootstrap 5.3)
- CLI: bin/console, bin/run-scan-worker.php
- Smoke test: scripts/check.sh
- README.md, PLAN.md
This commit is contained in:
2026-05-26 07:26:55 +08:00
commit e7732f5cee
31 changed files with 8790 additions and 0 deletions
+31
View File
@@ -0,0 +1,31 @@
<?php ob_start(); ?>
<div class="row justify-content-center">
<div class="col-md-4">
<div class="card mt-5">
<div class="card-body">
<h4 class="card-title text-center mb-4">Вход в Домовой</h4>
<?php if (isset($error)): ?>
<div class="alert alert-danger"><?= htmlspecialchars($error) ?></div>
<?php endif; ?>
<form method="POST" action="/login">
<div class="mb-3">
<label for="username" class="form-label">Имя пользователя</label>
<input type="text" class="form-control" id="username" name="username" required autofocus>
</div>
<div class="mb-3">
<label for="password" class="form-label">Пароль</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary w-100">Войти</button>
</form>
<div class="text-center mt-3">
<small class="text-muted">
Нет аккаунта? <a href="/setup">Создать первого пользователя</a>
</small>
</div>
</div>
</div>
</div>
</div>
<?php $content = ob_get_clean(); ?>
<?php require dirname(__DIR__) . '/layout.php'; ?>
+30
View File
@@ -0,0 +1,30 @@
<?php ob_start(); ?>
<div class="row justify-content-center">
<div class="col-md-4">
<div class="card mt-5">
<div class="card-body">
<h4 class="card-title text-center mb-4">Создание первого пользователя</h4>
<p class="text-muted text-center">Это будет администратор системы "Домовой"</p>
<?php if (isset($error)): ?>
<div class="alert alert-danger"><?= htmlspecialchars($error) ?></div>
<?php endif; ?>
<form method="POST" action="/setup">
<div class="mb-3">
<label for="username" class="form-label">Имя пользователя</label>
<input type="text" class="form-control" id="username" name="username" required autofocus
minlength="2" maxlength="255">
</div>
<div class="mb-3">
<label for="password" class="form-label">Пароль</label>
<input type="password" class="form-control" id="password" name="password" required
minlength="8">
<div class="form-text">Минимум 8 символов</div>
</div>
<button type="submit" class="btn btn-primary w-100">Создать аккаунт</button>
</form>
</div>
</div>
</div>
</div>
<?php $content = ob_get_clean(); ?>
<?php require dirname(__DIR__) . '/layout.php'; ?>
+71
View File
@@ -0,0 +1,71 @@
<?php ob_start(); ?>
<h2>Dashboard</h2>
<div class="row mb-4">
<div class="col-md-3">
<div class="card text-white bg-primary">
<div class="card-body">
<h5 class="card-title">Устройства</h5>
<p class="card-text display-6">0</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-success">
<div class="card-body">
<h5 class="card-title">Сервисы</h5>
<p class="card-text display-6">0</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-info">
<div class="card-body">
<h5 class="card-title">Новые находки</h5>
<p class="card-text display-6">0</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-warning">
<div class="card-body">
<h5 class="card-title">Требуют внимания</h5>
<p class="card-text display-6">0</p>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="card mb-4">
<div class="card-header">
Последние найденные хосты
</div>
<div class="card-body">
<p class="text-muted">Нет данных. Запустите сканирование сети.</p>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card mb-4">
<div class="card-header">
Последние события
</div>
<div class="card-body">
<p class="text-muted">Нет событий.</p>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-header">
Последний скан сети
</div>
<div class="card-body">
<p class="text-muted">Сканирование ещё не запускалось.</p>
</div>
</div>
<?php $content = ob_get_clean(); ?>
<?php require dirname(__DIR__) . '/layout.php'; ?>
+67
View File
@@ -0,0 +1,67 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Домовой</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/css/app.css" rel="stylesheet">
</head>
<body>
<div class="d-flex" id="wrapper">
<!-- Sidebar -->
<nav class="bg-dark text-white border-end" id="sidebar-wrapper" style="width: 250px; min-height: 100vh;">
<div class="sidebar-heading p-3 border-bottom border-secondary">
<a href="/dashboard" class="text-white text-decoration-none">
<h4 class="mb-0">Домовой</h4>
</a>
</div>
<div class="list-group list-group-flush">
<a href="/dashboard" class="list-group-item list-group-item-action bg-dark text-white border-0">
Dashboard
</a>
<a href="/discovery" class="list-group-item list-group-item-action bg-dark text-white border-0">
Сканирование сети
</a>
<a href="/devices" class="list-group-item list-group-item-action bg-dark text-white border-0">
Устройства
</a>
<a href="/services" class="list-group-item list-group-item-action bg-dark text-white border-0">
Сервисы
</a>
<a href="/documents" class="list-group-item list-group-item-action bg-dark text-white border-0">
Документы
</a>
<a href="/settings" class="list-group-item list-group-item-action bg-dark text-white border-0">
Настройки
</a>
</div>
</nav>
<!-- Page Content -->
<div id="page-content-wrapper" class="w-100">
<!-- Top Navbar -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark border-bottom border-secondary">
<div class="container-fluid">
<span class="navbar-brand text-light">Домовой</span>
<div class="ms-auto d-flex align-items-center">
<span class="text-light me-3"><?= htmlspecialchars($username ?? 'User') ?></span>
<form method="POST" action="/logout" class="d-inline">
<button type="submit" class="btn btn-outline-light btn-sm">Logout</button>
</form>
</div>
</div>
</nav>
<!-- Main Content -->
<div class="container-fluid p-4">
<?php if (isset($content)): ?>
<?= $content ?>
<?php endif; ?>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>