Skip to main content

Phase 11: Package Split & MX Pattern

Objective: Enable enterprises to build custom "MX" variants (e.g., MongoDB-primary, Cassandra-primary) without forking, via pure package composition.

[!NOTE] This phase should only be started AFTER Phases 1-10 are stable. The split is a refactor, not a feature addition.


1. Package Split Strategy

1.1 Split into Core + Standard

  • Create framework-m-core package:

    • All Protocols (Repository, Permission, EventBus, Cache, etc.)
    • DI Container setup (dependency-injector)
    • BaseDocTypeProtocol (not concrete class)
    • Controller/Hook system
    • CLI framework (cyclopts base)
    • Zero adapters, zero concrete implementations
  • Create framework-m-standard package:

    • Depends on framework-m-core
    • SQLAlchemy adapters (SchemaMapper, GenericRepository, UnitOfWork)
    • RBAC PermissionAdapter
    • Redis EventBusAdapter
    • Arq JobQueueAdapter
    • Default Bootstrap sequence
  • Create framework-m meta-package:

    • Depends on both framework-m-core + framework-m-standard
    • "Batteries included" install for Indie devs

1.2 Decouple Development Tooling

  • Move scaffolding and codegen from framework-m to framework-m-studio:
    • Move new:app command and templates
    • Move new:doctype command and templates
    • Move new:site (placeholder) to Studio
    • Move all Jinja2-based scaffolding code
    • Goal: framework-m (Core/Standard) should have zero dependencies on Jinja2 or LibCST.
    • Result: framework-m is optimized for production containers, while framework-m-studio remains the developer's workbench.

2. Protocols to Extract to Core

2.1 Ensure All Protocols are Pure

  • RepositoryProtocol — no SQLAlchemy types
  • UnitOfWorkProtocol — generic session interface
  • SchemaMapperProtocol — Pydantic → Storage mapping
  • BootstrapProtocol — Startup step interface
  • Verify: No imports from sqlalchemy in framework-m-core

2.2 BaseDocType as Protocol

  • Create BaseDocTypeProtocol:
    class BaseDocTypeProtocol(Protocol):
    id: str
    name: str
    created_at: datetime
    modified_at: datetime
  • framework-m-standard provides BaseDocType(BaseDocTypeProtocol) with owner, _version, etc.
  • MX packages can provide their own BaseDocType

3. Bootstrap via Entry Points

3.1 Define Bootstrap Plugin System

  • Create entry point group: framework_m.bootstrap
  • Define BootstrapStep protocol:
    class BootstrapStep(Protocol):
    name: str
    order: int # Lower runs first
    async def run(self, container: Container) -> None: ...
  • Discover and sort steps from entry points
  • Allow MX packages to override steps by name

3.2 Default Bootstrap Steps (framework-m-standard)

  • init_engine (order=10) — Create SQLAlchemy engine
  • init_registries (order=20) — MetaRegistry, FieldRegistry
  • sync_schema (order=30) — Run SchemaMapper on all DocTypes
  • init_adapters (order=40) — Bind adapters to DI container

4. Adapter Auto-Discovery

4.1 Entry Point Groups for Adapters

  • framework_m.adapters.repository — GenericRepository implementation
  • framework_m.adapters.schema_mapper — SchemaMapper implementation
  • framework_m.adapters.unit_of_work — UnitOfWork implementation
  • framework_m.adapters.permission — PermissionAdapter
  • framework_m.adapters.event_bus — EventBusAdapter

4.2 DI Auto-Binding

  • On startup, scan entry points
  • Bind discovered adapters to Protocols in DI container
  • Priority: Explicit config > Entry point > Default

5. Example: framework-mx-mongo

5.1 Package Structure

  • Create framework-mx-mongo package with proper structure
  • Implement MongoSchemaMapper (Pydantic → MongoDB collections)
  • Implement MongoGenericRepository (CRUD via Motor)
  • Implement MongoSessionFactory (MongoDB sessions & transactions)
  • Implement MongoInit bootstrap step

5.2 Entry Point Registration

  • Register repository adapter entry point
  • Register schema_mapper adapter entry point
  • Register unit_of_work adapter entry point
  • Register bootstrap entry point

5.3 Testing

  • Test protocol compliance for all adapters
  • Test entry point registration and discovery
  • Test MX pattern override scenarios
  • Verify 20/20 tests passing

6. Documentation

  • Architecture guide: "MX Pattern ADR" (docs/adr/0006-mx-pattern.md)
  • Tutorial: "MongoDB-Primary Framework MX" (docs/tutorials/mongodb-mx-tutorial.md)
  • Reference: All protocol definitions (docs/reference/protocol-reference.md)

7. Testing

  • Test: framework-m-core installs without SQLAlchemy
  • Test: framework-m-standard adds SQLAlchemy adapters
  • Test: MX package can override adapters
  • Test: Coverage configuration includes all workspace packages
  • Test: Bootstrap order respects priority

Migration Notes

[!WARNING] This phase involves significant refactoring:

  • All imports must be updated to use framework_m_core or framework_m_standard
  • Tests need updating for split packages
  • CI needs to test all three packages

Recommended approach:

  1. Create core and standard folders inside existing framework-m
  2. Move code incrementally
  3. Create separate packages only after internal split is stable