Working with Modules and Extension Development
A module is defined by registration.php (registering the module name with the component registrar) and etc/module.xml (module name and sequence dependencies). composer.json declares package metadata and autoloading. The sequence node controls load order of configuration files - if module A's di.xml references a class from module B, A must sequence B, otherwise merge order and class resolution can fail.
Module structure follows areas: etc/ for global config, etc/frontend/, etc/adminhtml/, etc/webapi.xml for REST/SOAP routes, etc/graphql or etc/schema.graphqls for GraphQL, Setup/ for install/upgrade scripts and patches, Controller/ for actions, Model/, Block/, ViewModel/, and view/ for layouts, templates, and static assets.
Schema changes should use declarative schema (etc/db_schema.xml) with data patches (Patch/ implementing DataPatchInterface) rather than legacy install scripts. Declarative schema is applied by setup:upgrade and supports whitelisting for destructive changes.
Extension points to know: plugins, preferences, observers (etc/events.xml), cron, REST/GraphQL, and UI component modifiers. A frequent trap is confusing an observer (event-driven, no return value control) with a plugin (intercepts a method and can alter arguments or return values). Another is forgetting that a new module must be enabled with bin/magento module:enable Vendor_Module before setup:upgrade will register it.
Worked example: To intercept a repository save, declare a plugin in etc/di.xml with <type name="Vendor\Module\Api\RepositoryInterface"><plugin name="..." type="Vendor\Module\Plugin\RepositoryPlugin"/></type>. Because the type is an interface, the plugin applies to whatever preference implements it - do not target the concrete class unless you intend to skip other implementations.