Instruction file imported from aKira041795/Ikabud-CMS-Kernel (
.github/instructions/module-creation-conventions.instructions.md). Copyright stays with the author.
New Module Instructions
User Seeding
- Role ENUM must include ALL roles upfront. Use
migration 020 → ALTER TABLEonly if missed. - Seed users: one per role with bcrypt hash, email, and store_id.
module.jsonauth_owned.email_columnmust be"email".module.jsonauth_ownedMUST declareid_column(matches table PK, e.g."user_id") androle_column(e.g."role"). The kernel tenant admin push handlers use these to build SQL — missingid_columncauses the table to be silently skipped on email/password changes.
Standalone Entry Modules
- Any new module that owns users/auth is a standalone tenant-entry module, not a shared helper module.
- Such modules MUST declare
auth_ownedinmodule.jsonand MUST be selected in Admin > Tenants for each tenant that should receive that module bundle. - If the module is intended to be the default tenant bundle, make that default explicit in the manifest/docs rather than relying on hidden assumptions.
- If the module is not an auth-owning entry module, keep it dependency-only and do not expect it to appear as a tenant dropdown default.
Tenant Entry Migration Scope (Mandatory)
- Tenant migration cleanup must be handled through tenant admin flows (
/api/v1/admin/tenants/create,/api/v1/admin/tenants/entry-module,/api/v1/admin/tenants/db) and never require manual SQL from users. - Any change to module dependency/planning logic MUST preserve scoped plans for entry modules and MUST NOT pull unrelated module trees.
- For entry-module tests, verify
tenantProvisionModulePlan(<entry>)excludes unrelated modules (example: AISS tables must never appear when testing CMS Akira entry). - If migration scope drift is detected, repair must target unrelated modules with owned tables only; avoid deleting same-family optional modules.
- New modules must include a regression assertion in tenant provisioning tests that proves no unrelated modules are introduced by the entry plan.
DiSyL Syntax
{block name}— NO quotes around block name.{block "name"}breaks silently.{ikb_entity_view name="X" view="Y"}— config usesname=notsource=.{ikb_entity_list source="X" view="Y" /}— template tag usessource=with self-closing/.- No
$prefix on variables:{user.name}not{$user.name}. - Use
|number_format:2,|capitalize,|date:"M d, Y"— not PHP functions.
Capability Handlers
- MUST be loaded from
helpers.php(nothandlers.php). - Module manager checks
is_callable()at registration time — handlers.php runs too late.
JWT Auth
- Login: generate JWT via
app()->jwt()->generate(), set cookie. DO NOT use$ctx->setUser(). - Payload MUST include
user_idandstore_id— handlers access these keys. - Logout: clear cookie. DO NOT use
$ctx->logout().
Forgot Password
- Table:
<prefix>_password_resets. MUST be inmodule.jsonowns_tables. - Reset URL is logged to
storage/logs/app.logviawrite_log()— no mail server needed in dev.- Build the reset URL using the request host, notconfig('app.url')—APP_URLmay differ from the actual domain. ✅$scheme . '://' . $_SERVER['HTTP_HOST'] . '/reset-password?token=' . $token❌config('app.url') . '/reset-password?token=' . $token - Send a branded email using
buildEmailTemplate()+sendEmail()— see skill for full pattern. Always checkfunction_exists()before calling. The URL is still logged toapp.logas fallback.
Post-Creation
- Run
php ikabud tenant:migrate <domain> <module> - Check app.log for capability warnings
- Test login with each seeded role
- Check app.log for
reset_urlafter forgot password - Verify
/admin/tenantspush handles the module's user table