| name | atomic-framework-core |
| description | Use when working on Atomic Core: bootstrap, config loading, App class, request/response helpers, routing, middleware, logging channels, error handling, Prefly checks, DB connections, migrations, crypto, guard roles, ID generation, upload, filesystem, and all route-loader behavior. |
| argument-hint | Core bootstrap, config, middleware, logging, routing, crypto, migrations |
| user-invocable | true |
Atomic Framework Core
When to Use
- Writing or changing bootstrap, config, or request lifecycle behavior.
- Adding/modifying middleware, routes, or error handling.
- Using logging, crypto, guard, ID, upload, or filesystem utilities.
- Running or writing migrations, seeders, or DB connection management.
Engine Files
engine/Atomic/Core/ - App, CacheManager, Config/, ConnectionManager, Crypto, ErrorHandler, ExceptionHandlerRegistrar, Filesystem, Guard, ID, Log, LogChannel, Methods, Middleware/, Migrations, Prefly, Redactor, Request, Response, RouteLoader, Routes/, Seeder, Traits/Singleton, Upload, Database/Migrations/
Reference Docs
docs/atomic_core.md, docs/atomic_methods.md, docs/config.md, docs/request.md, docs/prefly.md, docs/errorhandler.md, docs/log.md, docs/middleware.md, docs/security.md, docs/database.md, docs/migrations.md
Config Loading
use Engine\Atomic\Core\Config\ConfigLoader;
use Engine\Atomic\Core\Config\PhpConfigLoader;
$f3 = \Base::instance();
ConfigLoader::init($f3, realpath(__DIR__ . '/../.env'));
(new PhpConfigLoader($f3))->load();
Config values land in the F3 hive and are read by all subsystems via $f3->get('DB_CONFIG.host'), $f3->get('REDIS'), etc.
App Bootstrap
use Engine\Atomic\Core\App;
$app = App::instance($f3);
$app->prefly()
->register_logger()
->register_exception_handler()
->register_locales()
->register_middleware()
->register_routes()
->register_core_plugins()
->register_plugins()
->init_session()
->open_connections()
->register_user_provider();
$f3->run();
Routing
$app->route('GET /dashboard', 'App\\Http\\Controllers\\Dashboard->index', ['auth']);
$app->route('GET /posts/@id', 'App\\Http\\Controllers\\Posts->show', 60);
$app->route('GET /admin', 'App\\Http\\Admin->index', ['auth', 'role:admin']);
Middleware
use Engine\Atomic\Core\Middleware\MiddlewareInterface;
final class RequireAuth implements MiddlewareInterface
{
public function handle(\Base $atomic): bool
{
if (!is_authenticated()) {
$atomic->reroute('/login');
return false;
}
return true;
}
}
return [
'auth' => App\Http\Middleware\RequireAuth::class,
'role' => App\Http\Middleware\RequireRole::class,
];
Logging
use Engine\Atomic\Core\Log;
use Engine\Atomic\Enums\LogChannel;
use Engine\Atomic\Enums\LogLevel;
Log::error('Payment failed for order #' . $id);
Log::warning('Rate limit exceeded');
Log::info('User logged in');
Log::debug('Query params: ' . json_encode($params));
Log::channel('auth')->warning('Failed login attempt');
Log::channel('auth')->info('User authenticated');
Log::channel(LogChannel::QUEUE_WORKER)->error('Job failed');
Log::dump('cart_data', ['items' => $items]);
Log::dump_hive();
Log::add_channel('payments', storage_path('logs/payments.log'), LogLevel::INFO);
Log::channel('payments')->info('Invoice created');
$channels = Log::get_channel_names();
All PSR-3 methods take only string $msg. Embed context in the string itself.
Built-in channels: atomic (default), error, auth, queue_worker, queue_monitor.
Guard (Authorization)
use Engine\Atomic\Core\Guard;
use Engine\Atomic\Enums\Role;
if (!Guard::is_authenticated()) {
\Base::instance()->reroute('/login');
}
if (!Guard::has_role(Role::ADMIN)) {
\Base::instance()->error(403, 'Forbidden');
}
Guard::is_authenticated();
Guard::is_guest();
Guard::has_role(Role::ADMIN);
Guard::has_role('admin');
Guard::has_any_role([Role::ADMIN, Role::SELLER]);
Guard::lacks_role(Role::SELLER);
Guard::lacks_any_role([Role::SELLER, Role::BUYER]);
Note: has_role() requires the user to implement HasRolesInterface. When no user is authenticated, all has_* / lacks_* return appropriate defaults.
Crypto (sodium_crypto_secretbox)
use Engine\Atomic\Core\Crypto;
$crypto = new Crypto();
$cipher = $crypto->encrypt('sensitive payload');
$plain = $crypto->decrypt((string)$cipher);
$key = Crypto::generate_key();
Returns false on empty input, invalid base64, or tampered ciphertext.
DB Connections
use Engine\Atomic\Core\ConnectionManager;
$cm = ConnectionManager::instance();
$db = $cm->get_db();
$redis = $cm->get_redis(false);
$memcached = $cm->get_memcached(false);
$cm->open_all();
$cm->close();
Migrations
php atomic migrations/init
php atomic migrations/create create_users_table
php atomic migrations/migrate
php atomic migrations/rollback
php atomic migrations/rollback 3
php atomic migrations/status
php atomic migrations/publish <plugin-name>
return [
'up' => function () {
$db = ConnectionManager::instance()->get_db();
$schema = new \DB\Cortex\Schema\Schema($db);
},
'down' => function () {
},
];
Request Helpers (Methods + helpers.php)
is_home();
is_page('/account');
is_page(['/account', '/account/*']);
is_section('blog');
is_ssl(); is_ajax(); is_mobile(); is_404(); is_telegram();
is_botblocker(); is_gs();
current_path();
url_segments();
get_segment(0);
get_year();
get_copyright_years(2020);
get_date('d.m.Y');
get_copy();
get_encoding();
get_error_trace();
format_error_trace($code, $text, $trace);
Methods Class (low-level request context)
Engine\Atomic\Core\Methods (aliased AM) provides additional request context not exposed as global helpers:
use Engine\Atomic\Core\Methods;
$am = Methods::instance();
$am->get_public_url();
$am->get_current_url();
$am->get_current_route();
$am->get_current_method();
$am->get_user_ip();
$am->get_user_agent();
$am->get_user_language();
$am->get_is_debug();
$am->get_user_device(true);
$am->list_routes();
$am->get_public_dir();
Upload
Engine\Atomic\Core\Upload -- file upload and access token management. Paths follow public/uploads/{user_id}/{user_uuid}/{project_uuid}/ structure.
use Engine\Atomic\Core\Upload;
$up = Upload::instance();
$result = $up->upload_user_file($userId, $userUuid, $projectId, $projectUuid, $_FILES['file']);
$info = $up->get_file_info($userId, $userUuid, $projectId, $projectUuid, 'photo.jpg');
$info = $up->get_file_info($userId, $userUuid, $projectId, $projectUuid, 'photo.jpg', 'optimized');
$up->delete_file($userId, $userUuid, $projectId, $projectUuid, 'photo.jpg');
$up->delete_project_files($userId, $userUuid, $projectId, $projectUuid);
$up->delete_user_files($userId, $userUuid);
$result = $up->download_user_image($userId, $userUuid, $projectId, $projectUuid, $url, 'image.jpg');
$result = $up->download_system_file('filename.jpg');
$up->get_upload_path();
$up->get_user_upload_path();
$up->get_system_upload_path();
$token = $up->generate_access_token($id, $uuid, $length);
$valid = $up->verify_access_token($token, $uuid);
$up->store_access_token($uuid, $filename, $token);
$up->get_stored_access_token($uuid, $filename);
$up->create_and_store_access_token($id, $uuid, $filename);
$up->get_or_create_user_token($userId, $userUuid);
$up->get_or_create_project_token($projectId, $projectUuid);
HTTP Client Helpers
$res = remote_get('https://api.example.com/users', [
'query' => ['page' => 1],
'headers' => ['Authorization' => 'Bearer '.$token],
'timeout' => 5,
'retries' => 2,
]);
if ($res['ok']) {
$data = json_decode($res['body'], true);
}
$res = remote_post('https://api.example.com/posts', json_encode($payload), [
'headers' => ['Content-Type' => 'application/json'],
'raw' => true,
]);
$res = remote_put('https://api.example.com/posts/1', json_encode($payload));
$res = remote_head('https://example.com/file.pdf');
Return shape: ['ok'=>bool, 'status'=>int, 'headers'=>array, 'body'=>string, 'error'=>string, 'cached'=>bool, 'url'=>string]
Response Helpers
send_json(['user' => $user]);
send_json(['user' => $user], 201);
send_json_error('Unauthorized', 401);
send_json_error('Validation failed', 422, ['field' => 'email']);
send_json_success(['id' => $id]);
send_json_success([], 201);
send_json($data, 200, false);
json_response($data, 200);
$str = atomic_json_encode($data);
use Engine\Atomic\Core\Response;
Response::instance()->send_json($data, 200);
ID
Engine\Atomic\Core\ID -- UUID and token utilities.
use Engine\Atomic\Core\ID;
$uuid = ID::uuid_v4();
$ok = ID::is_valid_uuid_v4($uuid);
$bin = ID::uuid_v4_to_bytes($uuid);
$b64 = ID::uuid_v4_to_bytes_json($uuid);
$uuid = ID::bytes_to_uuid_v4($bin);
$uuid = ID::bytes_to_uuid_v4_json($b64);
$hex = ID::generate_unique_id(16);
$b64 = ID::generate_unique_id_json(16);
$token = ID::generate_access_token($userId, $uuid, 12);
$valid = ID::verify_access_token($token, $uuid);
$id = ID::extract_id_from_token($token);
$enc = ID::base64_url_encode($data);
$dec = ID::base64_url_decode($enc);
Filesystem
Engine\Atomic\Core\Filesystem -- file and directory operations.
use Engine\Atomic\Core\Filesystem;
$fs = Filesystem::instance();
$fs->copy($src, $dst);
$fs->move($src, $dst);
$fs->delete('/path/to/file.txt');
$fs->read('/path/to/file.txt');
$fs->write('/path/to/file.txt', $data, append: false);
$fs->exists('/path');
$fs->is_file('/path/to/file');
$fs->rename('/old', '/new');
$fs->filesize('/file');
$fs->created_time('/file');
$fs->modified_time('/file');
$fs->count_lines('/file');
$lines = $fs->read_lines_from_end('/path/app.log', $offset, $limit);
$fs->make_dir('/path', 0755, recursive: true);
$fs->remove_dir('/path', recursive: true);
$fs->copy_dir('/src', '/dst');
$files = $fs->list_files('/dir/', levels: 100, exclusions: ['.git']);
$tmp = $fs->get_temp_dir();
$fs->unzip_file('/archive.zip', '/extract/to');
$fs->zip_files(['/a.txt', '/b.txt'], '/archive.zip');
Seeder
Engine\Atomic\Core\Seeder -- run seed files.
use Engine\Atomic\Core\Seeder;
Seeder::run('/path/to/seeds/seed_posts.php');
Seed file shape:
return [
'run' => function () {
$post = new \App\Models\Post();
$post->title = 'Sample post';
$post->save();
},
];
Prefly Checks
App::prefly() validates PHP ≥ 8.1, required extensions (json, session, mbstring, fileinfo, pdo, pdo_mysql, curl), and that storage/ + storage/logs/ are writable. On failure: CLI exits 1, web returns HTTP 500/503.
Error Handling
ExceptionHandlerRegistrar::register($atomic) sets ONERROR in the F3 hive.
Behavior: reads ERROR.* hive keys → formats trace → dumps hive (debug only) → responds:
- API/AJAX (
/api/*, AJAX truthy, or Accept: application/json): JSON {"error": {...}}
- Web: renders
ErrorPages theme layout (e.g. layout/404.atom.php)
- CLI: writes structured error to stderr
Trigger manually: \Base::instance()->error(404, 'Not found')
Error Pages
Engine\Atomic\App\Error -- controller that renders themed error pages. Registered in routes/web.error.php.
Handled HTTP status codes: 400, 401, 403, 404, 405, 408, 429, 500, 502, 503
Each method sets PAGE.title, PAGE.color, and renders the corresponding template from the ErrorPages theme:
resources/views/layout/400.atom.php
resources/views/layout/404.atom.php
... (same pattern for each code)
resources/views/layout/500.atom.php // also sets ERROR.formatted_trace
To trigger programmatically:
\Base::instance()->error(404, 'Post not found');
\Base::instance()->error(403, 'Forbidden');
Redactor
Engine\Atomic\Core\Redactor -- sanitizes sensitive data before logging or display. Used automatically by the telemetry panel.
use Engine\Atomic\Core\Redactor;
Redactor::set_home_path('/var/www/myapp');
Redactor::init_from_hive(\Base::instance());
$safe = Redactor::redact($anyValue);
$safe = Redactor::redact_string($sensitiveString);
Redactor::MASKED constant: '[MASKED]'
Guardrails
- Core changes are wide-impact. Keep them minimal and well-tested.
- Never bypass middleware or route loader.
- Always verify that
APP_ENCRYPTION_KEY is properly set before using Crypto.
- Keep sensitive values out of logs - the Redactor sanitizes diagnostic output but not application log calls.