Module Skeleton: registration.php, module.xml, and Namespace Conventions
Module Skeleton: registration.php, module.xml, and Namespace Conventions
~6 Min. Lesezeit Zuletzt aktualisiert am August 9, 2026
Before chapter 3 designs the first table, the module itself needs to exist: a registered namespace that Magento recognizes at startup. This chapter sets up Mironsoft\Loyalty and explains the naming conventions that all 105 following chapters stick to.
Namespace and module name
The PHP namespace is Mironsoft\Loyalty, the Magento module name (with an underscore instead of a backslash, as required in module.xml and registration.php) is Mironsoft_Loyalty. The module folder lives under app/code/Mironsoft/Loyalty/ - vendor and module name directly form the first two directory levels, PSR-4 compliant.
Storefront URLs will later (block 6) get their own front name: treuepraemien on the German store view and rewards on the English one. That's just a side note at this point - the router itself only gets built in chapter 46, once there are actually controllers for it to route to.
Target structure after block 1
The overview below shows what the module looks like once all nine chapters of this block are done. The individual files are created gradually across chapters 3 through 9 - later blocks add further directories (Model/Reward/, Observer/, Cron/, Controller/, and so on) without changing anything from block 1.
Mironsoft\Loyalty after block 1 (chapters 1-9)
app/code/Mironsoft/Loyalty/
├── registration.php
├── composer.json
├── etc/
│ ├── module.xml
│ ├── di.xml
│ ├── acl.xml
│ ├── cache.xml
│ ├── config.xml
│ └── adminhtml/
│ └── system.xml
├── Api/
│ ├── PointsLedgerRepositoryInterface.php
│ └── Data/
│ └── PointsLedgerInterface.php
├── Model/
│ ├── PointsLedger.php
│ ├── PointsLedgerRepository.php
│ ├── Cache/
│ │ └── Type/
│ │ └── LoyaltyCatalog.php
│ ├── Config/
│ │ └── LoyaltyConfig.php
│ ├── ResourceModel/
│ │ ├── PointsLedger.php
│ │ └── PointsLedger/
│ │ └── Collection.php
│ └── Service/
│ └── PointsCalculator.php
└── Console/
└── Command/
└── RecalculatePointsCommand.phpregistration.php
Every Magento 2 module registers itself via ComponentRegistrar::register() - without this file, the module stays invisible to Magento no matter what else is in the folder.
<?php
declare(strict_types=1);
use Magento\Framework\Component\ComponentRegistrar;
ComponentRegistrar::register(
ComponentRegistrar::MODULE,
'Mironsoft_Loyalty',
__DIR__
);module.xml with a sequence
module.xml declares the module name and - important for chapter 3 - a <sequence>. The points ledger has foreign keys referencing tables from Magento_Customer and Magento_Sales; to guarantee setup:upgrade has already created those tables before db_schema.xml references them, both modules need to be listed in the sequence.
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Mironsoft_Loyalty">
<sequence>
<module name="Magento_Customer"/>
<module name="Magento_Sales"/>
</sequence>
</module>
</config>Achtung: A missing sequence doesn't stand out right away: on a development system where Magento_Customer and Magento_Sales are already installed anyway, everything just works. On a fresh installation, though, Magento might pick a different module order, and db_schema.xml tries to add a foreign key to a table that doesn't exist yet - setup:upgrade then aborts with a SQL error.
Naming conventions for the rest of the series
- PHP classes: always
declare(strict_types=1), constructor property promotion for dependency injection, full PHPDoc on every class and every method. - Database tables:
mironsoft_loyalty_<entity>, for examplemironsoft_loyalty_points_ledger(chapter 3). - Configuration paths:
mironsoft_loyalty/<group>/<field>, for examplemironsoft_loyalty/general/points_per_euro(chapter 7). - ACL resources:
Mironsoft_Loyalty::<area>, consistent with this project's other Mironsoft modules. addFieldToFilter()with an integer value is always written as['eq' => $value], never as a bare scalar - chapter 4 demonstrates this on the first collection.
Tipp: These conventions come directly from this project's CLAUDE.md - they apply identically to all twelve blocks of this series, not just block 1.
With the module registered and the correct sequence in place, chapter 3 can design the first table.