DACore · coming December 2026
How DACore replaces admin boilerplate in DotApp PHP Framework
The framework already has a one-shot install.php for a module that boots itself.
That is the right tool for a portable Shop or a public Docs site.
It is the wrong tool if the next thing you need is a complete administration workspace: users in MySQL, a login screen, 2FA, a sidebar, and a way to install the next module from a ZIP.
DACore replaces that boilerplate. It does not replace DotApp.
Common mistakes
| Wrong | Right |
|---|---|
Put install.php in a ZIP you upload to the DACore plugin installer. |
Use dainstall.php. DACore rejects a package that looks like a framework one-shot install. |
Create users or dotapp_users by hand in your module. |
DACore (with DotApp schema) owns core auth tables. Your tables are shop_*, never dacore_*. |
Track migrations only in a private {module}_installations table when you live under DACore. |
Guard with DACore:Installations@exist! and record with @insert!. |
| Leave the app broken when MySQL is missing. | DACore shows a setup page and holds back the admin until the database is ready. |
| Copy login views from an old project into the new module. | Use DACore login, then render your pages with Page@withMenu!. |
Two installers, two jobs
| Framework module | DACore plugin | |
|---|---|---|
| Entry file | install.php (one-shot, renamed after run) |
dainstall.php (runs on install and update) |
| Init files | Live at the module root | Canonical copies in init/; DACore copies them after a successful install |
| Migration log | Module-owned table if you add one | dacore_installations via DACore APIs |
| Menu and rights | You invent them, or you have none | Menu@register, Rights@createGroup! |
| Distribution | Copy the folder into app/modules/ |
ZIP through the DACore Plugins UI |
Framework migrations are still documented in the AI blog:
How to create database migrations with Installation.php.
DACore does not delete that path. It is the path for modules that do not sit under the admin desk.
The moment a module must appear in the DACore sidebar and survive uninstall, you switch to dainstall.php.
Two layers of schema
When MySQL is configured and reachable, DACore bootstraps two layers.
DotApp core auth tables (prefix from Config::db('prefix'), often dotapp_):
users, IP firewall, URL firewall, rights groups, rights list, user-right links, roles, role-right links, remember-me tokens, sessions, password resets.
That is the identity layer other modules must not recreate.
DACore tables (dacore_*):
installation audit, menu tree, AI tool registry, chat, user profiles, devices, settings, login events and lockouts, IP geo cache, installed module registry, plugin logs, notifications and inbox.
Those tables belong to DACore. Your module never INSERTs into them directly. Registration APIs exist so column compatibility and cache invalidation stay in one place.
What happens on first start
Installation::bootstrapIfNeeded() runs with the module.
If the database is not configured or not connected, DACore does not pretend the admin works. It keeps a setup route and a 503-style “database required” page.
If the core users table is missing, it runs the full DACore install.
If the core exists but a later migration is pending, it applies the rest.
When the database becomes ready, it can seed the first administrator from module config — you change those credentials in app/config.php for a real deployment. This article will not print default passwords.
That is the time save. You are not writing a custom “is MySQL up?” installer for the fifth project.
You point Config::addDatabase at a schema, load DACore, and the admin workspace appears behind the prefix.
Config stays in app/config.php
DACore sets fallbacks in initialize() the same way every portable module must:
URL prefix, whether / redirects into the admin, login / register / reset toggles, languages, 2FA QR colors, AI driver settings, cache for the menu.
Production overrides belong in app/config.php via Config::module('DACore', …).
You do not fork the DACore folder to change the prefix from /dacore to /admin.
Config::module('DACore', 'prefixUrl', '/admin');
Config::module('DACore', 'overtakeUrl', false);
overtakeUrl is the switch that claims site / for the desk. A public marketing site running Docs should leave that off. An intranet that is only the admin can turn it on.
What you still write
DACore does not write your warehouse, your CMS, or your booking calendar.
It gives you a logged-in operator, a permission string format Module.rightname, a sidebar slot, and a page chrome.
Your Installation.php still creates warehouse_* tables, seeds rights, and registers menu ids prefixed with your module name.
Uninstall still has to drop those tables. The host is shared. The data is yours.
FAQ
Is DB::migrate() how DACore installs?
No. Same rule as the rest of DotApp: DB::migrate() is not the installer. Versioned callbacks on Installation plus DACore’s installation log are.
Will /dacore on this documentation site collide?
This public site does not load the live DACore admin module. The documentation section uses the same path as a product URL. Do not install DACore into the Docs app if you want these pages to keep that prefix.
Can a framework-only module become a DACore plugin later?
Yes, if you add dainstall.php, init/ copies, rights, menu, and an uninstaller, and you remove root install.php from the ZIP. TestInstalatora is the shape to copy.