diff --git a/.vscode/ftp-kr.sync.cache.json b/.vscode/ftp-kr.sync.cache.json index 158d262..b6ed610 100644 --- a/.vscode/ftp-kr.sync.cache.json +++ b/.vscode/ftp-kr.sync.cache.json @@ -144,8 +144,8 @@ }, "CRON.md": { "type": "-", - "size": 4784, - "lmtime": 1771620216534, + "size": 4875, + "lmtime": 1771669072264, "modified": false }, "DATABASE.md": { @@ -169,8 +169,8 @@ }, ".env.example": { "type": "-", - "size": 442, - "lmtime": 1771626490188, + "size": 616, + "lmtime": 1771669059812, "modified": false }, ".htaccess": { @@ -245,6 +245,12 @@ "size": 829, "lmtime": 1771620035555, "modified": false + }, + "010_dataforseo_indexed_pages.sql": { + "type": "-", + "size": 238, + "lmtime": 1771668925563, + "modified": false } }, "src": { @@ -299,14 +305,14 @@ }, "SettingsController.php": { "type": "-", - "size": 1868, - "lmtime": 1771626466574, + "size": 2267, + "lmtime": 1771668989725, "modified": false }, "SiteController.php": { "type": "-", - "size": 16907, - "lmtime": 1771628191087, + "size": 17063, + "lmtime": 1771668985080, "modified": false }, "TopicController.php": { @@ -395,14 +401,14 @@ }, "Site.php": { "type": "-", - "size": 1441, - "lmtime": 1771627194103, + "size": 1668, + "lmtime": 1771669773477, "modified": false }, "SiteSeoMetric.php": { "type": "-", - "size": 4817, - "lmtime": 1771627676032, + "size": 6296, + "lmtime": 1771669766557, "modified": false }, "Topic.php": { @@ -419,6 +425,12 @@ } }, "Services": { + "DataForSeoService.php": { + "type": "-", + "size": 3670, + "lmtime": 1771668941654, + "modified": false + }, "FtpService.php": { "type": "-", "size": 7464, @@ -457,8 +469,8 @@ }, "SiteSeoSyncService.php": { "type": "-", - "size": 3146, - "lmtime": 1771620084332, + "size": 6697, + "lmtime": 1771669807579, "modified": false }, "TopicBalancer.php": { @@ -561,8 +573,8 @@ }, "seo-stats.php": { "type": "-", - "size": 7955, - "lmtime": 1771627707865, + "size": 8683, + "lmtime": 1771669055520, "modified": false } }, @@ -605,16 +617,16 @@ "settings": { "index.php": { "type": "-", - "size": 7022, - "lmtime": 1771626482753, + "size": 9423, + "lmtime": 1771669002362, "modified": false } }, "sites": { "create.php": { "type": "-", - "size": 5295, - "lmtime": 1771620136407, + "size": 5744, + "lmtime": 1771669030881, "modified": false }, "dashboard.php": { @@ -625,8 +637,8 @@ }, "edit.php": { "type": "-", - "size": 13837, - "lmtime": 1771628695879, + "size": 14374, + "lmtime": 1771669040355, "modified": false }, "index.php": { @@ -637,8 +649,8 @@ }, "seo.php": { "type": "-", - "size": 7545, - "lmtime": 1771626686595, + "size": 8656, + "lmtime": 1771669504439, "modified": false } }, @@ -665,6 +677,12 @@ "lmtime": 1771626947881, "modified": false }, + "tmp_semstorm_test.php": { + "type": "-", + "size": 1027, + "lmtime": 1771627094790, + "modified": false + }, "TODO.md": { "type": "-", "size": 233, @@ -792,12 +810,6 @@ "lmtime": 1771150407034, "modified": false } - }, - "tmp_semstorm_test.php": { - "type": "-", - "size": 1027, - "lmtime": 1771627094790, - "modified": false } } }, diff --git a/GEMINI.md b/GEMINI.md new file mode 100644 index 0000000..3fb125f --- /dev/null +++ b/GEMINI.md @@ -0,0 +1,85 @@ +# GEMINI.md - BackPRO (SEO Management System) + +## Project Overview +**BackPRO** is a custom PHP-based SEO management system designed to automate the management and content generation for a network of WordPress satellite sites. It leverages the WordPress REST API, OpenAI for content generation, and various image APIs (like Freepik) to create and publish SEO-optimized articles. + +### Core Technologies +- **Language:** PHP 8.3+ (Strict Types enabled) +- **Framework:** Custom MVC architecture (no external framework like Laravel/Symfony) +- **Database:** MySQL/MariaDB (via PDO) +- **Frontend:** Bootstrap 5, Vanilla CSS/JS, PHP Templates +- **Integrations:** + - WordPress REST API (via Application Passwords) + - OpenAI API (GPT models for content) + - Freepik/Unsplash/Pexels APIs (for images) + - Semstorm/DataForSeo (for SEO metrics) +- **Dependencies:** Managed via Composer (`guzzlehttp/guzzle`, `phpdotenv`) + +--- + +## Architecture & Structure + +The project follows a standard MVC pattern with a clear separation of concerns: + +- **`index.php`**: Front Controller - entry point for all web requests. +- **`src/Core/`**: The "engine" of the application. + - `App.php`: Application bootstrapper. + - `Router.php`: Maps URLs to controllers (defined in `config/routes.php`). + - `Model.php`: Base class for database interactions using PDO. + - `Controller.php`: Base class for all controllers. + - `Auth.php`: Session-based authentication system. +- **`src/Controllers/`**: Contains application logic (Auth, Dashboard, Sites, Topics, Articles, etc.). +- **`src/Models/`**: Database entity representations. +- **`src/Services/`**: External API clients and complex business logic (e.g., `WordPressService`, `OpenAIService`, `PublisherService`). +- **`templates/`**: PHP-based view templates. +- **`cron/`**: Scripts designed for CLI execution via system cron jobs (automated publishing). +- **`migrations/`**: SQL files for database schema evolution. + +--- + +## Development Guidelines + +### 1. Coding Standards +- **Naming:** Follow PSR-4 for class autoloading (Namespace `App\` maps to `src/`). +- **Database:** Always use Prepared Statements via `src/Core/Database.php` or `src/Core/Model.php` to prevent SQL Injection. +- **Security:** + - Use `htmlspecialchars()` in templates for XSS protection. + - Passwords must be hashed using `bcrypt` (via `password_hash`). + - API keys and sensitive data belong in the `.env` file. +- **Error Handling:** Use `App\Helpers\Logger` for logging application events and errors. Logs are stored in `storage/logs/`. + +### 2. Working with Models +Models extend `App\Core\Model` and should contain methods for specific data retrieval. Use `$this->db` (a PDO instance) for queries. + +### 3. Adding Routes +New endpoints must be registered in `config/routes.php`. Format: `$router->METHOD('/path', 'ControllerName', 'methodName')`. + +### 4. Integration Logic +Place logic for interacting with external services in the `src/Services/` directory. These should be designed as reusable components. + +--- + +## Deployment & Running + +### Environment Setup +1. **PHP:** Ensure PHP 8.1+ is installed. +2. **Composer:** Run `composer install` to install dependencies. +3. **Configuration:** Copy `.env.example` to `.env` and fill in: + - Database credentials (`DB_HOST`, `DB_NAME`, `DB_USER`, `DB_PASS`) + - API Keys (`OPENAI_API_KEY`, `FREEPIK_API_KEY`, etc.) +4. **Database:** Execute SQL scripts from the `migrations/` directory in order. + +### Commands & Scripts +- **Web Interface:** Accessible via a web server pointing to the root directory (ensure `.htaccess` is respected). +- **Automation (CRON):** + - `php cron/publish.php` - Triggers the automated publishing cycle. + - `php cron/semstorm.php` - Syncs SEO metrics. + +--- + +## Key Features +- **WordPress Site CRUD:** Add and manage WP instances. +- **Topic Balancer:** Ensures content is distributed evenly across assigned topics. +- **AI Content Engine:** Generates unique articles with contextual images. +- **Remote Installer:** Automates the installation of WordPress and themes on remote servers. +- **SEO Analytics:** Tracks visibility and indexing status via third-party services. diff --git a/assets/css/app.css b/assets/css/app.css index 2ed3cba..248ffa6 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -1,111 +1,172 @@ -/* BackPRO - Custom Styles */ +/* BackPRO - Compact Modern Dashboard Styles */ + +:root { + --primary-color: #4f46e5; + --primary-hover: #4338ca; + --bg-main: #f8fafc; + --sidebar-bg: #0f172a; + --sidebar-link: #94a3b8; + --sidebar-link-active: #ffffff; + --sidebar-link-hover: #1e293b; + --card-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); + --border-color: #e2e8f0; +} body { - background-color: #f4f6f9; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; + background-color: var(--bg-main); + font-family: 'Inter', sans-serif; + font-size: 0.875rem; /* Zmniejszona baza (14px zamiast 16px) */ + color: #1e293b; + -webkit-font-smoothing: antialiased; } +/* Global Links */ +a { + color: var(--primary-color); + text-decoration: none; + transition: color 0.2s ease; +} + +a:hover { + color: var(--primary-hover); +} + +/* Sidebar - Compact */ .sidebar { - position: sticky; - top: 0; - height: 100vh; - overflow-y: auto; + background-color: var(--sidebar-bg); + border-right: 1px solid rgba(255, 255, 255, 0.05); + z-index: 1000; } -.content-area { - min-width: 0; +.sidebar-header { + padding: 1rem 1.25rem; /* Zmniejszony padding */ + border-bottom: 1px solid rgba(255, 255, 255, 0.05); } .sidebar .nav-link { - padding: 0.6rem 1rem; + color: var(--sidebar-link); + padding: 0.5rem 1rem; /* Zmniejszony padding */ + margin: 0.15rem 0.75rem; /* Mniejsze marginesy */ border-radius: 0.375rem; - margin: 0.1rem 0; - transition: background-color 0.2s; + font-weight: 500; + font-size: 0.85rem; /* Mniejsza czcionka */ + display: flex; + align-items: center; + transition: all 0.2s ease; } -.sidebar .nav-link:hover { - background-color: rgba(255, 255, 255, 0.1); +.sidebar .nav-link i { + font-size: 1rem; + margin-right: 0.75rem; + opacity: 0.7; } -.sidebar .nav-link.active { - background-color: rgba(255, 255, 255, 0.15); +/* Header - Slim */ +header { + background-color: rgba(255, 255, 255, 0.8) !important; + backdrop-filter: blur(8px); + border-bottom: 1px solid var(--border-color) !important; + padding: 0.5rem 1.25rem !important; /* Odchudzony header */ } +header h5 { + font-size: 1rem; /* Mniejszy tytuł */ +} + +/* Cards - Compact */ .card { - border: none; - box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); + background-color: #ffffff; + border: 1px solid var(--border-color); + border-radius: 0.5rem; + box-shadow: var(--card-shadow); } -.table th { +.card-header { + padding: 0.75rem 1rem; /* Mniejszy padding */ + font-size: 0.9rem; + font-weight: 600; +} + +.card-body { + padding: 1rem; +} + +/* Tables - High Density */ +.table-container { + background: #fff; + border-radius: 0.5rem; +} + +.table thead th { + background-color: #f8fafc; + color: #64748b; font-weight: 600; - font-size: 0.85rem; text-transform: uppercase; - color: #6c757d; - border-bottom-width: 1px; + font-size: 0.7rem; /* Bardzo mały, czytelny label */ + letter-spacing: 0.05em; + padding: 0.6rem 0.85rem; /* Ciasne komórki */ + border-bottom: 1px solid var(--border-color); } -.article-content h2 { - font-size: 1.4rem; - margin-top: 1.5rem; +.table tbody td { + padding: 0.6rem 0.85rem; /* Ciasne komórki */ + font-size: 0.85rem; } -.article-content h3 { - font-size: 1.2rem; - margin-top: 1.2rem; +/* Stats Cards - Compact */ +.stat-card { + padding: 1rem; } -.article-content p { - line-height: 1.7; -} - -.article-content, -.article-content * { - overflow-wrap: anywhere; -} - -.btn-group .btn + form .btn { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} - -.bp-toast-container { - z-index: 2000; - max-width: 420px; -} - -.bp-toast { - border-radius: 12px; -} - -.bp-toast .toast-body { - font-size: 0.95rem; -} - -.bp-toast.text-bg-warning .btn-close { - filter: none; -} - -.bp-toast-fallback { - margin-bottom: 0.5rem; - padding: 0.75rem 0.95rem; - border-radius: 10px; - background: #1f2a44; - color: #fff; - box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.25); -} - -.bp-confirm-modal .modal-content { - border: 0; - border-radius: 14px; - box-shadow: 0 1rem 2rem rgba(19, 31, 56, 0.2); -} - -.bp-confirm-modal .modal-title { +.stat-icon { + width: 36px; + height: 36px; + border-radius: 8px; font-size: 1.1rem; + margin-bottom: 0.5rem; +} + +.stat-value { + font-size: 1.25rem; /* Mniejsza wartość */ font-weight: 700; } -.bp-confirm-modal .modal-body p { - color: #445066; - line-height: 1.5; +.stat-label { + font-size: 0.75rem; +} + +/* Badges - Small */ +.badge { + padding: 0.25em 0.6em; + font-size: 0.75rem; + font-weight: 600; +} + +/* Buttons - Slim */ +.btn { + border-radius: 0.375rem; + padding: 0.35rem 0.75rem; + font-size: 0.85rem; +} + +.btn-sm { + padding: 0.2rem 0.5rem; + font-size: 0.75rem; +} + +/* Main Content Padding */ +main.p-4 { + padding: 1.25rem !important; /* Mniejszy margines główny */ +} + +/* Forms - Compact */ +.form-control, .form-select { + padding: 0.4rem 0.6rem; + font-size: 0.875rem; + border-radius: 0.375rem; +} + +.article-content { + font-size: 0.95rem; /* Nieco mniejszy tekst artykułu */ + line-height: 1.6; } diff --git a/src/Core/Router.php b/src/Core/Router.php index 4714bda..9298ece 100644 --- a/src/Core/Router.php +++ b/src/Core/Router.php @@ -67,4 +67,13 @@ class Router http_response_code(404); echo '