Skip to content

Changed all services to use one instantiation pattern - #35

Open
ErisDS wants to merge 1 commit into
codex/service-instantiation-patternfrom
codex/standardise-all-services
Open

ErisDS wants to merge 1 commit into
codex/service-instantiation-patternfrom
codex/standardise-all-services

Conversation

@ErisDS

@ErisDS ErisDS commented Aug 18, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Gives every runtime service under core/server/services the same public shape: an explicit init() entry point and a service facade.
  • Makes boot responsible for construction and updates consumers to use the initialized facade, while retaining lazy failure messages for accidental use before initialization.
  • Adds a contract test that classifies every top-level directory and prevents actual service roots from drifting back to incompatible export shapes.

This PR is based on #34 so the complete pattern and this repository-wide application can be reviewed separately.

What counts as a service here?

The conversion classifies all 73 top-level directories: 60 runtime service roots and 13 directories that do not represent independently initialized runtime services.

  • subsystems or modules: auth, api-version-compatibility, public-config
  • actions or jobs: invitations, update-check
  • infrastructure or factories: mail
  • support or domain modules: email-rendering, exports, files, integrations, lib, tier-checkout-config, verification

The rebase also brings the five runtime services added since the original PR into the same contract: content-import, export-requests, jobs-service, members-metafields, and tinybird-sync.

Non-service directories are classified by the contract test but are not forced into a lifecycle they do not have. Moving them to their eventual domain or Kernel locations is intentionally separate from this mechanical standardisation.

Implementation notes

  • Service roots expose {init, service}. TypeScript roots use equivalent named exports.
  • init() owns construction and is safe to call more than once. Services whose state is intentionally refreshed on each Ghost boot, such as settings, permissions, themes, and route settings, retain that behaviour.
  • Composite services keep their existing nested API where changing it would be a separate design refactor.
  • Redundant lazy-construction wrappers are folded into their composition roots. Factories remain separate only where they perform meaningful composition.
  • Current main behaviour for background jobs, imports, exports, member metafields, Tinybird sync, and repeated in-process boots is preserved.

Follow-ups

  • Add a generator for the standard service skeleton and its boot registration.
  • Move the 13 classified non-service directories as the repo-structure work establishes their final homes.
  • Consider a small declarative boot loader once service dependencies and initialization phases are explicit. The shared lazySingleton facade is deliberately smaller than that future abstraction.

Testing

  • pnpm exec vitest run test/unit/server/services/service-roots.test.js test/unit/server/services/email-service/email-service-factory.test.js test/unit/server/services/link-tracking/index.test.ts test/unit/server/services/recommendations/service/incoming-recommendation-email-renderer.test.ts test/unit/server/services/automations/poll.test.ts — 91 tests passed
  • pnpm lint:server && pnpm lint:test
  • pnpm lint:frontend && pnpm lint:shared
  • git diff --cached --check
  • Commit checks: formatting, focused ESLint, dependency boundaries, secret scanning, and submodule checks
  • Full Core test suite and E2E suite will run in GitHub CI after the rebase

@github-actions

Copy link
Copy Markdown

E2E Tests Failed

To view the Playwright test report locally, run:

REPORT_DIR=$(mktemp -d) && gh run download 32101607621 -n playwright-report -D "$REPORT_DIR" && npx playwright show-report "$REPORT_DIR"

no ref

Service roots had accumulated incompatible export and lifecycle shapes. Standardising them on explicit init and service exports gives boot clear ownership and creates a stable base for generation and future boot-loader work.
@ErisDS
ErisDS force-pushed the codex/service-instantiation-pattern branch from 48d7bd3 to 33457ac Compare September 23, 2026 14:20
@ErisDS
ErisDS force-pushed the codex/standardise-all-services branch from 1dd74ea to 8e9c3c6 Compare September 23, 2026 14:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant