JCC Express

Service Provider

Introduction

Service providers are the main way to bootstrap features in JCC Express MVC. Each provider is a class that receives the Application (the service container) and uses register() to bind services and boot() to run logic after all providers have registered—mirroring Laravel’s register / boot split.

Listing providers in bootstrap/providers.ts and implementing them under app/Providers/ keeps startup explicit and ordered.


What a provider does

A provider connects the framework to your app:

  • Register container bindings (bind, singleton, instance) so other code can resolve them.
  • Boot behavior that depends on those bindings (routes are not registered here—RouteServiceProvider loads route files during app.run(), but your boot() can use Gate, events, or other services already on the container).

The abstract base class lives in jcc-express-mvc (ServiceProvider). Extend it from jcc-express-mvc/Core/Provider (re-export) or the underlying lib/Providers/ServiceProvider.


The ServiceProvider base class

  • constructor(protected app: Application) — Stores the application instance as this.app.
  • abstract register(): void — You must implement this. Put container registrations here only; avoid resolving services that other providers have not registered yet.
  • boot(): void | Promise<void> — Optional override. Runs after every provider’s register() has completed (see When register and boot run). Use for Gate.define, subscribing to events, or resolving bindings that need the full container.
  • listen / subscribe — Optional maps used when bootListeners or bootSubscribers is set on the provider so the Application wires event listeners or subscribers during registration.

Registration order (ApplicationBuilder)

In withProviders(), the builder does not use your array alone. It builds this chain:

  1. DatabaseServiceProvider — Always first (database-related setup).
  2. Your providers from bootstrap/providers.ts — If AuthServiceProvider (framework) is in the list but not first, the builder moves it to the front of your list so auth is set up early.
  3. QueueServiceProvider — Always last in the chain.

That order matters when one provider’s register() assumes another binding already exists.


When register and boot run

During bootstrap/app build:

  • For each provider class in the chain, new Provider(app) is called, then register() runs immediately.
  • If the provider sets bootSubscribers / bootListeners, the app may call subscribers() / listeners() right after that provider registers.

boot() for all providers:

  • When app.boot() runs (for example from app.run() if the app was not yet booted), the application loops this.providers and calls boot() on each in registration order.

Late registration:

  • If a provider is registered after the application is already booted, register() still runs, and bootProvider is invoked immediately for that provider so it does not miss the boot phase.

Writing a provider

  1. Create a class under app/Providers/ extending ServiceProvider.
  2. Implement register() with this.app.bind, singleton, etc.
  3. Override boot() when you need work after all register() methods have finished.
  4. Add the class to the providers array exported from bootstrap/providers.ts (already imported by bootstrap/app.ts via withProviders).

Keep register() free of heavy side effects and of resolve() calls that depend on providers later in the chain unless you know the order.


Example

TypeScript
TypeScript

Framework providers you should know about

  • DatabaseServiceProvider — Database / ORM wiring; runs before your list.
  • AuthServiceProvider (when included) — Intended to run early among your providers.
  • QueueServiceProvider — Queue binding; runs after your list.
  • RouteServiceProvider — Not in your bootstrap/providers.ts list by default; it is registered as a singleton on Application and loadRoutes() is invoked from app.run() to load route/web, route/api, etc.

Your AppServiceProvider (and any custom providers) are where application-specific bindings and boot logic belong.