ricardogj08/semillero

feat: Inicialización del proyecto

Commit fb767cc · Ricardo García Jiménez · 2026-09-01T01:11:11-06:00

Changeset
fb767ccb8adf8610eb9870f86a69609c4bebeede

View source at this commit

feat: Inicialización del proyecto

Signed-off-by: Ricardo García Jiménez <[email protected]>

Comments

No comments yet.

Log in to comment

Diff

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1786c28
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,129 @@
+#-------------------------
+# Operating Specific Junk Files
+#-------------------------
+
+# OS X
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# OS X Thumbnails
+._*
+
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+# Linux
+*~
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+#-------------------------
+# Environment Files
+#-------------------------
+# These should never be under version control,
+# as it poses a security risk.
+.env
+.vagrant
+Vagrantfile
+
+#-------------------------
+# Temporary Files
+#-------------------------
+/writable/cache/*
+!/writable/cache/index.html
+
+/writable/logs/*
+!/writable/logs/index.html
+
+/writable/session/*
+!/writable/session/index.html
+
+/writable/uploads/*
+!/writable/uploads/index.html
+
+/writable/debugbar/*
+!/writable/debugbar/index.html
+
+php_errors.log
+
+#-------------------------
+# User Guide Temp Files
+#-------------------------
+/user_guide_src/build/*
+/user_guide_src/cilexer/build/*
+/user_guide_src/cilexer/dist/*
+/user_guide_src/cilexer/pycilexer.egg-info/*
+
+#-------------------------
+# Test Files
+#-------------------------
+/tests/coverage*
+
+# Don't save phpunit under version control.
+/phpunit
+
+#-------------------------
+# Composer
+#-------------------------
+vendor/
+
+#-------------------------
+# IDE / Development Files
+#-------------------------
+
+# Modules Testing
+_modules/*
+
+# phpenv local config
+.php-version
+
+# Jetbrains editors (PHPStorm, etc)
+.idea/
+*.iml
+
+# NetBeans
+/nbproject/
+/build/
+/nbbuild/
+/dist/
+/nbdist/
+/nbactions.xml
+/nb-configuration.xml
+/.nb-gradle/
+
+# Sublime Text
+*.tmlanguage.cache
+*.tmPreferences.cache
+*.stTheme.cache
+*.sublime-workspace
+*.sublime-project
+.phpintel
+/api/
+
+# Visual Studio Code
+.vscode/
+
+/results/
+/phpunit.xml
+
+# CodeIgniter Coding Standard
+.php-cs-fixer.cache
diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
new file mode 100644
index 0000000..5d245e4
--- /dev/null
+++ b/.php-cs-fixer.dist.php
@@ -0,0 +1,6 @@
+<?php
+
+use CodeIgniter\CodingStandard\CodeIgniter4;
+use Nexus\CsConfig\Factory;
+
+return Factory::create(new CodeIgniter4())->forProjects();
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..24728f6
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2014-2019 British Columbia Institute of Technology
+Copyright (c) 2019-present CodeIgniter Foundation
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..45f98af
--- /dev/null
+++ b/README.md
@@ -0,0 +1,69 @@
+# CodeIgniter 4 Application Starter
+
+## What is CodeIgniter?
+
+CodeIgniter is a PHP full-stack web framework that is light, fast, flexible and secure.
+More information can be found at the [official site](https://codeigniter.com).
+
+This repository holds a composer-installable app starter.
+It has been built from the
+[development repository](https://github.com/codeigniter4/CodeIgniter4).
+
+More information about the plans for version 4 can be found in [CodeIgniter 4](https://forum.codeigniter.com/forumdisplay.php?fid=28) on the forums.
+
+You can read the [user guide](https://codeigniter.com/user_guide/)
+corresponding to the latest version of the framework.
+
+## Installation & updates
+
+`composer create-project codeigniter4/appstarter` then `composer update` whenever
+there is a new release of the framework.
+
+When updating, check the release notes to see if there are any changes you might need to apply
+to your `app` folder. The affected files can be copied or merged from
+`vendor/codeigniter4/framework/app`.
+
+## Setup
+
+Copy `env` to `.env` and tailor for your app, specifically the baseURL
+and any database settings.
+
+## Important Change with index.php
+
+`index.php` is no longer in the root of the project! It has been moved inside the *public* folder,
+for better security and separation of components.
+
+This means that you should configure your web server to "point" to your project's *public* folder, and
+not to the project root. A better practice would be to configure a virtual host to point there. A poor practice would be to point your web server to the project root and expect to enter *public/...*, as the rest of your logic and the
+framework are exposed.
+
+**Please** read the user guide for a better explanation of how CI4 works!
+
+## Repository Management
+
+We use GitHub issues, in our main repository, to track **BUGS** and to track approved **DEVELOPMENT** work packages.
+We use our [forum](http://forum.codeigniter.com) to provide SUPPORT and to discuss
+FEATURE REQUESTS.
+
+This repository is a "distribution" one, built by our release preparation script.
+Problems with it can be raised on our forum, or as issues in the main repository.
+
+## Server Requirements
+
+PHP version 8.2 or higher is required, with the following extensions installed:
+
+- [intl](http://php.net/manual/en/intl.requirements.php)
+- [mbstring](http://php.net/manual/en/mbstring.installation.php)
+
+> [!WARNING]
+> - The end of life date for PHP 7.4 was November 28, 2022.
+> - The end of life date for PHP 8.0 was November 26, 2023.
+> - The end of life date for PHP 8.1 was December 31, 2025.
+> - If you are still using below PHP 8.2, you should upgrade immediately.
+> - The end of life date for PHP 8.2 will be December 31, 2026.
+
+Additionally, make sure that the following extensions are enabled in your PHP:
+
+- json (enabled by default - don't turn it off)
+- [mysqlnd](http://php.net/manual/en/mysqlnd.install.php) if you plan to use MySQL
+- [libcurl](http://php.net/manual/en/curl.requirements.php) if you plan to use the HTTP\CURLRequest library
diff --git a/app/.htaccess b/app/.htaccess
new file mode 100644
index 0000000..3462048
--- /dev/null
+++ b/app/.htaccess
@@ -0,0 +1,6 @@
+<IfModule authz_core_module>
+	Require all denied
+</IfModule>
+<IfModule !authz_core_module>
+	Deny from all
+</IfModule>
diff --git a/app/Common.php b/app/Common.php
new file mode 100644
index 0000000..95f5544
--- /dev/null
+++ b/app/Common.php
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * The goal of this file is to allow developers a location
+ * where they can overwrite core procedural functions and
+ * replace them with their own. This file is loaded during
+ * the bootstrap process and is called during the framework's
+ * execution.
+ *
+ * This can be looked at as a `master helper` file that is
+ * loaded early on, and may also contain additional functions
+ * that you'd like to use throughout your entire application
+ *
+ * @see: https://codeigniter.com/user_guide/extending/common.html
+ */
diff --git a/app/Config/App.php b/app/Config/App.php
new file mode 100644
index 0000000..b761da7
--- /dev/null
+++ b/app/Config/App.php
@@ -0,0 +1,202 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class App extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Base Site URL
+     * --------------------------------------------------------------------------
+     *
+     * URL to your CodeIgniter root. Typically, this will be your base URL,
+     * WITH a trailing slash:
+     *
+     * E.g., http://example.com/
+     */
+    public string $baseURL = 'http://localhost:8080/';
+
+    /**
+     * Allowed Hostnames in the Site URL other than the hostname in the baseURL.
+     * If you want to accept multiple Hostnames, set this.
+     *
+     * E.g.,
+     * When your site URL ($baseURL) is 'http://example.com/', and your site
+     * also accepts 'http://media.example.com/' and 'http://accounts.example.com/':
+     *     ['media.example.com', 'accounts.example.com']
+     *
+     * @var list<string>
+     */
+    public array $allowedHostnames = [];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Index File
+     * --------------------------------------------------------------------------
+     *
+     * Typically, this will be your `index.php` file, unless you've renamed it to
+     * something else. If you have configured your web server to remove this file
+     * from your site URIs, set this variable to an empty string.
+     */
+    public string $indexPage = 'index.php';
+
+    /**
+     * --------------------------------------------------------------------------
+     * URI PROTOCOL
+     * --------------------------------------------------------------------------
+     *
+     * This item determines which server global should be used to retrieve the
+     * URI string. The default setting of 'REQUEST_URI' works for most servers.
+     * If your links do not seem to work, try one of the other delicious flavors:
+     *
+     *  'REQUEST_URI': Uses $_SERVER['REQUEST_URI']
+     * 'QUERY_STRING': Uses $_SERVER['QUERY_STRING']
+     *    'PATH_INFO': Uses $_SERVER['PATH_INFO']
+     *
+     * WARNING: If you set this to 'PATH_INFO', URIs will always be URL-decoded!
+     */
+    public string $uriProtocol = 'REQUEST_URI';
+
+    /*
+    |--------------------------------------------------------------------------
+    | Allowed URL Characters
+    |--------------------------------------------------------------------------
+    |
+    | This lets you specify which characters are permitted within your URLs.
+    | When someone tries to submit a URL with disallowed characters they will
+    | get a warning message.
+    |
+    | As a security measure you are STRONGLY encouraged to restrict URLs to
+    | as few characters as possible.
+    |
+    | By default, only these are allowed: `a-z 0-9~%.:_-`
+    |
+    | Set an empty string to allow all characters -- but only if you are insane.
+    |
+    | The configured value is actually a regular expression character group
+    | and it will be used as: '/\A[<permittedURIChars>]+\z/iu'
+    |
+    | DO NOT CHANGE THIS UNLESS YOU FULLY UNDERSTAND THE REPERCUSSIONS!!
+    |
+    */
+    public string $permittedURIChars = 'a-z 0-9~%.:_\-';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Default Locale
+     * --------------------------------------------------------------------------
+     *
+     * The Locale roughly represents the language and location that your visitor
+     * is viewing the site from. It affects the language strings and other
+     * strings (like currency markers, numbers, etc), that your program
+     * should run under for this request.
+     */
+    public string $defaultLocale = 'en';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Negotiate Locale
+     * --------------------------------------------------------------------------
+     *
+     * If true, the current Request object will automatically determine the
+     * language to use based on the value of the Accept-Language header.
+     *
+     * If false, no automatic detection will be performed.
+     */
+    public bool $negotiateLocale = false;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Supported Locales
+     * --------------------------------------------------------------------------
+     *
+     * If $negotiateLocale is true, this array lists the locales supported
+     * by the application in descending order of priority. If no match is
+     * found, the first locale will be used.
+     *
+     * IncomingRequest::setLocale() also uses this list.
+     *
+     * @var list<string>
+     */
+    public array $supportedLocales = ['en'];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Application Timezone
+     * --------------------------------------------------------------------------
+     *
+     * The default timezone that will be used in your application to display
+     * dates with the date helper, and can be retrieved through app_timezone()
+     *
+     * @see https://www.php.net/manual/en/timezones.php for list of timezones
+     *      supported by PHP.
+     */
+    public string $appTimezone = 'UTC';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Default Character Set
+     * --------------------------------------------------------------------------
+     *
+     * This determines which character set is used by default in various methods
+     * that require a character set to be provided.
+     *
+     * @see http://php.net/htmlspecialchars for a list of supported charsets.
+     */
+    public string $charset = 'UTF-8';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Force Global Secure Requests
+     * --------------------------------------------------------------------------
+     *
+     * If true, this will force every request made to this application to be
+     * made via a secure connection (HTTPS). If the incoming request is not
+     * secure, the user will be redirected to a secure version of the page
+     * and the HTTP Strict Transport Security (HSTS) header will be set.
+     */
+    public bool $forceGlobalSecureRequests = false;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Reverse Proxy IPs
+     * --------------------------------------------------------------------------
+     *
+     * If your server is behind a reverse proxy, you must whitelist the proxy
+     * IP addresses from which CodeIgniter should trust headers such as
+     * X-Forwarded-For or Client-IP in order to properly identify
+     * the visitor's IP address.
+     *
+     * You need to set a proxy IP address or IP address with subnets and
+     * the HTTP header for the client IP address.
+     *
+     * Here are some examples:
+     *     [
+     *         '10.0.1.200'     => 'X-Forwarded-For',
+     *         '192.168.5.0/24' => 'X-Real-IP',
+     *     ]
+     *
+     * @var array<string, string>
+     */
+    public array $proxyIPs = [];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Content Security Policy
+     * --------------------------------------------------------------------------
+     *
+     * Enables the Response's Content Secure Policy to restrict the sources that
+     * can be used for images, scripts, CSS files, audio, video, etc. If enabled,
+     * the Response object will populate default values for the policy from the
+     * `ContentSecurityPolicy.php` file. Controllers can always add to those
+     * restrictions at run time.
+     *
+     * For a better understanding of CSP, see these documents:
+     *
+     * @see http://www.html5rocks.com/en/tutorials/security/content-security-policy/
+     * @see http://www.w3.org/TR/CSP/
+     */
+    public bool $CSPEnabled = false;
+}
diff --git a/app/Config/Autoload.php b/app/Config/Autoload.php
new file mode 100644
index 0000000..9a92824
--- /dev/null
+++ b/app/Config/Autoload.php
@@ -0,0 +1,92 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\AutoloadConfig;
+
+/**
+ * -------------------------------------------------------------------
+ * AUTOLOADER CONFIGURATION
+ * -------------------------------------------------------------------
+ *
+ * This file defines the namespaces and class maps so the Autoloader
+ * can find the files as needed.
+ *
+ * NOTE: If you use an identical key in $psr4 or $classmap, then
+ *       the values in this file will overwrite the framework's values.
+ *
+ * NOTE: This class is required prior to Autoloader instantiation,
+ *       and does not extend BaseConfig.
+ */
+class Autoload extends AutoloadConfig
+{
+    /**
+     * -------------------------------------------------------------------
+     * Namespaces
+     * -------------------------------------------------------------------
+     * This maps the locations of any namespaces in your application to
+     * their location on the file system. These are used by the autoloader
+     * to locate files the first time they have been instantiated.
+     *
+     * The 'Config' (APPPATH . 'Config') and 'CodeIgniter' (SYSTEMPATH) are
+     * already mapped for you.
+     *
+     * You may change the name of the 'App' namespace if you wish,
+     * but this should be done prior to creating any namespaced classes,
+     * else you will need to modify all of those classes for this to work.
+     *
+     * @var array<string, list<string>|string>
+     */
+    public $psr4 = [
+        APP_NAMESPACE => APPPATH,
+    ];
+
+    /**
+     * -------------------------------------------------------------------
+     * Class Map
+     * -------------------------------------------------------------------
+     * The class map provides a map of class names and their exact
+     * location on the drive. Classes loaded in this manner will have
+     * slightly faster performance because they will not have to be
+     * searched for within one or more directories as they would if they
+     * were being autoloaded through a namespace.
+     *
+     * Prototype:
+     *   $classmap = [
+     *       'MyClass'   => '/path/to/class/file.php'
+     *   ];
+     *
+     * @var array<string, string>
+     */
+    public $classmap = [];
+
+    /**
+     * -------------------------------------------------------------------
+     * Files
+     * -------------------------------------------------------------------
+     * The files array provides a list of paths to __non-class__ files
+     * that will be autoloaded. This can be useful for bootstrap operations
+     * or for loading functions.
+     *
+     * Prototype:
+     *   $files = [
+     *       '/path/to/my/file.php',
+     *   ];
+     *
+     * @var list<string>
+     */
+    public $files = [];
+
+    /**
+     * -------------------------------------------------------------------
+     * Helpers
+     * -------------------------------------------------------------------
+     * Prototype:
+     *   $helpers = [
+     *       'form',
+     *   ];
+     *
+     * @var list<string>
+     */
+    public $helpers = [];
+}
diff --git a/app/Config/Boot/development.php b/app/Config/Boot/development.php
new file mode 100644
index 0000000..a868447
--- /dev/null
+++ b/app/Config/Boot/development.php
@@ -0,0 +1,34 @@
+<?php
+
+/*
+ |--------------------------------------------------------------------------
+ | ERROR DISPLAY
+ |--------------------------------------------------------------------------
+ | In development, we want to show as many errors as possible to help
+ | make sure they don't make it to production. And save us hours of
+ | painful debugging.
+ |
+ | If you set 'display_errors' to '1', CI4's detailed error report will show.
+ */
+error_reporting(E_ALL);
+ini_set('display_errors', '1');
+
+/*
+ |--------------------------------------------------------------------------
+ | DEBUG BACKTRACES
+ |--------------------------------------------------------------------------
+ | If true, this constant will tell the error screens to display debug
+ | backtraces along with the other error information. If you would
+ | prefer to not see this, set this value to false.
+ */
+defined('SHOW_DEBUG_BACKTRACE') || define('SHOW_DEBUG_BACKTRACE', true);
+
+/*
+ |--------------------------------------------------------------------------
+ | DEBUG MODE
+ |--------------------------------------------------------------------------
+ | Debug mode is an experimental flag that can allow changes throughout
+ | the system. This will control whether Kint is loaded, and a few other
+ | items. It can always be used within your own application too.
+ */
+defined('CI_DEBUG') || define('CI_DEBUG', true);
diff --git a/app/Config/Boot/production.php b/app/Config/Boot/production.php
new file mode 100644
index 0000000..1822cf5
--- /dev/null
+++ b/app/Config/Boot/production.php
@@ -0,0 +1,25 @@
+<?php
+
+/*
+ |--------------------------------------------------------------------------
+ | ERROR DISPLAY
+ |--------------------------------------------------------------------------
+ | Don't show ANY in production environments. Instead, let the system catch
+ | it and display a generic error message.
+ |
+ | If you set 'display_errors' to '1', CI4's detailed error report will show.
+ */
+error_reporting(E_ALL & ~E_DEPRECATED);
+// If you want to suppress more types of errors.
+// error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT & ~E_USER_NOTICE & ~E_USER_DEPRECATED);
+ini_set('display_errors', '0');
+
+/*
+ |--------------------------------------------------------------------------
+ | DEBUG MODE
+ |--------------------------------------------------------------------------
+ | Debug mode is an experimental flag that can allow changes throughout
+ | the system. It's not widely used currently, and may not survive
+ | release of the framework.
+ */
+defined('CI_DEBUG') || define('CI_DEBUG', false);
diff --git a/app/Config/Boot/testing.php b/app/Config/Boot/testing.php
new file mode 100644
index 0000000..40b6ca8
--- /dev/null
+++ b/app/Config/Boot/testing.php
@@ -0,0 +1,38 @@
+<?php
+
+/*
+ * The environment testing is reserved for PHPUnit testing. It has special
+ * conditions built into the framework at various places to assist with that.
+ * You can’t use it for your development.
+ */
+
+/*
+ |--------------------------------------------------------------------------
+ | ERROR DISPLAY
+ |--------------------------------------------------------------------------
+ | In development, we want to show as many errors as possible to help
+ | make sure they don't make it to production. And save us hours of
+ | painful debugging.
+ */
+error_reporting(E_ALL);
+ini_set('display_errors', '1');
+
+/*
+ |--------------------------------------------------------------------------
+ | DEBUG BACKTRACES
+ |--------------------------------------------------------------------------
+ | If true, this constant will tell the error screens to display debug
+ | backtraces along with the other error information. If you would
+ | prefer to not see this, set this value to false.
+ */
+defined('SHOW_DEBUG_BACKTRACE') || define('SHOW_DEBUG_BACKTRACE', true);
+
+/*
+ |--------------------------------------------------------------------------
+ | DEBUG MODE
+ |--------------------------------------------------------------------------
+ | Debug mode is an experimental flag that can allow changes throughout
+ | the system. It's not widely used currently, and may not survive
+ | release of the framework.
+ */
+defined('CI_DEBUG') || define('CI_DEBUG', true);
diff --git a/app/Config/CURLRequest.php b/app/Config/CURLRequest.php
new file mode 100644
index 0000000..bc5947f
--- /dev/null
+++ b/app/Config/CURLRequest.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class CURLRequest extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * CURLRequest Share Connection Options
+     * --------------------------------------------------------------------------
+     *
+     * Share connection options between requests.
+     *
+     * @var list<int>
+     *
+     * @see https://www.php.net/manual/en/curl.constants.php#constant.curl-lock-data-connect
+     */
+    public array $shareConnectionOptions = [
+        CURL_LOCK_DATA_CONNECT,
+        CURL_LOCK_DATA_DNS,
+    ];
+
+    /**
+     * --------------------------------------------------------------------------
+     * CURLRequest Share Options
+     * --------------------------------------------------------------------------
+     *
+     * Whether share options between requests or not.
+     *
+     * If true, all the options won't be reset between requests.
+     * It may cause an error request with unnecessary headers.
+     */
+    public bool $shareOptions = false;
+}
diff --git a/app/Config/Cache.php b/app/Config/Cache.php
new file mode 100644
index 0000000..38ac541
--- /dev/null
+++ b/app/Config/Cache.php
@@ -0,0 +1,198 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Cache\CacheInterface;
+use CodeIgniter\Cache\Handlers\ApcuHandler;
+use CodeIgniter\Cache\Handlers\DummyHandler;
+use CodeIgniter\Cache\Handlers\FileHandler;
+use CodeIgniter\Cache\Handlers\MemcachedHandler;
+use CodeIgniter\Cache\Handlers\PredisHandler;
+use CodeIgniter\Cache\Handlers\RedisHandler;
+use CodeIgniter\Cache\Handlers\WincacheHandler;
+use CodeIgniter\Config\BaseConfig;
+
+class Cache extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Primary Handler
+     * --------------------------------------------------------------------------
+     *
+     * The name of the preferred handler that should be used. If for some reason
+     * it is not available, the $backupHandler will be used in its place.
+     */
+    public string $handler = 'file';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Backup Handler
+     * --------------------------------------------------------------------------
+     *
+     * The name of the handler that will be used in case the first one is
+     * unreachable. Often, 'file' is used here since the filesystem is
+     * always available, though that's not always practical for the app.
+     */
+    public string $backupHandler = 'dummy';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Key Prefix
+     * --------------------------------------------------------------------------
+     *
+     * This string is added to all cache item names to help avoid collisions
+     * if you run multiple applications with the same cache engine.
+     */
+    public string $prefix = '';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Default TTL
+     * --------------------------------------------------------------------------
+     *
+     * The default number of seconds to save items when none is specified.
+     *
+     * WARNING: This is not used by framework handlers where 60 seconds is
+     * hard-coded, but may be useful to projects and modules. This will replace
+     * the hard-coded value in a future release.
+     */
+    public int $ttl = 60;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Reserved Characters
+     * --------------------------------------------------------------------------
+     *
+     * A string of reserved characters that will not be allowed in keys or tags.
+     * Strings that violate this restriction will cause handlers to throw.
+     * Default: {}()/\@:
+     *
+     * NOTE: The default set is required for PSR-6 compliance.
+     */
+    public string $reservedCharacters = '{}()/\@:';
+
+    /**
+     * --------------------------------------------------------------------------
+     * File settings
+     * --------------------------------------------------------------------------
+     *
+     * Your file storage preferences can be specified below, if you are using
+     * the File driver.
+     *
+     * @var array{storePath?: string, mode?: int}
+     */
+    public array $file = [
+        'storePath' => WRITEPATH . 'cache/',
+        'mode'      => 0640,
+    ];
+
+    /**
+     * -------------------------------------------------------------------------
+     * Memcached settings
+     * -------------------------------------------------------------------------
+     *
+     * Your Memcached servers can be specified below, if you are using
+     * the Memcached drivers.
+     *
+     * @see https://codeigniter.com/user_guide/libraries/caching.html#memcached
+     *
+     * @var array{host?: string, port?: int, weight?: int, raw?: bool}
+     */
+    public array $memcached = [
+        'host'   => '127.0.0.1',
+        'port'   => 11211,
+        'weight' => 1,
+        'raw'    => false,
+    ];
+
+    /**
+     * -------------------------------------------------------------------------
+     * Redis settings
+     * -------------------------------------------------------------------------
+     *
+     * Your Redis server can be specified below, if you are using
+     * the Redis or Predis drivers.
+     *
+     * @var array{
+     *     host?: string,
+     *     password?: string|null,
+     *     port?: int,
+     *     timeout?: int,
+     *     async?: bool,
+     *     persistent?: bool,
+     *     database?: int
+     * }
+     */
+    public array $redis = [
+        'host'       => '127.0.0.1',
+        'password'   => null,
+        'port'       => 6379,
+        'timeout'    => 0,
+        'async'      => false, // specific to Predis and ignored by the native Redis extension
+        'persistent' => false,
+        'database'   => 0,
+    ];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Available Cache Handlers
+     * --------------------------------------------------------------------------
+     *
+     * This is an array of cache engine alias' and class names. Only engines
+     * that are listed here are allowed to be used.
+     *
+     * @var array<string, class-string<CacheInterface>>
+     */
+    public array $validHandlers = [
+        'apcu'      => ApcuHandler::class,
+        'dummy'     => DummyHandler::class,
+        'file'      => FileHandler::class,
+        'memcached' => MemcachedHandler::class,
+        'predis'    => PredisHandler::class,
+        'redis'     => RedisHandler::class,
+        'wincache'  => WincacheHandler::class,
+    ];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Web Page Caching: Cache Include Query String
+     * --------------------------------------------------------------------------
+     *
+     * Whether to take the URL query string into consideration when generating
+     * output cache files. Valid options are:
+     *
+     *    false = Disabled
+     *    true  = Enabled, take all query parameters into account.
+     *            Please be aware that this may result in numerous cache
+     *            files generated for the same page over and over again.
+     *    ['q'] = Enabled, but only take into account the specified list
+     *            of query parameters.
+     *
+     * @var bool|list<string>
+     */
+    public $cacheQueryString = false;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Web Page Caching: Cache Status Codes
+     * --------------------------------------------------------------------------
+     *
+     * HTTP status codes that are allowed to be cached. Only responses with
+     * these status codes will be cached by the PageCache filter.
+     *
+     * Default: [] - Cache all status codes (backward compatible)
+     *
+     * Recommended: [200] - Only cache successful responses
+     *
+     * You can also use status codes like:
+     *   [200, 404, 410] - Cache successful responses and specific error codes
+     *   [200, 201, 202, 203, 204] - All 2xx successful responses
+     *
+     * WARNING: Using [] may cache temporary error pages (404, 500, etc).
+     * Consider restricting to [200] for production applications to avoid
+     * caching errors that should be temporary.
+     *
+     * @var list<int>
+     */
+    public array $cacheStatusCodes = [];
+}
diff --git a/app/Config/Constants.php b/app/Config/Constants.php
new file mode 100644
index 0000000..fb56bb1
--- /dev/null
+++ b/app/Config/Constants.php
@@ -0,0 +1,79 @@
+<?php
+
+/*
+ | --------------------------------------------------------------------
+ | App Namespace
+ | --------------------------------------------------------------------
+ |
+ | This defines the default Namespace that is used throughout
+ | CodeIgniter to refer to the Application directory. Change
+ | this constant to change the namespace that all application
+ | classes should use.
+ |
+ | NOTE: changing this will require manually modifying the
+ | existing namespaces of App\* namespaced-classes.
+ */
+defined('APP_NAMESPACE') || define('APP_NAMESPACE', 'App');
+
+/*
+ | --------------------------------------------------------------------------
+ | Composer Path
+ | --------------------------------------------------------------------------
+ |
+ | The path that Composer's autoload file is expected to live. By default,
+ | the vendor folder is in the Root directory, but you can customize that here.
+ */
+defined('COMPOSER_PATH') || define('COMPOSER_PATH', ROOTPATH . 'vendor/autoload.php');
+
+/*
+ |--------------------------------------------------------------------------
+ | Timing Constants
+ |--------------------------------------------------------------------------
+ |
+ | Provide simple ways to work with the myriad of PHP functions that
+ | require information to be in seconds.
+ */
+defined('SECOND') || define('SECOND', 1);
+defined('MINUTE') || define('MINUTE', 60);
+defined('HOUR')   || define('HOUR', 3600);
+defined('DAY')    || define('DAY', 86400);
+defined('WEEK')   || define('WEEK', 604800);
+defined('MONTH')  || define('MONTH', 2_592_000);
+defined('YEAR')   || define('YEAR', 31_536_000);
+defined('DECADE') || define('DECADE', 315_360_000);
+
+/*
+ | --------------------------------------------------------------------------
+ | Exit Status Codes
+ | --------------------------------------------------------------------------
+ |
+ | Used to indicate the conditions under which the script is exit()ing.
+ | While there is no universal standard for error codes, there are some
+ | broad conventions.  Three such conventions are mentioned below, for
+ | those who wish to make use of them.  The CodeIgniter defaults were
+ | chosen for the least overlap with these conventions, while still
+ | leaving room for others to be defined in future versions and user
+ | applications.
+ |
+ | The three main conventions used for determining exit status codes
+ | are as follows:
+ |
+ |    Standard C/C++ Library (stdlibc):
+ |       http://www.gnu.org/software/libc/manual/html_node/Exit-Status.html
+ |       (This link also contains other GNU-specific conventions)
+ |    BSD sysexits.h:
+ |       http://www.gsp.com/cgi-bin/man.cgi?section=3&topic=sysexits
+ |    Bash scripting:
+ |       http://tldp.org/LDP/abs/html/exitcodes.html
+ |
+ */
+defined('EXIT_SUCCESS')        || define('EXIT_SUCCESS', 0);        // no errors
+defined('EXIT_ERROR')          || define('EXIT_ERROR', 1);          // generic error
+defined('EXIT_CONFIG')         || define('EXIT_CONFIG', 3);         // configuration error
+defined('EXIT_UNKNOWN_FILE')   || define('EXIT_UNKNOWN_FILE', 4);   // file not found
+defined('EXIT_UNKNOWN_CLASS')  || define('EXIT_UNKNOWN_CLASS', 5);  // unknown class
+defined('EXIT_UNKNOWN_METHOD') || define('EXIT_UNKNOWN_METHOD', 6); // unknown class member
+defined('EXIT_USER_INPUT')     || define('EXIT_USER_INPUT', 7);     // invalid user input
+defined('EXIT_DATABASE')       || define('EXIT_DATABASE', 8);       // database error
+defined('EXIT__AUTO_MIN')      || define('EXIT__AUTO_MIN', 9);      // lowest automatically-assigned error code
+defined('EXIT__AUTO_MAX')      || define('EXIT__AUTO_MAX', 125);    // highest automatically-assigned error code
diff --git a/app/Config/ContentSecurityPolicy.php b/app/Config/ContentSecurityPolicy.php
new file mode 100644
index 0000000..f64a9af
--- /dev/null
+++ b/app/Config/ContentSecurityPolicy.php
@@ -0,0 +1,216 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+/**
+ * Stores the default settings for the ContentSecurityPolicy, if you
+ * choose to use it. The values here will be read in and set as defaults
+ * for the site. If needed, they can be overridden on a page-by-page basis.
+ *
+ * Suggested reference for explanations:
+ *
+ * @see https://www.html5rocks.com/en/tutorials/security/content-security-policy/
+ */
+class ContentSecurityPolicy extends BaseConfig
+{
+    // -------------------------------------------------------------------------
+    // Broadbrush CSP management
+    // -------------------------------------------------------------------------
+
+    /**
+     * Default CSP report context
+     */
+    public bool $reportOnly = false;
+
+    /**
+     * Specifies a URL where a browser will send reports
+     * when a content security policy is violated.
+     */
+    public ?string $reportURI = null;
+
+    /**
+     * Specifies a reporting endpoint to which violation reports ought to be sent.
+     */
+    public ?string $reportTo = null;
+
+    /**
+     * Instructs user agents to rewrite URL schemes, changing
+     * HTTP to HTTPS. This directive is for websites with
+     * large numbers of old URLs that need to be rewritten.
+     */
+    public bool $upgradeInsecureRequests = false;
+
+    // -------------------------------------------------------------------------
+    // CSP DIRECTIVES SETTINGS
+    // NOTE: once you set a policy to 'none', it cannot be further restricted
+    // -------------------------------------------------------------------------
+
+    /**
+     * Will default to `'self'` if not overridden
+     *
+     * @var list<string>|string|null
+     */
+    public $defaultSrc;
+
+    /**
+     * Lists allowed scripts' URLs.
+     *
+     * @var list<string>|string
+     */
+    public $scriptSrc = 'self';
+
+    /**
+     * Specifies valid sources for JavaScript <script> elements.
+     *
+     * @var list<string>|string
+     */
+    public array|string $scriptSrcElem = 'self';
+
+    /**
+     * Specifies valid sources for JavaScript inline event
+     * handlers and JavaScript URLs.
+     *
+     * @var list<string>|string
+     */
+    public array|string $scriptSrcAttr = 'self';
+
+    /**
+     * Lists allowed stylesheets' URLs.
+     *
+     * @var list<string>|string
+     */
+    public $styleSrc = 'self';
+
+    /**
+     * Specifies valid sources for stylesheets <link> elements.
+     *
+     * @var list<string>|string
+     */
+    public array|string $styleSrcElem = 'self';
+
+    /**
+     * Specifies valid sources for stylesheets inline
+     * style attributes and `<style>` elements.
+     *
+     * @var list<string>|string
+     */
+    public array|string $styleSrcAttr = 'self';
+
+    /**
+     * Defines the origins from which images can be loaded.
+     *
+     * @var list<string>|string
+     */
+    public $imageSrc = 'self';
+
+    /**
+     * Restricts the URLs that can appear in a page's `<base>` element.
+     *
+     * Will default to self if not overridden
+     *
+     * @var list<string>|string|null
+     */
+    public $baseURI;
+
+    /**
+     * Lists the URLs for workers and embedded frame contents
+     *
+     * @var list<string>|string
+     */
+    public $childSrc = 'self';
+
+    /**
+     * Limits the origins that you can connect to (via XHR,
+     * WebSockets, and EventSource).
+     *
+     * @var list<string>|string
+     */
+    public $connectSrc = 'self';
+
+    /**
+     * Specifies the origins that can serve web fonts.
+     *
+     * @var list<string>|string
+     */
+    public $fontSrc;
+
+    /**
+     * Lists valid endpoints for submission from `<form>` tags.
+     *
+     * @var list<string>|string
+     */
+    public $formAction = 'self';
+
+    /**
+     * Specifies the sources that can embed the current page.
+     * This directive applies to `<frame>`, `<iframe>`, `<embed>`,
+     * and `<applet>` tags. This directive can't be used in
+     * `<meta>` tags and applies only to non-HTML resources.
+     *
+     * @var list<string>|string|null
+     */
+    public $frameAncestors;
+
+    /**
+     * The frame-src directive restricts the URLs which may
+     * be loaded into nested browsing contexts.
+     *
+     * @var list<string>|string|null
+     */
+    public $frameSrc;
+
+    /**
+     * Restricts the origins allowed to deliver video and audio.
+     *
+     * @var list<string>|string|null
+     */
+    public $mediaSrc;
+
+    /**
+     * Allows control over Flash and other plugins.
+     *
+     * @var list<string>|string
+     */
+    public $objectSrc = 'self';
+
+    /**
+     * @var list<string>|string|null
+     */
+    public $manifestSrc;
+
+    /**
+     * @var list<string>|string
+     */
+    public array|string $workerSrc = [];
+
+    /**
+     * Limits the kinds of plugins a page may invoke.
+     *
+     * @var list<string>|string|null
+     */
+    public $pluginTypes;
+
+    /**
+     * List of actions allowed.
+     *
+     * @var list<string>|string|null
+     */
+    public $sandbox;
+
+    /**
+     * Nonce placeholder for style tags.
+     */
+    public string $styleNonceTag = '{csp-style-nonce}';
+
+    /**
+     * Nonce placeholder for script tags.
+     */
+    public string $scriptNonceTag = '{csp-script-nonce}';
+
+    /**
+     * Replace nonce tag automatically?
+     */
+    public bool $autoNonce = true;
+}
diff --git a/app/Config/Cookie.php b/app/Config/Cookie.php
new file mode 100644
index 0000000..3bad184
--- /dev/null
+++ b/app/Config/Cookie.php
@@ -0,0 +1,107 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use DateTimeInterface;
+
+class Cookie extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Cookie Prefix
+     * --------------------------------------------------------------------------
+     *
+     * Set a cookie name prefix if you need to avoid collisions.
+     */
+    public string $prefix = '';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Cookie Expires Timestamp
+     * --------------------------------------------------------------------------
+     *
+     * Default expires timestamp for cookies. Setting this to `0` will mean the
+     * cookie will not have the `Expires` attribute and will behave as a session
+     * cookie.
+     *
+     * @var DateTimeInterface|int|string
+     */
+    public $expires = 0;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Cookie Path
+     * --------------------------------------------------------------------------
+     *
+     * Typically will be a forward slash.
+     */
+    public string $path = '/';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Cookie Domain
+     * --------------------------------------------------------------------------
+     *
+     * Set to `.your-domain.com` for site-wide cookies.
+     */
+    public string $domain = '';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Cookie Secure
+     * --------------------------------------------------------------------------
+     *
+     * Cookie will only be set if a secure HTTPS connection exists.
+     */
+    public bool $secure = false;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Cookie HTTPOnly
+     * --------------------------------------------------------------------------
+     *
+     * Cookie will only be accessible via HTTP(S) (no JavaScript).
+     */
+    public bool $httponly = true;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Cookie SameSite
+     * --------------------------------------------------------------------------
+     *
+     * Configure cookie SameSite setting. Allowed values are:
+     * - None
+     * - Lax
+     * - Strict
+     * - ''
+     *
+     * Alternatively, you can use the constant names:
+     * - `Cookie::SAMESITE_NONE`
+     * - `Cookie::SAMESITE_LAX`
+     * - `Cookie::SAMESITE_STRICT`
+     *
+     * Defaults to `Lax` for compatibility with modern browsers. Setting `''`
+     * (empty string) means default SameSite attribute set by browsers (`Lax`)
+     * will be set on cookies. If set to `None`, `$secure` must also be set.
+     *
+     * @var ''|'Lax'|'None'|'Strict'
+     */
+    public string $samesite = 'Lax';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Cookie Raw
+     * --------------------------------------------------------------------------
+     *
+     * This flag allows setting a "raw" cookie, i.e., its name and value are
+     * not URL encoded using `rawurlencode()`.
+     *
+     * If this is set to `true`, cookie names should be compliant of RFC 2616's
+     * list of allowed characters.
+     *
+     * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#attributes
+     * @see https://tools.ietf.org/html/rfc2616#section-2.2
+     */
+    public bool $raw = false;
+}
diff --git a/app/Config/Cors.php b/app/Config/Cors.php
new file mode 100644
index 0000000..2b4edf6
--- /dev/null
+++ b/app/Config/Cors.php
@@ -0,0 +1,105 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+/**
+ * Cross-Origin Resource Sharing (CORS) Configuration
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
+ */
+class Cors extends BaseConfig
+{
+    /**
+     * The default CORS configuration.
+     *
+     * @var array{
+     *      allowedOrigins: list<string>,
+     *      allowedOriginsPatterns: list<string>,
+     *      supportsCredentials: bool,
+     *      allowedHeaders: list<string>,
+     *      exposedHeaders: list<string>,
+     *      allowedMethods: list<string>,
+     *      maxAge: int,
+     *  }
+     */
+    public array $default = [
+        /**
+         * Origins for the `Access-Control-Allow-Origin` header.
+         *
+         * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
+         *
+         * E.g.:
+         *   - ['http://localhost:8080']
+         *   - ['https://www.example.com']
+         */
+        'allowedOrigins' => [],
+
+        /**
+         * Origin regex patterns for the `Access-Control-Allow-Origin` header.
+         *
+         * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
+         *
+         * NOTE: A pattern specified here is part of a regular expression. It will
+         *       be actually `#\A<pattern>\z#`.
+         *
+         * E.g.:
+         *   - ['https://\w+\.example\.com']
+         */
+        'allowedOriginsPatterns' => [],
+
+        /**
+         * Weather to send the `Access-Control-Allow-Credentials` header.
+         *
+         * The Access-Control-Allow-Credentials response header tells browsers whether
+         * the server allows cross-origin HTTP requests to include credentials.
+         *
+         * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
+         */
+        'supportsCredentials' => false,
+
+        /**
+         * Set headers to allow.
+         *
+         * The Access-Control-Allow-Headers response header is used in response to
+         * a preflight request which includes the Access-Control-Request-Headers to
+         * indicate which HTTP headers can be used during the actual request.
+         *
+         * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
+         */
+        'allowedHeaders' => [],
+
+        /**
+         * Set headers to expose.
+         *
+         * The Access-Control-Expose-Headers response header allows a server to
+         * indicate which response headers should be made available to scripts running
+         * in the browser, in response to a cross-origin request.
+         *
+         * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers
+         */
+        'exposedHeaders' => [],
+
+        /**
+         * Set methods to allow.
+         *
+         * The Access-Control-Allow-Methods response header specifies one or more
+         * methods allowed when accessing a resource in response to a preflight
+         * request.
+         *
+         * E.g.:
+         *   - ['GET', 'POST', 'PUT', 'DELETE']
+         *
+         * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
+         */
+        'allowedMethods' => [],
+
+        /**
+         * Set how many seconds the results of a preflight request can be cached.
+         *
+         * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age
+         */
+        'maxAge' => 7200,
+    ];
+}
diff --git a/app/Config/Database.php b/app/Config/Database.php
new file mode 100644
index 0000000..060781e
--- /dev/null
+++ b/app/Config/Database.php
@@ -0,0 +1,204 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Database\Config;
+
+/**
+ * Database Configuration
+ */
+class Database extends Config
+{
+    /**
+     * The directory that holds the Migrations and Seeds directories.
+     */
+    public string $filesPath = APPPATH . 'Database' . DIRECTORY_SEPARATOR;
+
+    /**
+     * Lets you choose which connection group to use if no other is specified.
+     */
+    public string $defaultGroup = 'default';
+
+    /**
+     * The default database connection.
+     *
+     * @var array<string, mixed>
+     */
+    public array $default = [
+        'DSN'          => '',
+        'hostname'     => 'localhost',
+        'username'     => '',
+        'password'     => '',
+        'database'     => '',
+        'DBDriver'     => 'MySQLi',
+        'DBPrefix'     => '',
+        'pConnect'     => false,
+        'DBDebug'      => true,
+        'charset'      => 'utf8mb4',
+        'DBCollat'     => 'utf8mb4_general_ci',
+        'swapPre'      => '',
+        'encrypt'      => false,
+        'compress'     => false,
+        'strictOn'     => false,
+        'failover'     => [],
+        'port'         => 3306,
+        'numberNative' => false,
+        'foundRows'    => false,
+        'dateFormat'   => [
+            'date'     => 'Y-m-d',
+            'datetime' => 'Y-m-d H:i:s',
+            'time'     => 'H:i:s',
+        ],
+    ];
+
+    //    /**
+    //     * Sample database connection for SQLite3.
+    //     *
+    //     * @var array<string, mixed>
+    //     */
+    //    public array $default = [
+    //        'database'    => 'database.db',
+    //        'DBDriver'    => 'SQLite3',
+    //        'DBPrefix'    => '',
+    //        'DBDebug'     => true,
+    //        'swapPre'     => '',
+    //        'failover'    => [],
+    //        'foreignKeys' => true,
+    //        'busyTimeout' => 1000,
+    //        'synchronous' => null,
+    //        'dateFormat'  => [
+    //            'date'     => 'Y-m-d',
+    //            'datetime' => 'Y-m-d H:i:s',
+    //            'time'     => 'H:i:s',
+    //        ],
+    //    ];
+
+    //    /**
+    //     * Sample database connection for Postgre.
+    //     *
+    //     * @var array<string, mixed>
+    //     */
+    //    public array $default = [
+    //        'DSN'        => '',
+    //        'hostname'   => 'localhost',
+    //        'username'   => 'root',
+    //        'password'   => 'root',
+    //        'database'   => 'ci4',
+    //        'schema'     => 'public',
+    //        'DBDriver'   => 'Postgre',
+    //        'DBPrefix'   => '',
+    //        'pConnect'   => false,
+    //        'DBDebug'    => true,
+    //        'charset'    => 'utf8',
+    //        'swapPre'    => '',
+    //        'failover'   => [],
+    //        'port'       => 5432,
+    //        'dateFormat' => [
+    //            'date'     => 'Y-m-d',
+    //            'datetime' => 'Y-m-d H:i:s',
+    //            'time'     => 'H:i:s',
+    //        ],
+    //    ];
+
+    //    /**
+    //     * Sample database connection for SQLSRV.
+    //     *
+    //     * @var array<string, mixed>
+    //     */
+    //    public array $default = [
+    //        'DSN'        => '',
+    //        'hostname'   => 'localhost',
+    //        'username'   => 'root',
+    //        'password'   => 'root',
+    //        'database'   => 'ci4',
+    //        'schema'     => 'dbo',
+    //        'DBDriver'   => 'SQLSRV',
+    //        'DBPrefix'   => '',
+    //        'pConnect'   => false,
+    //        'DBDebug'    => true,
+    //        'charset'    => 'utf8',
+    //        'swapPre'    => '',
+    //        'encrypt'    => false,
+    //        'failover'   => [],
+    //        'port'       => 1433,
+    //        'dateFormat' => [
+    //            'date'     => 'Y-m-d',
+    //            'datetime' => 'Y-m-d H:i:s',
+    //            'time'     => 'H:i:s',
+    //        ],
+    //    ];
+
+    //    /**
+    //     * Sample database connection for OCI8.
+    //     *
+    //     * You may need the following environment variables:
+    //     *   NLS_LANG                = 'AMERICAN_AMERICA.UTF8'
+    //     *   NLS_DATE_FORMAT         = 'YYYY-MM-DD HH24:MI:SS'
+    //     *   NLS_TIMESTAMP_FORMAT    = 'YYYY-MM-DD HH24:MI:SS'
+    //     *   NLS_TIMESTAMP_TZ_FORMAT = 'YYYY-MM-DD HH24:MI:SS'
+    //     *
+    //     * @var array<string, mixed>
+    //     */
+    //    public array $default = [
+    //        'DSN'        => 'localhost:1521/FREEPDB1',
+    //        'username'   => 'root',
+    //        'password'   => 'root',
+    //        'DBDriver'   => 'OCI8',
+    //        'DBPrefix'   => '',
+    //        'pConnect'   => false,
+    //        'DBDebug'    => true,
+    //        'charset'    => 'AL32UTF8',
+    //        'swapPre'    => '',
+    //        'failover'   => [],
+    //        'dateFormat' => [
+    //            'date'     => 'Y-m-d',
+    //            'datetime' => 'Y-m-d H:i:s',
+    //            'time'     => 'H:i:s',
+    //        ],
+    //    ];
+
+    /**
+     * This database connection is used when running PHPUnit database tests.
+     *
+     * @var array<string, mixed>
+     */
+    public array $tests = [
+        'DSN'         => '',
+        'hostname'    => '127.0.0.1',
+        'username'    => '',
+        'password'    => '',
+        'database'    => ':memory:',
+        'DBDriver'    => 'SQLite3',
+        'DBPrefix'    => 'db_',  // Needed to ensure we're working correctly with prefixes live. DO NOT REMOVE FOR CI DEVS
+        'pConnect'    => false,
+        'DBDebug'     => true,
+        'charset'     => 'utf8',
+        'DBCollat'    => '',
+        'swapPre'     => '',
+        'encrypt'     => false,
+        'compress'    => false,
+        'strictOn'    => true,
+        'failover'    => [],
+        'port'        => 3306,
+        'foreignKeys' => true,
+        'busyTimeout' => 1000,
+        'synchronous' => null,
+        'dateFormat'  => [
+            'date'     => 'Y-m-d',
+            'datetime' => 'Y-m-d H:i:s',
+            'time'     => 'H:i:s',
+        ],
+    ];
+
+    public function __construct()
+    {
+        parent::__construct();
+
+        // Ensure that we always set the database group to 'tests' if
+        // we are currently running an automated test suite, so that
+        // we don't overwrite live data on accident.
+        if (ENVIRONMENT === 'testing') {
+            $this->defaultGroup = 'tests';
+        }
+    }
+}
diff --git a/app/Config/DocTypes.php b/app/Config/DocTypes.php
new file mode 100644
index 0000000..788d68f
--- /dev/null
+++ b/app/Config/DocTypes.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace Config;
+
+class DocTypes
+{
+    /**
+     * List of valid document types.
+     *
+     * @var array<string, string>
+     */
+    public array $list = [
+        'xhtml11'           => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
+        'xhtml1-strict'     => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
+        'xhtml1-trans'      => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
+        'xhtml1-frame'      => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
+        'xhtml-basic11'     => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',
+        'html5'             => '<!DOCTYPE html>',
+        'html4-strict'      => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">',
+        'html4-trans'       => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
+        'html4-frame'       => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">',
+        'mathml1'           => '<!DOCTYPE math SYSTEM "http://www.w3.org/Math/DTD/mathml1/mathml.dtd">',
+        'mathml2'           => '<!DOCTYPE math PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">',
+        'svg10'             => '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">',
+        'svg11'             => '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">',
+        'svg11-basic'       => '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Basic//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-basic.dtd">',
+        'svg11-tiny'        => '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">',
+        'xhtml-math-svg-xh' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">',
+        'xhtml-math-svg-sh' => '<!DOCTYPE svg:svg PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">',
+        'xhtml-rdfa-1'      => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">',
+        'xhtml-rdfa-2'      => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.1//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-2.dtd">',
+    ];
+
+    /**
+     * Whether to remove the solidus (`/`) character for void HTML elements (e.g. `<input>`)
+     * for HTML5 compatibility.
+     *
+     * Set to:
+     *    `true` - to be HTML5 compatible
+     *    `false` - to be XHTML compatible
+     */
+    public bool $html5 = true;
+}
diff --git a/app/Config/Email.php b/app/Config/Email.php
new file mode 100644
index 0000000..77c573a
--- /dev/null
+++ b/app/Config/Email.php
@@ -0,0 +1,126 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class Email extends BaseConfig
+{
+    public string $fromEmail  = '';
+    public string $fromName   = '';
+    public string $recipients = '';
+
+    /**
+     * The "user agent"
+     */
+    public string $userAgent = 'CodeIgniter';
+
+    /**
+     * The mail sending protocol: mail, sendmail, smtp
+     */
+    public string $protocol = 'mail';
+
+    /**
+     * The server path to Sendmail.
+     */
+    public string $mailPath = '/usr/sbin/sendmail';
+
+    /**
+     * SMTP Server Hostname
+     */
+    public string $SMTPHost = '';
+
+    /**
+     * Which SMTP authentication method to use: login, plain
+     */
+    public string $SMTPAuthMethod = 'login';
+
+    /**
+     * SMTP Username
+     */
+    public string $SMTPUser = '';
+
+    /**
+     * SMTP Password
+     */
+    public string $SMTPPass = '';
+
+    /**
+     * SMTP Port
+     */
+    public int $SMTPPort = 25;
+
+    /**
+     * SMTP Timeout (in seconds)
+     */
+    public int $SMTPTimeout = 5;
+
+    /**
+     * Enable persistent SMTP connections
+     */
+    public bool $SMTPKeepAlive = false;
+
+    /**
+     * SMTP Encryption.
+     *
+     * @var string '', 'tls' or 'ssl'. 'tls' will issue a STARTTLS command
+     *             to the server. 'ssl' means implicit SSL. Connection on port
+     *             465 should set this to ''.
+     */
+    public string $SMTPCrypto = 'tls';
+
+    /**
+     * Enable word-wrap
+     */
+    public bool $wordWrap = true;
+
+    /**
+     * Character count to wrap at
+     */
+    public int $wrapChars = 76;
+
+    /**
+     * Type of mail, either 'text' or 'html'
+     */
+    public string $mailType = 'text';
+
+    /**
+     * Character set (utf-8, iso-8859-1, etc.)
+     */
+    public string $charset = 'UTF-8';
+
+    /**
+     * Whether to validate the email address
+     */
+    public bool $validate = false;
+
+    /**
+     * Email Priority. 1 = highest. 5 = lowest. 3 = normal
+     */
+    public int $priority = 3;
+
+    /**
+     * Newline character. (Use “\r\n” to comply with RFC 822)
+     */
+    public string $CRLF = "\r\n";
+
+    /**
+     * Newline character. (Use “\r\n” to comply with RFC 822)
+     */
+    public string $newline = "\r\n";
+
+    /**
+     * Enable BCC Batch Mode.
+     */
+    public bool $BCCBatchMode = false;
+
+    /**
+     * Number of emails in each BCC batch
+     */
+    public int $BCCBatchSize = 200;
+
+    /**
+     * Enable notify message from server
+     */
+    public bool $DSN = false;
+}
diff --git a/app/Config/Encryption.php b/app/Config/Encryption.php
new file mode 100644
index 0000000..c6b8aad
--- /dev/null
+++ b/app/Config/Encryption.php
@@ -0,0 +1,109 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+/**
+ * Encryption configuration.
+ *
+ * These are the settings used for encryption, if you don't pass a parameter
+ * array to the encrypter for creation/initialization.
+ */
+class Encryption extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Encryption Key Starter
+     * --------------------------------------------------------------------------
+     *
+     * If you use the Encryption class you must set an encryption key (seed).
+     * You need to ensure it is long enough for the cipher and mode you plan to use.
+     * See the user guide for more info.
+     */
+    public string $key = '';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Previous Encryption Keys
+     * --------------------------------------------------------------------------
+     *
+     * When rotating encryption keys, add old keys here to maintain ability
+     * to decrypt data encrypted with previous keys. Encryption always uses
+     * the current $key. Decryption tries current key first, then falls back
+     * to previous keys if decryption fails.
+     *
+     * In .env file, use comma-separated string:
+     *   encryption.previousKeys = hex2bin:9be8c64fcea509867...,hex2bin:3f5a1d8e9c2b7a4f6...
+     *
+     * @var list<string>|string
+     */
+    public array|string $previousKeys = '';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Encryption Driver to Use
+     * --------------------------------------------------------------------------
+     *
+     * One of the supported encryption drivers.
+     *
+     * Available drivers:
+     * - OpenSSL
+     * - Sodium
+     */
+    public string $driver = 'OpenSSL';
+
+    /**
+     * --------------------------------------------------------------------------
+     * SodiumHandler's Padding Length in Bytes
+     * --------------------------------------------------------------------------
+     *
+     * This is the number of bytes that will be padded to the plaintext message
+     * before it is encrypted. This value should be greater than zero.
+     *
+     * See the user guide for more information on padding.
+     */
+    public int $blockSize = 16;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Encryption digest
+     * --------------------------------------------------------------------------
+     *
+     * HMAC digest to use, e.g. 'SHA512' or 'SHA256'. Default value is 'SHA512'.
+     */
+    public string $digest = 'SHA512';
+
+    /**
+     * Whether the cipher-text should be raw. If set to false, then it will be base64 encoded.
+     * This setting is only used by OpenSSLHandler.
+     *
+     * Set to false for CI3 Encryption compatibility.
+     */
+    public bool $rawData = true;
+
+    /**
+     * Encryption key info.
+     * This setting is only used by OpenSSLHandler.
+     *
+     * Set to 'encryption' for CI3 Encryption compatibility.
+     */
+    public string $encryptKeyInfo = '';
+
+    /**
+     * Authentication key info.
+     * This setting is only used by OpenSSLHandler.
+     *
+     * Set to 'authentication' for CI3 Encryption compatibility.
+     */
+    public string $authKeyInfo = '';
+
+    /**
+     * Cipher to use.
+     * This setting is only used by OpenSSLHandler.
+     *
+     * Set to 'AES-128-CBC' to decrypt encrypted data that encrypted
+     * by CI3 Encryption default configuration.
+     */
+    public string $cipher = 'AES-256-CTR';
+}
diff --git a/app/Config/Events.php b/app/Config/Events.php
new file mode 100644
index 0000000..7dc9507
--- /dev/null
+++ b/app/Config/Events.php
@@ -0,0 +1,57 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Events\Events;
+use CodeIgniter\Exceptions\FrameworkException;
+use CodeIgniter\HotReloader\HotReloader;
+
+/*
+ * --------------------------------------------------------------------
+ * Application Events
+ * --------------------------------------------------------------------
+ * Events allow you to tap into the execution of the program without
+ * modifying or extending core files. This file provides a central
+ * location to define your events, though they can always be added
+ * at run-time, also, if needed.
+ *
+ * You create code that can execute by subscribing to events with
+ * the 'on()' method. This accepts any form of callable, including
+ * Closures, that will be executed when the event is triggered.
+ *
+ * Example:
+ *      Events::on('create', [$myInstance, 'myMethod']);
+ */
+
+Events::on('pre_system', static function (): void {
+    if (ENVIRONMENT !== 'testing') {
+        $value = ini_get('zlib.output_compression');
+
+        if (filter_var($value, FILTER_VALIDATE_BOOLEAN) || (int) $value > 0) {
+            throw FrameworkException::forEnabledZlibOutputCompression();
+        }
+
+        while (ob_get_level() > 0) {
+            ob_end_flush();
+        }
+
+        ob_start(static fn ($buffer) => $buffer);
+    }
+
+    /*
+     * --------------------------------------------------------------------
+     * Debug Toolbar Listeners.
+     * --------------------------------------------------------------------
+     * If you delete, they will no longer be collected.
+     */
+    if (CI_DEBUG && ! is_cli()) {
+        Events::on('DBQuery', 'CodeIgniter\Debug\Toolbar\Collectors\Database::collect');
+        service('toolbar')->respond();
+        // Hot Reload route - for framework use on the hot reloader.
+        if (ENVIRONMENT === 'development') {
+            service('routes')->get('__hot-reload', static function (): void {
+                (new HotReloader())->run();
+            });
+        }
+    }
+});
diff --git a/app/Config/Exceptions.php b/app/Config/Exceptions.php
new file mode 100644
index 0000000..4e33963
--- /dev/null
+++ b/app/Config/Exceptions.php
@@ -0,0 +1,106 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use CodeIgniter\Debug\ExceptionHandler;
+use CodeIgniter\Debug\ExceptionHandlerInterface;
+use Psr\Log\LogLevel;
+use Throwable;
+
+/**
+ * Setup how the exception handler works.
+ */
+class Exceptions extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * LOG EXCEPTIONS?
+     * --------------------------------------------------------------------------
+     * If true, then exceptions will be logged
+     * through Services::Log.
+     *
+     * Default: true
+     */
+    public bool $log = true;
+
+    /**
+     * --------------------------------------------------------------------------
+     * DO NOT LOG STATUS CODES
+     * --------------------------------------------------------------------------
+     * Any status codes here will NOT be logged if logging is turned on.
+     * By default, only 404 (Page Not Found) exceptions are ignored.
+     *
+     * @var list<int>
+     */
+    public array $ignoreCodes = [404];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Error Views Path
+     * --------------------------------------------------------------------------
+     * This is the path to the directory that contains the 'cli' and 'html'
+     * directories that hold the views used to generate errors.
+     *
+     * Default: APPPATH.'Views/errors'
+     */
+    public string $errorViewPath = APPPATH . 'Views/errors';
+
+    /**
+     * --------------------------------------------------------------------------
+     * HIDE FROM DEBUG TRACE
+     * --------------------------------------------------------------------------
+     * Any data that you would like to hide from the debug trace.
+     * In order to specify 2 levels, use "/" to separate.
+     * ex. ['server', 'setup/password', 'secret_token']
+     *
+     * @var list<string>
+     */
+    public array $sensitiveDataInTrace = [];
+
+    /**
+     * --------------------------------------------------------------------------
+     * WHETHER TO THROW AN EXCEPTION ON DEPRECATED ERRORS
+     * --------------------------------------------------------------------------
+     * If set to `true`, DEPRECATED errors are only logged and no exceptions are
+     * thrown. This option also works for user deprecations.
+     */
+    public bool $logDeprecations = true;
+
+    /**
+     * --------------------------------------------------------------------------
+     * LOG LEVEL THRESHOLD FOR DEPRECATIONS
+     * --------------------------------------------------------------------------
+     * If `$logDeprecations` is set to `true`, this sets the log level
+     * to which the deprecation will be logged. This should be one of the log
+     * levels recognized by PSR-3.
+     *
+     * The related `Config\Logger::$threshold` should be adjusted, if needed,
+     * to capture logging the deprecations.
+     */
+    public string $deprecationLogLevel = LogLevel::WARNING;
+
+    /*
+     * DEFINE THE HANDLERS USED
+     * --------------------------------------------------------------------------
+     * Given the HTTP status code, returns exception handler that
+     * should be used to deal with this error. By default, it will run CodeIgniter's
+     * default handler and display the error information in the expected format
+     * for CLI, HTTP, or AJAX requests, as determined by is_cli() and the expected
+     * response format.
+     *
+     * Custom handlers can be returned if you want to handle one or more specific
+     * error codes yourself like:
+     *
+     *      if (in_array($statusCode, [400, 404, 500])) {
+     *          return new \App\Libraries\MyExceptionHandler();
+     *      }
+     *      if ($exception instanceOf PageNotFoundException) {
+     *          return new \App\Libraries\MyExceptionHandler();
+     *      }
+     */
+    public function handler(int $statusCode, Throwable $exception): ExceptionHandlerInterface
+    {
+        return new ExceptionHandler($this);
+    }
+}
diff --git a/app/Config/Feature.php b/app/Config/Feature.php
new file mode 100644
index 0000000..ec1435a
--- /dev/null
+++ b/app/Config/Feature.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+/**
+ * Enable/disable backward compatibility breaking features.
+ */
+class Feature extends BaseConfig
+{
+    /**
+     * Use improved new auto routing instead of the legacy version.
+     */
+    public bool $autoRoutesImproved = true;
+
+    /**
+     * Use filter execution order in 4.4 or before.
+     */
+    public bool $oldFilterOrder = false;
+
+    /**
+     * The behavior of `limit(0)` in Query Builder.
+     *
+     * If true, `limit(0)` returns all records. (the behavior of 4.4.x or before in version 4.x.)
+     * If false, `limit(0)` returns no records. (the behavior of 3.1.9 or later in version 3.x.)
+     */
+    public bool $limitZeroAsAll = true;
+
+    /**
+     * Use strict location negotiation.
+     *
+     * By default, the locale is selected based on a loose comparison of the language code (ISO 639-1)
+     * Enabling strict comparison will also consider the region code (ISO 3166-1 alpha-2).
+     */
+    public bool $strictLocaleNegotiation = false;
+}
diff --git a/app/Config/Filters.php b/app/Config/Filters.php
new file mode 100644
index 0000000..9c83ae9
--- /dev/null
+++ b/app/Config/Filters.php
@@ -0,0 +1,110 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\Filters as BaseFilters;
+use CodeIgniter\Filters\Cors;
+use CodeIgniter\Filters\CSRF;
+use CodeIgniter\Filters\DebugToolbar;
+use CodeIgniter\Filters\ForceHTTPS;
+use CodeIgniter\Filters\Honeypot;
+use CodeIgniter\Filters\InvalidChars;
+use CodeIgniter\Filters\PageCache;
+use CodeIgniter\Filters\PerformanceMetrics;
+use CodeIgniter\Filters\SecureHeaders;
+
+class Filters extends BaseFilters
+{
+    /**
+     * Configures aliases for Filter classes to
+     * make reading things nicer and simpler.
+     *
+     * @var array<string, class-string|list<class-string>>
+     *
+     * [filter_name => classname]
+     * or [filter_name => [classname1, classname2, ...]]
+     */
+    public array $aliases = [
+        'csrf'          => CSRF::class,
+        'toolbar'       => DebugToolbar::class,
+        'honeypot'      => Honeypot::class,
+        'invalidchars'  => InvalidChars::class,
+        'secureheaders' => SecureHeaders::class,
+        'cors'          => Cors::class,
+        'forcehttps'    => ForceHTTPS::class,
+        'pagecache'     => PageCache::class,
+        'performance'   => PerformanceMetrics::class,
+    ];
+
+    /**
+     * List of special required filters.
+     *
+     * The filters listed here are special. They are applied before and after
+     * other kinds of filters, and always applied even if a route does not exist.
+     *
+     * Filters set by default provide framework functionality. If removed,
+     * those functions will no longer work.
+     *
+     * @see https://codeigniter.com/user_guide/incoming/filters.html#provided-filters
+     *
+     * @var array{before: list<string>, after: list<string>}
+     */
+    public array $required = [
+        'before' => [
+            'forcehttps', // Force Global Secure Requests
+            'pagecache',  // Web Page Caching
+        ],
+        'after' => [
+            'pagecache',   // Web Page Caching
+            'performance', // Performance Metrics
+            'toolbar',     // Debug Toolbar
+        ],
+    ];
+
+    /**
+     * List of filter aliases that are always
+     * applied before and after every request.
+     *
+     * @var array{
+     *     before: array<string, array{except: list<string>|string}>|list<string>,
+     *     after: array<string, array{except: list<string>|string}>|list<string>
+     * }
+     */
+    public array $globals = [
+        'before' => [
+            // 'honeypot',
+            // 'csrf',
+            // 'invalidchars',
+        ],
+        'after' => [
+            // 'honeypot',
+            // 'secureheaders',
+        ],
+    ];
+
+    /**
+     * List of filter aliases that works on a
+     * particular HTTP method (GET, POST, etc.).
+     *
+     * Example:
+     * 'POST' => ['foo', 'bar']
+     *
+     * If you use this, you should disable auto-routing because auto-routing
+     * permits any HTTP method to access a controller. Accessing the controller
+     * with a method you don't expect could bypass the filter.
+     *
+     * @var array<string, list<string>>
+     */
+    public array $methods = [];
+
+    /**
+     * List of filter aliases that should run on any
+     * before or after URI patterns.
+     *
+     * Example:
+     * 'isLoggedIn' => ['before' => ['account/*', 'profiles/*']]
+     *
+     * @var array<string, array<string, list<string>>>
+     */
+    public array $filters = [];
+}
diff --git a/app/Config/ForeignCharacters.php b/app/Config/ForeignCharacters.php
new file mode 100644
index 0000000..f1a9572
--- /dev/null
+++ b/app/Config/ForeignCharacters.php
@@ -0,0 +1,12 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\ForeignCharacters as BaseForeignCharacters;
+
+/**
+ * @immutable
+ */
+class ForeignCharacters extends BaseForeignCharacters
+{
+}
diff --git a/app/Config/Format.php b/app/Config/Format.php
new file mode 100644
index 0000000..5bf56c2
--- /dev/null
+++ b/app/Config/Format.php
@@ -0,0 +1,73 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use CodeIgniter\Format\JSONFormatter;
+use CodeIgniter\Format\XMLFormatter;
+
+class Format extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Available Response Formats
+     * --------------------------------------------------------------------------
+     *
+     * When you perform content negotiation with the request, these are the
+     * available formats that your application supports. This is currently
+     * only used with the API\ResponseTrait. A valid Formatter must exist
+     * for the specified format.
+     *
+     * These formats are only checked when the data passed to the respond()
+     * method is an array.
+     *
+     * @var list<string>
+     */
+    public array $supportedResponseFormats = [
+        'application/json',
+        'application/xml', // machine-readable XML
+        'text/xml', // human-readable XML
+    ];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Formatters
+     * --------------------------------------------------------------------------
+     *
+     * Lists the class to use to format responses with of a particular type.
+     * For each mime type, list the class that should be used. Formatters
+     * can be retrieved through the getFormatter() method.
+     *
+     * @var array<string, string>
+     */
+    public array $formatters = [
+        'application/json' => JSONFormatter::class,
+        'application/xml'  => XMLFormatter::class,
+        'text/xml'         => XMLFormatter::class,
+    ];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Formatters Options
+     * --------------------------------------------------------------------------
+     *
+     * Additional Options to adjust default formatters behaviour.
+     * For each mime type, list the additional options that should be used.
+     *
+     * @var array<string, int>
+     */
+    public array $formatterOptions = [
+        'application/json' => JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES,
+        'application/xml'  => 0,
+        'text/xml'         => 0,
+    ];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Maximum depth for JSON encoding.
+     * --------------------------------------------------------------------------
+     *
+     * This value determines how deep the JSON encoder will traverse nested structures.
+     */
+    public int $jsonEncodeDepth = 512;
+}
diff --git a/app/Config/Generators.php b/app/Config/Generators.php
new file mode 100644
index 0000000..cc92c7a
--- /dev/null
+++ b/app/Config/Generators.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class Generators extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Generator Commands' Views
+     * --------------------------------------------------------------------------
+     *
+     * This array defines the mapping of generator commands to the view files
+     * they are using. If you need to customize them for your own, copy these
+     * view files in your own folder and indicate the location here.
+     *
+     * You will notice that the views have special placeholders enclosed in
+     * curly braces `{...}`. These placeholders are used internally by the
+     * generator commands in processing replacements, thus you are warned
+     * not to delete them or modify the names. If you will do so, you may
+     * end up disrupting the scaffolding process and throw errors.
+     *
+     * YOU HAVE BEEN WARNED!
+     *
+     * @var array<string, array<string, string>|string>
+     */
+    public array $views = [
+        'make:cell' => [
+            'class' => 'CodeIgniter\Commands\Generators\Views\cell.tpl.php',
+            'view'  => 'CodeIgniter\Commands\Generators\Views\cell_view.tpl.php',
+        ],
+        'make:command'      => 'CodeIgniter\Commands\Generators\Views\command.tpl.php',
+        'make:config'       => 'CodeIgniter\Commands\Generators\Views\config.tpl.php',
+        'make:controller'   => 'CodeIgniter\Commands\Generators\Views\controller.tpl.php',
+        'make:entity'       => 'CodeIgniter\Commands\Generators\Views\entity.tpl.php',
+        'make:filter'       => 'CodeIgniter\Commands\Generators\Views\filter.tpl.php',
+        'make:migration'    => 'CodeIgniter\Commands\Generators\Views\migration.tpl.php',
+        'make:model'        => 'CodeIgniter\Commands\Generators\Views\model.tpl.php',
+        'make:seeder'       => 'CodeIgniter\Commands\Generators\Views\seeder.tpl.php',
+        'make:validation'   => 'CodeIgniter\Commands\Generators\Views\validation.tpl.php',
+        'session:migration' => 'CodeIgniter\Commands\Generators\Views\migration.tpl.php',
+    ];
+}
diff --git a/app/Config/Honeypot.php b/app/Config/Honeypot.php
new file mode 100644
index 0000000..67ebcb0
--- /dev/null
+++ b/app/Config/Honeypot.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class Honeypot extends BaseConfig
+{
+    /**
+     * Makes Honeypot visible or not to human
+     */
+    public bool $hidden = true;
+
+    /**
+     * Honeypot Label Content
+     */
+    public string $label = 'Fill This Field';
+
+    /**
+     * Honeypot Field Name
+     */
+    public string $name = 'honeypot';
+
+    /**
+     * Honeypot HTML Template
+     */
+    public string $template = '<label>{label}</label><input type="text" name="{name}" value="">';
+
+    /**
+     * Honeypot container
+     *
+     * If you enabled CSP, you can remove `style="display:none"`.
+     */
+    public string $container = '<div style="display:none">{template}</div>';
+
+    /**
+     * The id attribute for Honeypot container tag
+     *
+     * Used when CSP is enabled.
+     */
+    public string $containerId = 'hpc';
+}
diff --git a/app/Config/Hostnames.php b/app/Config/Hostnames.php
new file mode 100644
index 0000000..1b4c722
--- /dev/null
+++ b/app/Config/Hostnames.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace Config;
+
+class Hostnames
+{
+    // List of known two-part TLDs for subdomain extraction
+    public const TWO_PART_TLDS = [
+        'co.uk', 'org.uk', 'gov.uk', 'ac.uk', 'sch.uk', 'ltd.uk', 'plc.uk',
+        'com.au', 'net.au', 'org.au', 'edu.au', 'gov.au', 'asn.au', 'id.au',
+        'co.jp', 'ac.jp', 'go.jp', 'or.jp', 'ne.jp', 'gr.jp',
+        'co.nz', 'org.nz', 'govt.nz', 'ac.nz', 'net.nz', 'geek.nz', 'maori.nz', 'school.nz',
+        'co.in', 'net.in', 'org.in', 'ind.in', 'ac.in', 'gov.in', 'res.in',
+        'com.cn', 'net.cn', 'org.cn', 'gov.cn', 'edu.cn',
+        'com.sg', 'net.sg', 'org.sg', 'gov.sg', 'edu.sg', 'per.sg',
+        'co.za', 'org.za', 'gov.za', 'ac.za', 'net.za',
+        'co.kr', 'or.kr', 'go.kr', 'ac.kr', 'ne.kr', 'pe.kr',
+        'co.th', 'or.th', 'go.th', 'ac.th', 'net.th', 'in.th',
+        'com.my', 'net.my', 'org.my', 'edu.my', 'gov.my', 'mil.my', 'name.my',
+        'com.mx', 'org.mx', 'net.mx', 'edu.mx', 'gob.mx',
+        'com.br', 'net.br', 'org.br', 'gov.br', 'edu.br', 'art.br', 'eng.br',
+        'co.il', 'org.il', 'ac.il', 'gov.il', 'net.il', 'muni.il',
+        'co.id', 'or.id', 'ac.id', 'go.id', 'net.id', 'web.id', 'my.id',
+        'com.hk', 'edu.hk', 'gov.hk', 'idv.hk', 'net.hk', 'org.hk',
+        'com.tw', 'net.tw', 'org.tw', 'edu.tw', 'gov.tw', 'idv.tw',
+        'com.sa', 'net.sa', 'org.sa', 'gov.sa', 'edu.sa', 'sch.sa', 'med.sa',
+        'co.ae', 'net.ae', 'org.ae', 'gov.ae', 'ac.ae', 'sch.ae',
+        'com.tr', 'net.tr', 'org.tr', 'gov.tr', 'edu.tr', 'av.tr', 'gen.tr',
+        'co.ke', 'or.ke', 'go.ke', 'ac.ke', 'sc.ke', 'me.ke', 'mobi.ke', 'info.ke',
+        'com.ng', 'org.ng', 'gov.ng', 'edu.ng', 'net.ng', 'sch.ng', 'name.ng',
+        'com.pk', 'net.pk', 'org.pk', 'gov.pk', 'edu.pk', 'fam.pk',
+        'com.eg', 'edu.eg', 'gov.eg', 'org.eg', 'net.eg',
+        'com.cy', 'net.cy', 'org.cy', 'gov.cy', 'ac.cy',
+        'com.lk', 'org.lk', 'edu.lk', 'gov.lk', 'net.lk', 'int.lk',
+        'com.bd', 'net.bd', 'org.bd', 'ac.bd', 'gov.bd', 'mil.bd',
+        'com.ar', 'net.ar', 'org.ar', 'gov.ar', 'edu.ar', 'mil.ar',
+        'gob.cl', 'com.pl', 'net.pl', 'org.pl', 'gov.pl', 'edu.pl',
+        'co.ir', 'ac.ir', 'org.ir', 'id.ir', 'gov.ir', 'sch.ir', 'net.ir',
+    ];
+}
diff --git a/app/Config/Images.php b/app/Config/Images.php
new file mode 100644
index 0000000..68e415e
--- /dev/null
+++ b/app/Config/Images.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use CodeIgniter\Images\Handlers\GDHandler;
+use CodeIgniter\Images\Handlers\ImageMagickHandler;
+
+class Images extends BaseConfig
+{
+    /**
+     * Default handler used if no other handler is specified.
+     */
+    public string $defaultHandler = 'gd';
+
+    /**
+     * The path to the image library.
+     * Required for ImageMagick, GraphicsMagick, or NetPBM.
+     *
+     * @deprecated 4.7.0 No longer used.
+     */
+    public string $libraryPath = '/usr/local/bin/convert';
+
+    /**
+     * The available handler classes.
+     *
+     * @var array<string, string>
+     */
+    public array $handlers = [
+        'gd'      => GDHandler::class,
+        'imagick' => ImageMagickHandler::class,
+    ];
+}
diff --git a/app/Config/Kint.php b/app/Config/Kint.php
new file mode 100644
index 0000000..931ad47
--- /dev/null
+++ b/app/Config/Kint.php
@@ -0,0 +1,63 @@
+<?php
+
+namespace Config;
+
+use Kint\Parser\ConstructablePluginInterface;
+use Kint\Renderer\Rich\TabPluginInterface;
+use Kint\Renderer\Rich\ValuePluginInterface;
+
+/**
+ * --------------------------------------------------------------------------
+ * Kint
+ * --------------------------------------------------------------------------
+ *
+ * We use Kint's `RichRenderer` and `CLIRenderer`. This area contains options
+ * that you can set to customize how Kint works for you.
+ *
+ * @see https://kint-php.github.io/kint/ for details on these settings.
+ */
+class Kint
+{
+    /*
+    |--------------------------------------------------------------------------
+    | Global Settings
+    |--------------------------------------------------------------------------
+    */
+
+    /**
+     * @var list<class-string<ConstructablePluginInterface>|ConstructablePluginInterface>|null
+     */
+    public $plugins;
+
+    public int $maxDepth           = 6;
+    public bool $displayCalledFrom = true;
+    public bool $expanded          = false;
+
+    /*
+    |--------------------------------------------------------------------------
+    | RichRenderer Settings
+    |--------------------------------------------------------------------------
+    */
+    public string $richTheme = 'aante-light.css';
+    public bool $richFolder  = false;
+
+    /**
+     * @var array<string, class-string<ValuePluginInterface>>|null
+     */
+    public $richObjectPlugins;
+
+    /**
+     * @var array<string, class-string<TabPluginInterface>>|null
+     */
+    public $richTabPlugins;
+
+    /*
+    |--------------------------------------------------------------------------
+    | CLI Settings
+    |--------------------------------------------------------------------------
+    */
+    public bool $cliColors      = true;
+    public bool $cliForceUTF8   = false;
+    public bool $cliDetectWidth = true;
+    public int $cliMinWidth     = 40;
+}
diff --git a/app/Config/Logger.php b/app/Config/Logger.php
new file mode 100644
index 0000000..799dc2c
--- /dev/null
+++ b/app/Config/Logger.php
@@ -0,0 +1,151 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use CodeIgniter\Log\Handlers\FileHandler;
+use CodeIgniter\Log\Handlers\HandlerInterface;
+
+class Logger extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Error Logging Threshold
+     * --------------------------------------------------------------------------
+     *
+     * You can enable error logging by setting a threshold over zero. The
+     * threshold determines what gets logged. Any values below or equal to the
+     * threshold will be logged.
+     *
+     * Threshold options are:
+     *
+     * - 0 = Disables logging, Error logging TURNED OFF
+     * - 1 = Emergency Messages - System is unusable
+     * - 2 = Alert Messages - Action Must Be Taken Immediately
+     * - 3 = Critical Messages - Application component unavailable, unexpected exception.
+     * - 4 = Runtime Errors - Don't need immediate action, but should be monitored.
+     * - 5 = Warnings - Exceptional occurrences that are not errors.
+     * - 6 = Notices - Normal but significant events.
+     * - 7 = Info - Interesting events, like user logging in, etc.
+     * - 8 = Debug - Detailed debug information.
+     * - 9 = All Messages
+     *
+     * You can also pass an array with threshold levels to show individual error types
+     *
+     *     array(1, 2, 3, 8) = Emergency, Alert, Critical, and Debug messages
+     *
+     * For a live site you'll usually enable Critical or higher (3) to be logged otherwise
+     * your log files will fill up very fast.
+     *
+     * @var int|list<int>
+     */
+    public $threshold = (ENVIRONMENT === 'production') ? 4 : 9;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Date Format for Logs
+     * --------------------------------------------------------------------------
+     *
+     * Each item that is logged has an associated date. You can use PHP date
+     * codes to set your own date formatting
+     */
+    public string $dateFormat = 'Y-m-d H:i:s';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Log Handlers
+     * --------------------------------------------------------------------------
+     *
+     * The logging system supports multiple actions to be taken when something
+     * is logged. This is done by allowing for multiple Handlers, special classes
+     * designed to write the log to their chosen destinations, whether that is
+     * a file on the getServer, a cloud-based service, or even taking actions such
+     * as emailing the dev team.
+     *
+     * Each handler is defined by the class name used for that handler, and it
+     * MUST implement the `CodeIgniter\Log\Handlers\HandlerInterface` interface.
+     *
+     * The value of each key is an array of configuration items that are sent
+     * to the constructor of each handler. The only required configuration item
+     * is the 'handles' element, which must be an array of integer log levels.
+     * This is most easily handled by using the constants defined in the
+     * `Psr\Log\LogLevel` class.
+     *
+     * Handlers are executed in the order defined in this array, starting with
+     * the handler on top and continuing down.
+     *
+     * @var array<class-string<HandlerInterface>, array<string, int|list<string>|string>>
+     */
+    public array $handlers = [
+        /*
+         * --------------------------------------------------------------------
+         * File Handler
+         * --------------------------------------------------------------------
+         */
+        FileHandler::class => [
+            // The log levels that this handler will handle.
+            'handles' => [
+                'critical',
+                'alert',
+                'emergency',
+                'debug',
+                'error',
+                'info',
+                'notice',
+                'warning',
+            ],
+
+            /*
+             * The default filename extension for log files.
+             * An extension of 'php' allows for protecting the log files via basic
+             * scripting, when they are to be stored under a publicly accessible directory.
+             *
+             * NOTE: Leaving it blank will default to 'log'.
+             */
+            'fileExtension' => '',
+
+            /*
+             * The file system permissions to be applied on newly created log files.
+             *
+             * IMPORTANT: This MUST be an integer (no quotes) and you MUST use octal
+             * integer notation (i.e. 0700, 0644, etc.)
+             */
+            'filePermissions' => 0644,
+
+            /*
+             * Logging Directory Path
+             *
+             * By default, logs are written to WRITEPATH . 'logs/'
+             * Specify a different destination here, if desired.
+             */
+            'path' => '',
+        ],
+
+        /*
+         * The ChromeLoggerHandler requires the use of the Chrome web browser
+         * and the ChromeLogger extension. Uncomment this block to use it.
+         */
+        // 'CodeIgniter\Log\Handlers\ChromeLoggerHandler' => [
+        //     /*
+        //      * The log levels that this handler will handle.
+        //      */
+        //     'handles' => ['critical', 'alert', 'emergency', 'debug',
+        //                   'error', 'info', 'notice', 'warning'],
+        // ],
+
+        /*
+         * The ErrorlogHandler writes the logs to PHP's native `error_log()` function.
+         * Uncomment this block to use it.
+         */
+        // 'CodeIgniter\Log\Handlers\ErrorlogHandler' => [
+        //     /* The log levels this handler can handle. */
+        //     'handles' => ['critical', 'alert', 'emergency', 'debug', 'error', 'info', 'notice', 'warning'],
+        //
+        //     /*
+        //     * The message type where the error should go. Can be 0 or 4, or use the
+        //     * class constants: `ErrorlogHandler::TYPE_OS` (0) or `ErrorlogHandler::TYPE_SAPI` (4)
+        //     */
+        //     'messageType' => 0,
+        // ],
+    ];
+}
diff --git a/app/Config/Migrations.php b/app/Config/Migrations.php
new file mode 100644
index 0000000..eb45e72
--- /dev/null
+++ b/app/Config/Migrations.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class Migrations extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Enable/Disable Migrations
+     * --------------------------------------------------------------------------
+     *
+     * Migrations are enabled by default.
+     *
+     * You should enable migrations whenever you intend to do a schema migration
+     * and disable it back when you're done.
+     */
+    public bool $enabled = true;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Migrations Table
+     * --------------------------------------------------------------------------
+     *
+     * This is the name of the table that will store the current migrations state.
+     * When migrations runs it will store in a database table which migration
+     * files have already been run.
+     */
+    public string $table = 'migrations';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Timestamp Format
+     * --------------------------------------------------------------------------
+     *
+     * This is the format that will be used when creating new migrations
+     * using the CLI command:
+     *   > php spark make:migration
+     *
+     * NOTE: if you set an unsupported format, migration runner will not find
+     *       your migration files.
+     *
+     * Supported formats:
+     * - YmdHis_
+     * - Y-m-d-His_
+     * - Y_m_d_His_
+     */
+    public string $timestampFormat = 'Y-m-d-His_';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Enable/Disable Migration Lock
+     * --------------------------------------------------------------------------
+     *
+     * Locking is disabled by default.
+     *
+     * When enabled, it will prevent multiple migration processes
+     * from running at the same time by using a lock mechanism.
+     *
+     * This is useful in production environments to avoid conflicts
+     * or race conditions during concurrent deployments.
+     */
+    public bool $lock = false;
+}
diff --git a/app/Config/Mimes.php b/app/Config/Mimes.php
new file mode 100644
index 0000000..c2db734
--- /dev/null
+++ b/app/Config/Mimes.php
@@ -0,0 +1,534 @@
+<?php
+
+namespace Config;
+
+/**
+ * This file contains an array of mime types.  It is used by the
+ * Upload class to help identify allowed file types.
+ *
+ * When more than one variation for an extension exist (like jpg, jpeg, etc)
+ * the most common one should be first in the array to aid the guess*
+ * methods. The same applies when more than one mime-type exists for a
+ * single extension.
+ *
+ * When working with mime types, please make sure you have the ´fileinfo´
+ * extension enabled to reliably detect the media types.
+ */
+class Mimes
+{
+    /**
+     * Map of extensions to mime types.
+     *
+     * @var array<string, list<string>|string>
+     */
+    public static array $mimes = [
+        'hqx' => [
+            'application/mac-binhex40',
+            'application/mac-binhex',
+            'application/x-binhex40',
+            'application/x-mac-binhex40',
+        ],
+        'cpt' => 'application/mac-compactpro',
+        'csv' => [
+            'text/csv',
+            'text/x-comma-separated-values',
+            'text/comma-separated-values',
+            'application/vnd.ms-excel',
+            'application/x-csv',
+            'text/x-csv',
+            'application/csv',
+            'application/excel',
+            'application/vnd.msexcel',
+            'text/plain',
+        ],
+        'bin' => [
+            'application/macbinary',
+            'application/mac-binary',
+            'application/octet-stream',
+            'application/x-binary',
+            'application/x-macbinary',
+        ],
+        'dms' => 'application/octet-stream',
+        'lha' => 'application/octet-stream',
+        'lzh' => 'application/octet-stream',
+        'exe' => [
+            'application/octet-stream',
+            'application/vnd.microsoft.portable-executable',
+            'application/x-dosexec',
+            'application/x-msdownload',
+        ],
+        'class' => 'application/octet-stream',
+        'psd'   => [
+            'application/x-photoshop',
+            'image/vnd.adobe.photoshop',
+        ],
+        'so'  => 'application/octet-stream',
+        'sea' => 'application/octet-stream',
+        'dll' => 'application/octet-stream',
+        'oda' => 'application/oda',
+        'pdf' => [
+            'application/pdf',
+            'application/force-download',
+            'application/x-download',
+        ],
+        'ai' => [
+            'application/pdf',
+            'application/postscript',
+        ],
+        'eps'  => 'application/postscript',
+        'ps'   => 'application/postscript',
+        'smi'  => 'application/smil',
+        'smil' => 'application/smil',
+        'mif'  => 'application/vnd.mif',
+        'xls'  => [
+            'application/vnd.ms-excel',
+            'application/msexcel',
+            'application/x-msexcel',
+            'application/x-ms-excel',
+            'application/x-excel',
+            'application/x-dos_ms_excel',
+            'application/xls',
+            'application/x-xls',
+            'application/excel',
+            'application/download',
+            'application/vnd.ms-office',
+            'application/msword',
+        ],
+        'ppt' => [
+            'application/vnd.ms-powerpoint',
+            'application/powerpoint',
+            'application/vnd.ms-office',
+            'application/msword',
+        ],
+        'pptx' => [
+            'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+        ],
+        'wbxml' => 'application/wbxml',
+        'wmlc'  => 'application/wmlc',
+        'dcr'   => 'application/x-director',
+        'dir'   => 'application/x-director',
+        'dxr'   => 'application/x-director',
+        'dvi'   => 'application/x-dvi',
+        'gtar'  => 'application/x-gtar',
+        'gz'    => 'application/x-gzip',
+        'gzip'  => 'application/x-gzip',
+        'php'   => [
+            'application/x-php',
+            'application/x-httpd-php',
+            'application/php',
+            'text/php',
+            'text/x-php',
+            'application/x-httpd-php-source',
+        ],
+        'php4'  => 'application/x-httpd-php',
+        'php3'  => 'application/x-httpd-php',
+        'phtml' => 'application/x-httpd-php',
+        'phps'  => 'application/x-httpd-php-source',
+        'js'    => [
+            'application/x-javascript',
+            'text/plain',
+        ],
+        'swf' => 'application/x-shockwave-flash',
+        'sit' => 'application/x-stuffit',
+        'tar' => 'application/x-tar',
+        'tgz' => [
+            'application/x-tar',
+            'application/x-gzip-compressed',
+        ],
+        'z'     => 'application/x-compress',
+        'xhtml' => 'application/xhtml+xml',
+        'xht'   => 'application/xhtml+xml',
+        'zip'   => [
+            'application/x-zip',
+            'application/zip',
+            'application/x-zip-compressed',
+            'application/s-compressed',
+            'multipart/x-zip',
+        ],
+        'rar' => [
+            'application/vnd.rar',
+            'application/x-rar',
+            'application/rar',
+            'application/x-rar-compressed',
+        ],
+        'mid'  => 'audio/midi',
+        'midi' => 'audio/midi',
+        'mpga' => 'audio/mpeg',
+        'mp2'  => 'audio/mpeg',
+        'mp3'  => [
+            'audio/mpeg',
+            'audio/mpg',
+            'audio/mpeg3',
+            'audio/mp3',
+        ],
+        'aif' => [
+            'audio/x-aiff',
+            'audio/aiff',
+        ],
+        'aiff' => [
+            'audio/x-aiff',
+            'audio/aiff',
+        ],
+        'aifc' => 'audio/x-aiff',
+        'ram'  => 'audio/x-pn-realaudio',
+        'rm'   => 'audio/x-pn-realaudio',
+        'rpm'  => 'audio/x-pn-realaudio-plugin',
+        'ra'   => 'audio/x-realaudio',
+        'rv'   => 'video/vnd.rn-realvideo',
+        'wav'  => [
+            'audio/x-wav',
+            'audio/wave',
+            'audio/wav',
+        ],
+        'bmp' => [
+            'image/bmp',
+            'image/x-bmp',
+            'image/x-bitmap',
+            'image/x-xbitmap',
+            'image/x-win-bitmap',
+            'image/x-windows-bmp',
+            'image/ms-bmp',
+            'image/x-ms-bmp',
+            'application/bmp',
+            'application/x-bmp',
+            'application/x-win-bitmap',
+        ],
+        'gif' => 'image/gif',
+        'jpg' => [
+            'image/jpeg',
+            'image/pjpeg',
+        ],
+        'jpeg' => [
+            'image/jpeg',
+            'image/pjpeg',
+        ],
+        'jpe' => [
+            'image/jpeg',
+            'image/pjpeg',
+        ],
+        'jp2' => [
+            'image/jp2',
+            'video/mj2',
+            'image/jpx',
+            'image/jpm',
+        ],
+        'j2k' => [
+            'image/jp2',
+            'video/mj2',
+            'image/jpx',
+            'image/jpm',
+        ],
+        'jpf' => [
+            'image/jp2',
+            'video/mj2',
+            'image/jpx',
+            'image/jpm',
+        ],
+        'jpg2' => [
+            'image/jp2',
+            'video/mj2',
+            'image/jpx',
+            'image/jpm',
+        ],
+        'jpx' => [
+            'image/jp2',
+            'video/mj2',
+            'image/jpx',
+            'image/jpm',
+        ],
+        'jpm' => [
+            'image/jp2',
+            'video/mj2',
+            'image/jpx',
+            'image/jpm',
+        ],
+        'mj2' => [
+            'image/jp2',
+            'video/mj2',
+            'image/jpx',
+            'image/jpm',
+        ],
+        'mjp2' => [
+            'image/jp2',
+            'video/mj2',
+            'image/jpx',
+            'image/jpm',
+        ],
+        'png' => [
+            'image/png',
+            'image/x-png',
+        ],
+        'webp' => 'image/webp',
+        'tif'  => 'image/tiff',
+        'tiff' => 'image/tiff',
+        'css'  => [
+            'text/css',
+            'text/plain',
+        ],
+        'html' => [
+            'text/html',
+            'text/plain',
+        ],
+        'htm' => [
+            'text/html',
+            'text/plain',
+        ],
+        'shtml' => [
+            'text/html',
+            'text/plain',
+        ],
+        'txt'  => 'text/plain',
+        'text' => 'text/plain',
+        'log'  => [
+            'text/plain',
+            'text/x-log',
+        ],
+        'rtx' => 'text/richtext',
+        'rtf' => 'text/rtf',
+        'xml' => [
+            'application/xml',
+            'text/xml',
+            'text/plain',
+        ],
+        'xsl' => [
+            'application/xml',
+            'text/xsl',
+            'text/xml',
+        ],
+        'mpeg' => 'video/mpeg',
+        'mpg'  => 'video/mpeg',
+        'mpe'  => 'video/mpeg',
+        'qt'   => 'video/quicktime',
+        'mov'  => 'video/quicktime',
+        'avi'  => [
+            'video/x-msvideo',
+            'video/msvideo',
+            'video/avi',
+            'application/x-troff-msvideo',
+        ],
+        'movie' => 'video/x-sgi-movie',
+        'doc'   => [
+            'application/msword',
+            'application/vnd.ms-office',
+        ],
+        'docx' => [
+            'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+            'application/zip',
+            'application/msword',
+            'application/x-zip',
+        ],
+        'dot' => [
+            'application/msword',
+            'application/vnd.ms-office',
+        ],
+        'dotx' => [
+            'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+            'application/zip',
+            'application/msword',
+        ],
+        'xlsx' => [
+            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+            'application/zip',
+            'application/vnd.ms-excel',
+            'application/msword',
+            'application/x-zip',
+        ],
+        'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
+        'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
+        'word' => [
+            'application/msword',
+            'application/octet-stream',
+        ],
+        'xl'   => 'application/excel',
+        'eml'  => 'message/rfc822',
+        'json' => [
+            'application/json',
+            'text/json',
+        ],
+        'pem' => [
+            'application/x-x509-user-cert',
+            'application/x-pem-file',
+            'application/octet-stream',
+        ],
+        'p10' => [
+            'application/x-pkcs10',
+            'application/pkcs10',
+        ],
+        'p12' => 'application/x-pkcs12',
+        'p7a' => 'application/x-pkcs7-signature',
+        'p7c' => [
+            'application/pkcs7-mime',
+            'application/x-pkcs7-mime',
+        ],
+        'p7m' => [
+            'application/pkcs7-mime',
+            'application/x-pkcs7-mime',
+        ],
+        'p7r' => 'application/x-pkcs7-certreqresp',
+        'p7s' => 'application/pkcs7-signature',
+        'crt' => [
+            'application/x-x509-ca-cert',
+            'application/x-x509-user-cert',
+            'application/pkix-cert',
+        ],
+        'crl' => [
+            'application/pkix-crl',
+            'application/pkcs-crl',
+        ],
+        'der' => 'application/x-x509-ca-cert',
+        'kdb' => 'application/octet-stream',
+        'pgp' => 'application/pgp',
+        'gpg' => 'application/gpg-keys',
+        'sst' => 'application/octet-stream',
+        'csr' => 'application/octet-stream',
+        'rsa' => 'application/x-pkcs7',
+        'cer' => [
+            'application/pkix-cert',
+            'application/x-x509-ca-cert',
+        ],
+        '3g2' => 'video/3gpp2',
+        '3gp' => [
+            'video/3gp',
+            'video/3gpp',
+        ],
+        'mp4' => 'video/mp4',
+        'm4a' => 'audio/x-m4a',
+        'f4v' => [
+            'video/mp4',
+            'video/x-f4v',
+        ],
+        'flv'  => 'video/x-flv',
+        'webm' => 'video/webm',
+        'aac'  => 'audio/x-acc',
+        'm4u'  => 'application/vnd.mpegurl',
+        'm3u'  => 'text/plain',
+        'xspf' => 'application/xspf+xml',
+        'vlc'  => 'application/videolan',
+        'wmv'  => [
+            'video/x-ms-wmv',
+            'video/x-ms-asf',
+        ],
+        'au'   => 'audio/x-au',
+        'ac3'  => 'audio/ac3',
+        'flac' => 'audio/x-flac',
+        'ogg'  => [
+            'audio/ogg',
+            'video/ogg',
+            'application/ogg',
+        ],
+        'kmz' => [
+            'application/vnd.google-earth.kmz',
+            'application/zip',
+            'application/x-zip',
+        ],
+        'kml' => [
+            'application/vnd.google-earth.kml+xml',
+            'application/xml',
+            'text/xml',
+        ],
+        'ics'  => 'text/calendar',
+        'ical' => 'text/calendar',
+        'zsh'  => 'text/x-scriptzsh',
+        '7zip' => [
+            'application/x-compressed',
+            'application/x-zip-compressed',
+            'application/zip',
+            'multipart/x-zip',
+        ],
+        'cdr' => [
+            'application/cdr',
+            'application/coreldraw',
+            'application/x-cdr',
+            'application/x-coreldraw',
+            'image/cdr',
+            'image/x-cdr',
+            'zz-application/zz-winassoc-cdr',
+        ],
+        'wma' => [
+            'audio/x-ms-wma',
+            'video/x-ms-asf',
+        ],
+        'jar' => [
+            'application/java-archive',
+            'application/x-java-application',
+            'application/x-jar',
+            'application/x-compressed',
+        ],
+        'svg' => [
+            'image/svg+xml',
+            'image/svg',
+            'application/xml',
+            'text/xml',
+        ],
+        'vcf' => 'text/x-vcard',
+        'srt' => [
+            'text/srt',
+            'text/plain',
+        ],
+        'vtt' => [
+            'text/vtt',
+            'text/plain',
+        ],
+        'ico' => [
+            'image/x-icon',
+            'image/x-ico',
+            'image/vnd.microsoft.icon',
+        ],
+        'stl' => [
+            'application/sla',
+            'application/vnd.ms-pki.stl',
+            'application/x-navistyle',
+            'model/stl',
+            'application/octet-stream',
+        ],
+    ];
+
+    /**
+     * Attempts to determine the best mime type for the given file extension.
+     *
+     * @return string|null The mime type found, or none if unable to determine.
+     */
+    public static function guessTypeFromExtension(string $extension)
+    {
+        $extension = trim(strtolower($extension), '. ');
+
+        if (! array_key_exists($extension, static::$mimes)) {
+            return null;
+        }
+
+        return is_array(static::$mimes[$extension]) ? static::$mimes[$extension][0] : static::$mimes[$extension];
+    }
+
+    /**
+     * Attempts to determine the best file extension for a given mime type.
+     *
+     * @param string|null $proposedExtension - default extension (in case there is more than one with the same mime type)
+     *
+     * @return string|null The extension determined, or null if unable to match.
+     */
+    public static function guessExtensionFromType(string $type, ?string $proposedExtension = null)
+    {
+        $type = trim(strtolower($type), '. ');
+
+        $proposedExtension = trim(strtolower($proposedExtension ?? ''));
+
+        if (
+            $proposedExtension !== ''
+            && array_key_exists($proposedExtension, static::$mimes)
+            && in_array($type, (array) static::$mimes[$proposedExtension], true)
+        ) {
+            // The detected mime type matches with the proposed extension.
+            return $proposedExtension;
+        }
+
+        // Reverse check the mime type list if no extension was proposed.
+        // This search is order sensitive!
+        foreach (static::$mimes as $ext => $types) {
+            if (in_array($type, (array) $types, true)) {
+                return $ext;
+            }
+        }
+
+        return null;
+    }
+}
diff --git a/app/Config/Modules.php b/app/Config/Modules.php
new file mode 100644
index 0000000..9e03fa4
--- /dev/null
+++ b/app/Config/Modules.php
@@ -0,0 +1,82 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Modules\Modules as BaseModules;
+
+/**
+ * Modules Configuration.
+ *
+ * NOTE: This class is required prior to Autoloader instantiation,
+ *       and does not extend BaseConfig.
+ */
+class Modules extends BaseModules
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Enable Auto-Discovery?
+     * --------------------------------------------------------------------------
+     *
+     * If true, then auto-discovery will happen across all elements listed in
+     * $aliases below. If false, no auto-discovery will happen at all,
+     * giving a slight performance boost.
+     *
+     * @var bool
+     */
+    public $enabled = true;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Enable Auto-Discovery Within Composer Packages?
+     * --------------------------------------------------------------------------
+     *
+     * If true, then auto-discovery will happen across all namespaces loaded
+     * by Composer, as well as the namespaces configured locally.
+     *
+     * @var bool
+     */
+    public $discoverInComposer = true;
+
+    /**
+     * The Composer package list for Auto-Discovery
+     * This setting is optional.
+     *
+     * E.g.:
+     *   [
+     *       'only' => [
+     *           // List up all packages to auto-discover
+     *           'codeigniter4/shield',
+     *       ],
+     *   ]
+     *   or
+     *   [
+     *       'exclude' => [
+     *           // List up packages to exclude.
+     *           'pestphp/pest',
+     *       ],
+     *   ]
+     *
+     * @var array{only?: list<string>, exclude?: list<string>}
+     */
+    public $composerPackages = [];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Auto-Discovery Rules
+     * --------------------------------------------------------------------------
+     *
+     * Aliases list of all discovery classes that will be active and used during
+     * the current application request.
+     *
+     * If it is not listed, only the base application elements will be used.
+     *
+     * @var list<string>
+     */
+    public $aliases = [
+        'events',
+        'filters',
+        'registrars',
+        'routes',
+        'services',
+    ];
+}
diff --git a/app/Config/Optimize.php b/app/Config/Optimize.php
new file mode 100644
index 0000000..8b93eb1
--- /dev/null
+++ b/app/Config/Optimize.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace Config;
+
+/**
+ * Optimization Configuration.
+ *
+ * NOTE: This class does not extend BaseConfig for performance reasons.
+ *       So you cannot replace the property values with Environment Variables.
+ *
+ * WARNING: Do not use these options when running the app in the Worker Mode.
+ */
+class Optimize
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Config Caching
+     * --------------------------------------------------------------------------
+     *
+     * @see https://codeigniter.com/user_guide/concepts/factories.html#config-caching
+     */
+    public bool $configCacheEnabled = false;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Config Caching
+     * --------------------------------------------------------------------------
+     *
+     * @see https://codeigniter.com/user_guide/concepts/autoloader.html#file-locator-caching
+     */
+    public bool $locatorCacheEnabled = false;
+}
diff --git a/app/Config/Pager.php b/app/Config/Pager.php
new file mode 100644
index 0000000..e341f4d
--- /dev/null
+++ b/app/Config/Pager.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class Pager extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Templates
+     * --------------------------------------------------------------------------
+     *
+     * Pagination links are rendered out using views to configure their
+     * appearance. This array contains aliases and the view names to
+     * use when rendering the links.
+     *
+     * Within each view, the Pager object will be available as $pager,
+     * and the desired group as $pagerGroup;
+     *
+     * @var array<string, string>
+     */
+    public array $templates = [
+        'default_full'   => 'CodeIgniter\Pager\Views\default_full',
+        'default_simple' => 'CodeIgniter\Pager\Views\default_simple',
+        'default_head'   => 'CodeIgniter\Pager\Views\default_head',
+    ];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Items Per Page
+     * --------------------------------------------------------------------------
+     *
+     * The default number of results shown in a single page.
+     */
+    public int $perPage = 20;
+}
diff --git a/app/Config/Paths.php b/app/Config/Paths.php
new file mode 100644
index 0000000..ee2d7ff
--- /dev/null
+++ b/app/Config/Paths.php
@@ -0,0 +1,90 @@
+<?php
+
+namespace Config;
+
+/**
+ * Paths
+ *
+ * Holds the paths that are used by the system to
+ * locate the main directories, app, system, etc.
+ *
+ * Modifying these allows you to restructure your application,
+ * share a system folder between multiple applications, and more.
+ *
+ * All paths are relative to the project's root folder.
+ *
+ * NOTE: This class is required prior to Autoloader instantiation,
+ *       and does not extend BaseConfig.
+ */
+class Paths
+{
+    /**
+     * ---------------------------------------------------------------
+     * SYSTEM FOLDER NAME
+     * ---------------------------------------------------------------
+     *
+     * This must contain the name of your "system" folder. Include
+     * the path if the folder is not in the same directory as this file.
+     */
+    public string $systemDirectory = __DIR__ . '/../../vendor/codeigniter4/framework/system';
+
+    /**
+     * ---------------------------------------------------------------
+     * APPLICATION FOLDER NAME
+     * ---------------------------------------------------------------
+     *
+     * If you want this front controller to use a different "app"
+     * folder than the default one you can set its name here. The folder
+     * can also be renamed or relocated anywhere on your server. If
+     * you do, use a full server path.
+     *
+     * @see http://codeigniter.com/user_guide/general/managing_apps.html
+     */
+    public string $appDirectory = __DIR__ . '/..';
+
+    /**
+     * ---------------------------------------------------------------
+     * WRITABLE DIRECTORY NAME
+     * ---------------------------------------------------------------
+     *
+     * This variable must contain the name of your "writable" directory.
+     * The writable directory allows you to group all directories that
+     * need write permission to a single place that can be tucked away
+     * for maximum security, keeping it out of the app and/or
+     * system directories.
+     */
+    public string $writableDirectory = __DIR__ . '/../../writable';
+
+    /**
+     * ---------------------------------------------------------------
+     * TESTS DIRECTORY NAME
+     * ---------------------------------------------------------------
+     *
+     * This variable must contain the name of your "tests" directory.
+     */
+    public string $testsDirectory = __DIR__ . '/../../tests';
+
+    /**
+     * ---------------------------------------------------------------
+     * VIEW DIRECTORY NAME
+     * ---------------------------------------------------------------
+     *
+     * This variable must contain the name of the directory that
+     * contains the view files used by your application. By
+     * default this is in `app/Views`. This value
+     * is used when no value is provided to `Services::renderer()`.
+     */
+    public string $viewDirectory = __DIR__ . '/../Views';
+
+    /**
+     * ---------------------------------------------------------------
+     * ENVIRONMENT DIRECTORY NAME
+     * ---------------------------------------------------------------
+     *
+     * This variable must contain the name of the directory where
+     * the .env file is located.
+     * Please consider security implications when changing this
+     * value - the directory should not be publicly accessible.
+     */
+    public string $envDirectory = __DIR__ . '/../../';
+}
diff --git a/app/Config/Publisher.php b/app/Config/Publisher.php
new file mode 100644
index 0000000..bf03be1
--- /dev/null
+++ b/app/Config/Publisher.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\Publisher as BasePublisher;
+
+/**
+ * Publisher Configuration
+ *
+ * Defines basic security restrictions for the Publisher class
+ * to prevent abuse by injecting malicious files into a project.
+ */
+class Publisher extends BasePublisher
+{
+    /**
+     * A list of allowed destinations with a (pseudo-)regex
+     * of allowed files for each destination.
+     * Attempts to publish to directories not in this list will
+     * result in a PublisherException. Files that do no fit the
+     * pattern will cause copy/merge to fail.
+     *
+     * @var array<string, string>
+     */
+    public $restrictions = [
+        ROOTPATH => '*',
+        FCPATH   => '#\.(s?css|js|map|html?|xml|json|webmanifest|ttf|eot|woff2?|gif|jpe?g|tiff?|png|webp|bmp|ico|svg)$#i',
+    ];
+}
diff --git a/app/Config/Routes.php b/app/Config/Routes.php
new file mode 100644
index 0000000..4cf109e
--- /dev/null
+++ b/app/Config/Routes.php
@@ -0,0 +1,6 @@
+<?php
+
+use CodeIgniter\Router\RouteCollection;
+
+/** @var RouteCollection $routes */
+$routes->get('/', 'Home::index');
diff --git a/app/Config/Routing.php b/app/Config/Routing.php
new file mode 100644
index 0000000..5aeee51
--- /dev/null
+++ b/app/Config/Routing.php
@@ -0,0 +1,149 @@
+<?php
+
+/**
+ * This file is part of CodeIgniter 4 framework.
+ *
+ * (c) CodeIgniter Foundation <[email protected]>
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+namespace Config;
+
+use CodeIgniter\Config\Routing as BaseRouting;
+
+/**
+ * Routing configuration
+ */
+class Routing extends BaseRouting
+{
+    /**
+     * For Defined Routes.
+     * An array of files that contain route definitions.
+     * Route files are read in order, with the first match
+     * found taking precedence.
+     *
+     * Default: APPPATH . 'Config/Routes.php'
+     *
+     * @var list<string>
+     */
+    public array $routeFiles = [
+        APPPATH . 'Config/Routes.php',
+    ];
+
+    /**
+     * For Defined Routes and Auto Routing.
+     * The default namespace to use for Controllers when no other
+     * namespace has been specified.
+     *
+     * Default: 'App\Controllers'
+     */
+    public string $defaultNamespace = 'App\Controllers';
+
+    /**
+     * For Auto Routing.
+     * The default controller to use when no other controller has been
+     * specified.
+     *
+     * Default: 'Home'
+     */
+    public string $defaultController = 'Home';
+
+    /**
+     * For Defined Routes and Auto Routing.
+     * The default method to call on the controller when no other
+     * method has been set in the route.
+     *
+     * Default: 'index'
+     */
+    public string $defaultMethod = 'index';
+
+    /**
+     * For Auto Routing.
+     * Whether to translate dashes in URIs for controller/method to underscores.
+     * Primarily useful when using the auto-routing.
+     *
+     * Default: false
+     */
+    public bool $translateURIDashes = false;
+
+    /**
+     * Sets the class/method that should be called if routing doesn't
+     * find a match. It can be the controller/method name like: Users::index
+     *
+     * This setting is passed to the Router class and handled there.
+     *
+     * If you want to use a closure, you will have to set it in the
+     * routes file by calling:
+     *
+     * $routes->set404Override(function() {
+     *    // Do something here
+     * });
+     *
+     * Example:
+     *  public $override404 = 'App\Errors::show404';
+     */
+    public ?string $override404 = null;
+
+    /**
+     * If TRUE, the system will attempt to match the URI against
+     * Controllers by matching each segment against folders/files
+     * in APPPATH/Controllers, when a match wasn't found against
+     * defined routes.
+     *
+     * If FALSE, will stop searching and do NO automatic routing.
+     */
+    public bool $autoRoute = false;
+
+    /**
+     * If TRUE, the system will look for attributes on controller
+     * class and methods that can run before and after the
+     * controller/method.
+     *
+     * If FALSE, will ignore any attributes.
+     */
+    public bool $useControllerAttributes = true;
+
+    /**
+     * For Defined Routes.
+     * If TRUE, will enable the use of the 'prioritize' option
+     * when defining routes.
+     *
+     * Default: false
+     */
+    public bool $prioritize = false;
+
+    /**
+     * For Defined Routes.
+     * If TRUE, matched multiple URI segments will be passed as one parameter.
+     *
+     * Default: false
+     */
+    public bool $multipleSegmentsOneParam = false;
+
+    /**
+     * For Auto Routing (Improved).
+     * Map of URI segments and namespaces.
+     *
+     * The key is the first URI segment. The value is the controller namespace.
+     * E.g.,
+     *   [
+     *       'blog' => 'Acme\Blog\Controllers',
+     *   ]
+     *
+     * @var array<string, string>
+     */
+    public array $moduleRoutes = [];
+
+    /**
+     * For Auto Routing (Improved).
+     * Whether to translate dashes in URIs for controller/method to CamelCase.
+     * E.g., blog-controller -> BlogController
+     *
+     * If you enable this, $translateURIDashes is ignored.
+     *
+     * Default: false
+     */
+    public bool $translateUriToCamelCase = true;
+}
diff --git a/app/Config/Security.php b/app/Config/Security.php
new file mode 100644
index 0000000..635f8b7
--- /dev/null
+++ b/app/Config/Security.php
@@ -0,0 +1,86 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class Security extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * CSRF Protection Method
+     * --------------------------------------------------------------------------
+     *
+     * Protection Method for Cross Site Request Forgery protection.
+     *
+     * @var string 'cookie' or 'session'
+     */
+    public string $csrfProtection = 'cookie';
+
+    /**
+     * --------------------------------------------------------------------------
+     * CSRF Token Randomization
+     * --------------------------------------------------------------------------
+     *
+     * Randomize the CSRF Token for added security.
+     */
+    public bool $tokenRandomize = false;
+
+    /**
+     * --------------------------------------------------------------------------
+     * CSRF Token Name
+     * --------------------------------------------------------------------------
+     *
+     * Token name for Cross Site Request Forgery protection.
+     */
+    public string $tokenName = 'csrf_test_name';
+
+    /**
+     * --------------------------------------------------------------------------
+     * CSRF Header Name
+     * --------------------------------------------------------------------------
+     *
+     * Header name for Cross Site Request Forgery protection.
+     */
+    public string $headerName = 'X-CSRF-TOKEN';
+
+    /**
+     * --------------------------------------------------------------------------
+     * CSRF Cookie Name
+     * --------------------------------------------------------------------------
+     *
+     * Cookie name for Cross Site Request Forgery protection.
+     */
+    public string $cookieName = 'csrf_cookie_name';
+
+    /**
+     * --------------------------------------------------------------------------
+     * CSRF Expires
+     * --------------------------------------------------------------------------
+     *
+     * Expiration time for Cross Site Request Forgery protection cookie.
+     *
+     * Defaults to two hours (in seconds).
+     */
+    public int $expires = 7200;
+
+    /**
+     * --------------------------------------------------------------------------
+     * CSRF Regenerate
+     * --------------------------------------------------------------------------
+     *
+     * Regenerate CSRF Token on every submission.
+     */
+    public bool $regenerate = true;
+
+    /**
+     * --------------------------------------------------------------------------
+     * CSRF Redirect
+     * --------------------------------------------------------------------------
+     *
+     * Redirect to previous page with error on failure.
+     *
+     * @see https://codeigniter4.github.io/userguide/libraries/security.html#redirection-on-failure
+     */
+    public bool $redirect = (ENVIRONMENT === 'production');
+}
diff --git a/app/Config/Services.php b/app/Config/Services.php
new file mode 100644
index 0000000..df7c8ad
--- /dev/null
+++ b/app/Config/Services.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseService;
+
+/**
+ * Services Configuration file.
+ *
+ * Services are simply other classes/libraries that the system uses
+ * to do its job. This is used by CodeIgniter to allow the core of the
+ * framework to be swapped out easily without affecting the usage within
+ * the rest of your application.
+ *
+ * This file holds any application-specific services, or service overrides
+ * that you might need. An example has been included with the general
+ * method format you should use for your service methods. For more examples,
+ * see the core Services file at system/Config/Services.php.
+ */
+class Services extends BaseService
+{
+    /*
+     * public static function example($getShared = true)
+     * {
+     *     if ($getShared) {
+     *         return static::getSharedInstance('example');
+     *     }
+     *
+     *     return new \CodeIgniter\Example();
+     * }
+     */
+}
diff --git a/app/Config/Session.php b/app/Config/Session.php
new file mode 100644
index 0000000..2491286
--- /dev/null
+++ b/app/Config/Session.php
@@ -0,0 +1,128 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use CodeIgniter\Session\Handlers\BaseHandler;
+use CodeIgniter\Session\Handlers\FileHandler;
+
+class Session extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Session Driver
+     * --------------------------------------------------------------------------
+     *
+     * The session storage driver to use:
+     * - `CodeIgniter\Session\Handlers\ArrayHandler` (for testing)
+     * - `CodeIgniter\Session\Handlers\FileHandler`
+     * - `CodeIgniter\Session\Handlers\DatabaseHandler`
+     * - `CodeIgniter\Session\Handlers\MemcachedHandler`
+     * - `CodeIgniter\Session\Handlers\RedisHandler`
+     *
+     * @var class-string<BaseHandler>
+     */
+    public string $driver = FileHandler::class;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Session Cookie Name
+     * --------------------------------------------------------------------------
+     *
+     * The session cookie name, must contain only [0-9a-z_-] characters
+     */
+    public string $cookieName = 'ci_session';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Session Expiration
+     * --------------------------------------------------------------------------
+     *
+     * The number of SECONDS you want the session to last.
+     * Setting to 0 (zero) means expire when the browser is closed.
+     */
+    public int $expiration = 7200;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Session Save Path
+     * --------------------------------------------------------------------------
+     *
+     * The location to save sessions to and is driver dependent.
+     *
+     * For the 'files' driver, it's a path to a writable directory.
+     * WARNING: Only absolute paths are supported!
+     *
+     * For the 'database' driver, it's a table name.
+     * Please read up the manual for the format with other session drivers.
+     *
+     * IMPORTANT: You are REQUIRED to set a valid save path!
+     */
+    public string $savePath = WRITEPATH . 'session';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Session Match IP
+     * --------------------------------------------------------------------------
+     *
+     * Whether to match the user's IP address when reading the session data.
+     *
+     * WARNING: If you're using the database driver, don't forget to update
+     *          your session table's PRIMARY KEY when changing this setting.
+     */
+    public bool $matchIP = false;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Session Time to Update
+     * --------------------------------------------------------------------------
+     *
+     * How many seconds between CI regenerating the session ID.
+     */
+    public int $timeToUpdate = 300;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Session Regenerate Destroy
+     * --------------------------------------------------------------------------
+     *
+     * Whether to destroy session data associated with the old session ID
+     * when auto-regenerating the session ID. When set to FALSE, the data
+     * will be later deleted by the garbage collector.
+     */
+    public bool $regenerateDestroy = false;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Session Database Group
+     * --------------------------------------------------------------------------
+     *
+     * DB Group for the database session.
+     */
+    public ?string $DBGroup = null;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Lock Retry Interval (microseconds)
+     * --------------------------------------------------------------------------
+     *
+     * This is used for RedisHandler.
+     *
+     * Time (microseconds) to wait if lock cannot be acquired.
+     * The default is 100,000 microseconds (= 0.1 seconds).
+     */
+    public int $lockRetryInterval = 100_000;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Lock Max Retries
+     * --------------------------------------------------------------------------
+     *
+     * This is used for RedisHandler.
+     *
+     * Maximum number of lock acquisition attempts.
+     * The default is 300 times. That is lock timeout is about 30 (0.1 * 300)
+     * seconds.
+     */
+    public int $lockMaxRetries = 300;
+}
diff --git a/app/Config/Toolbar.php b/app/Config/Toolbar.php
new file mode 100644
index 0000000..968653e
--- /dev/null
+++ b/app/Config/Toolbar.php
@@ -0,0 +1,147 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use CodeIgniter\Debug\Toolbar\Collectors\Database;
+use CodeIgniter\Debug\Toolbar\Collectors\Events;
+use CodeIgniter\Debug\Toolbar\Collectors\Files;
+use CodeIgniter\Debug\Toolbar\Collectors\Logs;
+use CodeIgniter\Debug\Toolbar\Collectors\Routes;
+use CodeIgniter\Debug\Toolbar\Collectors\Timers;
+use CodeIgniter\Debug\Toolbar\Collectors\Views;
+
+/**
+ * --------------------------------------------------------------------------
+ * Debug Toolbar
+ * --------------------------------------------------------------------------
+ *
+ * The Debug Toolbar provides a way to see information about the performance
+ * and state of your application during that page display. By default it will
+ * NOT be displayed under production environments, and will only display if
+ * `CI_DEBUG` is true, since if it's not, there's not much to display anyway.
+ */
+class Toolbar extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Toolbar Collectors
+     * --------------------------------------------------------------------------
+     *
+     * List of toolbar collectors that will be called when Debug Toolbar
+     * fires up and collects data from.
+     *
+     * @var list<class-string>
+     */
+    public array $collectors = [
+        Timers::class,
+        Database::class,
+        Logs::class,
+        Views::class,
+        // \CodeIgniter\Debug\Toolbar\Collectors\Cache::class,
+        Files::class,
+        Routes::class,
+        Events::class,
+    ];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Collect Var Data
+     * --------------------------------------------------------------------------
+     *
+     * If set to false var data from the views will not be collected. Useful to
+     * avoid high memory usage when there are lots of data passed to the view.
+     */
+    public bool $collectVarData = true;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Max History
+     * --------------------------------------------------------------------------
+     *
+     * `$maxHistory` sets a limit on the number of past requests that are stored,
+     * helping to conserve file space used to store them. You can set it to
+     * 0 (zero) to not have any history stored, or -1 for unlimited history.
+     */
+    public int $maxHistory = 20;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Toolbar Views Path
+     * --------------------------------------------------------------------------
+     *
+     * The full path to the the views that are used by the toolbar.
+     * This MUST have a trailing slash.
+     */
+    public string $viewsPath = SYSTEMPATH . 'Debug/Toolbar/Views/';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Max Queries
+     * --------------------------------------------------------------------------
+     *
+     * If the Database Collector is enabled, it will log every query that the
+     * the system generates so they can be displayed on the toolbar's timeline
+     * and in the query log. This can lead to memory issues in some instances
+     * with hundreds of queries.
+     *
+     * `$maxQueries` defines the maximum amount of queries that will be stored.
+     */
+    public int $maxQueries = 100;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Watched Directories
+     * --------------------------------------------------------------------------
+     *
+     * Contains an array of directories that will be watched for changes and
+     * used to determine if the hot-reload feature should reload the page or not.
+     * We restrict the values to keep performance as high as possible.
+     *
+     * NOTE: The ROOTPATH will be prepended to all values.
+     *
+     * @var list<string>
+     */
+    public array $watchedDirectories = [
+        'app',
+    ];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Watched File Extensions
+     * --------------------------------------------------------------------------
+     *
+     * Contains an array of file extensions that will be watched for changes and
+     * used to determine if the hot-reload feature should reload the page or not.
+     *
+     * @var list<string>
+     */
+    public array $watchedExtensions = [
+        'php', 'css', 'js', 'html', 'svg', 'json', 'env',
+    ];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Ignored HTTP Headers
+     * --------------------------------------------------------------------------
+     *
+     * CodeIgniter Debug Toolbar normally injects HTML and JavaScript into every
+     * HTML response. This is correct for full page loads, but it breaks requests
+     * that expect only a clean HTML fragment.
+     *
+     * Libraries like HTMX, Unpoly, and Hotwire (Turbo) update parts of the page or
+     * manage navigation on the client side. Injecting the Debug Toolbar into their
+     * responses can cause invalid HTML, duplicated scripts, or JavaScript errors
+     * (such as infinite loops or "Maximum call stack size exceeded").
+     *
+     * Any request containing one of the following headers is treated as a
+     * client-managed or partial request, and the Debug Toolbar injection is skipped.
+     *
+     * @var array<string, string|null>
+     */
+    public array $disableOnHeaders = [
+        'X-Requested-With' => 'xmlhttprequest', // AJAX requests
+        'HX-Request'       => 'true',           // HTMX requests
+        'X-Up-Version'     => null,             // Unpoly partial requests
+    ];
+}
diff --git a/app/Config/UserAgents.php b/app/Config/UserAgents.php
new file mode 100644
index 0000000..8ddfa05
--- /dev/null
+++ b/app/Config/UserAgents.php
@@ -0,0 +1,262 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+/**
+ * -------------------------------------------------------------------
+ * User Agents
+ * -------------------------------------------------------------------
+ *
+ * This file contains four arrays of user agent data. It is used by the
+ * User Agent Class to help identify browser, platform, robot, and
+ * mobile device data. The array keys are used to identify the device
+ * and the array values are used to set the actual name of the item.
+ */
+class UserAgents extends BaseConfig
+{
+    /**
+     * -------------------------------------------------------------------
+     * OS Platforms
+     * -------------------------------------------------------------------
+     *
+     * @var array<string, string>
+     */
+    public array $platforms = [
+        'windows nt 10.0' => 'Windows 10',
+        'windows nt 6.3'  => 'Windows 8.1',
+        'windows nt 6.2'  => 'Windows 8',
+        'windows nt 6.1'  => 'Windows 7',
+        'windows nt 6.0'  => 'Windows Vista',
+        'windows nt 5.2'  => 'Windows 2003',
+        'windows nt 5.1'  => 'Windows XP',
+        'windows nt 5.0'  => 'Windows 2000',
+        'windows nt 4.0'  => 'Windows NT 4.0',
+        'winnt4.0'        => 'Windows NT 4.0',
+        'winnt 4.0'       => 'Windows NT',
+        'winnt'           => 'Windows NT',
+        'windows 98'      => 'Windows 98',
+        'win98'           => 'Windows 98',
+        'windows 95'      => 'Windows 95',
+        'win95'           => 'Windows 95',
+        'windows phone'   => 'Windows Phone',
+        'windows'         => 'Unknown Windows OS',
+        'android'         => 'Android',
+        'blackberry'      => 'BlackBerry',
+        'iphone'          => 'iOS',
+        'ipad'            => 'iOS',
+        'ipod'            => 'iOS',
+        'os x'            => 'Mac OS X',
+        'ppc mac'         => 'Power PC Mac',
+        'freebsd'         => 'FreeBSD',
+        'ppc'             => 'Macintosh',
+        'linux'           => 'Linux',
+        'debian'          => 'Debian',
+        'sunos'           => 'Sun Solaris',
+        'beos'            => 'BeOS',
+        'apachebench'     => 'ApacheBench',
+        'aix'             => 'AIX',
+        'irix'            => 'Irix',
+        'osf'             => 'DEC OSF',
+        'hp-ux'           => 'HP-UX',
+        'netbsd'          => 'NetBSD',
+        'bsdi'            => 'BSDi',
+        'openbsd'         => 'OpenBSD',
+        'gnu'             => 'GNU/Linux',
+        'unix'            => 'Unknown Unix OS',
+        'symbian'         => 'Symbian OS',
+    ];
+
+    /**
+     * -------------------------------------------------------------------
+     * Browsers
+     * -------------------------------------------------------------------
+     *
+     * The order of this array should NOT be changed. Many browsers return
+     * multiple browser types so we want to identify the subtype first.
+     *
+     * @var array<string, string>
+     */
+    public array $browsers = [
+        'OPR'    => 'Opera',
+        'Flock'  => 'Flock',
+        'Edge'   => 'Spartan',
+        'Edg'    => 'Edge',
+        'Chrome' => 'Chrome',
+        // Opera 10+ always reports Opera/9.80 and appends Version/<real version> to the user agent string
+        'Opera.*?Version'   => 'Opera',
+        'Opera'             => 'Opera',
+        'MSIE'              => 'Internet Explorer',
+        'Internet Explorer' => 'Internet Explorer',
+        'Trident.* rv'      => 'Internet Explorer',
+        'Shiira'            => 'Shiira',
+        'Firefox'           => 'Firefox',
+        'Chimera'           => 'Chimera',
+        'Phoenix'           => 'Phoenix',
+        'Firebird'          => 'Firebird',
+        'Camino'            => 'Camino',
+        'Netscape'          => 'Netscape',
+        'OmniWeb'           => 'OmniWeb',
+        'Safari'            => 'Safari',
+        'Mozilla'           => 'Mozilla',
+        'Konqueror'         => 'Konqueror',
+        'icab'              => 'iCab',
+        'Lynx'              => 'Lynx',
+        'Links'             => 'Links',
+        'hotjava'           => 'HotJava',
+        'amaya'             => 'Amaya',
+        'IBrowse'           => 'IBrowse',
+        'Maxthon'           => 'Maxthon',
+        'Ubuntu'            => 'Ubuntu Web Browser',
+        'Vivaldi'           => 'Vivaldi',
+    ];
+
+    /**
+     * -------------------------------------------------------------------
+     * Mobiles
+     * -------------------------------------------------------------------
+     *
+     * @var array<string, string>
+     */
+    public array $mobiles = [
+        // legacy array, old values commented out
+        'mobileexplorer' => 'Mobile Explorer',
+        // 'openwave'             => 'Open Wave',
+        // 'opera mini'           => 'Opera Mini',
+        // 'operamini'            => 'Opera Mini',
+        // 'elaine'               => 'Palm',
+        'palmsource' => 'Palm',
+        // 'digital paths'        => 'Palm',
+        // 'avantgo'              => 'Avantgo',
+        // 'xiino'                => 'Xiino',
+        'palmscape' => 'Palmscape',
+        // 'nokia'                => 'Nokia',
+        // 'ericsson'             => 'Ericsson',
+        // 'blackberry'           => 'BlackBerry',
+        // 'motorola'             => 'Motorola'
+
+        // Phones and Manufacturers
+        'motorola'             => 'Motorola',
+        'nokia'                => 'Nokia',
+        'palm'                 => 'Palm',
+        'iphone'               => 'Apple iPhone',
+        'ipad'                 => 'iPad',
+        'ipod'                 => 'Apple iPod Touch',
+        'sony'                 => 'Sony Ericsson',
+        'ericsson'             => 'Sony Ericsson',
+        'blackberry'           => 'BlackBerry',
+        'cocoon'               => 'O2 Cocoon',
+        'blazer'               => 'Treo',
+        'lg'                   => 'LG',
+        'amoi'                 => 'Amoi',
+        'xda'                  => 'XDA',
+        'mda'                  => 'MDA',
+        'vario'                => 'Vario',
+        'htc'                  => 'HTC',
+        'samsung'              => 'Samsung',
+        'sharp'                => 'Sharp',
+        'sie-'                 => 'Siemens',
+        'alcatel'              => 'Alcatel',
+        'benq'                 => 'BenQ',
+        'ipaq'                 => 'HP iPaq',
+        'mot-'                 => 'Motorola',
+        'playstation portable' => 'PlayStation Portable',
+        'playstation 3'        => 'PlayStation 3',
+        'playstation vita'     => 'PlayStation Vita',
+        'hiptop'               => 'Danger Hiptop',
+        'nec-'                 => 'NEC',
+        'panasonic'            => 'Panasonic',
+        'philips'              => 'Philips',
+        'sagem'                => 'Sagem',
+        'sanyo'                => 'Sanyo',
+        'spv'                  => 'SPV',
+        'zte'                  => 'ZTE',
+        'sendo'                => 'Sendo',
+        'nintendo dsi'         => 'Nintendo DSi',
+        'nintendo ds'          => 'Nintendo DS',
+        'nintendo 3ds'         => 'Nintendo 3DS',
+        'wii'                  => 'Nintendo Wii',
+        'open web'             => 'Open Web',
+        'openweb'              => 'OpenWeb',
+
+        // Operating Systems
+        'android'    => 'Android',
+        'symbian'    => 'Symbian',
+        'SymbianOS'  => 'SymbianOS',
+        'elaine'     => 'Palm',
+        'series60'   => 'Symbian S60',
+        'windows ce' => 'Windows CE',
+
+        // Browsers
+        'obigo'         => 'Obigo',
+        'netfront'      => 'Netfront Browser',
+        'openwave'      => 'Openwave Browser',
+        'mobilexplorer' => 'Mobile Explorer',
+        'operamini'     => 'Opera Mini',
+        'opera mini'    => 'Opera Mini',
+        'opera mobi'    => 'Opera Mobile',
+        'fennec'        => 'Firefox Mobile',
+
+        // Other
+        'digital paths' => 'Digital Paths',
+        'avantgo'       => 'AvantGo',
+        'xiino'         => 'Xiino',
+        'novarra'       => 'Novarra Transcoder',
+        'vodafone'      => 'Vodafone',
+        'docomo'        => 'NTT DoCoMo',
+        'o2'            => 'O2',
+
+        // Fallback
+        'mobile'     => 'Generic Mobile',
+        'wireless'   => 'Generic Mobile',
+        'j2me'       => 'Generic Mobile',
+        'midp'       => 'Generic Mobile',
+        'cldc'       => 'Generic Mobile',
+        'up.link'    => 'Generic Mobile',
+        'up.browser' => 'Generic Mobile',
+        'smartphone' => 'Generic Mobile',
+        'cellphone'  => 'Generic Mobile',
+    ];
+
+    /**
+     * -------------------------------------------------------------------
+     * Robots
+     * -------------------------------------------------------------------
+     *
+     * There are hundred of bots but these are the most common.
+     *
+     * @var array<string, string>
+     */
+    public array $robots = [
+        'googlebot'            => 'Googlebot',
+        'google-pagerenderer'  => 'Google Page Renderer',
+        'google-read-aloud'    => 'Google Read Aloud',
+        'google-safety'        => 'Google Safety Bot',
+        'msnbot'               => 'MSNBot',
+        'baiduspider'          => 'Baiduspider',
+        'bingbot'              => 'Bing',
+        'bingpreview'          => 'BingPreview',
+        'slurp'                => 'Inktomi Slurp',
+        'yahoo'                => 'Yahoo',
+        'ask jeeves'           => 'Ask Jeeves',
+        'fastcrawler'          => 'FastCrawler',
+        'infoseek'             => 'InfoSeek Robot 1.0',
+        'lycos'                => 'Lycos',
+        'yandex'               => 'YandexBot',
+        'mediapartners-google' => 'MediaPartners Google',
+        'CRAZYWEBCRAWLER'      => 'Crazy Webcrawler',
+        'adsbot-google'        => 'AdsBot Google',
+        'feedfetcher-google'   => 'Feedfetcher Google',
+        'curious george'       => 'Curious George',
+        'ia_archiver'          => 'Alexa Crawler',
+        'MJ12bot'              => 'Majestic-12',
+        'Uptimebot'            => 'Uptimebot',
+        'duckduckbot'          => 'DuckDuckBot',
+        'sogou'                => 'Sogou Spider',
+        'exabot'               => 'Exabot',
+        'bot'                  => 'Generic Bot',
+        'crawler'              => 'Generic Crawler',
+        'spider'               => 'Generic Spider',
+    ];
+}
diff --git a/app/Config/Validation.php b/app/Config/Validation.php
new file mode 100644
index 0000000..6342dbb
--- /dev/null
+++ b/app/Config/Validation.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use CodeIgniter\Validation\StrictRules\CreditCardRules;
+use CodeIgniter\Validation\StrictRules\FileRules;
+use CodeIgniter\Validation\StrictRules\FormatRules;
+use CodeIgniter\Validation\StrictRules\Rules;
+
+class Validation extends BaseConfig
+{
+    // --------------------------------------------------------------------
+    // Setup
+    // --------------------------------------------------------------------
+
+    /**
+     * Stores the classes that contain the
+     * rules that are available.
+     *
+     * @var list<string>
+     */
+    public array $ruleSets = [
+        Rules::class,
+        FormatRules::class,
+        FileRules::class,
+        CreditCardRules::class,
+    ];
+
+    /**
+     * Specifies the views that are used to display the
+     * errors.
+     *
+     * @var array<string, string>
+     */
+    public array $templates = [
+        'list'   => 'CodeIgniter\Validation\Views\list',
+        'single' => 'CodeIgniter\Validation\Views\single',
+    ];
+
+    // --------------------------------------------------------------------
+    // Rules
+    // --------------------------------------------------------------------
+}
diff --git a/app/Config/View.php b/app/Config/View.php
new file mode 100644
index 0000000..b52d980
--- /dev/null
+++ b/app/Config/View.php
@@ -0,0 +1,73 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\View as BaseView;
+use CodeIgniter\View\ViewDecoratorInterface;
+
+class View extends BaseView
+{
+    /**
+     * When false, the view method will clear the data between each
+     * call. This keeps your data safe and ensures there is no accidental
+     * leaking between calls, so you would need to explicitly pass the data
+     * to each view. You might prefer to have the data stick around between
+     * calls so that it is available to all views. If that is the case,
+     * set $saveData to true.
+     *
+     * @var bool
+     */
+    public $saveData = true;
+
+    /**
+     * Parser Filters map a filter name with any PHP callable. When the
+     * Parser prepares a variable for display, it will chain it
+     * through the filters in the order defined, inserting any parameters.
+     * To prevent potential abuse, all filters MUST be defined here
+     * in order for them to be available for use within the Parser.
+     *
+     * Examples:
+     *  { title|esc(js) }
+     *  { created_on|date(Y-m-d)|esc(attr) }
+     *
+     * @var array<string, (callable(mixed): mixed)&string>
+     */
+    public $filters = [];
+
+    /**
+     * Parser Plugins provide a way to extend the functionality provided
+     * by the core Parser by creating aliases that will be replaced with
+     * any callable. Can be single or tag pair.
+     *
+     * @var array<string, (callable(mixed...): mixed)|((callable(mixed...): mixed)&string)|list<(callable(mixed...): mixed)&string>>
+     */
+    public $plugins = [];
+
+    /**
+     * View Decorators are class methods that will be run in sequence to
+     * have a chance to alter the generated output just prior to caching
+     * the results.
+     *
+     * All classes must implement CodeIgniter\View\ViewDecoratorInterface
+     *
+     * @var list<class-string<ViewDecoratorInterface>>
+     */
+    public array $decorators = [];
+
+    /**
+     * Subdirectory within app/Views for namespaced view overrides.
+     *
+     * Namespaced views will be searched in:
+     *
+     *   app/Views/{$appOverridesFolder}/{Namespace}/{view_path}.{php|html...}
+     *
+     * This allows application-level overrides for package or module views
+     * without modifying vendor source files.
+     *
+     * Examples:
+     *   'overrides' -> app/Views/overrides/Example/Blog/post/card.php
+     *   'vendor'    -> app/Views/vendor/Example/Blog/post/card.php
+     *   ''          -> app/Views/Example/Blog/post/card.php (direct mapping)
+     */
+    public string $appOverridesFolder = 'overrides';
+}
diff --git a/app/Config/WorkerMode.php b/app/Config/WorkerMode.php
new file mode 100644
index 0000000..fd8b494
--- /dev/null
+++ b/app/Config/WorkerMode.php
@@ -0,0 +1,62 @@
+<?php
+
+namespace Config;
+
+/**
+ * This configuration controls how CodeIgniter behaves when running
+ * in worker mode (with FrankenPHP).
+ */
+class WorkerMode
+{
+    /**
+     * Persistent Services
+     *
+     * List of service names that should persist across requests.
+     * These services will NOT be reset between requests.
+     *
+     * Services not in this list will be reset for each request to prevent
+     * state leakage.
+     *
+     * Recommended persistent services:
+     * - `autoloader`: PSR-4 autoloading configuration
+     * - `locator`: File locator
+     * - `exceptions`: Exception handler
+     * - `commands`: CLI commands registry
+     * - `codeigniter`: Main application instance
+     * - `superglobals`: Superglobals wrapper
+     * - `routes`: Router configuration
+     * - `cache`: Cache instance
+     *
+     * @var list<string>
+     */
+    public array $persistentServices = [
+        'autoloader',
+        'locator',
+        'exceptions',
+        'commands',
+        'codeigniter',
+        'superglobals',
+        'routes',
+        'cache',
+    ];
+
+    /**
+     * Reset Event Listeners
+     *
+     * List of event names whose listeners should be removed between requests.
+     * Use this if you register event listeners inside other event callbacks
+     * (rather than at the top level of Config/Events.php), which would cause
+     * them to accumulate across requests in worker mode.
+     *
+     * @var list<string>
+     */
+    public array $resetEventListeners = [];
+
+    /**
+     * Force Garbage Collection
+     *
+     * Whether to force garbage collection after each request.
+     * Helps prevent memory leaks at a small performance cost.
+     */
+    public bool $forceGarbageCollection = true;
+}
diff --git a/app/Controllers/BaseController.php b/app/Controllers/BaseController.php
new file mode 100644
index 0000000..ab45a77
--- /dev/null
+++ b/app/Controllers/BaseController.php
@@ -0,0 +1,45 @@
+<?php
+
+namespace App\Controllers;
+
+use CodeIgniter\Controller;
+use CodeIgniter\HTTP\RequestInterface;
+use CodeIgniter\HTTP\ResponseInterface;
+use Psr\Log\LoggerInterface;
+
+/**
+ * BaseController provides a convenient place for loading components
+ * and performing functions that are needed by all your controllers.
+ *
+ * Extend this class in any new controllers:
+ * ```
+ *     class Home extends BaseController
+ * ```
+ *
+ * For security, be sure to declare any new methods as protected or private.
+ */
+abstract class BaseController extends Controller
+{
+    /**
+     * Be sure to declare properties for any property fetch you initialized.
+     * The creation of dynamic property is deprecated in PHP 8.2.
+     */
+
+    // protected $session;
+
+    /**
+     * @return void
+     */
+    public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
+    {
+        // Load here all helpers you want to be available in your controllers that extend BaseController.
+        // Caution: Do not put the this below the parent::initController() call below.
+        // $this->helpers = ['form', 'url'];
+
+        // Caution: Do not edit this line.
+        parent::initController($request, $response, $logger);
+
+        // Preload any models, libraries, etc, here.
+        // $this->session = service('session');
+    }
+}
diff --git a/app/Controllers/Home.php b/app/Controllers/Home.php
new file mode 100644
index 0000000..5934333
--- /dev/null
+++ b/app/Controllers/Home.php
@@ -0,0 +1,11 @@
+<?php
+
+namespace App\Controllers;
+
+class Home extends BaseController
+{
+    public function index(): string
+    {
+        return view('welcome_message');
+    }
+}
diff --git a/app/Database/Migrations/.gitkeep b/app/Database/Migrations/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/Database/Seeds/.gitkeep b/app/Database/Seeds/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/Filters/.gitkeep b/app/Filters/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/Helpers/.gitkeep b/app/Helpers/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/Language/.gitkeep b/app/Language/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/Language/en/Validation.php b/app/Language/en/Validation.php
new file mode 100644
index 0000000..54d1e7a
--- /dev/null
+++ b/app/Language/en/Validation.php
@@ -0,0 +1,4 @@
+<?php
+
+// override core en language system validation or define your own en language validation message
+return [];
diff --git a/app/Libraries/.gitkeep b/app/Libraries/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/Models/.gitkeep b/app/Models/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/ThirdParty/.gitkeep b/app/ThirdParty/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/Views/errors/cli/error_404.php b/app/Views/errors/cli/error_404.php
new file mode 100644
index 0000000..456ea3e
--- /dev/null
+++ b/app/Views/errors/cli/error_404.php
@@ -0,0 +1,7 @@
+<?php
+
+use CodeIgniter\CLI\CLI;
+
+CLI::error('ERROR: ' . $code);
+CLI::write($message);
+CLI::newLine();
diff --git a/app/Views/errors/cli/error_exception.php b/app/Views/errors/cli/error_exception.php
new file mode 100644
index 0000000..624f3b5
--- /dev/null
+++ b/app/Views/errors/cli/error_exception.php
@@ -0,0 +1,65 @@
+<?php
+
+use CodeIgniter\CLI\CLI;
+
+// The main Exception
+CLI::write('[' . $exception::class . ']', 'light_gray', 'red');
+CLI::write($message);
+CLI::write('at ' . CLI::color(clean_path($exception->getFile()) . ':' . $exception->getLine(), 'green'));
+CLI::newLine();
+
+$last = $exception;
+
+while ($prevException = $last->getPrevious()) {
+    $last = $prevException;
+
+    CLI::write('  Caused by:');
+    CLI::write('  [' . $prevException::class . ']', 'red');
+    CLI::write('  ' . $prevException->getMessage());
+    CLI::write('  at ' . CLI::color(clean_path($prevException->getFile()) . ':' . $prevException->getLine(), 'green'));
+    CLI::newLine();
+}
+
+// The backtrace
+if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE) {
+    $backtraces = $last->getTrace();
+
+    if ($backtraces) {
+        CLI::write('Backtrace:', 'green');
+    }
+
+    foreach ($backtraces as $i => $error) {
+        $padFile  = '    '; // 4 spaces
+        $padClass = '       '; // 7 spaces
+        $c        = str_pad($i + 1, 3, ' ', STR_PAD_LEFT);
+
+        if (isset($error['file'])) {
+            $filepath = clean_path($error['file']) . ':' . $error['line'];
+
+            CLI::write($c . $padFile . CLI::color($filepath, 'yellow'));
+        } else {
+            CLI::write($c . $padFile . CLI::color('[internal function]', 'yellow'));
+        }
+
+        $function = '';
+
+        if (isset($error['class'])) {
+            $type = ($error['type'] === '->') ? '()' . $error['type'] : $error['type'];
+            $function .= $padClass . $error['class'] . $type . $error['function'];
+        } elseif (! isset($error['class']) && isset($error['function'])) {
+            $function .= $padClass . $error['function'];
+        }
+
+        $args = implode(', ', array_map(static fn ($value): string => match (true) {
+            is_object($value) => 'Object(' . $value::class . ')',
+            is_array($value)  => $value !== [] ? '[...]' : '[]',
+            $value === null   => 'null', // return the lowercased version
+            default           => var_export($value, true),
+        }, array_values($error['args'] ?? [])));
+
+        $function .= '(' . $args . ')';
+
+        CLI::write($function);
+        CLI::newLine();
+    }
+}
diff --git a/app/Views/errors/cli/production.php b/app/Views/errors/cli/production.php
new file mode 100644
index 0000000..7db744e
--- /dev/null
+++ b/app/Views/errors/cli/production.php
@@ -0,0 +1,5 @@
+<?php
+
+// On the CLI, we still want errors in productions
+// so just use the exception template.
+include __DIR__ . '/error_exception.php';
diff --git a/app/Views/errors/html/debug.css b/app/Views/errors/html/debug.css
new file mode 100644
index 0000000..b8539a4
--- /dev/null
+++ b/app/Views/errors/html/debug.css
@@ -0,0 +1,194 @@
+:root {
+    --main-bg-color: #fff;
+    --main-text-color: #555;
+    --dark-text-color: #222;
+    --light-text-color: #c7c7c7;
+    --brand-primary-color: #DC4814;
+    --light-bg-color: #ededee;
+    --dark-bg-color: #404040;
+}
+
+body {
+    height: 100%;
+    background: var(--main-bg-color);
+    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
+    color: var(--main-text-color);
+    font-weight: 300;
+    margin: 0;
+    padding: 0;
+}
+h1 {
+    font-weight: lighter;
+    font-size: 3rem;
+    color: var(--dark-text-color);
+    margin: 0;
+}
+h1.headline {
+    margin-top: 20%;
+    font-size: 5rem;
+}
+.text-center {
+    text-align: center;
+}
+p.lead {
+    font-size: 1.6rem;
+}
+.container {
+    max-width: 75rem;
+    margin: 0 auto;
+    padding: 1rem;
+}
+.header {
+    background: var(--light-bg-color);
+    color: var(--dark-text-color);
+    margin-top: 2.17rem;
+}
+.header .container {
+    padding: 1rem;
+}
+.header h1 {
+    font-size: 2.5rem;
+    font-weight: 500;
+}
+.header p {
+    font-size: 1.2rem;
+    margin: 0;
+    line-height: 2.5;
+}
+.header a {
+    color: var(--brand-primary-color);
+    margin-left: 2rem;
+    display: none;
+    text-decoration: none;
+}
+.header:hover a {
+    display: inline;
+}
+
+.environment {
+    background: var(--brand-primary-color);
+    color: var(--main-bg-color);
+    text-align: center;
+    padding: calc(4px + 0.2083vw);
+    width: 100%;
+    top: 0;
+    position: fixed;
+}
+
+.source {
+    background: #343434;
+    color: var(--light-text-color);
+    padding: 0.5em 1em;
+    border-radius: 5px;
+    font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
+    font-size: 0.85rem;
+    margin: 0;
+    overflow-x: scroll;
+}
+.source span.line {
+    line-height: 1.4;
+}
+.source span.line .number {
+    color: #666;
+}
+.source .line .highlight {
+    display: block;
+    background: var(--dark-text-color);
+    color: var(--light-text-color);
+}
+.source span.highlight .number {
+    color: #fff;
+}
+
+.tabs {
+    list-style: none;
+    list-style-position: inside;
+    margin: 0;
+    padding: 0;
+    margin-bottom: -1px;
+}
+.tabs li {
+    display: inline;
+}
+.tabs a:link,
+.tabs a:visited {
+    padding: 0 1rem;
+    line-height: 2.7;
+    text-decoration: none;
+    color: var(--dark-text-color);
+    background: var(--light-bg-color);
+    border: 1px solid rgba(0,0,0,0.15);
+    border-bottom: 0;
+    border-top-left-radius: 5px;
+    border-top-right-radius: 5px;
+    display: inline-block;
+}
+.tabs a:hover {
+    background: var(--light-bg-color);
+    border-color: rgba(0,0,0,0.15);
+}
+.tabs a.active {
+    background: var(--main-bg-color);
+    color: var(--main-text-color);
+}
+.tab-content {
+    background: var(--main-bg-color);
+    border: 1px solid rgba(0,0,0,0.15);
+}
+.content {
+    padding: 1rem;
+}
+.hide {
+    display: none;
+}
+
+.alert {
+    margin-top: 2rem;
+    display: block;
+    text-align: center;
+    line-height: 3.0;
+    background: #d9edf7;
+    border: 1px solid #bcdff1;
+    border-radius: 5px;
+    color: #31708f;
+}
+
+table {
+    width: 100%;
+    overflow: hidden;
+}
+th {
+    text-align: left;
+    border-bottom: 1px solid #e7e7e7;
+    padding-bottom: 0.5rem;
+}
+td {
+    padding: 0.2rem 0.5rem 0.2rem 0;
+}
+tr:hover td {
+    background: #f1f1f1;
+}
+td pre {
+    white-space: pre-wrap;
+}
+
+.trace a {
+    color: inherit;
+}
+.trace table {
+    width: auto;
+}
+.trace tr td:first-child {
+    min-width: 5em;
+    font-weight: bold;
+}
+.trace td {
+    background: var(--light-bg-color);
+    padding: 0 1rem;
+}
+.trace td pre {
+    margin: 0;
+}
+.args {
+    display: none;
+}
diff --git a/app/Views/errors/html/debug.js b/app/Views/errors/html/debug.js
new file mode 100644
index 0000000..99199ca
--- /dev/null
+++ b/app/Views/errors/html/debug.js
@@ -0,0 +1,116 @@
+var tabLinks    = new Array();
+var contentDivs = new Array();
+
+function init()
+{
+    // Grab the tab links and content divs from the page
+    var tabListItems = document.getElementById('tabs').childNodes;
+    console.log(tabListItems);
+    for (var i = 0; i < tabListItems.length; i ++)
+    {
+        if (tabListItems[i].nodeName == "LI")
+        {
+            var tabLink     = getFirstChildWithTagName(tabListItems[i], 'A');
+            var id          = getHash(tabLink.getAttribute('href'));
+            tabLinks[id]    = tabLink;
+            contentDivs[id] = document.getElementById(id);
+        }
+    }
+
+    // Assign onclick events to the tab links, and
+    // highlight the first tab
+    var i = 0;
+
+    for (var id in tabLinks)
+    {
+        tabLinks[id].onclick = showTab;
+        tabLinks[id].onfocus = function () {
+            this.blur()
+        };
+        if (i == 0)
+        {
+            tabLinks[id].className = 'active';
+        }
+        i ++;
+    }
+
+    // Hide all content divs except the first
+    var i = 0;
+
+    for (var id in contentDivs)
+    {
+        if (i != 0)
+        {
+            console.log(contentDivs[id]);
+            contentDivs[id].className = 'content hide';
+        }
+        i ++;
+    }
+}
+
+function showTab()
+{
+    var selectedId = getHash(this.getAttribute('href'));
+
+    // Highlight the selected tab, and dim all others.
+    // Also show the selected content div, and hide all others.
+    for (var id in contentDivs)
+    {
+        if (id == selectedId)
+        {
+            tabLinks[id].className    = 'active';
+            contentDivs[id].className = 'content';
+        }
+        else
+        {
+            tabLinks[id].className    = '';
+            contentDivs[id].className = 'content hide';
+        }
+    }
+
+    // Stop the browser following the link
+    return false;
+}
+
+function getFirstChildWithTagName(element, tagName)
+{
+    for (var i = 0; i < element.childNodes.length; i ++)
+    {
+        if (element.childNodes[i].nodeName == tagName)
+        {
+            return element.childNodes[i];
+        }
+    }
+}
+
+function getHash(url)
+{
+    var hashPos = url.lastIndexOf('#');
+    return url.substring(hashPos + 1);
+}
+
+function toggle(elem)
+{
+    elem = document.getElementById(elem);
+
+    if (elem.style && elem.style['display'])
+    {
+        // Only works with the "style" attr
+        var disp = elem.style['display'];
+    }
+    else if (elem.currentStyle)
+    {
+        // For MSIE, naturally
+        var disp = elem.currentStyle['display'];
+    }
+    else if (window.getComputedStyle)
+    {
+        // For most other browsers
+        var disp = document.defaultView.getComputedStyle(elem, null).getPropertyValue('display');
+    }
+
+    // Toggle the state of the "display" style
+    elem.style.display = disp == 'block' ? 'none' : 'block';
+
+    return false;
+}
diff --git a/app/Views/errors/html/error_400.php b/app/Views/errors/html/error_400.php
new file mode 100644
index 0000000..555da04
--- /dev/null
+++ b/app/Views/errors/html/error_400.php
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <title><?= lang('Errors.badRequest') ?></title>
+
+    <style>
+        div.logo {
+            height: 200px;
+            width: 155px;
+            display: inline-block;
+            opacity: 0.08;
+            position: absolute;
+            top: 2rem;
+            left: 50%;
+            margin-left: -73px;
+        }
+        body {
+            height: 100%;
+            background: #fafafa;
+            font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+            color: #777;
+            font-weight: 300;
+        }
+        h1 {
+            font-weight: lighter;
+            letter-spacing: normal;
+            font-size: 3rem;
+            margin-top: 0;
+            margin-bottom: 0;
+            color: #222;
+        }
+        .wrap {
+            max-width: 1024px;
+            margin: 5rem auto;
+            padding: 2rem;
+            background: #fff;
+            text-align: center;
+            border: 1px solid #efefef;
+            border-radius: 0.5rem;
+            position: relative;
+        }
+        pre {
+            white-space: normal;
+            margin-top: 1.5rem;
+        }
+        code {
+            background: #fafafa;
+            border: 1px solid #efefef;
+            padding: 0.5rem 1rem;
+            border-radius: 5px;
+            display: block;
+        }
+        p {
+            margin-top: 1.5rem;
+        }
+        .footer {
+            margin-top: 2rem;
+            border-top: 1px solid #efefef;
+            padding: 1em 2em 0 2em;
+            font-size: 85%;
+            color: #999;
+        }
+        a:active,
+        a:link,
+        a:visited {
+            color: #dd4814;
+        }
+    </style>
+</head>
+<body>
+<div class="wrap">
+    <h1>400</h1>
+
+    <p>
+        <?php if (ENVIRONMENT !== 'production') : ?>
+            <?= nl2br(esc($message)) ?>
+        <?php else : ?>
+            <?= lang('Errors.sorryBadRequest') ?>
+        <?php endif; ?>
+    </p>
+</div>
+</body>
+</html>
diff --git a/app/Views/errors/html/error_404.php b/app/Views/errors/html/error_404.php
new file mode 100644
index 0000000..e506f08
--- /dev/null
+++ b/app/Views/errors/html/error_404.php
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <title><?= lang('Errors.pageNotFound') ?></title>
+
+    <style>
+        div.logo {
+            height: 200px;
+            width: 155px;
+            display: inline-block;
+            opacity: 0.08;
+            position: absolute;
+            top: 2rem;
+            left: 50%;
+            margin-left: -73px;
+        }
+        body {
+            height: 100%;
+            background: #fafafa;
+            font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+            color: #777;
+            font-weight: 300;
+        }
+        h1 {
+            font-weight: lighter;
+            letter-spacing: normal;
+            font-size: 3rem;
+            margin-top: 0;
+            margin-bottom: 0;
+            color: #222;
+        }
+        .wrap {
+            max-width: 1024px;
+            margin: 5rem auto;
+            padding: 2rem;
+            background: #fff;
+            text-align: center;
+            border: 1px solid #efefef;
+            border-radius: 0.5rem;
+            position: relative;
+        }
+        pre {
+            white-space: normal;
+            margin-top: 1.5rem;
+        }
+        code {
+            background: #fafafa;
+            border: 1px solid #efefef;
+            padding: 0.5rem 1rem;
+            border-radius: 5px;
+            display: block;
+        }
+        p {
+            margin-top: 1.5rem;
+        }
+        .footer {
+            margin-top: 2rem;
+            border-top: 1px solid #efefef;
+            padding: 1em 2em 0 2em;
+            font-size: 85%;
+            color: #999;
+        }
+        a:active,
+        a:link,
+        a:visited {
+            color: #dd4814;
+        }
+    </style>
+</head>
+<body>
+    <div class="wrap">
+        <h1>404</h1>
+
+        <p>
+            <?php if (ENVIRONMENT !== 'production') : ?>
+                <?= nl2br(esc($message)) ?>
+            <?php else : ?>
+                <?= lang('Errors.sorryCannotFind') ?>
+            <?php endif; ?>
+        </p>
+    </div>
+</body>
+</html>
diff --git a/app/Views/errors/html/error_exception.php b/app/Views/errors/html/error_exception.php
new file mode 100644
index 0000000..6e54b13
--- /dev/null
+++ b/app/Views/errors/html/error_exception.php
@@ -0,0 +1,429 @@
+<?php
+use CodeIgniter\CodeIgniter;
+use CodeIgniter\HTTP\Header;
+
+$errorId = uniqid('error', true);
+?>
+<!doctype html>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <meta name="robots" content="noindex">
+
+    <title><?= esc($title) ?></title>
+    <style>
+        <?= preg_replace('#[\r\n\t ]+#', ' ', file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.css')) ?>
+    </style>
+
+    <script>
+        <?= file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.js') ?>
+    </script>
+</head>
+<body onload="init()">
+
+    <!-- Header -->
+    <div class="header">
+        <div class="environment">
+            Displayed at <?= esc(date('H:i:s')) ?> &mdash;
+            PHP: <?= esc(PHP_VERSION) ?>  &mdash;
+            CodeIgniter: <?= esc(CodeIgniter::CI_VERSION) ?> --
+            Environment: <?= ENVIRONMENT ?>
+        </div>
+        <div class="container">
+            <h1><?= esc($title), esc($exception->getCode() ? ' #' . $exception->getCode() : '') ?></h1>
+            <p>
+                <?= nl2br(esc($exception->getMessage())) ?>
+                <a href="https://www.duckduckgo.com/?q=<?= urlencode($title . ' ' . preg_replace('#\'.*\'|".*"#Us', '', $exception->getMessage())) ?>"
+                   rel="noreferrer" target="_blank">search &rarr;</a>
+            </p>
+        </div>
+    </div>
+
+    <!-- Source -->
+    <div class="container">
+        <p><b><?= esc(clean_path($file)) ?></b> at line <b><?= esc($line) ?></b></p>
+
+        <?php if (is_file($file)) : ?>
+            <div class="source">
+                <?= static::highlightFile($file, $line, 15); ?>
+            </div>
+        <?php endif; ?>
+    </div>
+
+    <div class="container">
+        <?php
+        $last = $exception;
+
+while ($prevException = $last->getPrevious()) {
+    $last = $prevException;
+    ?>
+
+    <pre>
+    Caused by:
+    <?= esc($prevException::class), esc($prevException->getCode() ? ' #' . $prevException->getCode() : '') ?>
+
+    <?= nl2br(esc($prevException->getMessage())) ?>
+    <a href="https://www.duckduckgo.com/?q=<?= urlencode($prevException::class . ' ' . preg_replace('#\'.*\'|".*"#Us', '', $prevException->getMessage())) ?>"
+       rel="noreferrer" target="_blank">search &rarr;</a>
+    <?= esc(clean_path($prevException->getFile()) . ':' . $prevException->getLine()) ?>
+    </pre>
+
+        <?php
+}
+?>
+    </div>
+
+    <?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE) : ?>
+    <div class="container">
+
+        <ul class="tabs" id="tabs">
+            <li><a href="#backtrace">Backtrace</a></li>
+            <li><a href="#server">Server</a></li>
+            <li><a href="#request">Request</a></li>
+            <li><a href="#response">Response</a></li>
+            <li><a href="#files">Files</a></li>
+            <li><a href="#memory">Memory</a></li>
+        </ul>
+
+        <div class="tab-content">
+
+            <!-- Backtrace -->
+            <div class="content" id="backtrace">
+
+                <ol class="trace">
+                <?php foreach ($trace as $index => $row) : ?>
+
+                    <li>
+                        <p>
+                            <!-- Trace info -->
+                            <?php if (isset($row['file']) && is_file($row['file'])) : ?>
+                                <?php
+                        if (isset($row['function']) && in_array($row['function'], ['include', 'include_once', 'require', 'require_once'], true)) {
+                            echo esc($row['function'] . ' ' . clean_path($row['file']));
+                        } else {
+                            echo esc(clean_path($row['file']) . ' : ' . $row['line']);
+                        }
+                    ?>
+                            <?php else: ?>
+                                {PHP internal code}
+                            <?php endif; ?>
+
+                            <!-- Class/Method -->
+                            <?php if (isset($row['class'])) : ?>
+                                &nbsp;&nbsp;&mdash;&nbsp;&nbsp;<?= esc($row['class'] . $row['type'] . $row['function']) ?>
+                                <?php if (! empty($row['args'])) : ?>
+                                    <?php $argsId = $errorId . 'args' . $index ?>
+                                    ( <a href="#" onclick="return toggle('<?= esc($argsId, 'attr') ?>');">arguments</a> )
+                                    <div class="args" id="<?= esc($argsId, 'attr') ?>">
+                                        <table cellspacing="0">
+
+                                        <?php
+                            $params = null;
+                                    // Reflection by name is not available for closure function
+                                    if (! str_ends_with($row['function'], '}')) {
+                                        $mirror = isset($row['class']) ? new ReflectionMethod($row['class'], $row['function']) : new ReflectionFunction($row['function']);
+                                        $params = $mirror->getParameters();
+                                    }
+
+                                    foreach ($row['args'] as $key => $value) : ?>
+                                            <tr>
+                                                <td><code><?= esc(isset($params[$key]) ? '$' . $params[$key]->name : "#{$key}") ?></code></td>
+                                                <td><pre><?= esc(print_r($value, true)) ?></pre></td>
+                                            </tr>
+                                        <?php endforeach ?>
+
+                                        </table>
+                                    </div>
+                                <?php else : ?>
+                                    ()
+                                <?php endif; ?>
+                            <?php endif; ?>
+
+                            <?php if (! isset($row['class']) && isset($row['function'])) : ?>
+                                &nbsp;&nbsp;&mdash;&nbsp;&nbsp;    <?= esc($row['function']) ?>()
+                            <?php endif; ?>
+                        </p>
+
+                        <!-- Source? -->
+                        <?php if (isset($row['file']) && is_file($row['file']) && isset($row['class'])) : ?>
+                            <div class="source">
+                                <?= static::highlightFile($row['file'], $row['line']) ?>
+                            </div>
+                        <?php endif; ?>
+                    </li>
+
+                <?php endforeach; ?>
+                </ol>
+
+            </div>
+
+            <!-- Server -->
+            <div class="content" id="server">
+                <?php foreach (['_SERVER', '_SESSION'] as $var) : ?>
+                    <?php
+                    if (empty($GLOBALS[$var]) || ! is_array($GLOBALS[$var])) {
+                        continue;
+                    } ?>
+
+                    <h3>$<?= esc($var) ?></h3>
+
+                    <table>
+                        <thead>
+                            <tr>
+                                <th>Key</th>
+                                <th>Value</th>
+                            </tr>
+                        </thead>
+                        <tbody>
+                        <?php foreach ($GLOBALS[$var] as $key => $value) : ?>
+                            <tr>
+                                <td><?= esc($key) ?></td>
+                                <td>
+                                    <?php if (is_string($value)) : ?>
+                                        <?= esc($value) ?>
+                                    <?php else: ?>
+                                        <pre><?= esc(print_r($value, true)) ?></pre>
+                                    <?php endif; ?>
+                                </td>
+                            </tr>
+                        <?php endforeach; ?>
+                        </tbody>
+                    </table>
+
+                <?php endforeach ?>
+
+                <!-- Constants -->
+                <?php $constants = get_defined_constants(true); ?>
+                <?php if (! empty($constants['user'])) : ?>
+                    <h3>Constants</h3>
+
+                    <table>
+                        <thead>
+                            <tr>
+                                <th>Key</th>
+                                <th>Value</th>
+                            </tr>
+                        </thead>
+                        <tbody>
+                        <?php foreach ($constants['user'] as $key => $value) : ?>
+                            <tr>
+                                <td><?= esc($key) ?></td>
+                                <td>
+                                    <?php if (is_string($value)) : ?>
+                                        <?= esc($value) ?>
+                                    <?php else: ?>
+                                        <pre><?= esc(print_r($value, true)) ?></pre>
+                                    <?php endif; ?>
+                                </td>
+                            </tr>
+                        <?php endforeach; ?>
+                        </tbody>
+                    </table>
+                <?php endif; ?>
+            </div>
+
+            <!-- Request -->
+            <div class="content" id="request">
+                <?php $request = service('request'); ?>
+
+                <table>
+                    <tbody>
+                        <tr>
+                            <td style="width: 10em">Path</td>
+                            <td><?= esc($request->getUri()) ?></td>
+                        </tr>
+                        <tr>
+                            <td>HTTP Method</td>
+                            <td><?= esc($request->getMethod()) ?></td>
+                        </tr>
+                        <tr>
+                            <td>IP Address</td>
+                            <td><?= esc($request->getIPAddress()) ?></td>
+                        </tr>
+                        <tr>
+                            <td style="width: 10em">Is AJAX Request?</td>
+                            <td><?= $request->isAJAX() ? 'yes' : 'no' ?></td>
+                        </tr>
+                        <tr>
+                            <td>Is CLI Request?</td>
+                            <td><?= $request->isCLI() ? 'yes' : 'no' ?></td>
+                        </tr>
+                        <tr>
+                            <td>Is Secure Request?</td>
+                            <td><?= $request->isSecure() ? 'yes' : 'no' ?></td>
+                        </tr>
+                        <tr>
+                            <td>User Agent</td>
+                            <td><?= esc($request->getUserAgent()->getAgentString()) ?></td>
+                        </tr>
+
+                    </tbody>
+                </table>
+
+
+                <?php $empty = true; ?>
+                <?php foreach (['_GET', '_POST', '_COOKIE'] as $var) : ?>
+                    <?php
+                    if (empty($GLOBALS[$var]) || ! is_array($GLOBALS[$var])) {
+                        continue;
+                    } ?>
+
+                    <?php $empty = false; ?>
+
+                    <h3>$<?= esc($var) ?></h3>
+
+                    <table style="width: 100%">
+                        <thead>
+                            <tr>
+                                <th>Key</th>
+                                <th>Value</th>
+                            </tr>
+                        </thead>
+                        <tbody>
+                        <?php foreach ($GLOBALS[$var] as $key => $value) : ?>
+                            <tr>
+                                <td><?= esc($key) ?></td>
+                                <td>
+                                    <?php if (is_string($value)) : ?>
+                                        <?= esc($value) ?>
+                                    <?php else: ?>
+                                        <pre><?= esc(print_r($value, true)) ?></pre>
+                                    <?php endif; ?>
+                                </td>
+                            </tr>
+                        <?php endforeach; ?>
+                        </tbody>
+                    </table>
+
+                <?php endforeach ?>
+
+                <?php if ($empty) : ?>
+
+                    <div class="alert">
+                        No $_GET, $_POST, or $_COOKIE Information to show.
+                    </div>
+
+                <?php endif; ?>
+
+                <?php $headers = $request->headers(); ?>
+                <?php if (! empty($headers)) : ?>
+
+                    <h3>Headers</h3>
+
+                    <table>
+                        <thead>
+                            <tr>
+                                <th>Header</th>
+                                <th>Value</th>
+                            </tr>
+                        </thead>
+                        <tbody>
+                        <?php foreach ($headers as $name => $value) : ?>
+                            <tr>
+                                <td><?= esc($name, 'html') ?></td>
+                                <td>
+                                <?php
+                                if ($value instanceof Header) {
+                                    echo esc($value->getValueLine(), 'html');
+                                } else {
+                                    foreach ($value as $i => $header) {
+                                        echo ' (' . $i + 1 . ') ' . esc($header->getValueLine(), 'html');
+                                    }
+                                }
+                            ?>
+                                </td>
+                            </tr>
+                        <?php endforeach; ?>
+                        </tbody>
+                    </table>
+
+                <?php endif; ?>
+            </div>
+
+            <!-- Response -->
+            <?php
+                $response = service('response');
+$response->setStatusCode(http_response_code());
+?>
+            <div class="content" id="response">
+                <table>
+                    <tr>
+                        <td style="width: 15em">Response Status</td>
+                        <td><?= esc($response->getStatusCode() . ' - ' . $response->getReasonPhrase()) ?></td>
+                    </tr>
+                </table>
+
+                <?php $headers = $response->headers(); ?>
+                <?php if (! empty($headers)) : ?>
+                    <h3>Headers</h3>
+
+                    <table>
+                        <thead>
+                            <tr>
+                                <th>Header</th>
+                                <th>Value</th>
+                            </tr>
+                        </thead>
+                        <tbody>
+                        <?php foreach ($headers as $name => $value) : ?>
+                            <tr>
+                                <td><?= esc($name, 'html') ?></td>
+                                <td>
+                                <?php
+                    if ($value instanceof Header) {
+                        echo esc($response->getHeaderLine($name), 'html');
+                    } else {
+                        foreach ($value as $i => $header) {
+                            echo ' (' . $i + 1 . ') ' . esc($header->getValueLine(), 'html');
+                        }
+                    }
+                            ?>
+                                </td>
+                            </tr>
+                        <?php endforeach; ?>
+                        </tbody>
+                    </table>
+
+                <?php endif; ?>
+            </div>
+
+            <!-- Files -->
+            <div class="content" id="files">
+                <?php $files = get_included_files(); ?>
+
+                <ol>
+                <?php foreach ($files as $file) :?>
+                    <li><?= esc(clean_path($file)) ?></li>
+                <?php endforeach ?>
+                </ol>
+            </div>
+
+            <!-- Memory -->
+            <div class="content" id="memory">
+
+                <table>
+                    <tbody>
+                        <tr>
+                            <td>Memory Usage</td>
+                            <td><?= esc(static::describeMemory(memory_get_usage(true))) ?></td>
+                        </tr>
+                        <tr>
+                            <td style="width: 12em">Peak Memory Usage:</td>
+                            <td><?= esc(static::describeMemory(memory_get_peak_usage(true))) ?></td>
+                        </tr>
+                        <tr>
+                            <td>Memory Limit:</td>
+                            <td><?= esc(ini_get('memory_limit')) ?></td>
+                        </tr>
+                    </tbody>
+                </table>
+
+            </div>
+
+        </div>  <!-- /tab-content -->
+
+    </div> <!-- /container -->
+    <?php endif; ?>
+
+</body>
+</html>
diff --git a/app/Views/errors/html/production.php b/app/Views/errors/html/production.php
new file mode 100644
index 0000000..2f59a8d
--- /dev/null
+++ b/app/Views/errors/html/production.php
@@ -0,0 +1,25 @@
+<!doctype html>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <meta name="robots" content="noindex">
+
+    <title><?= lang('Errors.whoops') ?></title>
+
+    <style>
+        <?= preg_replace('#[\r\n\t ]+#', ' ', file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.css')) ?>
+    </style>
+</head>
+<body>
+
+    <div class="container text-center">
+
+        <h1 class="headline"><?= lang('Errors.whoops') ?></h1>
+
+        <p class="lead"><?= lang('Errors.weHitASnag') ?></p>
+
+    </div>
+
+</body>
+
+</html>
diff --git a/app/Views/welcome_message.php b/app/Views/welcome_message.php
new file mode 100644
index 0000000..c18eca3
--- /dev/null
+++ b/app/Views/welcome_message.php
@@ -0,0 +1,331 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Welcome to CodeIgniter 4!</title>
+    <meta name="description" content="The small framework with powerful features">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <link rel="shortcut icon" type="image/png" href="/favicon.ico">
+
+    <!-- STYLES -->
+
+    <style {csp-style-nonce}>
+        * {
+            transition: background-color 300ms ease, color 300ms ease;
+        }
+        *:focus {
+            background-color: rgba(221, 72, 20, .2);
+            outline: none;
+        }
+        html, body {
+            color: rgba(33, 37, 41, 1);
+            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
+            font-size: 16px;
+            margin: 0;
+            padding: 0;
+            -webkit-font-smoothing: antialiased;
+            -moz-osx-font-smoothing: grayscale;
+            text-rendering: optimizeLegibility;
+        }
+        header {
+            background-color: rgba(247, 248, 249, 1);
+            padding: .4rem 0 0;
+        }
+        .menu {
+            padding: .4rem 2rem;
+        }
+        header ul {
+            border-bottom: 1px solid rgba(242, 242, 242, 1);
+            list-style-type: none;
+            margin: 0;
+            overflow: hidden;
+            padding: 0;
+            text-align: right;
+        }
+        header li {
+            display: inline-block;
+        }
+        header li a {
+            border-radius: 5px;
+            color: rgba(0, 0, 0, .5);
+            display: block;
+            height: 44px;
+            text-decoration: none;
+        }
+        header li.menu-item a {
+            border-radius: 5px;
+            margin: 5px 0;
+            height: 38px;
+            line-height: 36px;
+            padding: .4rem .65rem;
+            text-align: center;
+        }
+        header li.menu-item a:hover,
+        header li.menu-item a:focus {
+            background-color: rgba(221, 72, 20, .2);
+            color: rgba(221, 72, 20, 1);
+        }
+        header .logo {
+            float: left;
+            height: 44px;
+            padding: .4rem .5rem;
+        }
+        header .menu-toggle {
+            display: none;
+            float: right;
+            font-size: 2rem;
+            font-weight: bold;
+        }
+        header .menu-toggle button {
+            background-color: rgba(221, 72, 20, .6);
+            border: none;
+            border-radius: 3px;
+            color: rgba(255, 255, 255, 1);
+            cursor: pointer;
+            font: inherit;
+            font-size: 1.3rem;
+            height: 36px;
+            padding: 0;
+            margin: 11px 0;
+            overflow: visible;
+            width: 40px;
+        }
+        header .menu-toggle button:hover,
+        header .menu-toggle button:focus {
+            background-color: rgba(221, 72, 20, .8);
+            color: rgba(255, 255, 255, .8);
+        }
+        header .heroe {
+            margin: 0 auto;
+            max-width: 1100px;
+            padding: 1rem 1.75rem 1.75rem 1.75rem;
+        }
+        header .heroe h1 {
+            font-size: 2.5rem;
+            font-weight: 500;
+        }
+        header .heroe h2 {
+            font-size: 1.5rem;
+            font-weight: 300;
+        }
+        section {
+            margin: 0 auto;
+            max-width: 1100px;
+            padding: 2.5rem 1.75rem 3.5rem 1.75rem;
+        }
+        section h1 {
+            margin-bottom: 2.5rem;
+        }
+        section h2 {
+            font-size: 120%;
+            line-height: 2.5rem;
+            padding-top: 1.5rem;
+        }
+        section pre {
+            background-color: rgba(247, 248, 249, 1);
+            border: 1px solid rgba(242, 242, 242, 1);
+            display: block;
+            font-size: .9rem;
+            margin: 2rem 0;
+            padding: 1rem 1.5rem;
+            white-space: pre-wrap;
+            word-break: break-all;
+        }
+        section code {
+            display: block;
+        }
+        section a {
+            color: rgba(221, 72, 20, 1);
+        }
+        section svg {
+            margin-bottom: -5px;
+            margin-right: 5px;
+            width: 25px;
+        }
+        .further {
+            background-color: rgba(247, 248, 249, 1);
+            border-bottom: 1px solid rgba(242, 242, 242, 1);
+            border-top: 1px solid rgba(242, 242, 242, 1);
+        }
+        .further h2:first-of-type {
+            padding-top: 0;
+        }
+        .svg-stroke {
+            fill: none;
+            stroke: #000;
+            stroke-width: 32px;
+        }
+        footer {
+            background-color: rgba(221, 72, 20, .8);
+            text-align: center;
+        }
+        footer .environment {
+            color: rgba(255, 255, 255, 1);
+            padding: 2rem 1.75rem;
+        }
+        footer .copyrights {
+            background-color: rgba(62, 62, 62, 1);
+            color: rgba(200, 200, 200, 1);
+            padding: .25rem 1.75rem;
+        }
+        @media (max-width: 629px) {
+            header ul {
+                padding: 0;
+            }
+            header .menu-toggle {
+                padding: 0 1rem;
+            }
+            header .menu-item {
+                background-color: rgba(244, 245, 246, 1);
+                border-top: 1px solid rgba(242, 242, 242, 1);
+                margin: 0 15px;
+                width: calc(100% - 30px);
+            }
+            header .menu-toggle {
+                display: block;
+            }
+            header .hidden {
+                display: none;
+            }
+            header li.menu-item a {
+                background-color: rgba(221, 72, 20, .1);
+            }
+            header li.menu-item a:hover,
+            header li.menu-item a:focus {
+                background-color: rgba(221, 72, 20, .7);
+                color: rgba(255, 255, 255, .8);
+            }
+        }
+    </style>
+</head>
+<body>
+
+<!-- HEADER: MENU + HEROE SECTION -->
+<header>
+
+    <div class="menu">
+        <ul>
+            <li class="logo">
+                <a href="https://codeigniter.com" target="_blank">
+                    <svg role="img" aria-label="Visit CodeIgniter.com official website!" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2100 500" height="44"><path fill="#dd4814" d="M148.2 411c-20.53-9.07-34.48-28.61-36.31-50.99 1.2-23.02 13.36-44.06 32.67-56.61-3.17 7.73-2.4 16.53 2 23.6 5.01 7 13.63 10.36 22.07 8.61 12.02-3.38 19.06-15.86 15.68-27.89-1.2-4.21-3.6-8.03-6.88-10.91-13.6-11.06-20.43-28.44-18-45.81 2.33-9.2 7.42-17.52 14.61-23.8-5.4 14.4 9.83 28.61 20.05 35.6 18.14 10.88 35.6 22.84 52.32 35.81 18.27 14.4 28.23 36.94 26.67 60-4.11 24.54-21.47 44.8-45.13 52.4 47.33-10.53 96.13-48.13 97.06-101.46-.93-42.67-26.4-80.96-65.33-98.4h-1.73c.86 2.09 1.28 4.34 1.2 6.61.13-1.47.13-2.93 0-4.4.21 1.73.21 3.47 0 5.2-2.96 12.13-15.2 19.6-27.36 16.64-4.86-1.2-9.2-3.93-12.32-7.87-15.6-20 0-42.76 2.61-64.76 1.6-28.13-11.25-55.02-34.05-71.46 11.41 19.02-3.79 44-14.84 58.21-11.07 14.21-27.07 24.8-40.11 37.2-14.05 13.07-26.93 27.44-38.49 42.8-24.99 30.53-34.8 70.8-26.67 109.4 11.15 37.2 42.07 65.15 80.2 72.4h.21l-.13-.12Zm324.56-159.8q0-17.92 6.16-35.56 6.44-17.92 18.48-31.92t29.68-22.68q17.64-8.96 40.04-8.96 26.6 0 45.36 12.04 19.04 12.04 28 31.36l-15.4 9.52q-4.76-9.8-11.76-16.52-6.72-6.72-14.56-10.92-7.84-4.2-16.24-5.88-8.4-1.96-16.52-1.96-17.92 0-31.64 7.28-13.72 7.28-23.24 19.04-9.24 11.76-14 26.6-4.76 14.56-4.76 29.68 0 16.52 5.6 31.64 5.88 15.12 15.68 26.88 10.08 11.48 23.52 18.48 13.72 6.72 29.68 6.72 8.4 0 17.08-1.96 8.96-2.24 17.08-6.72 8.4-4.76 15.4-11.48 7-7 11.76-16.8l16.24 8.4q-4.76 11.2-13.44 19.88-8.68 8.4-19.32 14.28-10.64 5.88-22.68 8.96-11.76 3.08-23.24 3.08-20.44 0-37.52-8.96-17.08-8.96-29.4-23.24-12.32-14.56-19.32-32.76-6.72-18.48-6.72-37.52Zm263.48 103.6q-15.96 0-29.12-5.88-13.16-6.16-22.96-16.52-9.52-10.36-14.84-24.08Q664 294.6 664 279.48q0-15.4 5.32-29.12 5.6-13.72 15.12-24.08 9.8-10.36 22.96-16.52t28.84-6.16q15.68 0 28.84 6.16 13.44 6.16 22.96 16.52 9.8 10.36 15.12 24.08 5.6 13.72 5.6 29.12 0 15.12-5.32 28.84t-15.12 24.08q-9.52 10.36-22.96 16.52-13.16 5.88-29.12 5.88Zm-52.92-75.04q0 12.32 4.2 22.96 4.2 10.36 11.2 18.48 7.28 7.84 16.8 12.32 9.8 4.48 20.72 4.48 10.92 0 20.44-4.48 9.8-4.76 17.08-12.6 7.28-8.12 11.48-18.76 4.2-10.64 4.2-22.96 0-12.04-4.2-22.68-4.2-10.92-11.48-18.76-7.28-8.12-17.08-12.6-9.52-4.76-20.44-4.76-10.92 0-20.44 4.76-9.52 4.48-16.8 12.6-7.28 8.12-11.48 19.04-4.2 10.64-4.2 22.96ZM900.6 354.8q-15.12 0-28-6.16-12.88-6.44-22.12-16.8t-14.56-23.8q-5.04-13.72-5.04-28.56 0-15.4 5.04-29.12 5.04-14 13.72-24.36 8.96-10.36 21-16.24 12.32-6.16 26.88-6.16 18.48 0 32.76 9.8 14.28 9.52 22.4 23.24V147.6h19.04v179.76q0 7.84 6.72 7.84V352q-4.2.84-6.72.84-6.72 0-11.76-4.2-5.04-4.48-5.04-10.64v-14.28Q946.24 338 931.4 346.4t-30.8 8.4Zm4.2-16.8q7 0 14.84-2.8 8.12-2.8 15.12-7.56 7-5.04 11.76-11.48 5.04-6.72 6.16-14.28V256.8q-2.8-7.56-8.12-14-5.32-6.72-12.32-11.76-6.72-5.04-14.56-7.84-7.84-2.8-15.4-2.8-11.76 0-21.28 5.04-9.52 5.04-16.52 13.44-6.72 8.12-10.36 18.76-3.64 10.64-3.64 21.84 0 11.76 4.2 22.4 4.2 10.64 11.48 18.76 7.28 7.84 17.08 12.6Q893.32 338 904.8 338Zm173.04 16.8q-15.96 0-29.4-5.88-13.16-6.16-22.96-16.52-9.8-10.64-15.4-24.36-5.32-13.72-5.32-29.4 0-15.4 5.32-28.84 5.6-13.72 15.12-23.8 9.8-10.36 23.24-16.24 13.44-6.16 29.12-6.16 15.96 0 29.12 6.16 13.44 5.88 22.96 16.24 9.52 10.36 14.84 23.8 5.32 13.44 5.32 28.56v4.48q0 2.24-.28 3.08h-124.88q.84 11.76 5.32 21.84 4.76 9.8 12.04 17.08 7.28 7.28 16.52 11.48 9.52 3.92 20.16 3.92 7 0 14-1.96t12.88-5.32q5.88-3.36 10.64-8.12 4.76-5.04 7.28-10.92l16.52 4.48q-3.36 8.12-9.52 14.84-6.16 6.44-14.28 11.48-8.12 4.76-17.92 7.56-9.8 2.52-20.44 2.52Zm-53.48-83.44h107.24q-.84-11.76-5.6-21.28-4.48-9.8-11.76-16.8-7-7-16.52-10.92-9.24-3.92-19.88-3.92-10.64 0-20.16 3.92t-16.8 10.92q-7 7-11.48 16.8-4.2 9.8-5.04 21.28Zm193.2 80.64h-38.64V153.2h38.64V352Zm93.52.84q-14.84 0-26.88-5.88t-21-15.96q-8.68-10.36-13.44-23.8-4.76-13.44-4.76-28.56 0-15.96 5.04-29.68 5.04-13.72 14-24.08 8.96-10.36 21.56-16.24 12.6-5.88 27.72-5.88 17.08 0 29.96 7.84 12.88 7.56 21.28 20.44v-25.76h32.76V345q0 16.24-6.16 29.12-6.16 12.88-17.08 21.84-10.64 8.96-25.76 13.72-14.84 4.76-32.48 4.76-24.08 0-40.6-7.84-16.24-8.12-28-22.68l20.44-19.88q8.4 10.36 21 16.24 12.88 5.88 27.16 5.88 8.68 0 16.52-2.24 8.12-2.52 14.28-7.56 6.16-5.04 9.52-12.88 3.64-7.84 3.64-18.48v-18.48q-7.28 12.6-20.44 19.6-13.16 6.72-28.28 6.72Zm12.6-29.96q6.16 0 11.76-1.96t10.36-5.32q4.76-3.36 8.4-7.84 3.64-4.48 5.6-9.52v-35q-5.04-12.88-15.96-20.72-10.64-7.84-22.4-7.84-8.68 0-15.68 3.92-7 3.64-12.04 10.08-5.04 6.16-7.84 14.28-2.52 8.12-2.52 16.8 0 8.96 3.08 16.8t8.4 13.72q5.6 5.88 12.88 9.24 7.28 3.36 15.96 3.36Zm243.88-62.44V352h-37.52v-82.32q0-17.64-6.16-25.76-6.16-8.12-17.08-8.12-5.6 0-11.48 2.24-5.88 2.24-11.2 6.44-5.04 3.92-9.24 9.52t-6.16 12.32V352h-37.52V205.28h33.88v27.16q8.12-14 23.52-21.84t34.72-7.84q13.72 0 22.4 5.04 8.68 5.04 13.44 13.16 4.76 8.12 6.44 18.48 1.96 10.36 1.96 21Zm70.28 91.56h-37.52V205.28h37.52V352Zm0-167.16h-37.52V147.6h37.52v37.24Zm114.24 129.92 7.56 29.68q-7.56 3.36-18.48 6.72-10.92 3.36-22.96 3.36-7.84 0-14.84-1.96-6.72-1.96-12.04-6.16-5.04-4.48-8.12-11.2-3.08-7-3.08-16.8v-84.28h-19.32v-28.84h19.32v-47.6h37.52v47.6h30.8v28.84h-30.8v71.68q0 7.84 3.92 11.2 4.2 3.08 10.08 3.08t11.48-1.96q5.6-1.96 8.96-3.36Zm91.56 40.04q-17.64 0-31.92-5.88-14.28-6.16-24.36-16.52t-15.68-24.08q-5.32-13.72-5.32-28.84 0-15.68 5.32-29.4 5.32-14 15.4-24.36 10.08-10.64 24.36-16.8 14.56-6.16 32.48-6.16 17.92 0 31.92 6.16 14.28 6.16 24.08 16.52 10.08 10.36 15.12 24.08 5.32 13.72 5.32 28.56 0 3.64-.28 7 0 3.36-.56 5.6h-113.4q.84 8.68 4.2 15.4 3.36 6.72 8.68 11.48 5.32 4.76 12.04 7.28 6.72 2.52 14 2.52 11.2 0 21-5.32 10.08-5.6 13.72-14.56l32.2 8.96q-8.12 16.8-26.04 27.72-17.64 10.64-42.28 10.64Zm-38.08-88.48h76.16q-1.4-16.52-12.32-26.32-10.64-10.08-26.04-10.08-7.56 0-14.28 2.8-6.44 2.52-11.48 7.28t-8.4 11.48q-3.08 6.72-3.64 14.84Zm225.12-62.72v34.16q-17.08.28-30.52 6.72-13.44 6.16-19.32 18.76V352h-37.52V205.28h34.44v31.36q3.92-7.56 9.24-13.44 5.32-6.16 11.48-10.64t12.32-6.72q6.44-2.52 12.32-2.52h4.48q1.68 0 3.08.28Z"/></svg>
+                </a>
+            </li>
+            <li class="menu-toggle">
+                <button id="menuToggle">&#9776;</button>
+            </li>
+            <li class="menu-item hidden"><a href="#">Home</a></li>
+            <li class="menu-item hidden"><a href="https://codeigniter.com/user_guide/" target="_blank">Docs</a>
+            </li>
+            <li class="menu-item hidden"><a href="https://forum.codeigniter.com/" target="_blank">Community</a></li>
+            <li class="menu-item hidden"><a
+                    href="https://codeigniter.com/contribute" target="_blank">Contribute</a>
+            </li>
+        </ul>
+    </div>
+
+    <div class="heroe">
+
+        <h1>Welcome to CodeIgniter <?= CodeIgniter\CodeIgniter::CI_VERSION ?></h1>
+
+        <h2>The small framework with powerful features</h2>
+
+    </div>
+
+</header>
+
+<!-- CONTENT -->
+
+<section>
+
+    <h1>About this page</h1>
+
+    <p>The page you are looking at is being generated dynamically by CodeIgniter.</p>
+
+    <p>If you would like to edit this page you will find it located at:</p>
+
+    <pre><code>app/Views/welcome_message.php</code></pre>
+
+    <p>The corresponding controller for this page can be found at:</p>
+
+    <pre><code>app/Controllers/Home.php</code></pre>
+
+</section>
+
+<div class="further">
+
+    <section>
+
+        <h1>Go further</h1>
+
+        <h2>
+            <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'><rect x='32' y='96' width='64' height='368' rx='16' ry='16' class="svg-stroke" /><line x1='112' y1='224' x2='240' y2='224' class="svg-stroke" /><line x1='112' y1='400' x2='240' y2='400' class="svg-stroke" /><rect x='112' y='160' width='128' height='304' rx='16' ry='16' class="svg-stroke" /><rect x='256' y='48' width='96' height='416' rx='16' ry='16' class="svg-stroke" /><path d='M422.46,96.11l-40.4,4.25c-11.12,1.17-19.18,11.57-17.93,23.1l34.92,321.59c1.26,11.53,11.37,20,22.49,18.84l40.4-4.25c11.12-1.17,19.18-11.57,17.93-23.1L445,115C443.69,103.42,433.58,94.94,422.46,96.11Z' class="svg-stroke"/></svg>
+            Learn
+        </h2>
+
+        <p>The User Guide contains an introduction, tutorial, a number of "how to"
+            guides, and then reference documentation for the components that make up
+            the framework. Check the <a href="https://codeigniter.com/user_guide/"
+            target="_blank">User Guide</a> !</p>
+
+        <h2>
+            <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'><path d='M431,320.6c-1-3.6,1.2-8.6,3.3-12.2a33.68,33.68,0,0,1,2.1-3.1A162,162,0,0,0,464,215c.3-92.2-77.5-167-173.7-167C206.4,48,136.4,105.1,120,180.9a160.7,160.7,0,0,0-3.7,34.2c0,92.3,74.8,169.1,171,169.1,15.3,0,35.9-4.6,47.2-7.7s22.5-7.2,25.4-8.3a26.44,26.44,0,0,1,9.3-1.7,26,26,0,0,1,10.1,2L436,388.6a13.52,13.52,0,0,0,3.9,1,8,8,0,0,0,8-8,12.85,12.85,0,0,0-.5-2.7Z' class="svg-stroke" /><path d='M66.46,232a146.23,146.23,0,0,0,6.39,152.67c2.31,3.49,3.61,6.19,3.21,8s-11.93,61.87-11.93,61.87a8,8,0,0,0,2.71,7.68A8.17,8.17,0,0,0,72,464a7.26,7.26,0,0,0,2.91-.6l56.21-22a15.7,15.7,0,0,1,12,.2c18.94,7.38,39.88,12,60.83,12A159.21,159.21,0,0,0,284,432.11' class="svg-stroke" /></svg>
+            Discuss
+        </h2>
+
+        <p>CodeIgniter is a community-developed open source project, with several
+             venues for the community members to gather and exchange ideas. View all
+             the threads on <a href="https://forum.codeigniter.com/"
+             target="_blank">CodeIgniter's forum</a>, or <a href="https://join.slack.com/t/codeigniterchat/shared_invite/zt-rl30zw00-obL1Hr1q1ATvkzVkFp8S0Q"
+             target="_blank">chat on Slack</a> !</p>
+
+        <h2>
+        <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'><line x1='176' y1='48' x2='336' y2='48' class="svg-stroke" /><line x1='118' y1='304' x2='394' y2='304' class="svg-stroke" /><path d='M208,48v93.48a64.09,64.09,0,0,1-9.88,34.18L73.21,373.49C48.4,412.78,76.63,464,123.08,464H388.92c46.45,0,74.68-51.22,49.87-90.51L313.87,175.66A64.09,64.09,0,0,1,304,141.48V48' class="svg-stroke" /></svg>
+             Contribute
+        </h2>
+
+        <p>CodeIgniter is a community driven project and accepts contributions
+             of code and documentation from the community. Why not
+             <a href="https://codeigniter.com/contribute" target="_blank">
+             join us</a> ?</p>
+
+    </section>
+
+</div>
+
+<!-- FOOTER: DEBUG INFO + COPYRIGHTS -->
+
+<footer>
+    <div class="environment">
+
+        <p>Page rendered in {elapsed_time} seconds using {memory_usage} MB of memory.</p>
+
+        <p>Environment: <?= ENVIRONMENT ?></p>
+
+    </div>
+
+    <div class="copyrights">
+
+        <p>&copy; <?= date('Y') ?> CodeIgniter Foundation. CodeIgniter is open source project released under the MIT
+            open source licence.</p>
+
+    </div>
+
+</footer>
+
+<!-- SCRIPTS -->
+
+<script {csp-script-nonce}>
+    document.getElementById("menuToggle").addEventListener('click', toggleMenu);
+    function toggleMenu() {
+        var menuItems = document.getElementsByClassName('menu-item');
+        for (var i = 0; i < menuItems.length; i++) {
+            var menuItem = menuItems[i];
+            menuItem.classList.toggle("hidden");
+        }
+    }
+</script>
+
+<!-- -->
+
+</body>
+</html>
diff --git a/app/index.html b/app/index.html
new file mode 100644
index 0000000..69df4e1
--- /dev/null
+++ b/app/index.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>
diff --git a/builds b/builds
new file mode 100755
index 0000000..c68c089
--- /dev/null
+++ b/builds
@@ -0,0 +1,128 @@
+#!/usr/bin/env php
+<?php
+
+define('LATEST_RELEASE', '^4.7');
+define('DEVELOP_BRANCH', 'dev-develop');
+define('NEXT_MINOR', '^4.8-dev');
+define('GITHUB_URL', 'https://github.com/codeigniter4/codeigniter4');
+
+/*
+ * --------------------------------------------------------------------
+ * Stability Toggle
+ * --------------------------------------------------------------------
+ * Use this script to toggle the CodeIgniter dependency between the
+ * latest stable release and the most recent development update.
+ *
+ * Usage: php builds [release|development|next]
+ */
+
+$branch = $argv[1] ?? '';
+
+// Determine the requested stability
+if ($branch === '' || ! in_array($branch, ['release', 'development', 'next'], true)) {
+    echo 'Usage: php builds [release|development|next]' . PHP_EOL;
+
+    exit;
+}
+
+$modified = [];
+
+// Locate each file and update it for the requested stability
+
+$file = __DIR__ . DIRECTORY_SEPARATOR . 'composer.json';
+
+if (is_file($file)) {
+    $contents = file_get_contents($file);
+
+    if ((string) $contents !== '') {
+        $array = json_decode($contents, true);
+
+        if (is_array($array)) {
+            if ($branch !== 'release') {
+                $array['minimum-stability'] = 'dev';
+                $array['prefer-stable']     = true;
+                $array['repositories'] ??= [];
+
+                $found = false;
+
+                foreach ($array['repositories'] as $repository) {
+                    if ($repository['url'] === GITHUB_URL) {
+                        $found = true;
+                        break;
+                    }
+                }
+
+                if (! $found) {
+                    $array['repositories'][] = [
+                        'type' => 'vcs',
+                        'url'  => GITHUB_URL,
+                    ];
+                }
+
+                $array['require']['codeigniter4/codeigniter4'] = $branch === 'next' ? NEXT_MINOR : DEVELOP_BRANCH;
+                unset($array['require']['codeigniter4/framework']);
+            } else {
+                unset($array['minimum-stability']);
+
+                if (isset($array['repositories'])) {
+                    foreach ($array['repositories'] as $i => $repository) {
+                        if ($repository['url'] === GITHUB_URL) {
+                            unset($array['repositories'][$i]);
+                            break;
+                        }
+                    }
+
+                    if ($array['repositories'] === []) {
+                        unset($array['repositories']);
+                    }
+                }
+
+                $array['require']['codeigniter4/framework'] = LATEST_RELEASE;
+                unset($array['require']['codeigniter4/codeigniter4']);
+            }
+
+            file_put_contents($file, json_encode($array, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL);
+
+            $modified[] = $file;
+        } else {
+            echo 'Warning: Unable to decode composer.json! Skipping...' . PHP_EOL;
+        }
+    } else {
+        echo 'Warning: Unable to read composer.json! Skipping...' . PHP_EOL;
+    }
+}
+
+$files = [
+    __DIR__ . DIRECTORY_SEPARATOR . 'app/Config/Paths.php',
+    __DIR__ . DIRECTORY_SEPARATOR . 'phpunit.dist.xml',
+    __DIR__ . DIRECTORY_SEPARATOR . 'phpunit.xml',
+];
+
+foreach ($files as $file) {
+    if (is_file($file)) {
+        $contents = file_get_contents($file);
+
+        if ($branch !== 'release') {
+            $contents = str_replace('vendor/codeigniter4/framework', 'vendor/codeigniter4/codeigniter4', $contents);
+        } else {
+            $contents = str_replace('vendor/codeigniter4/codeigniter4', 'vendor/codeigniter4/framework', $contents);
+        }
+
+        file_put_contents($file, $contents);
+
+        $modified[] = $file;
+    }
+}
+
+if ($modified === []) {
+    echo 'No files modified.' . PHP_EOL;
+} else {
+    echo 'The following files were modified:' . PHP_EOL;
+
+    foreach ($modified as $file) {
+        echo " * {$file}" . PHP_EOL;
+    }
+}
+
+echo 'Run `composer update` to sync changes with your vendor folder.' . PHP_EOL;
+echo 'Don\'t forget to update the project files in app folder from "vendor/codeigniter4/*/app/".' . PHP_EOL;
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..8a47633
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,47 @@
+{
+    "name": "codeigniter4/appstarter",
+    "description": "CodeIgniter4 starter app",
+    "license": "MIT",
+    "type": "project",
+    "homepage": "https://codeigniter.com",
+    "support": {
+        "forum": "https://forum.codeigniter.com/",
+        "source": "https://github.com/codeigniter4/CodeIgniter4",
+        "slack": "https://codeigniterchat.slack.com"
+    },
+    "require": {
+        "php": "^8.2",
+        "codeigniter4/framework": "^4.7",
+        "codeigniter4/settings": "^2.4",
+        "codeigniter4/shield": "^1.4",
+        "codeigniter4/translations": "^4.7"
+    },
+    "require-dev": {
+        "codeigniter/coding-standard": "^1.9",
+        "fakerphp/faker": "^1.9",
+        "mikey179/vfsstream": "^1.6",
+        "phpunit/phpunit": "^10.5.16"
+    },
+    "autoload": {
+        "psr-4": {
+            "App\\": "app/",
+            "Config\\": "app/Config/"
+        },
+        "exclude-from-classmap": [
+            "**/Database/Migrations/**"
+        ]
+    },
+    "autoload-dev": {
+        "psr-4": {
+            "Tests\\Support\\": "tests/_support"
+        }
+    },
+    "config": {
+        "optimize-autoloader": true,
+        "preferred-install": "dist",
+        "sort-packages": true
+    },
+    "scripts": {
+        "test": "phpunit"
+    }
+}
diff --git a/composer.lock b/composer.lock
new file mode 100644
index 0000000..a365003
--- /dev/null
+++ b/composer.lock
@@ -0,0 +1,4967 @@
+{
+    "_readme": [
+        "This file locks the dependencies of your project to a known state",
+        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+        "This file is @generated automatically"
+    ],
+    "content-hash": "586e91984691adfcd3a7fe5c04628077",
+    "packages": [
+        {
+            "name": "codeigniter4/framework",
+            "version": "v4.7.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/codeigniter4/framework.git",
+                "reference": "67ead895b7491703e5e5bc17436778806192008f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/codeigniter4/framework/zipball/67ead895b7491703e5e5bc17436778806192008f",
+                "reference": "67ead895b7491703e5e5bc17436778806192008f",
+                "shasum": ""
+            },
+            "require": {
+                "ext-intl": "*",
+                "ext-mbstring": "*",
+                "laminas/laminas-escaper": "^2.18",
+                "php": "^8.2",
+                "psr/log": "^3.0"
+            },
+            "require-dev": {
+                "codeigniter/coding-standard": "^1.7",
+                "fakerphp/faker": "^1.24",
+                "friendsofphp/php-cs-fixer": "^3.47.1",
+                "kint-php/kint": "^6.1",
+                "mikey179/vfsstream": "^1.6.12",
+                "nexusphp/cs-config": "^3.6",
+                "phpunit/phpunit": "^10.5.16 || ^11.2",
+                "predis/predis": "^3.0"
+            },
+            "suggest": {
+                "ext-apcu": "If you use Cache class ApcuHandler",
+                "ext-curl": "If you use CURLRequest class",
+                "ext-dom": "If you use TestResponse",
+                "ext-exif": "If you run Image class tests",
+                "ext-fileinfo": "Improves mime type detection for files",
+                "ext-gd": "If you use Image class GDHandler",
+                "ext-imagick": "If you use Image class ImageMagickHandler",
+                "ext-libxml": "If you use TestResponse",
+                "ext-memcache": "If you use Cache class MemcachedHandler with Memcache",
+                "ext-memcached": "If you use Cache class MemcachedHandler with Memcached",
+                "ext-mysqli": "If you use MySQL",
+                "ext-oci8": "If you use Oracle Database",
+                "ext-pcntl": "If you use Signals",
+                "ext-pgsql": "If you use PostgreSQL",
+                "ext-posix": "If you use Signals",
+                "ext-readline": "Improves CLI::input() usability",
+                "ext-redis": "If you use Cache class RedisHandler",
+                "ext-simplexml": "If you format XML",
+                "ext-sodium": "If you use Encryption SodiumHandler",
+                "ext-sqlite3": "If you use SQLite3",
+                "ext-sqlsrv": "If you use SQL Server",
+                "ext-xdebug": "If you use CIUnitTestCase::assertHeaderEmitted()"
+            },
+            "type": "project",
+            "autoload": {
+                "psr-4": {
+                    "CodeIgniter\\": "system/"
+                },
+                "exclude-from-classmap": [
+                    "**/Database/Migrations/**"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "The CodeIgniter framework v4",
+            "homepage": "https://codeigniter.com",
+            "support": {
+                "forum": "https://forum.codeigniter.com/",
+                "slack": "https://codeigniterchat.slack.com",
+                "source": "https://github.com/codeigniter4/CodeIgniter4"
+            },
+            "time": "2026-07-07T09:23:35+00:00"
+        },
+        {
+            "name": "codeigniter4/settings",
+            "version": "v2.4.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/codeigniter4/settings.git",
+                "reference": "7cbd2e2146e32211cc8194d9c35632631500adad"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/codeigniter4/settings/zipball/7cbd2e2146e32211cc8194d9c35632631500adad",
+                "reference": "7cbd2e2146e32211cc8194d9c35632631500adad",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^8.2"
+            },
+            "require-dev": {
+                "codeigniter4/devkit": "^1.3",
+                "codeigniter4/framework": "^4.3"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "CodeIgniter\\Settings\\": "src"
+                },
+                "exclude-from-classmap": [
+                    "**/Database/Migrations/**"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Lonnie Ezell",
+                    "email": "[email protected]",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Settings library for CodeIgniter 4",
+            "homepage": "https://github.com/codeigniter4/settings",
+            "keywords": [
+                "Settings",
+                "codeigniter",
+                "codeigniter4"
+            ],
+            "support": {
+                "issues": "https://github.com/codeigniter4/settings/issues",
+                "source": "https://github.com/codeigniter4/settings/tree/v2.4.0"
+            },
+            "time": "2026-07-30T16:03:46+00:00"
+        },
+        {
+            "name": "codeigniter4/shield",
+            "version": "v1.4.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/codeigniter4/shield.git",
+                "reference": "93c5f1f1481ced93ceb4071ffa3a08a9647a7c8b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/codeigniter4/shield/zipball/93c5f1f1481ced93ceb4071ffa3a08a9647a7c8b",
+                "reference": "93c5f1f1481ced93ceb4071ffa3a08a9647a7c8b",
+                "shasum": ""
+            },
+            "require": {
+                "codeigniter4/settings": "^2.1",
+                "php": "^8.2"
+            },
+            "provide": {
+                "codeigniter4/authentication-implementation": "1.0"
+            },
+            "require-dev": {
+                "boundwize/pyrameter": "^0.5",
+                "boundwize/structarmed": "^0.15",
+                "codeigniter/phpstan-codeigniter": "^2.0",
+                "codeigniter4/devkit": "^1.3",
+                "codeigniter4/framework": ">=4.3.5 <4.5.0 || ^4.5.1",
+                "firebase/php-jwt": "^7.0.3",
+                "mikey179/vfsstream": "^1.6.7",
+                "mockery/mockery": "^1.0",
+                "phpstan/phpstan-strict-rules": "^2.0"
+            },
+            "suggest": {
+                "ext-curl": "Required to use the password validation rule via PwnedValidator class.",
+                "ext-openssl": "Required to use the JWT Authenticator."
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "CodeIgniter\\Shield\\": "src"
+                },
+                "exclude-from-classmap": [
+                    "**/Database/Migrations/**"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Lonnie Ezell",
+                    "email": "[email protected]",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Authentication and Authorization for CodeIgniter 4",
+            "homepage": "https://github.com/codeigniter4/shield",
+            "keywords": [
+                "Authentication",
+                "authorization",
+                "codeigniter",
+                "codeigniter4"
+            ],
+            "support": {
+                "docs": "https://codeigniter4.github.io/shield/",
+                "forum": "https://github.com/codeigniter4/shield/discussions",
+                "issues": "https://github.com/codeigniter4/shield/issues",
+                "slack": "https://codeigniterchat.slack.com",
+                "source": "https://github.com/codeigniter4/shield"
+            },
+            "time": "2026-08-18T12:02:04+00:00"
+        },
+        {
+            "name": "codeigniter4/translations",
+            "version": "v4.7.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/codeigniter4/translations.git",
+                "reference": "a5df30934aa25a65bc1f78e6462b47fae0a0179a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/codeigniter4/translations/zipball/a5df30934aa25a65bc1f78e6462b47fae0a0179a",
+                "reference": "a5df30934aa25a65bc1f78e6462b47fae0a0179a",
+                "shasum": ""
+            },
+            "require": {
+                "ext-intl": "*",
+                "php": "^8.2"
+            },
+            "require-dev": {
+                "codeigniter/coding-standard": "^1.7",
+                "codeigniter4/codeigniter4": "dev-develop",
+                "ext-tokenizer": "*",
+                "friendsofphp/php-cs-fixer": "^3.53",
+                "nexusphp/cs-config": "^3.22",
+                "phpunit/phpunit": "^11.5 || ^12.5"
+            },
+            "type": "project",
+            "extra": {
+                "branch-alias": {
+                    "dev-develop": "4.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Translations\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "Translations for CodeIgniter v4 web framework",
+            "homepage": "https://codeigniter.com",
+            "support": {
+                "forum": "http://forum.codeigniter.com/",
+                "issues": "https://github.com/codeigniter4/translations/issues",
+                "slack": "https://codeigniterchat.slack.com",
+                "source": "https://github.com/codeigniter4/translations"
+            },
+            "time": "2026-08-05T12:38:16+00:00"
+        },
+        {
+            "name": "laminas/laminas-escaper",
+            "version": "2.18.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/laminas/laminas-escaper.git",
+                "reference": "06f211dfffff18d91844c1f55250d5d13c007e18"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/06f211dfffff18d91844c1f55250d5d13c007e18",
+                "reference": "06f211dfffff18d91844c1f55250d5d13c007e18",
+                "shasum": ""
+            },
+            "require": {
+                "ext-ctype": "*",
+                "ext-mbstring": "*",
+                "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0"
+            },
+            "conflict": {
+                "zendframework/zend-escaper": "*"
+            },
+            "require-dev": {
+                "infection/infection": "^0.31.0",
+                "laminas/laminas-coding-standard": "~3.1.0",
+                "phpunit/phpunit": "^11.5.42",
+                "psalm/plugin-phpunit": "^0.19.5",
+                "vimeo/psalm": "^6.13.1"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Laminas\\Escaper\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "description": "Securely and safely escape HTML, HTML attributes, JavaScript, CSS, and URLs",
+            "homepage": "https://laminas.dev",
+            "keywords": [
+                "escaper",
+                "laminas"
+            ],
+            "support": {
+                "chat": "https://laminas.dev/chat",
+                "docs": "https://docs.laminas.dev/laminas-escaper/",
+                "forum": "https://discourse.laminas.dev",
+                "issues": "https://github.com/laminas/laminas-escaper/issues",
+                "rss": "https://github.com/laminas/laminas-escaper/releases.atom",
+                "source": "https://github.com/laminas/laminas-escaper"
+            },
+            "funding": [
+                {
+                    "url": "https://funding.communitybridge.org/projects/laminas-project",
+                    "type": "community_bridge"
+                }
+            ],
+            "time": "2025-10-14T18:31:13+00:00"
+        },
+        {
+            "name": "psr/log",
+            "version": "3.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/log.git",
+                "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+                "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=8.0.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Log\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "https://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for logging libraries",
+            "homepage": "https://github.com/php-fig/log",
+            "keywords": [
+                "log",
+                "psr",
+                "psr-3"
+            ],
+            "support": {
+                "source": "https://github.com/php-fig/log/tree/3.0.2"
+            },
+            "time": "2024-09-11T13:17:53+00:00"
+        }
+    ],
+    "packages-dev": [
+        {
+            "name": "clue/ndjson-react",
+            "version": "v1.3.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/clue/reactphp-ndjson.git",
+                "reference": "392dc165fce93b5bb5c637b67e59619223c931b0"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/clue/reactphp-ndjson/zipball/392dc165fce93b5bb5c637b67e59619223c931b0",
+                "reference": "392dc165fce93b5bb5c637b67e59619223c931b0",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3",
+                "react/stream": "^1.2"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35",
+                "react/event-loop": "^1.2"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Clue\\React\\NDJson\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Christian Lück",
+                    "email": "[email protected]"
+                }
+            ],
+            "description": "Streaming newline-delimited JSON (NDJSON) parser and encoder for ReactPHP.",
+            "homepage": "https://github.com/clue/reactphp-ndjson",
+            "keywords": [
+                "NDJSON",
+                "json",
+                "jsonlines",
+                "newline",
+                "reactphp",
+                "streaming"
+            ],
+            "support": {
+                "issues": "https://github.com/clue/reactphp-ndjson/issues",
+                "source": "https://github.com/clue/reactphp-ndjson/tree/v1.3.0"
+            },
+            "funding": [
+                {
+                    "url": "https://clue.engineering/support",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/clue",
+                    "type": "github"
+                }
+            ],
+            "time": "2022-12-23T10:58:28+00:00"
+        },
+        {
+            "name": "codeigniter/coding-standard",
+            "version": "v1.9.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/CodeIgniter/coding-standard.git",
+                "reference": "e9c690ebb86140a2ddf874940b0758c4b88110ce"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/CodeIgniter/coding-standard/zipball/e9c690ebb86140a2ddf874940b0758c4b88110ce",
+                "reference": "e9c690ebb86140a2ddf874940b0758c4b88110ce",
+                "shasum": ""
+            },
+            "require": {
+                "ext-tokenizer": "*",
+                "friendsofphp/php-cs-fixer": "^3.95",
+                "nexusphp/cs-config": "^3.28",
+                "php": "^8.2"
+            },
+            "require-dev": {
+                "nexusphp/tachycardia": "^2.4",
+                "phpstan/phpstan": "^2.1",
+                "phpunit/phpunit": "^11.5 || ^12.5"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "CodeIgniter\\CodingStandard\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "John Paul E. Balandan, CPA",
+                    "email": "[email protected]"
+                }
+            ],
+            "description": "Official Coding Standards for CodeIgniter based on PHP CS Fixer",
+            "keywords": [
+                "phpcs",
+                "static analysis"
+            ],
+            "support": {
+                "forum": "http://forum.codeigniter.com/",
+                "issues": "https://github.com/CodeIgniter/coding-standard/issues",
+                "slack": "https://codeigniterchat.slack.com",
+                "source": "https://github.com/CodeIgniter/coding-standard"
+            },
+            "time": "2026-04-11T20:06:02+00:00"
+        },
+        {
+            "name": "composer/pcre",
+            "version": "3.4.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/composer/pcre.git",
+                "reference": "d5a341b3fb61f3001970940afb1d332968a183ed"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/composer/pcre/zipball/d5a341b3fb61f3001970940afb1d332968a183ed",
+                "reference": "d5a341b3fb61f3001970940afb1d332968a183ed",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.4 || ^8.0"
+            },
+            "conflict": {
+                "phpstan/phpstan": "<2.2.2"
+            },
+            "require-dev": {
+                "phpstan/phpstan": "^2",
+                "phpstan/phpstan-deprecation-rules": "^2",
+                "phpstan/phpstan-strict-rules": "^2",
+                "phpunit/phpunit": "^9"
+            },
+            "type": "library",
+            "extra": {
+                "phpstan": {
+                    "includes": [
+                        "extension.neon"
+                    ]
+                },
+                "branch-alias": {
+                    "dev-main": "3.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Composer\\Pcre\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jordi Boggiano",
+                    "email": "[email protected]",
+                    "homepage": "http://seld.be"
+                }
+            ],
+            "description": "PCRE wrapping library that offers type-safe preg_* replacements.",
+            "keywords": [
+                "PCRE",
+                "preg",
+                "regex",
+                "regular expression"
+            ],
+            "support": {
+                "issues": "https://github.com/composer/pcre/issues",
+                "source": "https://github.com/composer/pcre/tree/3.4.0"
+            },
+            "funding": [
+                {
+                    "url": "https://packagist.com",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/composer",
+                    "type": "github"
+                }
+            ],
+            "time": "2026-06-07T11:47:49+00:00"
+        },
+        {
+            "name": "composer/semver",
+            "version": "3.4.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/composer/semver.git",
+                "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95",
+                "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.3.2 || ^7.0 || ^8.0"
+            },
+            "require-dev": {
+                "phpstan/phpstan": "^1.11",
+                "symfony/phpunit-bridge": "^3 || ^7"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "3.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Composer\\Semver\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nils Adermann",
+                    "email": "[email protected]",
+                    "homepage": "http://www.naderman.de"
+                },
+                {
+                    "name": "Jordi Boggiano",
+                    "email": "[email protected]",
+                    "homepage": "http://seld.be"
+                },
+                {
+                    "name": "Rob Bast",
+                    "email": "[email protected]",
+                    "homepage": "http://robbast.nl"
+                }
+            ],
+            "description": "Semver library that offers utilities, version constraint parsing and validation.",
+            "keywords": [
+                "semantic",
+                "semver",
+                "validation",
+                "versioning"
+            ],
+            "support": {
+                "irc": "ircs://irc.libera.chat:6697/composer",
+                "issues": "https://github.com/composer/semver/issues",
+                "source": "https://github.com/composer/semver/tree/3.4.4"
+            },
+            "funding": [
+                {
+                    "url": "https://packagist.com",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/composer",
+                    "type": "github"
+                }
+            ],
+            "time": "2025-08-20T19:15:30+00:00"
+        },
+        {
+            "name": "composer/xdebug-handler",
+            "version": "3.0.5",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/composer/xdebug-handler.git",
+                "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef",
+                "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef",
+                "shasum": ""
+            },
+            "require": {
+                "composer/pcre": "^1 || ^2 || ^3",
+                "php": "^7.2.5 || ^8.0",
+                "psr/log": "^1 || ^2 || ^3"
+            },
+            "require-dev": {
+                "phpstan/phpstan": "^1.0",
+                "phpstan/phpstan-strict-rules": "^1.1",
+                "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Composer\\XdebugHandler\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "John Stevenson",
+                    "email": "[email protected]"
+                }
+            ],
+            "description": "Restarts a process without Xdebug.",
+            "keywords": [
+                "Xdebug",
+                "performance"
+            ],
+            "support": {
+                "irc": "ircs://irc.libera.chat:6697/composer",
+                "issues": "https://github.com/composer/xdebug-handler/issues",
+                "source": "https://github.com/composer/xdebug-handler/tree/3.0.5"
+            },
+            "funding": [
+                {
+                    "url": "https://packagist.com",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/composer",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2024-05-06T16:37:16+00:00"
+        },
+        {
+            "name": "ergebnis/agent-detector",
+            "version": "1.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/ergebnis/agent-detector.git",
+                "reference": "e211f17928c8b95a51e06040792d57f5462fb271"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/ergebnis/agent-detector/zipball/e211f17928c8b95a51e06040792d57f5462fb271",
+                "reference": "e211f17928c8b95a51e06040792d57f5462fb271",
+                "shasum": ""
+            },
+            "require": {
+                "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0 || ~8.6.0"
+            },
+            "require-dev": {
+                "ergebnis/composer-normalize": "^2.51.0",
+                "ergebnis/license": "^2.7.0",
+                "ergebnis/php-cs-fixer-config": "^6.60.2",
+                "ergebnis/phpstan-rules": "^2.13.1",
+                "ergebnis/phpunit-slow-test-detector": "^2.24.0",
+                "ergebnis/rector-rules": "^1.18.1",
+                "fakerphp/faker": "^1.24.1",
+                "infection/infection": "^0.26.6",
+                "phpstan/extension-installer": "^1.4.3",
+                "phpstan/phpstan": "^2.1.54",
+                "phpstan/phpstan-deprecation-rules": "^2.0.4",
+                "phpstan/phpstan-phpunit": "^2.0.16",
+                "phpstan/phpstan-strict-rules": "^2.0.10",
+                "phpunit/phpunit": "^9.6.34",
+                "rector/rector": "^2.4.2"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.2-dev"
+                },
+                "composer-normalize": {
+                    "indent-size": 2,
+                    "indent-style": "space"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Ergebnis\\AgentDetector\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Andreas Möller",
+                    "email": "[email protected]",
+                    "homepage": "https://localheinz.com"
+                }
+            ],
+            "description": "Provides a detector for detecting the presence of an agent.",
+            "homepage": "https://github.com/ergebnis/agent-detector",
+            "support": {
+                "issues": "https://github.com/ergebnis/agent-detector/issues",
+                "security": "https://github.com/ergebnis/agent-detector/blob/main/.github/SECURITY.md",
+                "source": "https://github.com/ergebnis/agent-detector"
+            },
+            "time": "2026-05-07T08:19:07+00:00"
+        },
+        {
+            "name": "evenement/evenement",
+            "version": "v3.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/igorw/evenement.git",
+                "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc",
+                "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9 || ^6"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Evenement\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Igor Wiedler",
+                    "email": "[email protected]"
+                }
+            ],
+            "description": "Événement is a very simple event dispatching library for PHP",
+            "keywords": [
+                "event-dispatcher",
+                "event-emitter"
+            ],
+            "support": {
+                "issues": "https://github.com/igorw/evenement/issues",
+                "source": "https://github.com/igorw/evenement/tree/v3.0.2"
+            },
+            "time": "2023-08-08T05:53:35+00:00"
+        },
+        {
+            "name": "fakerphp/faker",
+            "version": "v1.24.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/FakerPHP/Faker.git",
+                "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5",
+                "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.4 || ^8.0",
+                "psr/container": "^1.0 || ^2.0",
+                "symfony/deprecation-contracts": "^2.2 || ^3.0"
+            },
+            "conflict": {
+                "fzaninotto/faker": "*"
+            },
+            "require-dev": {
+                "bamarni/composer-bin-plugin": "^1.4.1",
+                "doctrine/persistence": "^1.3 || ^2.0",
+                "ext-intl": "*",
+                "phpunit/phpunit": "^9.5.26",
+                "symfony/phpunit-bridge": "^5.4.16"
+            },
+            "suggest": {
+                "doctrine/orm": "Required to use Faker\\ORM\\Doctrine",
+                "ext-curl": "Required by Faker\\Provider\\Image to download images.",
+                "ext-dom": "Required by Faker\\Provider\\HtmlLorem for generating random HTML.",
+                "ext-iconv": "Required by Faker\\Provider\\ru_RU\\Text::realText() for generating real Russian text.",
+                "ext-mbstring": "Required for multibyte Unicode string functionality."
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Faker\\": "src/Faker/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "François Zaninotto"
+                }
+            ],
+            "description": "Faker is a PHP library that generates fake data for you.",
+            "keywords": [
+                "data",
+                "faker",
+                "fixtures"
+            ],
+            "support": {
+                "issues": "https://github.com/FakerPHP/Faker/issues",
+                "source": "https://github.com/FakerPHP/Faker/tree/v1.24.1"
+            },
+            "time": "2024-11-21T13:46:39+00:00"
+        },
+        {
+            "name": "fidry/cpu-core-counter",
+            "version": "1.3.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/theofidry/cpu-core-counter.git",
+                "reference": "db9508f7b1474469d9d3c53b86f817e344732678"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678",
+                "reference": "db9508f7b1474469d9d3c53b86f817e344732678",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.2 || ^8.0"
+            },
+            "require-dev": {
+                "fidry/makefile": "^0.2.0",
+                "fidry/php-cs-fixer-config": "^1.1.2",
+                "phpstan/extension-installer": "^1.2.0",
+                "phpstan/phpstan": "^2.0",
+                "phpstan/phpstan-deprecation-rules": "^2.0.0",
+                "phpstan/phpstan-phpunit": "^2.0",
+                "phpstan/phpstan-strict-rules": "^2.0",
+                "phpunit/phpunit": "^8.5.31 || ^9.5.26",
+                "webmozarts/strict-phpunit": "^7.5"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Fidry\\CpuCoreCounter\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Théo FIDRY",
+                    "email": "[email protected]"
+                }
+            ],
+            "description": "Tiny utility to get the number of CPU cores.",
+            "keywords": [
+                "CPU",
+                "core"
+            ],
+            "support": {
+                "issues": "https://github.com/theofidry/cpu-core-counter/issues",
+                "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/theofidry",
+                    "type": "github"
+                }
+            ],
+            "time": "2025-08-14T07:29:31+00:00"
+        },
+        {
+            "name": "friendsofphp/php-cs-fixer",
+            "version": "v3.95.24",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
+                "reference": "9a4b8050f8768646bf3693ee7416978ceeca6206"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/9a4b8050f8768646bf3693ee7416978ceeca6206",
+                "reference": "9a4b8050f8768646bf3693ee7416978ceeca6206",
+                "shasum": ""
+            },
+            "require": {
+                "clue/ndjson-react": "^1.3",
+                "composer/semver": "^3.4",
+                "composer/xdebug-handler": "^3.0.5",
+                "ergebnis/agent-detector": "^1.2",
+                "ext-filter": "*",
+                "ext-hash": "*",
+                "ext-json": "*",
+                "ext-tokenizer": "*",
+                "fidry/cpu-core-counter": "^1.3",
+                "php": "^7.4 || ^8.0",
+                "react/child-process": "^0.6.6",
+                "react/event-loop": "^1.5",
+                "react/socket": "^1.16",
+                "react/stream": "^1.4",
+                "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0 || ^8.0 || ^9.0",
+                "symfony/console": "^5.4.47 || ^6.4.24 || ^7.0 || ^8.0",
+                "symfony/event-dispatcher": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0",
+                "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0",
+                "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0",
+                "symfony/options-resolver": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0",
+                "symfony/polyfill-mbstring": "^1.37",
+                "symfony/polyfill-php80": "^1.37",
+                "symfony/polyfill-php81": "^1.37",
+                "symfony/polyfill-php84": "^1.37",
+                "symfony/process": "^5.4.47 || ^6.4.24 || ^7.2 || ^8.0",
+                "symfony/stopwatch": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0"
+            },
+            "require-dev": {
+                "facile-it/paraunit": "^1.3.1 || ^2.11.0",
+                "infection/infection": "^0.32.7",
+                "justinrainbow/json-schema": "^6.10.0",
+                "keradus/cli-executor": "^2.3",
+                "php-coveralls/php-coveralls": "^2.9.1",
+                "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.8",
+                "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.8",
+                "phpunit/phpunit": "^9.6.35 || ^10.5.64 || ^11.5.56 || ^12.5.31 || ^13.0.6",
+                "symfony/polyfill-php85": "^1.38",
+                "symfony/var-dumper": "^5.4.48 || ^6.4.36 || ^7.4.8 || ^8.1.1",
+                "symfony/yaml": "^5.4.53 || ^6.4.41 || ^7.4.13 || ^8.1.1"
+            },
+            "suggest": {
+                "ext-dom": "For handling output formats in XML",
+                "ext-mbstring": "For handling non-UTF8 characters."
+            },
+            "bin": [
+                "php-cs-fixer"
+            ],
+            "type": "application",
+            "autoload": {
+

[Diff truncated. Use the raw view or local clone for the full content.]