Routing in an addon works exactly like core Laravel: Routes/web.php holds session-based web routes and Routes/api.php holds stateless API routes, both loaded by your addon's RouteServiceProvider via module_path() with the web or api middleware groups. Group routes under your addon's URL prefix and give every route a namespaced name (e.g. emailvalidator.rules.show); resource routes, route parameters, constraints, and API versioning prefixes all work as usual. The provider can even load different route files conditionally by user role (common, admin, client).
Available middleware includes web, auth, 2fa, lang, and admin; apply them on route groups, individual routes, or in a controller constructor. You can also write addon-specific middleware in Http/Middleware/ (e.g. a quota check) and register it with aliasMiddleware() in your service provider before using the alias in routes.
Controllers live in Http/Controllers/ under your addon namespace and extend the core App\Http\Controllers\Controller. Keep them thin: validate with form request classes in Http/Requests/ (rules, authorize, custom messages), authorize with policies via $this->authorize(), and move business logic into services. Web actions return addon views with the youralias::view syntax; API controllers should return a consistent JSON shape — success, data, and pagination meta on success, success: false with errors and a proper status code on failure. Webhook endpoints can drop auth with withoutMiddleware().