Framework M Features
Auto-generated feature list from phase checklists.
Overview
| Phase | Title | Completion |
|---|---|---|
| 01 | Phase 01: Core Kernel & Interfaces | ██████████ 100% |
| 02 | Phase 02: DocType Engine & Database | ██████████ 100% |
| 03 | Phase 03: API Layer & Authorization | ██████████ 100% |
| 04 | Phase 04: Background Jobs & Events | █████████░ 98% |
| 05 | Phase 05: CLI & Developer Tools | █████████░ 97% |
| 06 | Phase 06: Built-in DocTypes & Core Features | █████████░ 99% |
| 07 | Phase 07: Studio (Code Generation UI) | █████████░ 93% |
| 08 | Phase 08: Workflows & Advanced Features | ██████████ 100% |
| 09a | Phase 09A: Frontend | █████████░ 97% |
| 09b | Phase 09B: Documentation | ██████████ 100% |
| 10 | Phase 10: ERP Enterprise Features | ██████████ 100% |
| 10 | Phase 10: Production Readiness & Deployment | ████████░░ 88% |
| 11 | Phase 11: Package Split & MX Pattern | ██████████ 100% |
| 12 | Phase 12: LLM-Ready Documentation & Automation | ██████████ 100% |
| 13 | Phase 13 Pending Checkpoints | ░░░░░░░░░░ 0% |
| 13 | Phase 13: UI/UX Polish & Design System Enhancement | ████████░░ 90% |
| 14 | Phase 14: Studio Enhancements (Connected Citizen Edition) | ██████████ 100% |
| 15 | Phase 15: Frontend Plugin Architecture | █████████░ 100% |
Phase 01: Core Kernel & Interfaces
Phase: 01 Objective: Set up the project foundation with clean hexagonal architecture. Define all protocol interfaces (ports) without any implementation. Status: 100% Complete
1. Project Initialization
Progress: 17/17 (100%)
Completed:
- ✅ Create project structure using
uv: - ✅ Setup
pyproject.tomlwith dependencies - ✅ Add
litestar[standard]>=2.0.0 - ✅ Add
sqlalchemy[asyncio]>=2.0.0(ensure agnostic, test with sqlite) - ✅ Add
pydantic>=2.0.0 - ✅ Add
pydantic-settings>=2.0.0 - ✅ Add
dependency-injector>=4.41.0(powerful DI container) - ✅ Add
asyncpg>=0.29.0(PostgreSQL async driver) - ✅ Add
redis>=5.0.0 - ✅ Remove
arq>=0.26.0 - ✅ Add
taskiq>=0.11.0,taskiq-nats>=0.4.0,nats-py>=2.0.0 - ✅ Add dev dependencies:
pytest,pytest-asyncio,mypy,ruff - ✅ Configure development tools
- ✅ Setup
mypywith strict mode inpyproject.toml - ✅ Configure
rufffor linting and formatting - ✅ Add
.gitignorefor Python projects - ✅ Create directory structure
2. Define Port Interfaces > 2.1 Repository Protocol
Progress: 16/16 (100%)
Completed:
- ✅ Create
tests/core/interfaces/test_repository.py - ✅ Define test for
RepositoryProtocolinterface compliance - ✅ Create
src/framework_m/core/interfaces/repository.py - ✅ Define supporting models:
- ✅
FilterSpec- Typed filter specification (field, operator, value) - ✅
OrderSpec- Sorting specification (field, direction) - ✅
PaginatedResult[T]- Result withitems,total,limit,offset,has_more - ✅ Define
RepositoryProtocol[T](Generic): - ✅
async def get(self, id: UUID) -> T | None - ✅
async def save(self, entity: T, version: int | None = None) -> T(OCC support) - ✅
async def delete(self, id: UUID) -> None - ✅
async def exists(self, id: UUID) -> bool - ✅
async def count(self, filters: list[FilterSpec] | None = None) -> int - ✅
async def list(self, filters: list[FilterSpec] | None, order_by: list[OrderSpec] | None, limit: int, offset: int) -> PaginatedResult[T] - ✅
async def bulk_save(self, entities: list[T]) -> list[T] - ✅ Add type hints with
Generic[T]andProtocol
2. Define Port Interfaces > 2.2 Event Bus Protocol
Progress: 10/10 (100%)
Completed:
- ✅ Create
src/framework_m/core/interfaces/event_bus.py - ✅ Define
Eventbase model withid,timestamp,source,type,data - ✅ Define
EventBusProtocolwith methods: - ✅
async def connect(self) -> None(for NATS/Kafka) - ✅
async def disconnect(self) -> None - ✅
def is_connected(self) -> bool - ✅
async def publish(self, topic: str, event: Event) -> None - ✅
async def subscribe(self, topic: str, handler: Callable[[Event], Awaitable[None]]) -> str(returns subscription_id) - ✅
async def subscribe_pattern(self, pattern: str, handler: Callable) -> str(e.g.,doc.*) - ✅
async def unsubscribe(self, subscription_id: str) -> None
2. Define Port Interfaces > 2.3 Auth Context Protocol
Progress: 8/8 (100%)
Completed:
- ✅ Create
src/framework_m/core/interfaces/auth_context.py - ✅ Define
UserContextPydantic model with fields: - ✅
id: str - ✅
email: str - ✅
roles: list[str] - ✅
tenants: list[str] - ✅ Define
AuthContextProtocolwith methods: - ✅
async def get_current_user() -> UserContext
2. Define Port Interfaces > 2.4 Storage Protocol
Progress: 11/11 (100%)
Completed:
- ✅ Create
src/framework_m/core/interfaces/storage.py - ✅ Define
FileMetadatamodel withpath,size,content_type,modified,etag - ✅ Define
StorageProtocolwith methods: - ✅
async def save_file(self, path: str, content: bytes, content_type: str | None = None) -> str - ✅
async def get_file(self, path: str) -> bytes - ✅
async def delete_file(self, path: str) -> None - ✅
async def list_files(self, prefix: str) -> list[str] - ✅
async def get_metadata(self, path: str) -> FileMetadata | None - ✅
async def get_url(self, path: str, expires: int = 3600) -> str(presigned URL for S3) - ✅
async def copy(self, src: str, dest: str) -> str - ✅
async def move(self, src: str, dest: str) -> str
2. Define Port Interfaces > 2.5 Job Queue Protocol
Progress: 9/9 (100%)
Completed:
- ✅ Create
src/framework_m/core/interfaces/job_queue.py - ✅ Define
JobStatusenum:PENDING,RUNNING,SUCCESS,FAILED,CANCELLED - ✅ Define
JobInfomodel withid,name,status,enqueued_at,started_at,result,error - ✅ Define
JobQueueProtocolwith methods: - ✅
async def enqueue(self, job_name: str, **kwargs) -> str(returns job_id) - ✅
async def schedule(self, job_name: str, cron: str, **kwargs) -> str - ✅
async def cancel(self, job_id: str) -> bool - ✅
async def get_status(self, job_id: str) -> JobInfo | None - ✅
async def retry(self, job_id: str) -> str(returns new job_id)
2. Define Port Interfaces > 2.6 Permission Protocol
Progress: 5/5 (100%)
Completed:
- ✅ Create
src/framework_m/core/interfaces/permission.py - ✅ Define
PermissionProtocolwith methods: - ✅
async def has_permission(user: UserContext, doctype: str, action: str, doc_id: str | None) -> bool - ✅
async def get_permitted_filters(user: UserContext, doctype: str) -> dict - ✅ Add action types:
"read","write","create","delete","submit"
2. Define Port Interfaces > 2.7 Print Protocol
Progress: 3/3 (100%)
Completed:
- ✅ Create
src/framework_m/core/interfaces/print.py - ✅ Define
PrintProtocolwith methods: - ✅
async def render(doc: BaseModel, template: str, format: str = "pdf") -> bytes
2. Define Port Interfaces > 2.8 Cache Protocol
Progress: 10/10 (100%)
Completed:
- ✅ Create
src/framework_m/core/interfaces/cache.py - ✅ Define
CacheProtocol: - ✅
async def get(self, key: str) -> Any | None - ✅
async def set(self, key: str, value: Any, ttl: int | None = None) -> None - ✅
async def delete(self, key: str) -> None - ✅
async def exists(self, key: str) -> bool - ✅
async def get_many(self, keys: list[str]) -> dict[str, Any] - ✅
async def set_many(self, items: dict[str, Any], ttl: int | None = None) -> None - ✅
async def delete_pattern(self, pattern: str) -> int(returns count deleted) - ✅
async def ttl(self, key: str) -> int | None(remaining TTL)
2. Define Port Interfaces > 2.9 Notification Protocol
Progress: 4/4 (100%)
Completed:
- ✅ Create
src/framework_m/core/interfaces/notification.py - ✅ Define
NotificationProtocol: - ✅
async def send_email(to: str, subject: str, body: str) - ✅
async def send_sms(to: str, body: str)
2. Define Port Interfaces > 2.10 Search Protocol
Progress: 7/7 (100%)
Completed:
- ✅ Create
src/framework_m/core/interfaces/search.py - ✅ Define
SearchResultmodel withitems,total,facets,highlights - ✅ Define
SearchProtocol: - ✅
async def index(self, doctype: str, doc_id: str, doc: dict) -> None - ✅
async def delete_index(self, doctype: str, doc_id: str) -> None - ✅
async def search(self, doctype: str, query: str, filters: dict | None = None, limit: int = 20, offset: int = 0) -> SearchResult - ✅
async def reindex(self, doctype: str) -> int(returns count indexed)
2. Define Port Interfaces > 2.11 I18n Protocol
Progress: 4/4 (100%)
Completed:
- ✅ Create
src/framework_m/core/interfaces/i18n.py - ✅ Define
I18nProtocol: - ✅
async def translate(text: str, locale: str) -> str - ✅
async def get_locale() -> str
3. Define Domain Layer > 3.1 Base DocType
Progress: 12/12 (100%)
Completed:
- ✅ Create
src/framework_m/core/domain/base_doctype.py - ✅ Define
BaseDocTypeclass inheriting frompydantic.BaseModel - ✅ Add standard fields:
- ✅
name: Optional[str](primary key, auto-generated if None) - ✅
creation: datetime - ✅
modified: datetime - ✅
modified_by: Optional[str] - ✅
owner: Optional[str] - ✅ Add
Metanested class for metadata: - ✅
layout: dict = {}(viaget_layout()) - ✅
permissions: dict = {}(viaget_permissions()) - ✅ Add class method
get_doctype_name() -> str
3. Define Domain Layer > 3.2 Base Controller
Progress: 12/12 (100%)
Completed:
- ✅ Create
src/framework_m/core/domain/base_controller.py - ✅ Define
BaseController[T]generic class - ✅ Add lifecycle hook methods:
- ✅
async def validate(self, context: Any = None) -> None - ✅
async def before_insert(self, context: Any = None) -> None - ✅
async def after_insert(self, context: Any = None) -> None - ✅
async def before_save(self, context: Any = None) -> None - ✅
async def after_save(self, context: Any = None) -> None - ✅
async def before_delete(self, context: Any = None) -> None - ✅
async def after_delete(self, context: Any = None) -> None - ✅
async def on_submit(self, context: Any = None) -> None - ✅
async def on_cancel(self, context: Any = None) -> None
3. Define Domain Layer > 3.3 Mixins
Progress: 10/10 (100%)
Completed:
- ✅ Create
src/framework_m/core/domain/mixins.py - ✅ Define
DocStatusenum: - ✅
DRAFT = 0 - ✅
SUBMITTED = 1 - ✅
CANCELLED = 2 - ✅ Define
SubmittableMixinclass with: - ✅
docstatus: DocStatus = DocStatus.DRAFT - ✅
def is_submitted() -> bool - ✅
def is_cancelled() -> bool - ✅
def can_edit() -> bool(returns False if submitted)
4. Meta Registry
Progress: 13/13 (100%)
Completed:
- ✅ Create
src/framework_m/core/registry.py - ✅ Implement
MetaRegistryas singleton - ✅ Add storage dictionaries:
- ✅
_doctypes: Dict[str, Type[BaseDocType]] - ✅
_controllers: Dict[str, Type[BaseController]] - ✅ Implement methods:
- ✅
register_doctype(doctype_class, controller_class=None) - ✅
get_doctype(name: str) -> Type[BaseDocType] - ✅
get_controller(name: str) -> Type[BaseController] | None - ✅
list_doctypes() -> list[str] - ✅
discover_doctypes(package_name: str)(scans for BaseDocType subclasses) - ✅ Load Order: Follows
installed_appslist. - ✅ Conflict Policy: Raise
DuplicateDocTypeErrorif same name registered twice.
5. Port Implementation (Adapters) > 5.1 Dependency Injection
Progress: 5/5 (100%)
Completed:
- ✅ Create
tests/core/test_container.py - ✅ Write test for Container initialization and service resolution
- ✅ Create
src/framework_m/core/container.py - ✅ Implement
Containerclass (usingdependency_injector): - ✅ Define
Containerclass:
5. Port Implementation (Adapters) > 5.2 Provider Types
Progress: 6/6 (100%)
Completed:
- ✅ Understand provider types:
- ✅
Singleton- Single instance shared across app - ✅
Factory- New instance each time - ✅
Resource- For resources with lifecycle (db connections) - ✅
Callable- For functions - ✅
Dependency- For protocol injection
5. Port Implementation (Adapters) > 5.3 Configuration Provider
Progress: 1/1 (100%)
Completed:
- ✅ Setup configuration loading:
5. Port Implementation (Adapters) > 5.4 Wiring
Progress: 2/2 (100%)
Completed:
- ✅ Configure wiring for automatic injection:
- ✅ Use
@injectdecorator in functions:
5. Port Implementation (Adapters) > 5.5 Entrypoint Scanning for Overrides
Progress: 5/5 (100%)
Completed:
- ✅ Create override mechanism:
- ✅ Scan
framework_m.overridesentrypoints - ✅ Allow apps to override providers
- ✅ Example:
- ✅ Implement override loader:
5. Port Implementation (Adapters) > 5.6 Testing Support
Progress: 2/2 (100%)
Completed:
- ✅ Use
overridefor testing: - ✅ Reset overrides after tests:
6. Testing Setup
Progress: 8/8 (100%)
Completed:
- ✅ Create
tests/directory structure - ✅ Setup
conftest.pywith fixtures: - ✅
pytest_asyncioconfiguration - ✅ Mock implementations of all protocols
- ✅ Write initial tests:
- ✅ Test
MetaRegistryregistration and retrieval - ✅ Test
BaseDocTypefield validation - ✅ Test
BaseControllerhook method existence
7. Documentation
Progress: 7/7 (100%)
Completed:
- ✅ Create
README.mdwith: - ✅ Project overview
- ✅ Installation instructions
- ✅ Basic usage example
- ✅ Create
docs/folder with: - ✅
architecture.md- Hexagonal architecture explanation - ✅
ports.md- List of all protocol interfaces (Repository, EventBus, Cache, Search, etc.)
Validation Checklist
Progress: 6/6 (100%)
Completed:
- ✅ All protocol interfaces are defined with proper type hints
- ✅
mypy --strictpasses with no errors - ✅ No infrastructure dependencies in
core/(no imports of litestar, sqlalchemy, redis) - ✅
BaseDocTypeandBaseControllerare properly generic - ✅
MetaRegistrycan register and retrieve DocTypes - ✅ All tests pass with
pytest
Phase 02: DocType Engine & Database
Phase: 02 Objective: Implement the metadata engine that dynamically creates database tables from Pydantic models and provides generic CRUD operations. Status: 100% Complete
1. Schema Mapper (Pydantic → SQLAlchemy) > 1.1 Field Registry & Type Mapping
Progress: 15/15 (100%)
Completed:
- ✅ Create
src/framework_m/adapters/db/field_registry.py - ✅ Implement
FieldRegistryclass (Singleton): - ✅ Start with standard types: str, int, float, bool, datetime, date, decimal, uuid, json
- ✅ Allow registration of custom types:
register_type(pydantic_type, sqlalchemy_type) - ✅ Define type mapping using Registry:
- ✅
str→String - ✅
int→Integer - ✅
float→Float - ✅
bool→Boolean - ✅
datetime→DateTime - ✅
date→Date - ✅
Decimal→Numeric - ✅
UUID→UUID - ✅
list[str]→JSON(portable, works on all databases) - ✅
dict→JSON
1. Schema Mapper (Pydantic → SQLAlchemy) > 1.2 Schema Mapper Implementation
Progress: 19/19 (100%)
Completed:
- ✅ Create
tests/adapters/db/test_schema_mapper.py - ✅ Test mapping simple fields (str, int)
- ✅ Test mapping relationships
- ✅ Create
SchemaMapperclass - ✅ Use
FieldRegistryto look up SQLAlchemy types - ✅ Implement
create_table(model: Type[BaseDocType]) -> Table: - ✅ Extract table name from model class name (lowercase)
- ✅ Iterate over
model.model_fields - ✅ Map each field to SQLAlchemy column
- ✅ Handle
Optionaltypes (nullable=True) - ✅ Set
idfield as primary key (UUID, auto-generated) - ✅ Set
namefield as unique index (for human-readable lookup) - ✅ OCC: Add
_version(Integer, default=0) ifMeta.concurrency="optimistic" - ✅ Return SQLAlchemy
Tableobject - ✅ Handle special field types:
- ✅ Relationships (ForeignKey) - detect by field name pattern
*_id - ✅ Enums - map to SQLAlchemy String type (database agnostic)
- ✅ Nested Pydantic models (
list[BaseModel]) - store as JSON - ✅ Child DocTypes (
list[DocType]) - map to Relational Table with Foreign Key
1. Schema Mapper (Pydantic → SQLAlchemy) > 1.3 Table Registry
Progress: 5/5 (100%)
Completed:
- ✅ Create
TableRegistryclass to store created tables - ✅ Add methods:
- ✅
register_table(doctype_name: str, table: Table) - ✅
get_table(doctype_name: str) -> Table - ✅
table_exists(doctype_name: str) -> bool
2. Database Connection Setup > 2.1 Connection Factory & Virtual DocTypes
Progress: 5/5 (100%)
Completed:
- ✅ Create
src/framework_m/adapters/db/connection.py - ✅ Implement
ConnectionFactory(supports Multiple Bindings): - ✅ Load
db_bindsfrom config (e.g.,legacy,timescale) - ✅ Create generic async engine (supports Postgres, SQLite for testing)
- ✅ Maintain map of
engine_name -> AsyncEngine
2. Database Connection Setup > 2.2 Session Factory (SQL Support)
Progress: 3/3 (100%)
Completed:
- ✅ Add session factory:
- ✅
async def get_session(bind: str = "default") -> AsyncSession - ✅ Support
VirtualDocType(SQL Bind) by acceptingbind_keyfrom DocType Meta
2. Database Connection Setup > 2.3 Non-SQL Virtual DocTypes (Custom Repositories)
Progress: 7/7 (100%)
Completed:
- ✅ Create concept of
RepositoryOverride: - ✅ Allow DocType to define
repository_classin Meta - ✅
RepositoryFactoryinstantiates this instead ofGenericRepository - ✅ Create
tests/adapters/db/test_repository_factory.py: - ✅ Implement a Mock
FileRepositorythat reads from JSON file - ✅ Register it for a
VirtualDoc - ✅ Verify
VirtualDoc.get()callsFileRepository.get()
3. Generic Repository Implementation
Progress: 9/9 (100%)
Completed:
- ✅ Create
tests/adapters/db/test_generic_repository.py - ✅ Define tests for CRUD operations (mock
AsyncSession) - ✅ Create
src/framework_m/adapters/db/generic_repository.py - ✅ Implement
GenericRepository[T]class - ✅ Constructor dependencies (session is NOT stored here):
- ✅
model: Type[T] - ✅
table: Table - ✅
controller_class: Type[BaseController] | None - ✅
event_bus: EventBusProtocol | None(InMemoryEventBus for dev)
3. Generic Repository Implementation > 3.1 CRUD Operations
Progress: 49/49 (100%)
Completed:
- ✅ Implement
async def get(session: AsyncSession, id: UUID) -> Optional[T]: - ✅ Build SELECT query
- ✅ Filter
deleted_at IS NULL(unless specific flag overrides) - ✅ Execute with provided session (not stored session)
- ✅ Convert row to Pydantic model
- ✅ Return None if not found
- ✅ Implement
async def get_by_name(session: AsyncSession, name: str) -> Optional[T]: - ✅ Helper for looking up by human-readable name
- ✅ Implement
async def save(session: AsyncSession, entity: T, version: int | None = None) -> T: - ✅ Check if entity exists (by
id) - ✅ If new:
- ✅ Generate
id(UUIDv7) - ✅ Note:
created_by/ownermust be set by Controller/Service before calling save - ✅ Call controller
validate() - ✅ Call controller
before_create() - ✅ Call controller
before_save() - ✅ Execute INSERT with provided session
- ✅ Call controller
after_save() - ✅ Call controller
after_create() - ✅ Emit Event:
event_bus.publish(f"{doctype}.create", payload) - ✅ If existing:
- ✅ Note:
modified_bymust be set by Controller/Service before calling save - ✅ Call controller
validate() - ✅ Call controller
before_save() - ✅ OCC: If
optimistic: - ✅
UPDATE table SET ..., _version=_version+1 WHERE id=:id AND _version=:old_ver - ✅ If rowcount == 0, raise
VersionConflictError - ✅ Else: Execute standard UPDATE
- ✅ Call controller
after_save() - ✅ Emit Event:
event_bus.publish(f"{doctype}.update", payload) - ✅ Return saved entity (caller calls
uow.commit()when ready) - ✅ Implement
async def delete(session: AsyncSession, id: UUID, hard: bool = False) -> None: - ✅ Load entity
- ✅ Call controller
before_delete() - ✅ If
hard: - ✅ Execute DELETE
- ✅ Else (Soft Delete):
- ✅ Update
deleted_at = now() - ✅ Call controller
after_delete() - ✅ Emit Event:
event_bus.publish(f"{doctype}.delete", payload) - ✅ Return (caller calls
uow.commit()when ready) - ✅ Implement
async def list(session: AsyncSession, filters, limit, offset, order_by) -> Sequence[T]: - ✅ Build SELECT query with filters
- ✅ Default filter:
deleted_at IS NULL - ✅ Apply pagination (limit, offset)
- ✅ Apply sorting (order_by)
- ✅ Execute query
- ✅ Convert rows to Pydantic models
- ✅ Return list
3. Generic Repository Implementation > 3.2 Lifecycle Hook Integration
Progress: 5/5 (100%)
Completed:
- ✅ Create helper method
_call_hook(hook_name: str): - ✅ Check if controller exists
- ✅ Check if hook method exists on controller
- ✅ Call hook method if present
- ✅ Handle exceptions and rollback on error
4. Migration System > 4.1 Alembic Integration
Progress: 8/8 (100%)
Completed:
- ✅ Initialize Alembic in project:
- ✅ Configure
alembic.ini: - ✅ Set database URL from environment
- ✅ Configure migration file location
- ✅ Create
alembic/env.py: - ✅ Import
MetaRegistry - ✅ Import all registered DocTypes
- ✅ Set
target_metadatafrom SchemaMapper tables
4. Migration System > 4.2 Auto-Migration Detection
Progress: 11/11 (100%)
Completed:
- ✅ Create
src/framework_m/adapters/db/migration.py - ✅ Implement
detect_schema_changes(): - ✅ Compare registered DocTypes with database schema
- ✅ Detect new tables
- ✅ Detect new columns
- ✅ Detect type changes
- ✅ Return list of changes
- ✅ Implement
auto_migrate(): - ✅ Call
detect_schema_changes() - ✅ Generate Alembic migration if changes detected
- ✅ Apply migration automatically (dev mode only)
4. Migration System > 4.3 CLI Commands
Progress: 5/5 (100%)
Completed:
- ✅ Add migration commands to CLI:
- ✅
m migrate- run pending migrations - ✅
m migrate:create <name>- create new migration - ✅
m migrate:rollback- rollback last migration - ✅
m migrate:status- show migration status
5. Repository Factory
Progress: 9/9 (100%)
Completed:
- ✅ Create
src/framework_m/adapters/db/repository_factory.py - ✅ Implement
RepositoryFactoryclass: - ✅
create_generic_repository(doctype_name: str) -> GenericRepository - ✅ Look up DocType from MetaRegistry
- ✅ Look up Table from TableRegistry
- ✅ Look up Controller from MetaRegistry
- ✅ Create and return GenericRepository instance
- ✅ Support
event_busparameter for domain events - ✅ Support custom repository overrides for Virtual DocTypes
6. Engine, Session Factory & Unit of Work > 6.1 Engine & Session Factory Setup
Progress: 8/8 (100%)
Completed:
- ✅ Create
src/framework_m/adapters/db/connection.py(ConnectionFactory) - ✅ Implement
create_engine(url: str) -> AsyncEngine - ✅ Pool configuration (pool_size, max_overflow, timeout, recycle, pre_ping)
- ✅ Environment variable expansion (
${VAR}syntax) - ✅ Implement
SessionFactory(returnsAsyncSessioncontext managers) - ✅ Support multiple binds (for Virtual DocTypes with SQL binds)
- ✅ Configuration from ConnectionFactory
- ✅ Auto commit/rollback in context manager
6. Engine, Session Factory & Unit of Work > 6.2 Unit of Work (UnitOfWork)
Progress: 14/14 (100%)
Completed:
- ✅ Create
tests/core/test_unit_of_work.py - ✅ Test: UoW provides session
- ✅ Test:
commit()persists changes - ✅ Test: Exception causes rollback (no explicit rollback call needed)
- ✅ Test: Session is closed after
__aexit__ - ✅ Create
src/framework_m/core/unit_of_work.py - ✅ Implement
UnitOfWorkcontext manager: - ✅
__init__(session_factory: Callable[[], AsyncSession]) - ✅
sessionproperty with safety check - ✅
async __aenter__()creates session - ✅
async commit()calls session.commit() - ✅
async rollback()for explicit rollback - ✅
async __aexit__()with auto-rollback on exception - ✅ Register
UnitOfWorkFactoryin DI container
6. Engine, Session Factory & Unit of Work > 6.3 Multi-Source Coordination (Outbox Pattern)
Progress: 17/17 (100%)
Completed:
- ✅ Create
src/framework_m/core/domain/outbox.py - ✅ Define
OutboxEntrymodel: - ✅
id: UUID - ✅
target: str(e.g., "mongodb.audit_log", "api.payment_gateway") - ✅
payload: dict - ✅
status: str(pending, processed, failed) - ✅
created_at: datetime - ✅
processed_at: datetime | None - ✅
error_message: str | None - ✅
retry_count: int - ✅ Create
OutboxRepository(SQL-backed) inadapters/db/outbox_repository.py - ✅
add(session, entry)- add entry in same transaction - ✅
get_pending(session, limit)- get pending entries - ✅
mark_processed(session, id)- mark as processed - ✅
mark_failed(session, id, error)- mark as failed - ✅ Document: Services write to Outbox in the same SQL transaction
- ✅ (Phase 04) Background worker processes Outbox entries
6. Engine, Session Factory & Unit of Work > 6.4 Startup Sequence (Schema Sync)
Progress: 7/7 (100%)
Completed:
- ✅ Create
src/framework_m/adapters/db/__init__.py - ✅ Implement startup sequence (called once at app boot, NOT per-request):
- ✅ Initialize database engine (NOT session)
- ✅ Discover all DocTypes via MetaRegistry
- ✅ Create/sync tables via SchemaMapper
- ✅ Register tables in TableRegistry
- ✅ Run auto-migration (if enabled)
7. Testing > 7.1 Unit Tests
Progress: 9/9 (100%)
Completed:
- ✅ Test
SchemaMapper: - ✅ Test type mapping for all supported types (
test_schema_mapper.py) - ✅ Test primary key creation (
test_table_has_id_column_as_primary_key) - ✅ Test nullable fields (
TestSchemaMapperNullableFields) - ✅ Test enum mapping (
TestSchemaMapperEnums) - ✅ Test
GenericRepository: - ✅ Test CRUD operations with mock data (
test_generic_repository.py) - ✅ Test lifecycle hook calls (
TestControllerHooks) - ✅ Test transaction rollback on error (
TestTransactionRollback)
7. Testing > 7.2 Integration Tests
Progress: 13/13 (100%)
Completed:
- ✅ Setup testcontainers for PostgreSQL (skips if Docker unavailable)
- ✅ Create test DocType (
IntegrationTestDoc/PostgresTestDoc) - ✅ Test full flow (SQLite & Postgres - Postgres skipped without Docker):
- ✅ Register DocType (
test_register_doctype) - ✅ Create table (
test_table_created) - ✅ Insert document (
test_insert_document) - ✅ Query document (
test_query_document) - ✅ Update document (
test_update_document) - ✅ Delete document (
test_delete_document) - ✅ Test migration:
- ✅ Add field to DocType
- ✅ Run auto-migration
- ✅ Verify column added to table
8. Error Handling
Progress: 10/10 (100%)
Completed:
- ✅ Create custom exceptions (
core/exceptions.py): - ✅
DocTypeNotFoundError - ✅
ValidationError - ✅
PermissionDeniedError - ✅
DuplicateNameError - ✅
RepositoryError,EntityNotFoundError,DatabaseError,IntegrityError - ✅ Add error handling in repository (
generic_repository.py): - ✅ Catch SQLAlchemy errors (
IntegrityError,OperationalError,SQLAlchemyError) - ✅ Convert to domain exceptions (
DuplicateNameError,DatabaseError, etc.) - ✅ Log errors with context (using
logger.errorwithextradict)
9. Performance Optimizations
Progress: 13/13 (100%)
Completed:
- ✅ Add query result caching (phase-04):
- ✅ Cache
get()results by ID - ✅ Invalidate cache on save/delete
- ✅ Use Redis for distributed cache
- ✅ Add bulk operations (
generic_repository.py): - ✅
async def bulk_save(entities)- separates new/existing - ✅
async def _bulk_insert(entities)- true SQLAlchemy bulk insert - ✅ Uses
insert().values([...])for performance - ✅ Add query optimization (add indexes after the API layer exists):
- ✅ Add indexes for common queries (schema_mapper: owner, creation, Meta.indexes)
- ✅ Add parent index for child tables (efficient joins)
- ✅ Use
select_in_loadingfor relationships (load_children_for_parentsmethod) - ✅ Add query logging in dev mode (
logger.debugfor GET/LIST)
Validation Checklist
Progress: 6/6 (100%)
Completed:
- ✅ Can create tables from Pydantic models dynamically
- ✅ CRUD operations work with lifecycle hooks
- ✅ Migrations are generated and applied correctly
- ✅ All integration tests pass with real PostgreSQL (skips if Docker unavailable)
- ✅ No direct SQLAlchemy imports in domain layer
- ✅ Repository implements
RepositoryProtocolcorrectly
Phase 03: API Layer & Authorization
Phase: 03 Objective: Expose DocTypes via HTTP with auto-generated CRUD endpoints, implement permission system with row-level security, and add RPC support. Status: 100% Complete
1. Litestar Application Setup
Progress: 14/14 (100%)
Completed:
- ✅ Create
src/framework_m/adapters/web/app.py - ✅ Initialize Litestar app:
- ✅ Configure CORS for development
- ✅ Add exception handlers
- ✅ Configure OpenAPI documentation
- ✅ Integrate with
dependency-injectorContainer (wire modules) - ✅ Middleware Discovery:
- ✅ Scan
MiddlewareRegistryfor registered App Middlewares. - ✅ Allow Apps to inject ASGI Middleware (e.g.
RateLimit,cors,Compression). - ✅ APM & Tracing: Support OpenTelemetry, DataDog, Sentry via standard ASGI middleware.
- ✅ Support ordering (priority).
- ✅ Add application lifecycle:
- ✅
on_startup: Initialize Container, database, discover DocTypes - ✅
on_shutdown: Close database connections, unwire Container
2. Authentication Middleware
Progress: 9/9 (100%)
Completed:
- ✅ Create
src/framework_m/adapters/web/middleware.py - ✅ Implement
AuthMiddleware: - ✅ Extract
x-user-idheader - ✅ Extract
x-rolesheader (comma-separated) - ✅ Extract
x-tenantsheader (optional, comma-separated) - ✅ Create
UserContextobject - ✅ Store in
request.state.user - ✅ Return 401 if headers missing (configurable)
- ✅ Add middleware to Litestar app (available via
create_auth_middleware())
3. Permission System > 3.1 Permission Protocol Implementation
Progress: 7/7 (100%)
Completed:
- ✅ Create
src/framework_m/adapters/auth/rbac_permission.py - ✅ Implement
RbacPermissionAdapter: - ✅ Implement
evaluate(request: PolicyEvaluateRequest) -> PolicyEvaluateResult - ✅ Read permissions from
DocType.Meta.permissions - ✅ Match
request.principal_attributes["roles"]against allowed roles - ✅
CustomPermissionDocType created (integration pending) - ✅ Return
PolicyEvaluateResult(authorized=True/False, decision_source=DecisionSource.RBAC)
3. Permission System > 3.2 Permission Configuration
Progress: 7/7 (100%)
Completed:
- ✅ Define permission structure in DocType:
- ✅ Implement
has_permission(): - ✅ Check
requires_auth— if False and no user, allow read - ✅ Check if user has required role
- ✅ Check database overrides via
PermissionLookupService(CustomPermission DocType) - ✅ For object-level: check ownership or custom rules
- ✅ Return boolean
3. Permission System > 3.3 System Context (Elevated Operations)
Progress: 4/4 (100%)
Completed:
- ✅ Create
src/framework_m/core/system_context.py - ✅ Implement
SystemContext: - ✅ Usage in background jobs:
- ✅ Audit: All system operations logged with
principal="system"
3. Permission System > 3.4 Row-Level Security (RLS)
Progress: 13/13 (100%)
Completed:
- ✅ Implement
get_permitted_filters(): - ✅ For standard users: add
WHERE owner = :user_id - ✅ For admins: no filter (see all)
- ✅ For custom rules: via
Meta.rls_field(completed by Section 3.5 Team-Based Access) - ✅ Return dict of SQLAlchemy filters
- ✅ Update
GenericRepository.list(): - ✅
list_for_user()method with RLS filtering - ✅
apply_rls_filters()helper available - ✅ Merge with user-provided filters
- ✅ Apply to SQL query
- ✅ Update
GenericRepository.get(): - ✅
get_for_user()method with permission check - ✅ Raise
PermissionDeniedErrorif denied
3. Permission System > 3.5 Team-Based Access (Indie)
Progress: 5/5 (100%)
Completed:
- ✅ Add
Meta.rls_fieldoption: - ✅ Update
get_permitted_filters(): - ✅ If
rls_field = "owner"(default):WHERE owner = :user_id - ✅ If
rls_field = "team":WHERE team IN :user_teams - ✅ Support custom fields
3. Permission System > 3.6 Explicit Sharing (DocumentShare)
Progress: 6/6 (100%)
Completed:
- ✅ Create built-in
DocumentShareDocType: - ✅ Update
get_permitted_filters()to include shares viaget_rls_filters_with_shares(): - ✅ Add share management API:
- ✅
POST /api/v1/share— Create share - ✅
DELETE /api/v1/share/{id}— Remove share - ✅
GET /api/v1/{doctype}/{id}/shares— List shares for a doc
3. Permission System > 3.7 Indie Mode: Permission Conveniences
Progress: 14/14 (100%)
Completed:
- ✅ Create
src/framework_m/core/decorators.py(if not exists) - ✅ Implement
@requires_permission(action: PermissionAction): - ✅ Internally builds
PolicyEvaluateRequestfromself.user,self.doctype_name - ✅ Calls
permission.evaluate(request) - ✅ Raises
PermissionDeniedErrorif not authorized - ✅ Works on Controller methods
- ✅ Add to
BaseController: - ✅ Add to
BaseController: - ✅ Verify: All auto-generated CRUD routes (Section 4) automatically call
permission.evaluate(): - ✅
POST /api/v1/{doctype}→ checksCREATEpermission (verified via test) - ✅
GET /api/v1/{doctype}/{id}→ checksREADpermission (verified via test) - ✅
PUT /api/v1/{doctype}/{id}→ checksWRITEpermission (verified via test) - ✅
DELETE /api/v1/{doctype}/{id}→ checksDELETEpermission (verified via test) - ✅ No manual code required for indie devs using auto-CRUD (verified via test)
4. Auto-CRUD Router > 4.1 Meta Router Implementation
Progress: 6/6 (100%)
Completed:
- ✅ Create
src/framework_m/adapters/web/meta_router.py - ✅ Implement
create_crud_routes(doctype_class: type[BaseDocType]): - ✅ Check Opt-in: Verify
DocType.Meta.api_resource is True. Skip if False. - ✅ Generate 5 routes per DocType
- ✅ Inject repository and permission service
- ✅ Parse filters from JSON string via
_parse_filters()
4. Auto-CRUD Router > 4.2 List Endpoint
Progress: 5/5 (100%)
Completed:
- ✅ Create
GET /api/v1/{doctype}: - ✅ Accept query parameters:
limit,offset,filters,order_by - ✅ Parse filters from JSON string
- ✅ Call repository
list_entities()with RLS filters viaapply_rls_filters() - ✅ Return paginated response with metadata:
4. Auto-CRUD Router > 4.3 Create Endpoint
Progress: 6/6 (100%)
Completed:
- ✅ Create
POST /api/v1/{doctype}: - ✅ Validate request body against Pydantic model
- ✅ Check
CREATEpermission via_check_permission() - ✅ Set
ownerto current user (data["owner"] = user_id) - ✅ Call repository
save() - ✅ Return 201 with created document
4. Auto-CRUD Router > 4.4 Read Endpoint
Progress: 6/6 (100%)
Completed:
- ✅ Create
GET /api/v1/{doctype}/{id}: - ✅ Call repository
get(id) - ✅ Check
READpermission - ✅ Return 404 if not found (via
NotFoundException) - ✅ Return 403 if permission denied
- ✅ Return document
4. Auto-CRUD Router > 4.5 Update Endpoint
Progress: 7/7 (100%)
Completed:
- ✅ Create
PUT /api/v1/{doctype}/{id}: - ✅ Load existing document via
repo.get() - ✅ Check
WRITEpermission - ✅ Check if submitted (deny if immutable) via
_check_submitted() - ✅ Merge changes via
entity.model_copy(update=data) - ✅ Call repository
save() - ✅ Return updated document
4. Auto-CRUD Router > 4.6 Delete Endpoint
Progress: 6/6 (100%)
Completed:
- ✅ Create
DELETE /api/v1/{doctype}/{id}: - ✅ Load document
- ✅ Check
DELETEpermission - ✅ Check if submitted (deny if immutable) via
_check_submitted() - ✅ Call repository
delete() - ✅ Return 204 No Content
4. Auto-CRUD Router > 4.7 Router Registration
Progress: 5/5 (100%)
Completed:
- ✅ Implement
create_meta_router(): - ✅ Get all DocTypes from MetaRegistry
- ✅ For each DocType with
api_resource=True, callcreate_crud_routes() - ✅ Register all routes with Litestar
- ✅ Return Router instance
5. RPC System > 5.1 Whitelisted Controller Methods
Progress: 13/13 (100%)
Completed:
- ✅ Create
@whitelistdecorator: - ✅ Mark controller methods as publicly callable
- ✅ Store metadata on method (
WHITELIST_ATTR) - ✅
is_whitelisted()helper function - ✅
get_whitelist_options()helper function - ✅ Create
POST /api/v1/rpc/{doctype}/{method}: - ✅ Load DocType controller
- ✅ Check if method has
@whitelistdecorator - ✅ Validate method exists
- ✅ Parse request body as method arguments
- ✅ Instantiate controller with document (if doc_id provided)
- ✅ Call method
- ✅ Return result
5. RPC System > 5.2 Arbitrary RPC Functions
Progress: 16/16 (100%)
Completed:
- ✅ Create
@rpcdecorator for standalone functions: - ✅ Register function in RPC registry (
RpcRegistrysingleton) - ✅ Store function path (e.g.,
my_app.api.send_email) - ✅
is_rpc_function()helper - ✅
get_rpc_options()helper - ✅ Create
POST /api/v1/rpc/fn/{dotted.path}: - ✅ Parse dotted path (e.g.,
my_app.api.send_email) - ✅ Look up function in registry
- ✅ Validate function has
@rpcdecorator - ✅ Parse request body as function arguments
- ✅ Call function
- ✅ Return result
- ✅ Add permission check for RPC:
- ✅ Support
@rpc(permission="custom_permission") - ✅ Check permission before calling function
- ✅ Support
@rpc(allow_guest=True)for public endpoints
6. Metadata API
Progress: 11/11 (100%)
Completed:
- ✅ Create
GET /api/meta/{doctype}: - ✅ Get DocType class from registry
- ✅ Generate JSON Schema from Pydantic model:
- ✅ Extract layout from
Meta.layout - ✅ Extract permissions from
Meta.permissions - ✅ Return:
- ✅ Add field metadata:
- ✅ Field labels (from
Field(title=...)) - included in JSON Schema - ✅ Help text (from
Field(description=...)) - included in JSON Schema - ✅ Validation rules (from Pydantic validators) - included in JSON Schema
- ✅ Field types and options - included in JSON Schema
7. OpenAPI Documentation
Progress: 10/10 (100%)
Completed:
- ✅ Configure Litestar OpenAPI:
- ✅ Set title, version, description
- ✅ Add authentication scheme (header-based:
x-user-id,x-roles) - ✅ Enable Swagger UI at
/schema/swagger - ✅ Enable ReDoc at
/schema/redoc - ✅ Enhance auto-generated docs:
- ✅ Add descriptions to CRUD endpoints (via docstrings)
- ✅ Add examples for request/response (via Pydantic models)
- ✅ Document RPC endpoints (auto-generated from route handlers)
- ✅ Add permission requirements to docs (via security schemes)
8. Error Handling
Progress: 7/7 (100%)
Completed:
- ✅ Create exception handlers:
- ✅
ValidationError→ 400 Bad Request (validation_error_handler) - ✅
PermissionDeniedError→ 403 Forbidden (permission_denied_handler) - ✅
DocTypeNotFoundError→ 404 Not Found (not_found_handler) - ✅
DuplicateNameError→ 409 Conflict (duplicate_name_handler) - ✅ Generic exceptions → 500 Internal Server Error (
framework_error_handler) - ✅ Return consistent error format:
9. Request/Response DTOs
Progress: 7/7 (100%)
Completed:
- ✅ Use Litestar DTOs for validation:
- ✅ Auto-generate from Pydantic models (via Litestar)
- ✅ Add DTO for list response (pagination):
PaginatedResponse[T] - ✅ Add DTO for error responses:
ErrorResponse - ✅ Implement response filtering:
- ✅ Exclude sensitive fields based on permissions (via field selection)
- ✅ Support field selection via query param:
?fields=name,title
10. Testing > 10.1 Unit Tests
Progress: 8/8 (100%)
Completed:
- ✅ Test permission system:
- ✅ Test role-based access (
test_rbac_permission.py) - ✅ Test RLS filter generation (
test_rls.py) - ✅ Test object-level permissions (
test_object_level_permissions.py) - ✅ Test RPC system:
- ✅ Test
@whitelistdecorator (test_whitelist_decorator.py) - ✅ Test
@rpcdecorator (test_rpc_decorator.py) - ✅ Test dotted path resolution (
test_rpc_routes.py)
10. Testing > 10.2 Integration Tests
Progress: 15/15 (100%)
Completed:
- ✅ Test CRUD endpoints (
test_api_endpoints.py): - ✅ Test create with valid data
- ✅ Test create with invalid data (validation)
- ✅ Test create without permission (403)
- ✅ Test list with RLS (only see own docs)
- ✅ Test update immutable doc (covered by existing
test_meta_router.py) - ✅ Test delete with permission (covered by existing permission tests)
- ✅ Test RPC endpoints (
test_api_endpoints.py,test_rpc_routes.py): - ✅ Test whitelisted controller method
- ✅ Test arbitrary RPC function
- ✅ Test RPC with permissions
- ✅ Test with real HTTP client (
test_real_http_client.py): - ✅ Uses
httpx.AsyncClientagainst real uvicorn server - ✅ Tests: list endpoint, create endpoint, health check
- ✅ Manual testing scripts available in
examples/folder
Validation Checklist
Progress: 6/6 (100%)
Completed:
- ✅ All CRUD endpoints work with permissions (verified via
test_meta_router.py,test_api_endpoints.py) - ✅ RLS filters are applied correctly (verified via
test_rls.py,test_object_level_permissions.py) - ✅ RPC system works for controller methods and functions (verified via
test_rpc_routes.py) - ✅ OpenAPI docs are generated correctly (SwaggerUI + ReDoc enabled)
- ✅ Error handling returns proper status codes (verified via
test_app.py) - ✅ Integration tests pass with real HTTP requests (verified via
test_real_http_client.py)
Edge Cases to Handle > Child Table Permissions
Progress: 4/4 (100%)
Completed:
- ✅ Define: Child tables inherit parent's RLS by default (
Meta.is_child_table = True) - ✅ Child rows are not independently permission-checked (
api_resource = False) - ✅ Loading parent loads all its children (no separate RLS query)
- ✅ Document: If independent child access needed, make it a separate DocType (tests in
test_child_table_permissions.py)
Edge Cases to Handle > Link Field Data Leakage
Progress: 3/3 (100%)
Completed:
- ✅ When serializing a doc with Link fields, do NOT auto-include linked doc data (Link fields store UUID, not embedded objects)
- ✅ If linked doc data is needed, make a separate API call (permission checked) - documented pattern
- ✅ Optional:
?expand=customerparam design documented (checks permission before expanding)
Edge Cases to Handle > Bulk Operations & RLS
Progress: 3/3 (100%)
Completed:
- ✅
GenericRepository.delete_many_for_user(filters)applies RLS - ✅
GenericRepository.update_many_for_user(filters, data)applies RLS - ✅ User can only bulk-modify docs they have access to (tests in
test_bulk_operations_rls.py)
Phase 04: Background Jobs & Events
Phase: 04 Objective: Implement asynchronous job processing, event-driven architecture, and webhook system with pluggable backends (Redis, NATS, In-Memory). Status: 98% Complete
0. Backend Selection (Cross-Platform) > 0.2 Dev Mode (No External Deps)
Progress: 3/3 (100%)
Completed:
- ✅ Implement
InMemoryJobQueuefor local dev (asyncio.Queue). - ✅ Implement
InMemoryEventBusfor local dev. - ✅ Auto-detect: If
NATS_URLnot set, use in-memory.
1. Taskiq + NATS Integration (Primary) > 1.1 Taskiq Setup
Progress: 8/8 (100%)
Completed:
- ✅ Add dependencies:
taskiq,taskiq-nats. - ✅ Create
src/framework_m/adapters/jobs/taskiq_adapter.py - ✅ Configure Taskiq with NATS JetStream:
- ✅ Set NATS connection URL from environment (
NATS_URL) - ✅ Configure job timeout (default: 300s)
- ✅ Configure max retries (default: 3)
- ✅ Use
PullBasedJetStreamBrokerfor reliable delivery - ✅ Create broker instance:
1. Taskiq + NATS Integration (Primary) > 1.2 Job Queue Protocol Implementation
Progress: 7/7 (100%)
Completed:
- ✅ Implement
TaskiqJobQueueAdapter: - ✅
async def enqueue(job_name: str, **kwargs) -> str: - ✅ Get registered task
- ✅ Call
.kiq()to enqueue - ✅ Return job ID
- ✅
async def schedule(job_name: str, cron: str, **kwargs): - ✅ Use
TaskiqSchedulerwith cron triggers
1. Taskiq + NATS Integration (Primary) > 1.3 Job Registration
Progress: 4/4 (100%)
Completed:
- ✅ Create job decorator
@job: - ✅ Implement job registry:
- ✅ Store all
@broker.taskdecorated functions - ✅ Auto-discover on startup
2. Worker Process > 2.1 Worker Implementation
Progress: 7/7 (100%)
Completed:
- ✅ Create
src/framework_m/cli/worker.py - ✅ Implement worker command:
- ✅ Worker startup:
- ✅ Initialize database connection
- ✅ Discover and register all jobs
- ✅ Start Taskiq worker
- ✅ Listen for jobs from NATS JetStream
2. Worker Process > 2.2 Job Context
Progress: 10/10 (100%)
Completed:
- ✅ Create job context for dependency injection:
- ✅ Provide database session
- ✅ Provide repository factory
- ✅ Provide event bus
- ✅ Pass to job functions
- ✅ Add job metadata:
- ✅ Job ID
- ✅ Enqueued time
- ✅ Started time
- ✅ User context (Must re-hydrate from job arguments if applicable)
3. Scheduler > 3.1 Cron Jobs
Progress: 8/8 (100%)
Completed:
- ✅ Support Taskiq's native cron syntax:
- ✅ Create
ScheduledJobDocType: - ✅
name: str- Job identifier - ✅
function: str- Dotted path to function - ✅
cron_expression: str- Cron syntax - ✅
enabled: bool- Active/inactive - ✅
last_run: datetime | None - ✅
next_run: datetime | None
3. Scheduler > 3.2 Dynamic Scheduler
Progress: 3/4 (75%)
Completed:
- ✅ Implement dynamic job scheduling:
- ✅ Load
ScheduledJobDocTypes from database - ✅ Register with Taskiq at startup
Pending:
- ⏳ Support adding/removing jobs without restart (via signal) NOT NEEDED: Worker restart is acceptable for schedule changes; k8s rolling updates handle this gracefully. If needed in future, can use NATS pub/sub to signal workers in Phase 06+ (Ops/Deployment).
4. Event Bus > 4.1 NATS Event Bus Implementation
Progress: 9/9 (100%)
Completed:
- ✅ Create
src/framework_m/adapters/events/nats_event_bus.py - ✅ Implement
NatsEventBusAdapter: - ✅
async def publish(topic: str, event: BaseModel): - ✅ Serialize event to JSON
- ✅ Publish to NATS JetStream subject
- ✅
async def subscribe(topic: str, handler: Callable): - ✅ Subscribe to NATS JetStream subject
- ✅ Deserialize event
- ✅ Call handler function
4. Event Bus > 4.2 Event Types
Progress: 7/7 (100%)
Completed:
- ✅ Create base event class:
- ✅ Define standard events:
- ✅
DocCreated - ✅
DocUpdated - ✅
DocDeleted - ✅
DocSubmitted - ✅
DocCancelled
4. Event Bus > 4.3 Event Publishing from Lifecycle Hooks
Progress: 6/6 (100%)
Completed:
- ✅ Update
GenericRepository: - ✅ Inject event bus
- ✅ Publish
DocCreatedafter insert - ✅ Publish
DocUpdatedafter update - ✅ Publish
DocDeletedafter delete - ✅ Add event publishing to controller hooks:
5. Webhook System > 5.1 Webhook DocType
Progress: 9/9 (100%)
Completed:
- ✅ Create
WebhookDocType: - ✅
name: str - ✅
event: str- Event to listen to (e.g., "doc.created") - ✅
doctype_filter: str | None- Filter by DocType - ✅
url: str- Webhook endpoint URL - ✅
method: str- HTTP method (POST, PUT) - ✅
headers: dict- Custom headers - ✅
enabled: bool - ✅
secret: str- For signature verification
5. Webhook System > 5.2 Webhook Listener
Progress: 6/6 (100%)
Completed:
- ✅ Create
src/framework_m/adapters/webhooks/listener.py - ✅ Implement webhook listener:
- ✅ Subscribe to all events
- ✅ Load active webhooks from database
- ✅ Filter events by webhook configuration
- ✅ Trigger HTTP call to webhook URL
5. Webhook System > 5.3 Webhook Delivery
Progress: 9/9 (100%)
Completed:
- ✅ Implement webhook delivery:
- ✅ Use
httpxfor async HTTP calls - ✅ Add signature header (HMAC-SHA256 with secret)
- ✅ Set timeout (default: 30s)
- ✅ Handle errors and retries
- ✅ Add retry logic:
- ✅ Retry on failure (exponential backoff)
- ✅ Max retries: 3
- ✅ Log failed deliveries
5. Webhook System > 5.4 Webhook Logs
Progress: 8/8 (100%)
Completed:
- ✅ Create
WebhookLogDocType: - ✅
webhook: str- Reference to Webhook - ✅
event: str- Event that triggered - ✅
status: str- Success/Failed - ✅
response_code: int - ✅
response_body: str - ✅
error: str | None - ✅
timestamp: datetime
6. Job Monitoring > 6.1 Job Status Tracking
Progress: 13/13 (100%)
Completed:
- ✅ Create
JobLogDocType: - ✅
job_id: str - ✅
job_name: str - ✅
status: str- Queued/Running/Success/Failed - ✅
enqueued_at: datetime - ✅
started_at: datetime | None - ✅
completed_at: datetime | None - ✅
error: str | None - ✅
result: dict | None - ✅ Update job execution to log status:
- ✅ Create log entry on enqueue
- ✅ Update on start
- ✅ Update on completion/failure
6. Job Monitoring > 6.2 Job Management API
Progress: 5/5 (100%)
Completed:
- ✅ Create endpoints:
- ✅
GET /api/v1/jobs- List jobs - ✅
GET /api/v1/jobs/{job_id}- Get job status - ✅
POST /api/v1/jobs/{job_id}/cancel- Cancel job - ✅
POST /api/v1/jobs/{job_id}/retry- Retry failed job
6. Job Monitoring > 6.3 Job Monitor (Admin UI)
Progress: 3/6 (50%)
Completed:
- ✅ Option A: Native Desk UI (IMPLEMENTED):
- ✅
Job LogList View (auto-generated viaapi_resource=True). - ✅ Shows Status, Error, Duration (
duration_secondsproperty).
Pending:
- ⏳
Option B: Taskiq Dashboard (External)- NOT NEEDED for MVP: Native JobLog UI is sufficient for debugging. External dashboards can be mounted in Phase 06+ (Ops/Deployment) if production monitoring requires deeper worker introspection. - ⏳ Mount
taskiq-dashboard(if available) or similar tool. - ⏳ Useful for sysadmins to debug worker health.
4. Real-time Events (WebSockets) > 4.1 WebSocket Protocol (The Port)
Progress: 4/4 (100%)
Completed:
- ✅ Create
src/framework_m/core/interfaces/socket.py - ✅ Define
SocketProtocol: - ✅
async def broadcast(topic: str, message: dict) - ✅
async def send_to_user(user_id: str, message: dict)
4. Real-time Events (WebSockets) > 4.2 NATS Backplane (The Adapter)
Progress: 7/7 (100%)
Completed:
- ✅ Create
tests/adapters/socket/test_nats_socket.py - ✅ Write tests using testcontainers-nats to verify Pub/Sub.
- ✅ Create
src/framework_m/adapters/socket/nats_socket.py - ✅ Implement
NatsSocketAdapter: - ✅ On Boot: Subscribe to
framework.events.*. - ✅ On Event:
await nc.publish(subject, json.dumps(msg).encode()). - ✅ On Receive (Sub): Forward to local connected Websocket clients (Connection Manager).
4. Real-time Events (WebSockets) > 4.3 WebSocket Endpoint (Litestar)
Progress: 8/8 (100%)
Completed:
- ✅ Create
src/framework_m/adapters/web/socket.py - ✅ Implement
ConnectionManager: - ✅ Store active connections
Dict[UserId, List[WebSocket]]. - ✅ Add route
WS /api/v1/stream: - ✅ Authenticate user (Query param token).
- ✅ Upgrade connection.
- ✅ Register with
ConnectionManager. - ✅ Listen for client disconnect.
7. Testing > 7.1 Unit Tests
Progress: 6/6 (100%)
Completed:
- ✅ Test job registration:
- ✅ Test
@jobdecorator - ✅ Test job registry
- ✅ Test event bus:
- ✅ Test publish/subscribe
- ✅ Test event serialization
7. Testing > 7.2 Integration Tests
Progress: 13/13 (100%)
Completed:
- ✅ Test job execution:
- ✅ Enqueue job
- ✅ Verify job runs
- ✅ Check job result
- ✅ Test scheduled jobs:
- ✅ Register cron job
- ✅ Verify execution at scheduled time (use time mocking)
- ✅ Test webhooks:
- ✅ Create webhook
- ✅ Trigger event
- ✅ Verify HTTP call made
- ✅ Check webhook log
- ✅ Use testcontainers for NATS
8. CLI Commands
Progress: 5/5 (100%)
Completed:
- ✅ Add job management commands:
- ✅
m worker- Start worker process - ✅
m job:list- List registered jobs - ✅
m job:run <name>- Run job immediately - ✅
m job:status <id>- Check job status
Validation Checklist
Progress: 6/6 (100%)
Completed:
- ✅ Jobs can be enqueued and executed
- ✅ Scheduled jobs run at correct times
- ✅ Events are published and received
- ✅ Webhooks are triggered on events
- ✅ Job logs are created and updated
- ✅ Worker process starts and processes jobs
Phase 05: CLI & Developer Tools
Phase: 05
Objective: Build a comprehensive CLI tool (m) to replace Frappe's "bench", with commands for development, deployment, and management.
Status: 97% Complete
1. CLI Framework Setup
Progress: 5/5 (100%)
Completed:
- ✅ Create
src/framework_m/cli/main.py - ✅ Use
cycloptsfor CLI framework (native async, better type support) - ✅ Setup main CLI app:
- ✅ Add version command:
- ✅ Add help documentation for all commands
1. CLI Framework Setup > 1.1 Pluggable CLI Architecture (Entry Points)
Progress: 11/11 (100%)
Completed:
- ✅ Define Entry Point Group:
framework_m.cli_commands - ✅ Implement Plugin Loader in
plugin_loader.py: - ✅ Use
importlib.metadata.entry_points(group="framework_m.cli_commands") - ✅ Iterate over registered entry points
- ✅ If entry point is a
cyclopts.App:app.command(plugin_app, name=ep.name) - ✅ If entry point is a function:
app.command(plugin_func, name=ep.name) - ✅ Goal: 3rd party apps (and
framework-m-studio) can add commands tomwithout modifying core. - ✅ Customization Philosophy:
- ✅ Standard commands (
start,test) are strict relays. - ✅ For customization (e.g.,
start-mqtt,super-test): Users MUST register a custom command via entry points. - ✅ Result:
mremains a clean, standard runner.
2. Development Server (Uvicorn Relay) > 2.1 Start Command
Progress: 5/5 (100%)
Completed:
- ✅ Implement
m prod: - ✅ Implementation: Wrapper around
uvicorn. - ✅ Argument Forwarding: Uses cyclopts Parameter for options.
- ✅ Usage:
m prod --workers 4 --log-level debug - ✅ Value Add: Sets
PYTHONPATH, auto-detects app, transparently passes args.
2. Development Server (Uvicorn Relay) > 2.2 Worker Command (Taskiq Relay)
Progress: 4/4 (100%)
Completed:
- ✅ Implement
m worker: - ✅ Implementation: Native Taskiq integration (better than wrapper).
- ✅ Options:
--concurrency,--verbose. - ✅ Usage:
m worker --concurrency 8
2. Development Server (Uvicorn Relay) > 2.3 Studio Command (Litestar Relay)
Progress: 4/4 (100%)
Completed:
- ✅ Implement
m studio: - ✅ Implementation: Wrapper around
uvicornfor Studio app. - ✅ Options:
--host,--port,--reload,--log-level. - ✅ Usage:
m studio --port 9000 --reload
3. Database Commands (Alembic Relay) > 3.1 Migration Commands
Progress: 5/5 (100%)
Completed:
- ✅ Implement
m migrate: - ✅ Implementation: Wrapper around MigrationManager (uses Alembic).
- ✅ Commands:
migrate,create,rollback,status,history,init. - ✅ Usage:
m migrate create "add users" --autogenerate - ✅ Value Add: Auto-detects schema changes, supports custom DB URL, env vars.
4. Scaffolding (Cruft/Cookiecutter Relay) > 4.1 New App (Starter Template)
Progress: 4/4 (100%)
Completed:
- ✅ Implement
m new:app: - ✅ Implementation: Wrapper around
cruft(cookiecutter). - ✅ Options:
--template,--checkout,--no-input. - ✅ Usage:
m new:app myapp --checkout main
4. Scaffolding (Cruft/Cookiecutter Relay) > 4.2 New DocType (Jinja Relay)
Progress: 26/26 (100%)
Completed:
- ✅ Implement
m new:doctype <name>: - ✅ Implementation: Template rendering (embedded templates).
- ✅ Output:
doctype.py,controller.py,test_*.py,__init__.py. - ✅ App Detection:
--app> pyproject.toml > interactive prompt. - ✅ CLI Parameter (Unattended/Automation):
- ✅
--app <app_name>: Explicit app target. - ✅ If
--appprovided, use it directly (no prompt). - ✅ Automation Friendly: Scripts can pass
--appto avoid prompts. - ✅ Auto-Detection from CWD:
- ✅ If
--appnot provided, attempt to detect from current directory. - ✅ Check if CWD is inside an app's source tree.
- ✅ Look for
pyproject.tomlin CWD or parent directories. - ✅ Read
[project] nameto determine app. - ✅ Interactive Prompt (Default Fallback):
- ✅ If detection fails AND stdin is interactive (TTY):
- ✅ List installed apps from
framework_m.appsentry points. - ✅ Prompt user to select:
"Which app? [my_app, other_app]". - ✅ If stdin is NOT interactive (pipe/automation):
- ✅ Fail with clear error:
"Cannot detect app. Use --app <name>.". - ✅ Exit code 1 (enables CI/automation to catch failures).
- ✅ Implementation: check
require_app()innew.py - ✅ Scaffold Output Location:
- ✅ Files created in:
{cwd}/doctypes/{doctype_name}/ - ✅ Structure:
__init__.py,doctype.py,controller.py,test_*.py - ✅ Templates:
- ✅ Embedded templates in
new.py(no external Jinja2 files needed).
5. Testing & Quality (Standard Tool Relays) > 5.1 Test Relay
Progress: 5/5 (100%)
Completed:
- ✅ Implement
m test: - ✅ Command:
pytest - ✅ Options:
--verbose,--coverage,-k. - ✅ Usage:
m test -k "user" --verbose - ✅ Value Add: Configures
PYTHONPATH.
5. Testing & Quality (Standard Tool Relays) > 5.2 Lint/Format Relay
Progress: 6/6 (100%)
Completed:
- ✅ Implement
m lint: - ✅ Command:
ruff check . --fix - ✅ Implement
m format: - ✅ Command:
ruff format . - ✅ Implement
m typecheck: - ✅ Command:
mypy .
6. Configuration Management > 6.1 Config File
Progress: 4/4 (100%)
Completed:
- ✅ Create
framework_config.tomlstructure: - ✅ Supports
[framework],[apps]sections - ✅ Load/save with TOML format
- ✅ Auto-detect in CWD or parent directories
6. Configuration Management > 6.2 Config Commands
Progress: 2/2 (100%)
Completed:
- ✅ Implement
m config:show: Display current config. - ✅ Implement
m config:set <key> <value>: Update config.
7. Utility Relays > 7.1 Console (IPython Relay)
Progress: 4/4 (100%)
Completed:
- ✅ Implement
m console: - ✅ Implementation: Wrapper around
ipythonorpython -m asyncio. - ✅ Value Add: Pre-imports framework, async support.
- ✅ Options:
--no-ipythonfor plain Python.
7. Utility Relays > 7.2 System Info
Progress: 3/3 (100%)
Completed:
- ✅ Implement
m info: - ✅ Show versions (Framework, Python).
- ✅
--verbosefor platform and service info.
7. Utility Relays > 7.3 Routes
Progress: 2/2 (100%)
Completed:
- ✅ Implement
m routes: - ✅ Points to OpenAPI/Swagger docs.
8. Build Commands > 8.1 Frontend Build
Progress: 3/3 (100%)
Completed:
- ✅ Implement
m build(placeholder): - ✅ Relay to frontend build system (see Phase 09).
- ✅ Detects package.json and runs
npm run build.
8. Build Commands > 8.2 Docker Build
Progress: 4/4 (100%)
Completed:
- ✅ Implement
m build:docker: - ✅ Command: Wrapper around
docker build. - ✅ Value Add: Reads image name/tag from
framework_config.toml. - ✅ Options:
--tag,--file,--no-cache,--push.
9. Pluggable Extensions
Progress: 1/4 (25%)
Completed:
- ✅ Plugin loader implemented (
load_plugins())
Pending:
- ⏳
m studio(external) - ⏳
m docs:generate(external) - ⏳
m codegen(external)
10. CLI Entry Point
Progress: 2/2 (100%)
Completed:
- ✅ Configure
pyproject.tomlscripts:m = "framework_m.cli.main:app" - ✅ Test installation (
m --help) - 22 commands registered.
Phase 06: Built-in DocTypes & Core Features
Phase: 06 Objective: Implement essential built-in DocTypes (User, Role, Permission) and core features like file attachments, audit logging, and printing. Status: 99% Complete
1. Identity & Access Management (PIM) > 1.1 Identity Provider Protocol
Progress: 4/4 (100%)
Completed:
- ✅ Create
IdentityProtocol(Interface): - ✅
get_user(id: str) -> User - ✅
authenticate(credentials) -> Token - ✅
get_attributes(user) -> dict[str, Any](ABAC replacement for get_roles)
1. Identity & Access Management (PIM) > 1.2 User DocTypes (Pluggable)
Progress: 8/8 (100%)
Completed:
- ✅ Mode A: Local (Indie):
- ✅
LocalUser(SQL Table): Stores email, password_hash, full_name. - ✅
LocalIdentityAdapter: argon2 password hashing, JWT generation. - ✅ Mode B: Federated (Enterprise):
- ✅
FederatedIdentityAdapter(Proxy): - ✅ No SQL Table required.
- ✅ Hydrates from Auth Header (
X-User-ID,X-Email) viahydrate_from_headers(). - ✅
UserPreferencesDocType stores settings locally.
1. Identity & Access Management (PIM) > 1.3 User Controller (Adapter)
Progress: 4/4 (100%)
Completed:
- ✅ Implement
UserManager: - ✅ Delegates to configured
IdentityProviderviaIdentityProtocol. - ✅ Abstraction layer:
user = await user_manager.get(id). - ✅ Additional
create()method for Indie mode with password hashing.
1. Identity & Access Management (PIM) > 1.4 Auth API (Indie Mode)
Progress: 8/8 (100%)
Completed:
- ✅ Create
GET /api/v1/auth/me: - ✅ Returns current user context (or 401).
- ✅ Create
POST /api/v1/auth/login(Indie Only): - ✅ Accepts
username,password. - ✅ Validates against
LocalUserviaUserManager.authenticate(). - ✅ Returns JWT token.
- ✅ Create
POST /api/v1/auth/logout: - ✅ Returns success message (JWT auth is client-side logout).
1. Identity & Access Management (PIM) > 1.5 Authentication Strategies (Multi-Method)
Progress: 24/24 (100%)
Completed:
- ✅ Create
AuthenticationProtocol(Interface): - ✅
supports(headers: Mapping) -> bool— Can this strategy handle this request? - ✅
authenticate(headers: Mapping) -> UserContext | None— Extract user from request. - ✅ Built-in Strategies:
- ✅
SessionCookieAuth— Browser sessions via cookies. - ✅
BearerTokenAuth— JWT/OAuth2 access tokens. - ✅
ApiKeyAuth—X-API-Keyheader for scripts/integrations. - ✅
HeaderAuth— Federated mode gateway header hydration. - ✅
BasicAuth— HTTP Basic for CLI tools. - ✅ Strategy Chain (
AuthChain): - ✅ Try each strategy in priority order.
- ✅ First successful match wins.
- ✅ Configurable order via
framework_config.toml(create_auth_chain_from_config). - ✅ API Key DocType (Indie Mode):
- ✅
ApiKeyDocType: - ✅
key_hash: str— Hashed API key (never store plaintext, excluded from serialization). - ✅
user_id: str— Owner of the key. - ✅
name: str— Human-readable label. - ✅
scopes: list[str]— Optional permission scopes. - ✅
expires_at: datetime | None— Expiration. - ✅
last_used_at: datetime | None— Usage tracking. - ✅
POST /api/v1/auth/api-keys— Create new key. - ✅
DELETE /api/v1/auth/api-keys/{id}— Revoke key. - ✅
GET /api/v1/auth/api-keys— List user's keys.
1. Identity & Access Management (PIM) > 1.6 Social Login (OAuth2/OIDC)
Progress: 26/27 (96%)
Completed:
- ✅ Option A: Built-in OAuth2 (Indie):
- ✅ Supported Providers (config structure ready):
- ✅ Google (well-known URLs configured)
- ✅ GitHub (well-known URLs configured)
- ✅ Microsoft (well-known URLs configured)
- ✅ Generic OIDC (any compliant provider via
get_oidc_well_known) - ✅ Configuration via
framework_config.toml: - ✅ Endpoints:
- ✅
GET /api/v1/auth/oauth/{provider}/start— Redirect to provider. - ✅
GET /api/v1/auth/oauth/{provider}/callback— Handle callback. (Placeholder) - ✅ Option B: Federated (Enterprise):
- ✅ Delegate to Keycloak / Authelia / Auth0 via
HeaderAuthstrategy. - ✅ Framework receives headers only (
X-User-ID,X-Email). - ✅ Zero PII stored locally.
- ✅ SocialAccount DocType:
- ✅
provider: str— OAuth provider name. - ✅
provider_user_id: str— Unique ID from provider. - ✅
user_id: str— Links to local user. - ✅
email: str | None— For lookup (optional). - ✅
display_name: str— For UI display. - ✅ One User can have multiple SocialAccounts.
- ✅ Passwordless Option (Requires Section 10: Email):
- ✅
POST /api/v1/auth/magic-link— Send email with login link. - ✅
GET /api/v1/auth/magic-link/{token}— Verify and create session. - ✅
MagicLinkCredentialsadded to identity protocol - ✅ Token generation with HMAC-SHA256 signing
Pending:
- ⏳ Use
authlibfor OAuth2 flows. (Full implementation deferred)
1. Identity & Access Management (PIM) > 1.7 Session Management
Progress: 20/20 (100%)
Completed:
- ✅ Session Storage:
- ✅ Redis (Default):
RedisSessionAdapterwith JSON storage and TTL. - ✅ Database (Fallback):
DatabaseSessionAdapterfor indie apps. - ✅ Configurable via
framework_config.toml: - ✅ Session DocType (database backend):
- ✅
session_id: str— Unique session identifier. - ✅
user_id: str— Links to user. - ✅
expires_at: datetime - ✅
ip_address: str | None - ✅
user_agent: str | None - ✅ SessionProtocol Interface:
- ✅
create()— Create new session - ✅
get()— Retrieve by ID - ✅
delete()— Remove session - ✅
delete_all_for_user()— Logout all - ✅
list_for_user()— List active sessions - ✅ Session API:
- ✅
GET /api/v1/auth/sessions— List active sessions. - ✅
DELETE /api/v1/auth/sessions/{id}— Revoke session. - ✅
DELETE /api/v1/auth/sessions— Logout all.
1. Identity & Access Management (PIM) > 1.8 PII Handling (Indie Guidance)
Progress: 16/16 (100%)
Completed:
- ✅ Auth Mode Presets (
AuthModeenum incore/pii.py): - ✅ Minimal PII Pattern:
- ✅
LocalUserstores only: - ✅
email(for login/notification) - ✅
display_name(for UI) - ✅
password_hash(only ifmode = "local") - ✅ Do NOT store by default (
PII_SENSITIVE_FIELDS): - ✅ Full legal name
- ✅ Phone number
- ✅ Address
- ✅ Date of birth
- ✅ Helper:
is_sensitive_pii(field_name)to detect sensitive fields. - ✅ Data Deletion (
DeletionModeenum): - ✅
DELETE /api/v1/auth/me— Delete user account (GDPR right to erasure). - ✅
GET /api/v1/auth/me/data— Export user data (GDPR data portability). - ✅ Configurable: Hard delete vs anonymize.
2. Tenancy & Attributes (Multi-Tenant Core) > 2.1 Tenant Protocol
Progress: 5/5 (100%)
Completed:
- ✅ Create
TenantProtocol(Interface incore/interfaces/tenant.py): - ✅
get_current_tenant() -> str - ✅
get_tenant_attributes(tenant_id) -> dict - ✅
TenantContextmodel for request context - ✅ Configuration helpers:
is_multi_tenant(),get_default_tenant_id()
2. Tenancy & Attributes (Multi-Tenant Core) > 2.2 Tenancy Adapters
Progress: 12/12 (100%)
Completed:
- ✅ Mode A: Single Tenant (Indie):
- ✅
ImplicitTenantAdapter(adapters/tenant.py): - ✅
tenant_id="default"(configurable). - ✅
attributes={"plan": "unlimited", "features": "*"}. - ✅
get_context()returnsTenantContextwithis_default=True. - ✅ Factory:
create_tenant_adapter_from_headers()auto-selects. - ✅ Mode B: Multi-Tenant (Enterprise):
- ✅
HeaderTenantAdapter(adapters/tenant.py): - ✅ Extracts
X-Tenant-IDfrom Gateway headers. - ✅ Extracts
X-Tenant-Attributes(JSON) for feature flags, plan. - ✅
get_context()parses headers intoTenantContext. - ✅ Benefit: Feature toggling per tenant without DB lookup.
2. Tenancy & Attributes (Multi-Tenant Core) > 2.3 Attributes (The New Roles)
Progress: 7/7 (100%)
Completed:
- ✅ Goal: Replace "Roles" with refined "Attributes" (ABAC).
- ✅ Implementation (in
UserContext): - ✅
user.attributes(dict): Stores{"department": "sales", "level": 5, "roles": ["admin"]}. - ✅
user.get_attribute(key, default)— Get attribute value. - ✅
user.has_attribute(key, value)— Check attribute equality. - ✅ Legacy Support:
user.has_role("x")checks bothroleslist ANDattributes.roles. - ✅
is_system_useruseshas_role("System")for consistency.
3. Permission Management (Pluggable) > 3.1 Permission Protocol
Progress: 7/7 (100%)
Completed:
- ✅ Create
PermissionProtocol(core/interfaces/permission.py): - ✅
PolicyEvaluateRequest- Stateless authorization request - ✅
PolicyEvaluateResult- Result with authorized, decision_source, reason - ✅
async def evaluate(request) -> PolicyEvaluateResult - ✅
async def get_permitted_filters(...) -> dict- RLS support - ✅
PermissionActionenum (read, write, create, delete, submit, cancel, amend) - ✅
DecisionSourceenum (rbac, abac, rebac, combo, custom)
3. Permission Management (Pluggable) > 3.2 Permission Adapters
Progress: 18/18 (100%)
Completed:
- ✅ Mode A: Standard (Indie) -
RbacPermissionAdapter: - ✅ Reads permissions from
DocType.Meta.permissions. - ✅ Checks
CustomPermissionrules from database. - ✅ Role matching against
principal_attributes["roles"]. - ✅ Admin role bypass (configurable).
- ✅ RLS via
get_permitted_filters()usingMeta.rls_field. - ✅ Mode B: Citadel Policy (Enterprise) -
CitadelPolicyAdapter: - ✅
AuthorizationRequestmodel (Cedar-compatible format): - ✅
Principal:user.id - ✅
Action:doctype:action(e.g.,Invoice:create) - ✅
Resource:doctype:name(e.g.,Invoice:INV-001) - ✅
TenantID:user.tenant_id - ✅
Context:doc.as_dict() - ✅
PrincipalAttributes:user.attributes(Diet Claims) - ✅
AuthorizationResponsemodel withallowed,reason,policy_id - ✅ Calls configurable policy endpoint (Cedar/OPA)
- ✅ Fallback behavior on error (configurable)
- ✅ Configuration via
[permissions.citadel]inframework_config.toml
4. File Management > 4.1 File DocType
Progress: 10/10 (100%)
Completed:
- ✅ Create
src/framework_m/core/doctypes/file.py - ✅ Define
FileDocType: - ✅
name: str- File ID (inherited from BaseDocType) - ✅
file_name: str- Original filename - ✅
file_url: str- Storage URL - ✅
file_size: int- Size in bytes - ✅
content_type: str- MIME type - ✅
attached_to_doctype: str | None - ✅
attached_to_name: str | None - ✅
is_private: bool- Private/public file (default: True)
4. File Management > 4.2 File Upload API
Progress: 9/9 (100%)
Completed:
- ✅ Create
POST /api/v1/file/upload(adapters/web/file_routes.py): - ✅ Accept multipart/form-data via
UploadFile - ✅ Validate file size (max 10MB default, configurable)
- ✅ Validate file type (configurable whitelist)
- ✅ Generate unique storage path (YYYY/MM/DD/random_filename)
- ✅ Create File DocType record
- ✅ Return file URL and metadata
- ✅ Configuration via
[files]inframework_config.toml - ✅ Response models:
FileUploadResponse,FileDeleteResponse
4. File Management > 4.3 File Download API
Progress: 8/8 (100%)
Completed:
- ✅ Create
GET /api/v1/file/{file_id}: - ✅ Check permissions for private files (RLS on owner)
- ✅ Prepare streaming response from storage
- ✅ Set correct
Content-Typeheader - ✅ Set
Content-Dispositionheader (inline/attachment) - ✅ Support
?inline=truefor browser display - ✅ Create
GET /api/v1/file/{file_id}/info: - ✅ Return metadata without downloading content
4. File Management > 4.4 Storage Adapters
Progress: 13/13 (100%)
Completed:
- ✅ Implement
LocalStorageAdapter(adapters/storage/local.py): - ✅ Save files to local directory with atomic writes
- ✅ Organize by date (YYYY/MM/DD) via path parameter
- ✅ Generate unique filenames (handled by file_routes)
- ✅ Path traversal protection
- ✅ Async operations via
aiofiles - ✅ Implement
S3StorageAdapter(adapters/storage/s3.py): - ✅ Use
aioboto3for async S3 operations - ✅ Presigned URLs for direct client uploads (PUT method)
- ✅ Multipart upload for large files (>25MB)
- ✅ Configure bucket and region from
framework_config.toml - ✅ Support S3-compatible services (MinIO, DigitalOcean Spaces)
- ✅
InMemoryStorageAdapterfor testing (adapters/storage/memory.py)
5. Audit Logging (Pluggable) > 5.1 Audit Log Protocol
Progress: 5/5 (100%)
Completed:
- ✅ Create
AuditLogProtocol(core/interfaces/audit.py): - ✅
AuditEntrymodel (user, action, doctype, document_id, changes, metadata) - ✅
async def log(...)- Record audit entry - ✅
async def query(...)- Query with filters/pagination - ✅
InMemoryAuditAdapterfor testing
5. Audit Logging (Pluggable) > 5.2 Audit Adapters
Progress: 6/7 (86%)
Completed:
- ✅ Mode A: Database (Indie):
- ✅
DatabaseAuditAdapter: Writes toActivityLogrecords. - ✅ Uses ActivityLog DocType from 5.3
- ✅ Mode B: External (Enterprise):
- ✅
FileAuditAdapter: Writes toaudit.log(JSONL) for Splunk/Filebeat. - ✅ Prevents main DB bloat.
Pending:
- ⏳
ElasticAuditAdapter: Writes directly to Elasticsearch (Phase 10).
5. Audit Logging (Pluggable) > 5.3 Activity Log DocType (Indie Only)
Progress: 10/10 (100%)
Completed:
- ✅ Create
src/framework_m/core/doctypes/activity_log.py - ✅ Define
ActivityLogDocType: - ✅
user_id: str - ✅
action: str(create, read, update, delete) - ✅
doctype: str - ✅
document_id: str - ✅
timestamp: datetime - ✅
changes: dict | None - ✅
metadata: dict | None - ✅ Immutable (no write/delete permissions)
5. Audit Logging (Pluggable) > 5.4 Activity Feed API
Progress: 4/4 (100%)
Completed:
- ✅ Create
GET /api/v1/activity: - ✅ List recent activities
- ✅ Filter by user, doctype, document, action
- ✅ Paginate results (limit, offset)
6. Error Logging > 6.1 Error Log DocType
Progress: 12/12 (100%)
Completed:
- ✅ Create
src/framework_m/core/doctypes/error_log.py - ✅ Define
ErrorLogDocType: - ✅
title: str- Short error description - ✅
error_type: str- Exception class name - ✅
error_message: str- Full error message - ✅
traceback: str | None- Full stack trace - ✅
request_url: str | None - ✅
user_id: str | None - ✅
request_id: str | None- For log correlation - ✅
timestamp: datetime - ✅
context: dict | None- Additional context - ✅ Admin-only permissions (immutable)
6. Error Logging > 6.2 Error Logging Integration
Progress: 6/6 (100%)
Completed:
- ✅ Add global exception handler (
adapters/web/error_handler.py): - ✅ Catch all unhandled exceptions
- ✅ Create ErrorLog entry with full context
- ✅ Return user-friendly ErrorResponse (no sensitive data)
- ✅ Log to console in dev mode (configurable)
- ✅
create_error_handler()factory for Litestar
7. Printing & PDF Generation > 7.1 Print Format DocType
Progress: 10/10 (100%)
Completed:
- ✅ Create
src/framework_m/core/doctypes/print_format.py - ✅ Define
PrintFormatDocType: - ✅
name: str- Display name - ✅
doctype: str- Target DocType - ✅
template: str- Jinja2 template path - ✅
is_default: bool - ✅
css: str | None- Custom CSS - ✅
header_html: str | None,footer_html: str | None - ✅
page_size: str(A4, Letter, etc.) - ✅
orientation: str(portrait, landscape)
7. Printing & PDF Generation > 7.2 Jinja Print Adapter
Progress: 8/8 (100%)
Completed:
- ✅ Create
src/framework_m/adapters/print/jinja_adapter.py - ✅ Implement
JinjaPrintAdapter: - ✅
async def render_html(doc, template) -> str - ✅ Load Jinja2 template
- ✅ Render with document context
- ✅ Return HTML string
- ✅
async def render_html_string(template_string, doc) -> str - ✅ Custom filters:
currency,date,datetime
7. Printing & PDF Generation > 7.3 Gotenberg PDF Adapter
Progress: 8/8 (100%)
Completed:
- ✅ Create
src/framework_m/adapters/print/gotenberg_adapter.py - ✅ Implement
GotenbergPrintAdapter: - ✅
async def html_to_pdf(html, page_size, orientation, ...) -> bytes - ✅ Send HTML to Gotenberg service
- ✅ Return PDF bytes
- ✅
async def is_available() -> bool- Health check - ✅
GotenbergConfigwith URL, timeout, page size, margins - ✅ Page sizes: A4, Letter, Legal, A3, A5
7. Printing & PDF Generation > 7.4 Print API
Progress: 9/9 (100%)
Completed:
- ✅ Create
GET /api/v1/print/{doctype}/{id}: - ✅ Query parameters:
- ✅
format- pdf/html (default: pdf) - ✅
print_format- Custom format name - ✅ Load document (TODO: integrate with repository - phase 10)
- ✅ Check read permission (TODO: integrate with permission - phase 10)
- ✅ Render using JinjaPrintAdapter → GotenbergPrintAdapter
- ✅ Return PDF or HTML with appropriate headers
- ✅ Fallback to HTML if Gotenberg unavailable
8. System Settings > 8.1 System Settings DocType
Progress: 11/11 (100%)
Completed:
- ✅ Create
src/framework_m/core/doctypes/system_settings.py - ✅ Define
SystemSettingsDocType (singleton): - ✅
name: str- Always "System Settings" (frozen) - ✅
app_name: str- Application display name - ✅
timezone: str- Default timezone - ✅
date_format: str- Date format string - ✅
time_format: str- Time format string - ✅
language: str- Default language code - ✅
enable_signup: bool- Allow registration - ✅
session_expiry: int- Session timeout in minutes - ✅
maintenance_mode: bool- Admin-only access
8. System Settings > 8.2 Settings API
Progress: 5/5 (100%)
Completed:
- ✅ Create
GET /api/v1/settings: - ✅ Return system settings via
SettingsResponse - ✅ Cache aggressively (5 min Cache-Control header)
- ✅
invalidate_settings_cache()helper - ✅
set_settings_cache()helper
9. Notification System > 9.1 Notification DocType
Progress: 13/13 (100%)
Completed:
- ✅ Create
src/framework_m/core/doctypes/notification.py - ✅ Define
NotificationDocType: - ✅
user_id: str- Recipient - ✅
subject: str - ✅
message: str - ✅
notification_type: str(info, success, warning, error, etc.) - ✅
read: bool - ✅
doctype: str | None- Related DocType - ✅
document_id: str | None - ✅
timestamp: datetime - ✅
from_user: str | None - ✅
metadata: dict | None - ✅ RLS on user_id field
9. Notification System > 9.2 Notification API
Progress: 9/9 (100%)
Completed:
- ✅ Create
GET /api/v1/notifications: - ✅ List user's notifications
- ✅ Filter by read/unread
- ✅ Create
PATCH /api/v1/notifications/{id}/read- Mark as read - ✅ Create
DELETE /api/v1/notifications/{id}- Delete notification - ✅ Create WebSocket endpoint for real-time notifications:
- ✅
WS /api/v1/notifications/stream- Real-time notification stream - ✅
push_notification(user_id, notification)- Push to connected clients - ✅
create_notification_websocket_router()factory
10. Email Integration > 10.1 Email Queue DocType
Progress: 20/20 (100%)
Completed:
- ✅ Create
src/framework_m/core/doctypes/email_queue.py - ✅ Define
EmailQueueDocType: - ✅
to: list[str]- Recipients - ✅
cc/bcc: list[str] | None - ✅
subject: str - ✅
body: str- HTML body - ✅
text_body: str | None- Plain text alt - ✅
status: str- Queued/Sending/Sent/Failed/Cancelled - ✅
priority: str- low/normal/high - ✅
error: str | None - ✅
retry_count/max_retries: int - ✅
queued_at/sent_at: datetime - ✅
reference_doctype/reference_id- for tracking - ✅ Port-Adapter Pattern:
- ✅
EmailQueueProtocol(interface/port) - ✅
DatabaseEmailQueueAdapter(default - uses EmailQueue DocType) - ✅
InMemoryEmailQueueAdapter(testing) - ✅
queue_email()helper function - ✅
configure_email_queue()for swapping adapters - ✅ Ready for
NotificationServiceAdapterintegration
10. Email Integration > 10.2 Email Sender
Progress: 13/13 (100%)
Completed:
- ✅ Create email sender protocol and adapters:
- ✅
EmailSenderProtocol(interface/port) - ✅
SMTPEmailSender- SMTP delivery adapter - ✅
LogEmailSender- Console logging (development) - ✅
SMTPConfig- Configuration dataclass - ✅ Create background job
EmailProcessor: - ✅
process_queue()- Process pending emails - ✅
process_single(queue_id)- Process single email - ✅ Update EmailQueue status
- ✅ Retry logic (placeholder)
- ✅ Add helper function:
- ✅
queue_email()- Queue for sending - ✅
send_queued_email()- Process single email
11. Testing > 11.1 Unit Tests
Progress: 5/5 (100%)
Completed:
- ✅ Test User DocType validation (
core/doctypes/test_user.py,core/services/test_user_manager.py) - ✅ Test Role assignment (
adapters/auth/test_rbac_permission.py) - ✅ Test Permission checking (8 permission test files)
- ✅ Test File upload/download (
core/test_file.py,adapters/web/test_file_routes.py) - ✅ Test Print rendering (
core/test_print_format.py,adapters/print/test_*.py)
11. Testing > 11.2 Integration Tests
Progress: 5/5 (100%)
Completed:
- ✅ Test user creation and login (
integration/test_api_endpoints.py) - ✅ Test permission enforcement (
core/test_object_level_permissions.py) - ✅ Test file storage (local and S3) (
adapters/storage/test_local.py,adapters/storage/test_s3.py) - ✅ Test PDF generation with Gotenberg (
adapters/print/test_gotenberg_adapter.py) - ✅ Test email sending (
adapters/email/test_sender_processor.py)
Validation Checklist
Progress: 6/6 (100%)
Completed:
- ✅ User and Role management works
- ✅ Permissions are enforced correctly
- ✅ Files can be uploaded and downloaded
- ✅ Audit logs are created
- ✅ PDFs can be generated
- ✅ Emails can be sent
Phase 07: Studio (Code Generation UI)
Phase: 07
Objective: Build a visual DocType builder (framework-m-studio) that generates Python code, running as a Litestar app.
Status: 93% Complete
1. Packaging Strategy (Runtime vs DevTools) > 1.1 framework-m (Runtime)
Progress: 4/4 (100%)
Completed:
- ✅ Goal: Production-grade kernel.
- ✅ Content: API Server, ORM, DocType Engine, Basic CLI (
start,migrate,worker). - ✅ Dependencies:
litestar,sqlalchemy,pydantic,cyclopts. - ✅ Excluded: Code generators, Studio UI, Heavy formatting/linting libs.
1. Packaging Strategy (Runtime vs DevTools) > 1.2 framework-m-studio (DevTools)
Progress: 4/4 (100%)
Completed:
- ✅ Goal: Developer Productivity & SaaS Component.
- ✅ Content: Studio UI, Code Generators, Visual Editors.
- ✅ Dependencies:
framework-m,libcst,jinja2. - ✅ Integration: Plugs into
mCLI via entry points (m codegen).
2. Studio Backend (Litestar App) > 1. Project Structure (Monorepo)
Progress: 6/6 (100%)
Completed:
- ✅ Create
apps/studio/in the workspace - ✅ Initialize
apps/studio/pyproject.toml: - ✅ Add dependency:
framework-m = { workspace = true } - ✅ Add dependency:
libcst(for code modification) - ✅ Add dependency:
jinja2(for code generation) - ✅ Add code generation endpoints
2. Studio Backend (Litestar App) > 1.2 File System API
Progress: 14/14 (100%)
Completed:
- ✅ Create
GET /studio/api/doctypes: - ✅ Scan project for
*.pyfiles containing DocType classes - ✅ Return list of DocTypes with metadata
- ✅ Create
GET /studio/api/doctype/{name}: - ✅ Read DocType file
- ✅ Parse with LibCST
- ✅ Return structured JSON
- ✅ Create
POST /studio/api/doctype/{name}: - ✅ Accept DocType schema JSON
- ✅ Generate Python code
- ✅ Write to file system
- ✅ Create
DELETE /studio/api/doctype/{name}: - ✅ Delete DocType file
- ✅ Delete Controller file (if exists)
2. LibCST Code Transformer > 2.1 Parser
Progress: 7/7 (100%)
Completed:
- ✅ Create
src/framework_m_studio/codegen/parser.py - ✅ Implement
parse_doctype(file_path: str) -> dict: - ✅ Use LibCST to parse Python file
- ✅ Extract class definition
- ✅ Extract fields with types and defaults
- ✅ Extract Config metadata
- ✅ Return structured dict
2. LibCST Code Transformer > 2.2 Generators (The Strategy)
Progress: 8/8 (100%)
Completed:
- ✅ Creation (Scaffolding):
- ✅ Use
jinja2templates (shared with CLIm new:doctype). - ✅ Goal: Generate clean, standard Python code from scratch.
- ✅ Implement
generate_doctype_source(schema: dict) -> str. - ✅ Mutation (Transformer):
- ✅ Use
LibCSTto parse and modify existing files. - ✅ Goal: Add/Edit fields while preserving comments and custom methods.
- ✅ Implement
update_doctype_source(source: str, schema: dict) -> str.
2. LibCST Code Transformer > 2.3 Test Generator
Progress: 6/6 (100%)
Completed:
- ✅ Create
src/framework_m_studio/codegen/test_generator.py - ✅ Implement
generate_test(schema: dict) -> str: - ✅ Generate
test_{doctype}.py - ✅ Import
pytestand DocType - ✅ Generate basic CRUD test (Create, Read, Update, Delete)
- ✅ Generate validation failure test (if required fields exist)
2. LibCST Code Transformer > 2.4 Transformer
Progress: 12/12 (100%)
Completed:
- ✅ Create
src/framework_m_studio/codegen/transformer.py - ✅ Implement
update_doctype(file_path: str, schema: dict): - ✅ Parse existing file with LibCST
- ✅ Locate DocType class
- ✅ Update/add/remove fields
- ✅ Preserve comments and custom methods
- ✅ Write back to file
- ✅ Handle edge cases:
- ✅ Field renamed (detect and update)
- ✅ Field type changed
- ✅ Field deleted (remove from class)
- ✅ Custom methods preserved
3. Studio Frontend > 3.1 React App Setup (Refine Stack)
Progress: 8/8 (100%)
Completed:
- ✅ Create
apps/studio/studio_ui/directory - ✅ Initialize Refine app:
- ✅ Install dependencies per ADR-0005:
- ✅ Create Framework M Data Provider (
src/providers/dataProvider.ts): - ✅ Configure API base URLs (per ADR-0005):
- ✅ Read from
window.__FRAMEWORK_CONFIG__or env vars - ✅ Support same-origin, subdomain, and CDN scenarios
- ✅ Default to
/studio/apifor Studio endpoints
3. Studio Frontend > 3.2 DocType List View (Refine Resource)
Progress: 5/5 (100%)
Completed:
- ✅ Create
pages/doctypes/list.tsx: - ✅ Use
useListhook from@refinedev/coreto fetch DocTypes - ✅ Display with
@tanstack/react-table+ Tailwind styling - ✅ Add search/filter with
useTableglobalFilter - ✅ Add "New DocType" button → navigates to
/doctypes/create
3. Studio Frontend > 3.3 DocType Editor (Refine Form)
Progress: 5/5 (100%)
Completed:
- ✅ Create
pages/doctypes/edit.tsx: - ✅ Use
useOne/useUpdate/useCreatehooks for data - ✅ Left panel: Field list with
@dnd-kit/sortable - ✅ Right panel: Field properties form (name, type, required, default, description)
- ✅ Top bar: DocType name input + Save button
3. Studio Frontend > 3.4 Field Editor (Uniforms Schema-Driven)
Progress: 5/5 (100%)
Completed:
- ✅ Create
components/FieldEditor.tsx: - ✅ Render with Uniforms using JSON Schema for field properties
- ✅ Custom Tailwind widgets:
TextWidget,SelectWidget,CheckboxWidget,TextareaWidget - ✅ Dynamic "Validators" collapsible for min/max length, pattern, etc.
- ✅ Live preview of generated Python type annotation
3. Studio Frontend > 3.5 Drag & Drop
Progress: 4/4 (100%)
Completed:
- ✅ Implement field reordering:
- ✅ Use
@dnd-kit/core+@dnd-kit/sortable - ✅ Allow dragging fields to reorder
- ✅ Update schema on drop (via
arrayMove)
3. Studio Frontend > 3.6 Code Preview (Monaco Editor)
Progress: 6/6 (100%)
Completed:
- ✅ Create
components/CodePreview.tsx: - ✅ Use
@monaco-editor/reactwithlanguage="python" - ✅ Read-only mode (
readOnly: true) - ✅ Theme:
vs-dark - ✅ Auto-update on schema change (memoized generation)
- ✅ Copy button for generated code
3. Studio Frontend > 3.7 Save Flow
Progress: 5/5 (100%)
Completed:
- ✅ Implement save functionality:
- ✅ Validate schema (name required)
- ✅ Call backend API via
useCreate/useUpdate - ✅ Navigate back to list on success
- ✅ Loading state on save button
3. Studio Frontend > 3.8 Visual Data Modeling (Mind Map)
Progress: 5/5 (100%)
Completed:
- ✅ Implement ERD/Mind Map View:
- ✅ Central Node: Current DocType (highlighted)
- ✅ Connected Nodes: Related DocTypes via Link fields
- ✅ Visual Action: Drag to connect nodes → Creates Link Field
- ✅ Using
@xyflow/react(React Flow v12)
3. Studio Frontend > 3.9 Layout Designer (Grid System)
Progress: 5/5 (100%)
Completed:
- ✅ Implement Visual Layout Drag & Drop:
- ✅ Define Sections with title and Columns (1/2/3 cols selector)
- ✅ Drag fields from palette into grid cells
- ✅ Real-time form preview toggle
- ✅ Add/delete sections
3. Studio Frontend > 3.10 Module Explorer
Progress: 5/5 (100%)
Completed:
- ✅ Implement Module Scanner:
- ✅ Group DocTypes by directory/app module (tree structure)
- ✅ Tree view navigation in Sidebar
- ✅ Expand/collapse all, search filter
- ✅ Click to navigate to DocType editor
4. Studio Cloud Mode (Ephemeral & Git-Backed) > 4.2 GitOps Integration (FluxCD/ArgoCD)
Progress: 2/2 (100%)
Completed:
- ✅ Implement "Pull Latest" Button (
POST /workspace/{id}/pull). - ✅ Show "Updates Available" indicator (
POST /workspace/{id}/check-updates).
4. Studio Cloud Mode (Ephemeral & Git-Backed) > 4.3 Git Adapter (Data Agnostic)
Progress: 11/11 (100%)
Completed:
- ✅ Create
src/framework_m_studio/git/protocol.py- GitAdapterProtocol (Port) - ✅ Create
src/framework_m_studio/git/adapter.py- GitAdapter (Adapter) - ✅ Implement
GitAdapter: - ✅ Wraps standard
gitbinary via asyncio subprocess. - ✅
clone(repo_url, auth): Clone to temp dir. - ✅
commit(message): Stage and commit changes. - ✅
push(branch): Push to remote. - ✅
pull(): Pull latest changes. - ✅
create_branch(name): Create new branch. - ✅
get_status(): Get workspace status. - ✅ Unit tests in
tests/test_git_adapter.py(12 tests)
4. Studio Cloud Mode (Ephemeral & Git-Backed) > 4.4 GitHub Provider
Progress: 9/9 (100%)
Completed:
- ✅ Create
src/framework_m_studio/git/github_provider.py - ✅ Implement
GitHubProvider: - ✅ Use GitHub API for operations (REST API with urllib)
- ✅ Support personal access tokens (Bearer auth)
- ✅ Handle authentication (GitHubAuthError)
- ✅ Create pull requests
- ✅ List pull requests
- ✅ Validate tokens
- ✅ Unit tests in
tests/test_github_provider.py(9 tests)
4. Studio Cloud Mode (Ephemeral & Git-Backed) > 4.5 Generic Git Provider
Progress: 2/2 (100%)
Completed:
- ✅ Support HTTPS and SSH (via git CLI)
- ✅ Work with any Git server (generic implementation)
4. Studio Cloud Mode (Ephemeral & Git-Backed) > 4.6 Workspace Management
Progress: 7/7 (100%)
Completed:
- ✅ Create
src/framework_m_studio/workspace.py - ✅ Implement workspace lifecycle:
- ✅ Clone repo to temp directory
- ✅ Track workspace sessions
- ✅ Clean up old workspaces (TTL-based)
- ✅ Handle concurrent edits (asyncio lock)
- ✅ Unit tests in
tests/test_workspace.py(12 tests)
4. Studio Cloud Mode (Ephemeral & Git-Backed) > 4.7 Cloud Studio API
Progress: 12/12 (100%)
Completed:
- ✅ Create
POST /studio/api/workspace/connect: - ✅ Accept repo URL and token
- ✅ Clone repository
- ✅ Return workspace ID
- ✅ Create
POST /studio/api/workspace/{id}/commit: - ✅ Commit changes
- ✅ Push to branch
- ✅ Return commit SHA
- ✅ Create
GET /studio/api/workspace/{id}/status: Git status - ✅ Create
POST /studio/api/workspace/{id}/pull: Pull latest - ✅ Create
DELETE /studio/api/workspace/{id}: Cleanup workspace - ✅ Create
GET /studio/api/workspace/sessions: List all sessions
5. Studio CLI Command > 5.1 SPA Packaging & Serving (Path Prefix Architecture)
Progress: 20/21 (95%)
Completed:
- ✅ Build Process:
- ✅
pnpm run buildinstudio_uioutputs tosrc/framework_m_studio/static/(vite.config.ts). - ✅
pyproject.tomlincludesframework_m_studio/static/**/*. - ✅ Serving Strategy (Litestar) (in
app.py): - ✅ UI Routes: Serve
/studio/ui/*→ React SPA (HTML pages) - ✅ API Routes: Serve
/studio/api/*→ JSON endpoints - ✅ Assets: Serve
/studio/ui/assets/*as static files (Cached) - ✅ SPA Catch-all:
/studio/ui/{path:path}→ returnsindex.htmlfor client-side routing - ✅ Redirect:
/studio→/studio/ui/for convenience - ✅ Content-Type Fix: All responses use explicit
media_typeto prevent download issues - ✅ Implementation:
serve_spa()and_get_spa_response()functions inapp.py - ✅ Implement
m studio(inframework-m-studiopackage): - ✅ Register CLI command via entry point:
- ✅ Start uvicorn server on port 9000 (default)
- ✅ Serve Studio UI
- ✅ Options:
- ✅
--port- Custom port - ✅
--host- Custom host - ✅
--reload- Development mode - ✅
--cloud- Enable cloud mode
Pending:
- ⏳ Open browser automatically (TODO)
6. DevTools CLI (Extensions) > 6.1 Documentation Generator (m docs:generate)
Progress: 6/6 (100%)
Completed:
- ✅ Dependencies: Uses stdlib
urllib,json,subprocess(no external deps required). - ✅ Command:
m docs:generate: - ✅ API Reference: Generates markdown from DocTypes in
docs_generator.py. - ✅ OpenAPI Export: Exports
openapi.jsonfrom URL (--openapi-url). - ✅ Site Build: Runs
mkdocs buildif available (--build-site). - ✅ Unit tests in
tests/test_docs_generator.py(10 tests)
6. DevTools CLI (Extensions) > 6.2 Client SDK Generator (m codegen client)
Progress: 8/8 (100%)
Completed:
- ✅ Dependencies: Uses stdlib only (no external deps required).
- ✅ Command:
m codegen client: - ✅ Flow:
- ✅ Arguments:
- ✅ TypeScript: Generates interfaces + fetch client in
sdk_generator.py. - ✅ Python: Generates Pydantic models in
sdk_generator.py. - ✅ Unit tests in
tests/test_codegen.py(6 tests) - ✅ CLI tests updated in
tests/test_cli.py
7. Field Type Library > 7.1 Supported Field Types
Progress: 13/13 (100%)
Completed:
- ✅ Implement field type definitions:
- ✅ Text (str)
- ✅ Number (int, float)
- ✅ Checkbox (bool)
- ✅ Date (date)
- ✅ DateTime (datetime)
- ✅ Select (enum)
- ✅ Link (foreign key)
- ✅ Table (child table)
- ✅ Level 1: Grid/Table view
- ✅ Level 2+: Drill-down pattern (Button -> Drawer/Dialog) for infinite nesting
- ✅ JSON (dict)
- ✅ File (file upload)
7. Field Type Library > 7.2 Custom Field Type Discovery
Progress: 5/5 (100%)
Completed:
- ✅ Dynamic Loading: Studio reads available types from
FieldRegistryat runtime. - ✅ API Endpoint:
GET /studio/api/field-types - ✅ Returns: Built-in types + Types registered by installed apps.
- ✅ Each type includes:
name,pydantic_type,sqlalchemy_type,ui_component(optional). - ✅ UI Integration: Field Type Selector in DocType Editor dynamically populates from this API.
7. Field Type Library > 7.3 Custom UI Components (Client-Side)
Progress: 6/6 (100%)
Completed:
- ✅ Goal: Allow apps to register custom React components for their field types.
- ✅ Registration (App-Side):
- ✅ Discovery (Studio-Side):
- ✅ Shadow Build (Phase 09) loads all app
frontend/plugins. - ✅ Studio UI checks
window.__STUDIO_FIELD_COMPONENTS__map. - ✅ Falls back to default
<input>if no custom component.
7. Field Type Library > 7.5 Live Preview & Sandbox Mode
Progress: 0/11 (0%)
Pending:
- ⏳ Recommendation: Default to feature branches for teams. Add branch selector to Studio UI.
- ⏳ Goal: Preview the DocType being edited with mock data AND simulate CRUD.
- ⏳ Implementation:
- ⏳ Preview Tab: Toggle between "Schema Editor" and "Sandbox".
- ⏳ Mock Data Generation:
- ⏳ Use
@faker-js/fakeror simple generators. - ⏳ Generate sample rows based on field types.
- ⏳ Form Preview: Render
AutoFormwith generated mock doc. - ⏳ List Preview: Render
AutoTablewith 5-10 mock rows. - ⏳ Schema Source: Uses the in-memory schema being edited, NOT the saved file.
- ⏳ Allows instant feedback without saving.
7. Field Type Library > 7.6 Sandbox: Interactive CRUD Simulation
Progress: 11/11 (100%)
Completed:
- ✅ Goal: Let users test the full UX before committing the DocType.
- ✅ Features:
- ✅ New: Create a new mock document. Test mandatory field validation.
- ✅ Update: Edit an existing mock document. See form behavior.
- ✅ Delete: Delete mock document. See confirmation dialogs.
- ✅ List (Few): Show 5 rows. Test basic list rendering.
- ✅ List (Many): Paginate 100+ mock rows. Test performance.
- ✅ Filter: Apply filters and see results change.
- ✅ Validation: Submit form with missing required fields. See error messages.
- ✅ Data Store: In-memory array (resets on page reload).
- ✅ Benefit: No database required. Test UX before writing to disk.
7. Field Type Library > 7.7 Local Hot Reload (Optional Enhancement)
Progress: 0/8 (0%)
Pending:
- ⏳ Goal: For users who want to test with a real local database instead of mock data.
- ⏳ Prerequisites: Local Postgres/SQLite +
m prodrunning. - ⏳ Flow:
- ⏳ Studio saves DocType to file.
- ⏳ File watcher detects change → triggers schema sync.
- ⏳ Table created/updated in local DB.
- ⏳ User can now test with real CRUD operations.
- ⏳ Benefit: Bridge between mock sandbox and production—test with actual data locally.
7. Field Type Library > 7.2 Field Metadata
Progress: 7/7 (100%)
Completed:
- ✅ Define field options:
- ✅ Label
- ✅ Description
- ✅ Required
- ✅ Default value
- ✅ Validation rules
- ✅ Display options (hidden, read-only)
8. Controller Scaffolding
Progress: 8/8 (100%)
Completed:
- ✅ Add controller generation:
- ✅ Generate controller file template
- ✅ Add common hook methods
- ✅ Add validation examples
- ✅ Controller editor in UI:
- ✅ List hook methods
- ✅ Add custom methods
- ✅ Code editor for method bodies
9. Testing > 9.1 Unit Tests
Progress: 8/8 (100%)
Completed:
- ✅ Test LibCST parser:
- ✅ Parse valid DocType
- ✅ Extract fields correctly
- ✅ Handle edge cases
- ✅ Test code generator:
- ✅ Generate valid Python code
- ✅ Format correctly
- ✅ Handle all field types
9. Testing > 9.2 Integration Tests
Progress: 11/11 (100%)
Completed:
- ✅ Test full flow:
- ✅ Create DocType via UI
- ✅ Save to file system
- ✅ Reload and verify
- ✅ Update DocType
- ✅ Verify changes preserved
- ✅ Test Git integration:
- ✅ Clone repository
- ✅ Make changes
- ✅ Commit and push
- ✅ Verify on GitHub
10. Documentation
Progress: 6/6 (100%)
Completed:
- ✅ Create Studio user guide:
- ✅ How to start Studio
- ✅ How to create DocType
- ✅ How to add fields
- ✅ How to configure permissions
- ✅ How to use Git mode
Validation Checklist
Progress: 6/6 (100%)
Completed:
- ✅ Studio UI can create and edit DocTypes
- ✅ Generated code is valid Python
- ✅ Changes are saved to file system
- ✅ LibCST preserves custom code
- ✅ Git mode can commit and push
- ✅ Studio works in both local and cloud modes
Phase 08: Workflows & Advanced Features
Phase: 08 Objective: Implement pluggable workflow engine, DocType overrides, app-defined ports, and advanced extensibility features. Status: 100% Complete
1. Workflow System > 1.1 Workflow Protocol
Progress: 6/6 (100%)
Completed:
- ✅ Create
src/framework_m/core/interfaces/workflow.py - ✅ Define
WorkflowProtocol: - ✅
async def start_workflow(doctype: str, doc_id: str, workflow_name: str) - ✅
async def get_workflow_state(doc_id: str) -> str - ✅
async def transition(doc_id: str, action: str, user: UserContext) - ✅
async def get_available_actions(doc_id: str, user: UserContext) -> list[str]
1. Workflow System > 1.2 Internal Workflow Adapter
Progress: 28/28 (100%)
Completed:
- ✅ Create
src/framework_m/adapters/workflow/internal_workflow.py - ✅ Create
WorkflowStateDocType: - ✅
name: str - ✅
workflow: str- Workflow name - ✅
doctype: str - ✅
document_name: str - ✅
current_state: str - ✅
updated_at: datetime - ✅ Create
WorkflowTransitionDocType: - ✅
name: str - ✅
workflow: str - ✅
from_state: str - ✅
to_state: str - ✅
action: str- Action name - ✅
allowed_roles: list[str] - ✅
condition: str | None- Python expression - ✅ Create
WorkflowDocType: - ✅
name: str- Workflow name - ✅
doctype: str- Target DocType - ✅
initial_state: str - ✅
states: list[dict]- State definitions - ✅
transitions: list[WorkflowTransition] - ✅ Implement
InternalWorkflowAdapter: - ✅ Load workflow definition
- ✅ Validate transitions
- ✅ Check permissions
- ✅ Update state
- ✅ Trigger hooks / Emit Event (Side effects via Event Bus only)
1. Workflow System > 1.3 Temporal Workflow Adapter (Optional)
Progress: 6/6 (100%)
Completed:
- ✅ Create
src/framework_m/adapters/workflow/temporal_adapter.py - ✅ Implement
TemporalWorkflowAdapter: - ✅ Connect to Temporal server
- ✅ Start workflows
- ✅ Query workflow state
- ✅ Signal workflows for transitions
2. DocType Overrides > 2.1 Override Registry
Progress: 4/4 (100%)
Completed:
- ✅ Update
MetaRegistry: - ✅ Add
register_override(base_doctype: str, override_class: Type[BaseDocType]) - ✅ When loading DocType, check for overrides
- ✅ Use override class if registered
2. DocType Overrides > 2.2 Schema Extension
Progress: 5/5 (100%)
Completed:
- ✅ Implement schema merging:
- ✅ Combine fields from base and override
- ✅ Override can add new fields
- ✅ Override can modify field properties
- ✅ Base fields cannot be removed
2. DocType Overrides > 2.3 Table Alteration
Progress: 5/5 (100%)
Completed:
- ✅ Update
SchemaMapper: - ✅ Detect schema changes from overrides
- ✅ Generate ALTER TABLE migrations
- ✅ Add new columns
- ✅ Modify column types (with caution)
3. App-Defined Ports > 3.1 Custom Protocol Registration
Progress: 4/4 (100%)
Completed:
- ✅ Update Container to support app-defined protocols:
- ✅ Allow apps to define custom protocols
- ✅ Register via entrypoints
- ✅ Other apps can override using
container.override()
4. Child Tables (Nested DocTypes) > 4.1 Child Table Support
Progress: 3/3 (100%)
Completed:
- ✅ Add
is_childflag to DocType Config - ✅ Child tables don't have independent routes
- ✅ Stored as JSON or separate table with parent reference
4. Child Tables (Nested DocTypes) > 4.2 Implementation
Progress: 8/8 (100%)
Completed:
- ✅ Update
SchemaMapper: - ✅ Create separate table for child
- ✅ Add
parentandparenttypecolumns - ✅ Add
idxfor ordering - ✅ Update
GenericRepository: - ✅ Save child records when saving parent
- ✅ Delete old children and insert new ones
- ✅ Load children when loading parent
5. Virtual Fields > 5.1 Computed Fields
Progress: 4/4 (100%)
Completed:
- ✅ Add
@computed_fielddecorator: - ✅ Virtual fields not stored in database
- ✅ Computed on load
- ✅ Included in API responses
6. Link Fields (Foreign Keys) > 6.1 Link Field Type
Progress: 1/1 (100%)
Completed:
- ✅ Add Link field type using json_schema_extra:
6. Link Fields (Foreign Keys) > 6.2 Implementation
Progress: 8/8 (100%)
Completed:
- ✅ Update
SchemaMapper: - ✅ Detect link fields via json_schema_extra
- ✅ Create foreign key constraint to target table
- ✅ Reference target table's id column
- ✅ Add database enforcement:
- ✅ Foreign key constraints enforce referential integrity
- ✅ Works with SQLite and PostgreSQL (database-agnostic)
- ✅ SQLite foreign keys enabled via PRAGMA
6. Link Fields (Foreign Keys) > 6.3 Link Fetching
Progress: 6/6 (100%)
Completed:
- ✅ Add
fetch_fromoption: - ✅ Auto-populate field from linked document
- ✅ Update GenericRepository to fetch values before save
- ✅ Fetch values automatically on insert and update
- ✅ Handle null links gracefully
- ✅ Support multiple fetch_from fields
7. Naming Series (Human-Readable Names) > 7.1 Auto-Naming Configuration
Progress: 7/7 (100%)
Completed:
- ✅ Add naming configuration to DocType:
- ✅ Implement naming patterns:
- ✅
.YYYY.- Year (2026) - ✅
.MM.- Month (01-12) - ✅
.DD.- Day (01-31) - ✅
.####- Sequential number with padding (0001, 0002...) - ✅
{field}- Field value from entity
7. Naming Series (Human-Readable Names) > 7.2 Implementation (Optimistic Approach)
Progress: 2/2 (100%)
Completed:
- ✅ Name generation happens AFTER insert (id already assigned):
- ✅ For high-volume DocTypes, use PostgreSQL sequences:
7. Naming Series (Human-Readable Names) > 7.3 Counter Storage
Progress: 4/4 (100%)
Completed:
- ✅ Create
NamingCounterDocType: - ✅
prefix: str- e.g., "INV-2024-" - ✅
current: int- Current counter value - ✅ Note: No row-level locking needed. Use optimistic update with retry.
8. Validation Rules > 8.1 Field Validators
Progress: 1/1 (100%)
Completed:
- ✅ Add Pydantic validators:
8. Validation Rules > 8.2 Document Validators
Progress: 1/1 (100%)
Completed:
- ✅ Use controller
validate()hook:
9. Testing > 9.1 Unit Tests
Progress: 5/5 (100%)
Completed:
- ✅ Test workflow transitions (15 tests in
test_workflow.py) - ✅ Test DocType overrides (16 tests in
test_meta_registry_overrides.py) - ✅ Test child table operations (38 tests in
test_child_tables.py) - ✅ Test link field validation (16 tests in
test_link_fields.py) - ✅ Test naming series (29 tests in
test_naming_series.py+ validation tests)
9. Testing > 9.2 Integration Tests
Progress: 4/4 (100%)
Completed:
- ✅ Test full workflow lifecycle (6 tests in
test_workflow_lifecycle.py) - ✅ Test override schema migration (10 tests in
test_override_migration.py) - ✅ Test child table CRUD (12 tests in
test_child_table_integration.py) - ✅ Test app-defined ports (9 tests in
test_app_ports.py)
Validation Checklist
Progress: 6/6 (100%)
Completed:
- ✅ Workflows can be defined and executed (15 unit + 6 integration tests)
- ✅ DocTypes can be extended via overrides (16 unit + 10 integration tests)
- ✅ Child tables work correctly (38 unit + 12 integration tests)
- ✅ Link fields create proper foreign keys (16 tests in
test_link_fields.py) - ✅ Naming series generates unique names (29 tests in
test_naming_series.py) - ✅ App-defined ports can be registered (9 tests in
test_app_ports.py)
Phase 09A: Frontend
Phase: 09a Objective: Build a generic admin UI (the "Desk") that renders forms and lists from metadata. Status: 97% Complete
1. Frontend Architecture > 1.2 Project Setup
Progress: 1/6 (17%)
Completed:
- ✅ Option A: Use Refine CLI (Recommended)
Pending:
- ⏳ Option B: Manual Setup (Full Control)
- ⏳ Install form libraries (Uniforms):
- ⏳ Install UI layer (shadcn/ui):
- ⏳ Install dashboard/charts (Tremor):
- ⏳ Install Studio-specific tools:
1. Frontend Architecture > 1.3 Refine Data Provider
Progress: 4/4 (100%)
Completed:
- ✅ Create
frameworkMDataProvider.ts: - ✅ Implements Refine's
DataProviderinterface - ✅ Maps to Framework M REST API (
/api/v1/{resource}) - ✅ Handles pagination, sorting, filtering
1. Frontend Architecture > 1.4 Base URL Configuration
Progress: 2/2 (100%)
Completed:
- ✅ Support configurable base URLs for different deployment scenarios:
- ✅ Inject configuration via
window.__FRAMEWORK_CONFIG__:
1. Frontend Architecture > 1.5 App Entry Point
Progress: 1/1 (100%)
Completed:
- ✅ Create Refine app entry (
src/App.tsx):
2. Metadata-Driven UI > 2.1 Metadata Fetcher
Progress: 3/3 (100%)
Completed:
- ✅ Create
useDocTypeMetahook: - ✅ Fetch from
GET /api/meta/{doctype} - ✅ Cache metadata aggressively using React Query
2. Metadata-Driven UI > 2.2 Auto Form Generator (Uniforms Integration)
Progress: 14/14 (100%)
Completed:
- ✅ Create
AutoFormcomponent using Uniforms: - ✅ Accept JSON Schema from
GET /api/meta/{doctype} - ✅ Generate form fields dynamically
- ✅ Map schema types to shadcn/ui components:
- ✅
string→<Input /> - ✅
number→<Input type="number" /> - ✅
boolean→<Checkbox /> - ✅
enum→<Select /> - ✅
date→<DatePicker /> - ✅ Link →
<Combobox />with async search (LinkWidget) - ✅ Use Uniforms with custom bridge/registry for our UI primitives
- ✅ Architecture: Export
AutoFormas standalone component - ✅ Allow developers to use it inside custom pages ("Ejection Strategy")
- ✅ Do not couple strictly to a "Meta-Driven Page" route
2. Metadata-Driven UI > 2.3 Auto Table Generator (TanStack Table)
Progress: 4/4 (100%)
Completed:
- ✅ Create
AutoTablecomponent using@refinedev/react-table: - ✅ Columns generated from metadata
- ✅ Sorting, filtering, pagination built-in
- ✅ Row selection for bulk actions
2. Metadata-Driven UI > 2.4 Workflow UI (State Buttons)
Progress: 6/6 (100%)
Completed:
- ✅ State Indicator:
- ✅ Show current state badge (e.g., "Draft", "Approved") in Form Header
- ✅ Action Buttons:
- ✅ Fetch available transitions:
GET /api/workflow/{doctype}/{id}/actions - ✅ Render buttons: "Submit", "Approve", "Reject"
- ✅ Handle transition API call on click
2. Metadata-Driven UI > 2.5 Plugin System (The "Shadow Build")
Progress: 7/7 (100%)
Completed:
- ✅ Goal: "Easy as Frappe" but with Vite/React tooling
- ✅ Strategy:
- ✅
m proddetectsfrontend/index.tsin all installed apps - ✅ Generates a temporary
entry.tsxthat imports all app plugins - ✅ Runs Vite Dev Server on this generated entry
- ✅ Result: Hot Module Replacement (HMR) for custom apps inside the main Desk
- ✅ No Monkey Patching: Plugins register via
app.registerPlugin()
2. Metadata-Driven UI > 2.6 Progressive Customization (The "Zero Cliff")
Progress: 11/11 (100%)
Completed:
- ✅ Level 1: Configuration (Low Code)
- ✅ Edit Labels/Visibility via
Client Scriptor JSON overrides - ✅ No build step required
- ✅ Level 2: Injection (Mid Code)
- ✅ Custom Fields:
app.registerField('rating', StarRating) - ✅ Slot Injection:
app.registerSlot('form-header', PaymentButton) - ✅ Uses Shadow Build (HMR)
- ✅ Level 3: Ejection (Pro Code)
- ✅ Page Override: Replace
FormViewentirely with custom React component - ✅ Whitelabel: Replace
Layout/Themevia Plugin - ✅ Uses Shadow Build (HMR)
3. Core UI Pages > 3.1 List View
Progress: 7/7 (100%)
Completed:
- ✅ Create
ListViewcomponent: - ✅ Route:
/app/{doctype}/list - ✅ Fetch metadata
- ✅ Render
AutoTable - ✅ Add "New" button
- ✅ Add search and filters
- ✅ Add bulk actions
3. Core UI Pages > 3.2 Form View
Progress: 10/10 (100%)
Completed:
- ✅ Create
FormViewcomponent: - ✅ Route - Create:
/app/{doctype}/new - ✅ Route - Edit:
/app/{doctype}/detail/{id} - ✅ Benefit: No reserved keywords for IDs. An ID can be "new", "create", or "dashboard" without collision.
- ✅ Fetch metadata
- ✅ Fetch document (if editing)
- ✅ Render
AutoForm - ✅ Render Workflow Actions (if applicable)
- ✅ Save/Submit/Cancel buttons
- ✅ Show validation errors
3. Core UI Pages > 3.3 Dashboard
Progress: 5/5 (100%)
Completed:
- ✅ Create
Dashboardcomponent: - ✅ Route:
/app/dashboard - ✅ Show recent documents
- ✅ Show notifications
- ✅ Show quick links
4. Navigation & Auth > 4.1 Auth Configuration
Progress: 4/4 (100%)
Completed:
- ✅ Inject
window.__FRAMEWORK_CONFIG__(or fetch/api/v1/config): - ✅
authStrategy:"cookie"(Indie/BFF) or"oidc"(Client-Side) - ✅
loginUrl: URL to redirect to if 401 (for Cookie mode) - ✅
oidcConfig:{ authority, clientId, redirectUri }(for OIDC mode)
4. Navigation & Auth > 4.2 Refine Auth Provider Implementation
Progress: 1/1 (100%)
Completed:
- ✅ Create
authProvider.tsimplementing Refine'sAuthProviderinterface:
4. Navigation & Auth > 4.3 Auth Strategy Variants
Progress: 8/8 (100%)
Completed:
- ✅ Strategy A: Cookie (Indie / Gateway BFF):
- ✅ "It Just Works". Relies on browser's HttpOnly cookie
- ✅
credentials: "include"in all fetch calls - ✅ No token management in frontend
- ✅ Strategy B: OIDC (Client-Side PKCE):
- ✅ Uses
oidc-client-tslibrary - ✅ Store tokens in memory (not localStorage for security)
- ✅ Inject
Authorization: Bearer <token>header via custom fetch
4. Navigation & Auth > 4.4 Login Page (Indie Only)
Progress: 3/3 (100%)
Completed:
- ✅ Create
LoginPagecomponent: - ✅ Route:
/login - ✅ Use Refine's
useLoginhook:
4. Navigation & Auth > 4.5 Sidebar
Progress: 5/5 (100%)
Completed:
- ✅ Create
Sidebarcomponent: - ✅ List all DocTypes (grouped by module)
- ✅ Use Refine's
useMenu()hook for resource navigation - ✅ Collapsible sections
- ✅ Search DocTypes
4. Navigation & Auth > 4.6 Navbar
Progress: 6/6 (100%)
Completed:
- ✅ Create
Navbarcomponent: - ✅ App logo/name
- ✅ Global search
- ✅ Use Refine's
useGetIdentity()for user menu - ✅ Use Refine's
useLogout()for logout button - ✅ Notifications icon
5. Advanced UI Features > 5.1 Custom Views
Progress: 5/5 (100%)
Completed:
- ✅ Support custom view types:
- ✅ Kanban view (for status-based DocTypes)
- ✅ Calendar view (for date-based DocTypes)
- ✅ Gantt view (for project management)
- ✅ Register custom views in DocType Config:
5. Advanced UI Features > 5.2 Inline Editing
Progress: 4/4 (100%)
Completed:
- ✅ Add inline edit for list view:
- ✅ Click cell to edit
- ✅ Save on blur
- ✅ Show validation errors
5. Advanced UI Features > 5.3 Bulk Operations
Progress: 3/3 (100%)
Completed:
- ✅ Add checkbox column to table
- ✅ Select multiple rows
- ✅ Bulk actions: Delete, Export, Update field
6. Real-time Updates > 6.1 Refine Live Provider Implementation
Progress: 1/1 (100%)
Completed:
- ✅ Create
liveProvider.tsimplementing Refine'sLiveProviderinterface:
6. Real-time Updates > 6.2 Register Live Provider with Refine
Progress: 1/1 (100%)
Completed:
- ✅ Add
liveProviderto Refine app:
6. Real-time Updates > 6.3 Automatic UI Updates
Progress: 5/5 (100%)
Completed:
- ✅ With
liveMode: "auto", Refine automatically: - ✅ Refetches list data on
created,updated,deletedevents - ✅ Shows notification on document changes
- ✅ Invalidates React Query cache
- ✅ Manual control with
useLiveMode()hook:
6. Real-time Updates > 6.4 Desk Workspace Configuration (Code-First)
Progress: 11/11 (100%)
Completed:
- ✅ Define Workspace Schema (Pydantic):
- ✅
name: str— unique identifier - ✅
label: str— display name in sidebar - ✅
icon: str— sidebar icon - ✅
items: list[Shortcut | Link | Chart]— workspace contents - ✅
roles: list[str]— who can see this workspace - ✅ Implement
desktop.pyloader: - ✅ Scan apps for
desktop.py - ✅ Load workspace definitions
- ✅ Merge into unified Desk navigation
- ✅ Respect role-based visibility
6. Real-time Updates > 6.5 Global Command Palette
Progress: 4/4 (100%)
Completed:
- ✅ Implement
Ctrl+KGlobal Search: - ✅ Search DocTypes (Navigation)
- ✅ Search Documents (Title)
- ✅ Run Commands (e.g., "New User")
6. Real-time Updates > 6.6 Public API Specs
Progress: 3/3 (100%)
Completed:
- ✅ Ensure strict OpenAPI 3.1 generation:
- ✅
m docs:generate --json— Litestar provides/schema/openapi.json - ✅ Verify compatibility with low-code tools (Retool, Refine)
7. Frontend Build & Serving > 7.1 Build Command (m build)
Progress: 17/17 (100%)
Completed:
- ✅ Implement build logic:
- ✅ Detect Mode from
framework_config.toml: - ✅
frontend_mode = "indie"(default) - ✅
frontend_mode = "plugin"(Shadow Build) - ✅
frontend_mode = "eject"(skip, user handles build) - ✅ Indie Mode:
- ✅ No custom frontend code.
- ✅ Build default Desk:
cd framework_m/frontend && pnpm build - ✅ Output:
framework_m/static/dist/ - ✅ Plugin Mode (Shadow Build):
- ✅ Detect
frontend/index.tsin all installed apps. - ✅ Generate temp
entry.tsximporting all app plugins. - ✅ Run
vite buildon generated entry. - ✅ Output:
dist/(unified build with all app assets) - ✅ Eject Mode:
- ✅ Skip. User has their own frontend repo and build process.
- ✅ Framework M just serves API.
7. Frontend Build & Serving > 7.2 Static File Serving (Production)
Progress: 5/5 (100%)
Completed:
- ✅ Configure Litestar
StaticFilesConfig: - ✅ Serve from
dist/orstatic/dist/ - ✅ Route:
/static/*or/assets/* - ✅ Option: Configure CDN URL in
framework_config.toml: - ✅ If CDN configured, inject CDN prefix into HTML asset URLs.
Phase 09B: Documentation
Phase: 09b Objective: Create comprehensive documentation covering fundamentals, migration guides, i18n, multi-tenancy usage, and API references. Status: 100% Complete
1. Documentation (Basic Setup) > 1.1 Basic User Documentation ✅
Progress: 9/9 (100%)
Completed:
- ✅ Create
docs/user/directory - ✅ Write essential guides:
- ✅ Getting started (
docs/user/getting-started.md) - ✅ Creating DocTypes (
docs/user/creating-doctypes.md) - ✅ Using the Desk (
docs/user/using-the-desk.md) - ✅ Auto-generated docs (
m docs:generate): - ✅
docs/user/generated/field-types.md - ✅
docs/user/generated/api-endpoints.md - ✅ Truthfulness tests (
tests/docs/test_user_docs.py- 17 tests passing)
1. Documentation (Basic Setup) > 1.2 Basic Developer Documentation ✅
Progress: 10/10 (100%)
Completed:
- ✅ Create
docs/developer/directory - ✅ Write essential guides:
- ✅ Architecture overview (
docs/developer/architecture.md) - ✅ Creating custom apps (
docs/developer/creating-apps.md) - ✅ Defining DocTypes (
docs/developer/defining-doctypes.md) - ✅ Auto-generated docs (
m docs:generate): - ✅
docs/developer/generated-core/protocols.md(32 protocols) - ✅
docs/developer/generated-core/hooks.md(10 hooks) - ✅
docs/developer/generated-core/cli-reference.md - ✅ Truthfulness tests (
tests/docs/test_developer_docs.py- 16 tests passing)
1. Documentation (Basic Setup) > 1.3 Framework Fundamentals ✅
Progress: 6/6 (100%)
Completed:
- ✅ Minimal core principle (irreplaceable: async Python, DI, protocols, entrypoints)
- ✅ DI as universal composer
- ✅ Bootstrap flow
- ✅ Layer composition
- ✅ Adding custom adapters
- ✅ Testing with DI
1. Documentation (Basic Setup) > 1.4 Migration Guide (Frappe → Framework M) ✅
Progress: 3/3 (100%)
Completed:
- ✅ Cover backend patterns
- ✅ Cover frontend patterns
- ✅ Practical examples
1. Documentation (Basic Setup) > 1.5 API Documentation ✅
Progress: 4/4 (100%)
Completed:
- ✅ Litestar auto-generates OpenAPI spec (
/schema) - ✅ Swagger UI (
/schema/swagger) - ✅ ReDoc (
/schema/redoc) - ✅ Truthfulness tests (
test_developer_docs.py::TestAPIDocumentation- 3 tests)
1. Documentation (Basic Setup) > 1.6 Example Apps ✅
Progress: 4/4 (100%)
Completed:
- ✅ Create minimal example apps:
- ✅ Simple TODO app (
docs/examples/todo/) - ✅ Basic CRM (
docs/examples/crm/) - ✅ Example index (
docs/examples/README.md)
2. Internationalization (i18n) > 2.1 Backend i18n ✅
Progress: 27/27 (100%)
Completed:
- ✅ Create
I18nProtocolinterface (core/interfaces/i18n.py): - ✅
translate(text, locale, context, default) -> str - ✅
get_locale() -> str - ✅
set_locale(locale) -> None - ✅
get_available_locales() -> list[str] - ✅ Create
InMemoryI18nAdapter(adapters/i18n/__init__.py): - ✅ Dict-based translation storage
- ✅ Add translations dynamically
- ✅ String interpolation with context
- ✅ Create
TranslationDocType: - ✅
source_text: str(original) - ✅
translated_text: str - ✅
locale: str(e.g. "hi", "ta", "en") - ✅
context: str | None(e.g. "button", "label") - ✅ Unique constraint:
(source_text, locale, context) - ✅ Create
DefaultI18nAdapter: - ✅ Load translations from DB on startup
- ✅ Cache in memory (Redis optional)
- ✅ Fallback chain: request locale → default locale → source text
- ✅ Locale resolution order:
- ✅ 1.
Accept-Languageheader - ✅ 2. User preference (
user.locale) - ✅ 3. Tenant default (
tenant.attributes.default_locale) - ✅ 4. System default (
settings.DEFAULT_LOCALE) - ✅ DocType field labels:
- ✅
Field.labelsupports i18n key - ✅ Meta API returns translated labels based on request locale
2. Internationalization (i18n) > 2.2 Frontend i18n
Progress: 11/11 (100%)
Completed:
- ✅ Install
react-i18next: - ✅ Configure with backend translations endpoint
- ✅ Lazy load locale bundles
- ✅ Translation workflow:
- ✅ Extract strings from components (
i18next-parser) - ✅ Upload to Translation DocType
- ✅ Download merged translations as JSON
- ✅ Components:
- ✅
useTranslation()hook in all components - ✅
<Trans>for interpolated strings - ✅ Locale switcher in navbar
2. Internationalization (i18n) > 2.3 Per-Tenant Locales
Progress: 3/3 (100%)
Completed:
- ✅ Tenant can override default locale
- ✅ Tenant can provide custom translations (override system)
- ✅ Tenant locale from
TenantContext.default_locale
3. Multi-Tenancy Usage & Documentation > 3.1 Tenancy Modes Documentation ✅
Progress: 12/12 (100%)
Completed:
- ✅ Document Mode A (Single Tenant / Indie):
- ✅
ImplicitTenantAdapterusage - ✅ Default tenant ID configuration
- ✅ When to use (standalone deployments)
- ✅ Document Mode B (Multi-Tenant / Enterprise):
- ✅
HeaderTenantAdapterusage - ✅ Gateway configuration (X-Tenant-ID, X-Tenant-Attributes)
- ✅ Citadel IAM integration for tenant extraction
- ✅ Document tenant isolation patterns:
- ✅ Logical isolation (tenant_id column, RLS)
- ✅ Database-per-tenant (db_binds per tenant)
- ✅ Schema-per-tenant (PostgreSQL schemas)
3. Multi-Tenancy Usage & Documentation > 3.2 Using TenantContext in Code ✅
Progress: 8/8 (100%)
Completed:
- ✅ Document injection pattern:
- ✅ Dependency injection via
request.state.tenant - ✅ Feature flags from tenant attributes
- ✅ Example endpoints using TenantContext
- ✅ Document tenant-aware queries:
- ✅ Automatic RLS filtering with GenericRepository
- ✅ Manual tenant_id filtering with FilterSpec
- ✅ Cross-tenant queries (admin only)
3. Multi-Tenancy Usage & Documentation > 3.3 Frontend Multi-Tenancy ✅
Progress: 8/8 (100%)
Completed:
- ✅ Tenant context in frontend:
- ✅ Extract from JWT or API response
- ✅ Store in React context (TenantProvider, useTenant hook)
- ✅ Pass tenant_id in API requests (if not in headers)
- ✅ Tenant-specific UI:
- ✅ Tenant branding (logo, colors) - useTenantBranding hook
- ✅ Feature flags from
tenant.attributes- FeatureGate component - ✅ Tenant selector (admin UI) - TenantSelector component
3. Multi-Tenancy Usage & Documentation > 3.4 Switching Adapters ✅
Progress: 5/5 (100%)
Completed:
- ✅ Document adapter selection:
- ✅ Configuration via
framework_config.toml(mode = "single" | "multi") - ✅ Factory function
create_tenant_adapter_from_headers() - ✅ Entrypoint registration for custom adapters
- ✅ Testing with MockTenantAdapter
4. Theming ✅
Progress: 5/5 (100%)
Completed:
- ✅ Add theme support:
- ✅ Light/dark mode with ThemeContext and useTheme hook
- ✅ Custom color schemes via CSS variables (
:rootand.dark) - ✅ Store user preference in localStorage with system detection fallback
- ✅ ThemeToggle component integrated in Navbar
5. Testing > 5.1 Frontend Tests ✅
Progress: 20/20 (100%)
Completed:
- ✅ Unit tests for components:
- ✅ Test
AutoFormrendering (12 tests) - ✅ Test
AutoTablerendering (11 tests) - ✅ Test
ThemeTogglefunctionality (6 tests) - ✅ Test form validation
- ✅ Integration tests:
- ✅ Test full CRUD flow (3 tests)
- ✅ Test theme persistence (7 tests)
- ✅ Test navigation
- ✅ Test real-time updates
- ✅ E2E tests with Playwright:
- ✅ Test user login workflows (7 tests)
- ✅ Test create record workflows (9 tests)
- ✅ Test cross-browser compatibility (10 tests)
- ✅ Test infrastructure:
- ✅ Vitest setup with happy-dom
- ✅ Testing Library integration
- ✅ Playwright configuration
- ✅ CI/CD test scripts
- ✅ Coverage reporting
Validation Checklist
Progress: 6/6 (100%)
Completed:
- ✅ Frontend can render any DocType
- ✅ Forms are generated from metadata
- ✅ Tables support sorting and filtering
- ✅ Real-time updates work
- ✅ Documentation is comprehensive
- ✅ Example apps demonstrate features
Phase 10: ERP Enterprise Features
Phase: 10 Objective: Implement scalable ERP features using CQRS for Reporting, Analytics, and Integrations. Ensure "Zero Cliff" scalability from startup to enterprise. Status: 100% Complete
1. Analytics & Read Models (CQRS) > 1.1 Read Model Protocol
Progress: 5/5 (100%)
Completed:
- ✅ Create
src/framework_m/core/interfaces/read_model.py: - ✅ Define
ReadModelProtocol: - ✅
async def project(event: Event) -> None - ✅
async def query(filters: dict) -> list[dict] - ✅
async def rebuild() -> None
1. Analytics & Read Models (CQRS) > 1.2 Enterprise Projectors
Progress: 4/4 (100%)
Completed:
- ✅ Implement
Projector(Event Handler): - ✅ Subscribe to
doc.created,doc.updated - ✅ Transform transactional data into "Read Optimized" format
- ✅ Upsert into Read Store (Postgres Read Replica, ClickHouse, Elastic)
1. Analytics & Read Models (CQRS) > 1.3 Report Engine (Scalable)
Progress: 5/5 (100%)
Completed:
- ✅ Create
ReportDocType: - ✅
report_type: - ✅
Code Report(SQL file in repo or Python Class - Indie Mode) - ✅
Analytics Report(Queries Read Model / OLAP - Enterprise Mode) - ✅
data_source: SQL / Elastic / ClickHouse adapter
2. Webhook System (Integration) > 2.1 Webhook DocType
Progress: 8/8 (100%)
Completed:
- ✅ Create
src/framework_m/public/webhook.py - ✅ Define
WebhookDocType: - ✅
doctype: str- Trigger DocType - ✅
event: str- Event name (after_save, on_submit) - ✅
url: str- Target Endpoint - ✅
headers: dict- Auth/Custom Headers - ✅
condition: str | None- JMESPath or SimpleEval expression (Noeval()) - ✅
payload_transform: str | None- Jinja2 template for JSON payload
2. Webhook System (Integration) > 2.2 Webhook Dispatcher
Progress: 4/4 (100%)
Completed:
- ✅ Implement
WebhookListener: - ✅ Subscribe to
doc.*events - ✅ Queue background job
fire_webhook - ✅ Resilience: Exponential Backoff (handled by Job Queue)
2. Webhook System (Integration) > 2.3 Webhook Visualization (Native UI)
Progress: 6/6 (100%)
Completed:
- ✅ Webhook Log DocType (defined in Phase 04):
- ✅ Stores Request/Response/Error.
- ✅ Status:
Success(Green),Failed(Red). - ✅ Desk Integration:
- ✅ Add "Recent Logs" table to
WebhookForm View. - ✅ Action: "Retry Now" button (re-queues the job).
3. Data Import / Export (Bulk)
Progress: 1/1 (100%)
Completed:
- ✅ Defined in Phase 05 CLI (See
m import --bypass-controllers)
Phase 10: Production Readiness & Deployment
Phase: 10 Objective: Optimize for production, add monitoring, implement security best practices, and create deployment configurations. Status: 88% Complete
1. Optimization & Performance [x] > 1.1 Database Optimization
Progress: 12/12 (100%)
Completed:
- ✅ Add database indexes:
- ✅ Index on
id(primary key, UUID) - ✅ Index on
name(unique, human-readable identifier) - ✅ Index on
owner(for RLS) - ✅ Index on
modified(for sorting) - ✅ Index on foreign keys
- ✅ Composite indexes for common queries
- ✅ Implement query optimization:
- ✅ Use
select_in_loadingfor relationships - ✅ Avoid N+1 queries
- ✅ Add query logging in dev mode
- ✅ Analyze slow queries
1. Optimization & Performance [x] > 1.2 Caching Strategy
Progress: 9/10 (90%)
Completed:
- ✅ Implement multi-level caching:
- ✅ L1: In-memory cache (per-request)
- ✅ L2: Redis cache (shared)
- ✅ Cache metadata (DocType schemas)
- ✅ Cache permission checks
- ✅ Cache frequently accessed documents
- ✅ Add cache invalidation:
- ✅ Invalidate on document update
- ✅ Use cache tags for bulk invalidation
Pending:
- ⏳ Invalidate on permission change
1. Optimization & Performance [x] > 1.3 Connection Pooling
Progress: 7/7 (100%)
Completed:
- ✅ Configure SQLAlchemy pool:
- ✅ Pool size: 20
- ✅ Max overflow: 10
- ✅ Pool timeout: 30s
- ✅ Pool recycle: 3600s
- ✅ Configure Redis pool:
- ✅ Max connections: 50
1. Optimization & Performance [x] > 1.4 Async Optimization
Progress: 4/4 (100%)
Completed:
- ✅ Group small async operations:
- ✅ Use asyncio.gather for independent I/O
- ✅ Parallelize cache invalidation
- ✅ Parallelize metadata loading (N/A - synchronous)
1. Optimization & Performance [x] > 1.5 Database Indexing
Progress: 4/4 (100%)
Completed:
- ✅ Add missing indexes:
- ✅ Modified column (Handled in SchemaMapper)
- ✅ Foreign Keys (Handled in SchemaMapper)
- ✅ Owner column (for RLS) (Handled in SchemaMapper)
2. Security Hardening > 2.1 Input Validation
Progress: 4/4 (100%)
Completed:
- ✅ Validate all inputs with Pydantic
- ✅ Sanitize user-provided data
- ✅ Prevent SQL injection (use parameterized queries)
- ✅ Prevent XSS (API-only, no HTML rendering)
2. Security Hardening > 2.2 Authentication Security
Progress: 7/8 (88%)
Completed:
- ✅ Support JWT token validation:
- ✅ Verify signature
- ✅ Check expiration
- ✅ Validate issuer (N/A - using shared secret)
- ✅ Add rate limiting:
- ✅ Limit login attempts
- ✅ Use Redis for rate limit storage
Pending:
- ⏳ Limit API requests per user
2. Security Hardening > 2.3 Authorization Security
Progress: 4/4 (100%)
Completed:
- ✅ Enforce permissions on all endpoints
- ✅ Apply RLS to all queries
- ✅ Validate object-level permissions
- ✅ Log permission denials
2. Security Hardening > 2.4 Secrets Management
Progress: 4/4 (100%)
Completed:
- ✅ Never commit secrets to Git
- ✅ Use environment variables (standardized via
EnvSecretAdapter) - ✅ Implement fail-fast validation for mandatory production secrets
- ✅ Support pluggable secret providers (Hexagonal Architecture)
2. Security Hardening > 2.5 HTTPS & CORS
Progress: 3/4 (75%)
Completed:
- ✅ Configure CORS properly:
- ✅ Whitelist allowed origins
- ✅ Restrict methods and headers
Pending:
- ⏳ Enforce HTTPS in production (Cookies secured)
3. Monitoring & Observability > 3.1 Logging [x]
Progress: 5/5 (100%)
Completed:
- ✅ Implement structured logging: (Standard Python logging used)
- ✅ Use JSON format (Optional adapter)
- ✅ Include request ID
- ✅ Include user context
- ✅ Log levels: DEBUG, INFO, WARNING, ERROR
3. Monitoring & Observability > 3.2 Metrics [x]
Progress: 3/3 (100%)
Completed:
- ✅ Add Prometheus metrics: (Scraped via /metrics if enabled)
- ✅ Request count by endpoint
- ✅ Request duration histogram
3. Monitoring & Observability > 3.3 Tracing [x]
Progress: 1/1 (100%)
Completed:
- ✅ Implement OpenTelemetry support [x]
3. Monitoring & Observability > 3.4 Health Checks
Progress: 7/7 (100%)
Completed:
- ✅ Create
/healthendpoint: - ✅ Check database connection
- ✅ Check Redis connection
- ✅ Return 200 if healthy, 503 if not
- ✅ Create
/readyendpoint: [x] - ✅ Check if app is ready to serve traffic
- ✅ Check migrations are up to date (Implemented ZDM-aware
MigrationStatusUtilitywith Alembic + Declarative sync)
4. Error Handling & Resilience [x]
Progress: 3/3 (100%)
Completed:
- ✅ Handle database failures gracefully
- ✅ Handle Redis failures (fallback to no cache)
- ✅ Retry transient errors
4. Error Handling & Resilience [x] > 4.2 Circuit Breaker [x]
Progress: 4/4 (100%)
Completed:
- ✅ Set timeouts for all operations:
- ✅ HTTP requests: 30s
- ✅ Database queries: 10s
- ✅ Background jobs: 300s
5. Deployment Configurations [x] > 5.1 Docker [x]
Progress: 4/4 (100%)
Completed:
- ✅ Create production
Dockerfile: (Registry-First Workflow) [x] - ✅ Multi-stage build for smaller images (Alternative for custom builds) [x]
- ✅ Use non-root user [x]
- ✅ Add health check [x]
5. Deployment Configurations [x] > 5.2 Docker Compose [x]
Progress: 5/5 (100%)
Completed:
- ✅ Create
docker-compose.yml: [x] - ✅ API service
- ✅ Worker service
- ✅ PostgreSQL
- ✅ Redis
5. Deployment Configurations [x] > 5.3 Kubernetes [x]
Progress: 3/3 (100%)
Completed:
- ✅ Create Kubernetes manifests: /docs/deployment/kubernetes [x]
- ✅ Add resource limits [x]
- ✅ Add liveness and readiness probes [x]
5. Deployment Configurations [x] > 5.4 Cloud Platforms
Progress: 0/7 (0%)
Pending:
- ⏳ Create deployment guides for:
- ⏳ Google Cloud Run
- ⏳ AWS ECS/Fargate
- ⏳ Azure Container Apps
- ⏳ Heroku
- ⏳ Railway
- ⏳ Render
6. CI/CD Pipeline [x] > 6.1 GitLab CI [x]
Progress: 1/1 (100%)
Completed:
- ✅ Configure
.gitlab-ci.yml(already exists in repo):
6. CI/CD Pipeline [x] > 6.2 Pre-commit Hooks [x]
Progress: 4/4 (100%)
Completed:
- ✅ Setup pre-commit:
- ✅ Run ruff formatter
- ✅ Run mypy
- ✅ Run tests
6. CI/CD Pipeline [x] > 6.3 Release Versioning & Publishing [x]
Progress: 6/6 (100%)
Completed:
- ✅ Adopt Semantic Versioning (SemVer)
- ✅ CHANGELOG management (Automated via GitLab MRs)
- ✅ Conventional Commits
- ✅ Release workflow (add to
.gitlab-ci.yml) - ✅ Version sources (pyproject.toml)
- ✅ Pre-release versions (Manual/Automated patches)
6. CI/CD Pipeline [x] > 6.4 Git Branching Strategy [x]
Progress: 9/9 (100%)
Completed:
- ✅ release/next (Automated rolling distribution)
- ✅ Branch naming conventions:
- ✅
main— Always deployable, latest development - ✅
feature/<name>— New features (merge to main via PR) - ✅
fix/<issue-id>— Bug fixes (merge to main via PR) - ✅
release/next— Managed bycreate-release-mr - ✅ Release branches (Rejected/NA): (Rolling Distribution used instead)
- ✅ LTS (Rejected/NA): (Rolling Distribution used instead)
- ✅ Backporting workflow (Rejected/NA): (Forward-fixes on main only)
7. Database Migration Strategy > 7.2 Safe Changes (Auto-Migration in Dev Mode)
Progress: 0/4 (0%)
Pending:
- ⏳ Add table: New DocType → new table
- ⏳ Add nullable column: New optional field →
ALTER TABLE ADD COLUMN ... NULL - ⏳ Add index:
Meta.indexes→CREATE INDEX - ⏳ Add foreign key: Link field →
ALTER TABLE ADD CONSTRAINT
7. Database Migration Strategy > 7.3 Safe Changes (Auto-Migration in Dev Mode)
Progress: 4/4 (100%)
Completed:
- ✅ Add table: New DocType → new table
- ✅ Add nullable column: New optional field →
ALTER TABLE ADD COLUMN ... NULL - ✅ Add index:
Meta.indexes→CREATE INDEX - ✅ Add foreign key: Link field →
ALTER TABLE ADD CONSTRAINT
7. Database Migration Strategy > 7.6 Zero-Downtime Migrations [x]
Progress: 4/4 (100%)
Completed:
- ✅ Never drop columns in the same deploy as code changes
- ✅ Always add columns as nullable first
- ✅ Always backfill data before making non-nullable
- ✅ Always deploy code changes before dropping columns
8. Backup & Recovery [x] > 8.1 Database Backups [x]
Progress: 4/4 (100%)
Completed:
- ✅ Automated daily backups (/docs/operations/backup)
- ✅ Store backups in S3 or equivalent
- ✅ Retention policy (30 days)
- ✅ Test restore process
8. Backup & Recovery [x] > 8.2 Disaster Recovery [x]
Progress: 4/4 (100%)
Completed:
- ✅ Document recovery procedures (/docs/operations/backup#disaster-recovery)
- ✅ Test recovery regularly
- ✅ RTO (Recovery Time Objective): 4 hours
- ✅ RPO (Recovery Point Objective): 24 hours
9. Scaling Strategy [x] > 9.1 Horizontal Scaling [x]
Progress: 3/3 (100%)
Completed:
- ✅ API servers: Stateless, scale horizontally [x]
- ✅ Workers: Scale based on queue length [x]
- ✅ Database: Use read replicas for read-heavy workloads [x]
9. Scaling Strategy [x] > 9.2 Load Balancing [x]
Progress: 2/2 (100%)
Completed:
- ✅ Use load balancer (Nginx, ALB, or CDN) [x]
- ✅ Health check endpoints [x]
10. Documentation [x] > 1. Minimal Deployment Guide [x]
Progress: 4/4 (100%)
Completed:
- ✅ Create standardized deployment guide: [x]
- ✅ Docker setup (/docs/deployment/docker)
- ✅ Simple Kubernetes manifest (/docs/deployment/kubernetes)
- ✅ Environment variable configuration
10. Documentation [x] > 10.2 Operations Runbook [x]
Progress: 5/5 (100%)
Completed:
- ✅ Document common operations: (/docs/operations/runbook)
- ✅ Scaling up/down
- ✅ Running migrations
- ✅ Backup and restore
- ✅ Monitoring and alerts
11. Testing [x] > 11.1 Performance Testing [x]
Progress: 4/12 (33%)
Completed:
- ✅ Run baseline performance tests: [x]
- ✅ Request/Response latency (/docs/testing/load-testing)
- ✅ Concurrent connections
- ✅ Background job throughput
Pending:
- ⏳ Test scenarios:
- ⏳ 1000 concurrent users
- ⏳ 10,000 requests/minute
- ⏳ Sustained load for 1 hour
- ⏳ Measure:
- ⏳ Response times (p50, p95, p99)
- ⏳ Error rate
- ⏳ Resource usage
11. Testing [x] > 11.2 Security Testing [x]
Progress: 4/4 (100%)
Completed:
- ✅ Run security scans: [x]
- ✅ Python SAST (Bandit)
- ✅ Secret Detection (Gitleaks)
- ✅ Dependency vulnerability scan (uv tree)
Validation Checklist [x]
Progress: 10/10 (100%)
Completed:
- ✅ All tests pass (unit, integration, E2E)
- ✅ Load testing shows acceptable performance
- ✅ Security scans show no critical issues
- ✅ Monitoring and alerts are configured
- ✅ Backups are automated and tested
- ✅ Documentation is complete
- ✅ Deployment pipeline works
- ✅ Health checks return 200
- ✅ Logs are structured and useful
- ✅ Secrets are not in code
Phase 11: Package Split & MX Pattern
Phase: 11 Objective: Enable enterprises to build custom "MX" variants (e.g., MongoDB-primary, Cassandra-primary) without forking, via pure package composition. Status: 100% Complete
1. Package Split Strategy > 1.1 Split into Core + Standard
Progress: 17/17 (100%)
Completed:
- ✅ Create
framework-m-corepackage: - ✅ All Protocols (Repository, Permission, EventBus, Cache, etc.)
- ✅ DI Container setup (
dependency-injector) - ✅ BaseDocTypeProtocol (not concrete class)
- ✅ Controller/Hook system
- ✅ CLI framework (
cycloptsbase) - ✅ Zero adapters, zero concrete implementations
- ✅ Create
framework-m-standardpackage: - ✅ Depends on
framework-m-core - ✅ SQLAlchemy adapters (SchemaMapper, GenericRepository, UnitOfWork)
- ✅ RBAC PermissionAdapter
- ✅ Redis EventBusAdapter
- ✅ Arq JobQueueAdapter
- ✅ Default Bootstrap sequence
- ✅ Create
framework-mmeta-package: - ✅ Depends on both
framework-m-core+framework-m-standard - ✅ "Batteries included" install for Indie devs
1. Package Split Strategy > 1.2 Decouple Development Tooling
Progress: 7/7 (100%)
Completed:
- ✅ Move scaffolding and codegen from
framework-mtoframework-m-studio: - ✅ Move
new:appcommand and templates - ✅ Move
new:doctypecommand 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-mis optimized for production containers, whileframework-m-studioremains the developer's workbench.
2. Protocols to Extract to Core > 2.1 Ensure All Protocols are Pure
Progress: 5/5 (100%)
Completed:
- ✅
RepositoryProtocol— no SQLAlchemy types - ✅
UnitOfWorkProtocol— generic session interface - ✅
SchemaMapperProtocol— Pydantic → Storage mapping - ✅
BootstrapProtocol— Startup step interface - ✅ Verify: No imports from
sqlalchemyinframework-m-core
2. Protocols to Extract to Core > 2.2 BaseDocType as Protocol
Progress: 3/3 (100%)
Completed:
- ✅ Create
BaseDocTypeProtocol: - ✅
framework-m-standardprovidesBaseDocType(BaseDocTypeProtocol)withowner,_version, etc. - ✅ MX packages can provide their own BaseDocType
3. Bootstrap via Entry Points > 3.1 Define Bootstrap Plugin System
Progress: 4/4 (100%)
Completed:
- ✅ Create entry point group:
framework_m.bootstrap - ✅ Define
BootstrapStepprotocol: - ✅ Discover and sort steps from entry points
- ✅ Allow MX packages to override steps by name
3. Bootstrap via Entry Points > 3.2 Default Bootstrap Steps (framework-m-standard)
Progress: 4/4 (100%)
Completed:
- ✅
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
Progress: 5/5 (100%)
Completed:
- ✅
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. Adapter Auto-Discovery > 4.2 DI Auto-Binding
Progress: 3/3 (100%)
Completed:
- ✅ 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
Progress: 5/5 (100%)
Completed:
- ✅ 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. Example: framework-mx-mongo > 5.2 Entry Point Registration
Progress: 4/4 (100%)
Completed:
- ✅ Register repository adapter entry point
- ✅ Register schema_mapper adapter entry point
- ✅ Register unit_of_work adapter entry point
- ✅ Register bootstrap entry point
5. Example: framework-mx-mongo > 5.3 Testing
Progress: 4/4 (100%)
Completed:
- ✅ Test protocol compliance for all adapters
- ✅ Test entry point registration and discovery
- ✅ Test MX pattern override scenarios
- ✅ Verify 20/20 tests passing
6. Documentation
Progress: 3/3 (100%)
Completed:
- ✅ 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
Progress: 5/5 (100%)
Completed:
- ✅ Test:
framework-m-coreinstalls without SQLAlchemy - ✅ Test:
framework-m-standardadds SQLAlchemy adapters - ✅ Test: MX package can override adapters
- ✅ Test: Coverage configuration includes all workspace packages
- ✅ Test: Bootstrap order respects priority
Phase 12: LLM-Ready Documentation & Automation
Phase: 12 Objective: Create comprehensive, machine-readable documentation with automated screenshot generation and LLM-assisted content workflows. Status: 100% Complete
1. Documentation Architecture > 1.1 Source-of-Truth Hierarchy
Progress: 9/9 (100%)
Completed:
- ✅ Define documentation sources:
- ✅ ADRs (
docs/adr/) → Design decisions, rationale - ✅ Checklists (
checklists/) → Feature completion status - ✅ DocType Source (
*.py) → API reference (auto-generated) - ✅ User Docs (
docs/user/) → How-to guides - ✅ Developer Docs (
docs/developer/) → Architecture, patterns - ✅ Create documentation discovery logic (Dynamic manifest):
- ✅ Implemented in
m docs:generateandm docs:export - ✅ Auto-scans
docs/,checklists/, andsrc/doctypes/
Phase 13 Pending Checkpoints
Phase: 13 Objective: Status: 0% Complete
Phase 13: UI/UX Polish & Design System Enhancement
Phase: 13 Objective: Polish the custom design system by integrating Tamagui as the universal component engine while maintaining strict brand alignment via JSON Design Tokens. The goal is a professional, accessible, and mobile-first universal UI. Status: 90% Complete
1. Audit Current Design System > 1.1 Review Existing Implementation
Progress: 9/9 (100%)
Completed:
- ✅ Audit
frontend/src/App.cssdesign tokens: - ✅ Color palette (align with
#8B5CF6Violet and#021526Midnight Navy) - ✅ Typography (Google Sans font family)
- ✅ Logo & Icon usage (min 40px clear space, min 40px size)
- ✅ Spacing scale (xs to xl)
- ✅ Border radius (sm, md, lg)
- ✅ Review dark mode implementation in
ThemeContext - ✅ Test current mobile responsiveness
- ✅ Run accessibility audit (Lighthouse, axe-core)
1. Audit Current Design System > 1.2 Identify Gaps
Progress: 4/4 (100%)
Completed:
- ✅ Document missing components (tooltips, dropdowns, etc.)
- ✅ Identify inconsistent spacing/colors
- ✅ List accessibility issues (contrast, keyboard nav, ARIA)
- ✅ Note missing animations/transitions
2. Refine Color Palette & Token Transformation > 2.1 Implement Token Transformation Pipeline
Progress: 6/6 (100%)
Completed:
- ✅ Create
libs/framework-m-ui/src/tokens/to hold JSON tokens from the UX team. - ✅ Implement a transformation script/utility to:
- ✅ Generate CSS Variables from JSON (for vanilla CSS components).
- ✅ Generate Tamagui Tokens & Themes (from JSON).
- ✅ Apply Brand Colors:
- ✅ Ensure Midnight Navy (#021526) is the base for Dark Mode surfaces.
2. Refine Color Palette & Token Transformation > 2.2 Tamagui Configuration
Progress: 0/3 (0%)
Pending:
- ⏳ Wrap application in
TamaguiProviderwithin@framework-m/ui. (deferred — see above) - ⏳ Map JSON tokens to Tamagui's
tokensandthemesconfiguration. (deferred) - ⏳ Verify brand fonts (Google Sans) are injected into the Tamagui theme. (deferred)
2. Refine Color Palette & Token Transformation > 2.3 Verify WCAG AA Contrast
Progress: 2/2 (100%)
Completed:
- ✅ Test all text/background combinations generated by the token engine.
- ✅ Ensure brand purple
#8B5CF6remains accessible (>4.5:1) on dark backgrounds.
3. Typography & Spacing Refinement > 3.1 Typography Scale
Progress: 5/5 (100%)
Completed:
- ✅ Update font family to brand standard:
- ✅ Review current font sizes (14px base)
- ✅ Add missing heading sizes if needed
- ✅ Ensure consistent line-heights (1.3 for headings, 1.5 for body)
- ✅ Test readability at different viewport sizes
3. Typography & Spacing Refinement > 3.2 Spacing Consistency
Progress: 4/4 (100%)
Completed:
- ✅ Audit all components for consistent spacing
- ✅ Use spacing scale consistently (xs, sm, md, lg, xl)
- ✅ Fix any hard-coded pixel values
- ✅ Document spacing patterns (e.g., card padding, button spacing)
4. Component Polish > 4.1 Buttons
Progress: 5/5 (100%)
Completed:
- ✅ Add hover/active/focus states
- ✅ Add loading state (spinner)
- ✅ Add disabled state styling
- ✅ Ensure consistent sizing (height, padding)
- ✅ Add keyboard focus indicators (visible outline)
4. Component Polish > 4.2 Form Inputs
Progress: 5/5 (100%)
Completed:
- ✅ Polish input focus states (already has blue ring)
- ✅ Add error state styling (red border + message)
- ✅ Add success state styling (green border)
- ✅ Improve placeholder text contrast
- ✅ Add floating labels (optional enhancement)
4. Component Polish > 4.3 Tables
Progress: 13/13 (100%)
Completed:
- ✅ Add row hover effects (already exists)
- ✅ Add sortable column indicators (
th.sortable,sort-asc,sort-descCSS classes) - ✅ Add loading skeleton for data tables (
.table-skeleton-row+.skeletonclasses) - ✅ Improve mobile table responsiveness (card view via
table.responsive-table) - ✅ Add empty state illustration (
.table-empty-state) - ✅ Kanban View:
- ✅ Implement draggable cards for state-based DocTypes.
- ✅ Add "Quick Edit" from Kanban cards.
- ✅ Grouping by Select/Link fields.
- ✅ Tree View:
- ✅ Implement nested hierarchy for DocTypes with
parent_doctype. - ✅ Add drag-and-drop for re-parenting.
- ✅ Inline "Add Child" and "Rename" actions.
4. Component Polish > 4.4 Cards
Progress: 4/4 (100%)
Completed:
- ✅ Add subtle shadow on hover
- ✅ Ensure consistent border radius
- ✅ Add loading skeleton variant
- ✅ Test card layouts on mobile
4. Component Polish > 4.5 Sidebar
Progress: 5/5 (100%)
Completed:
- ✅ Polish active state (already uses primary color)
- ✅ Add smooth collapse animation (
.sidebar-collapsibleCSS class) - ✅ Improve search input styling
- ✅ Add keyboard navigation support
- ✅ Test mobile drawer behavior
4. Component Polish > 4.6 Navbar & Shell
Progress: 25/25 (100%)
Completed:
- ✅ Polish search bar styling
- ✅ Add user menu dropdown
- ✅ Add notification badge
- ✅ Ensure consistent height (56px)
- ✅ Metadata-Driven View Rendering (UIMeta):
- ✅ Implement
useUIMetahook in@framework-m/desk(fetches/api/meta/:doctype, returns{ form, list, additional_views }) - ✅
UIMeta.form: Layout sections and tabs for form view - ✅
UIMeta.list: Columns, sorting, row-level styling for list view - ✅
UIMeta.additional_views: Kanban, Tree, Calendar configurations (plugin-extensible) - ✅ Implement System Info sidepanel CSS (
.system-info-panel) for audit fields - ✅ Generic Workspace Shell:
- ✅ Dynamic Breadcrumbs (DocType + Document)
- ✅ View Switcher (List/Kanban/Tree/Calendar)
- ✅ Quick Add Button (context-aware)
- ✅ Plugin Hooks (
ShellContext, OmniSearch,registry.registerSection()) - ✅ App Escape Hatch ("Focus Mode" / "Kiosk Mode")
- ✅ Real-time UX (WebSockets):
- ✅ Pluggable WebSocket Hub
- ✅ Live Collaboration Indicators (Avatar stack)
- ✅ Frictionless Child Tables:
- ✅ Inline Grid Edit (Excel-like)
- ✅ Popover/Full-Screen Detail
- ✅ Bulk Actions (Copy/Paste from spreadsheet)
- ✅ Row drag-and-drop reorder
- ✅ Print & PDF Engine
5. Animations & Micro-interactions > 5.1 Add CSS Transitions
Progress: 5/5 (100%)
Completed:
- ✅ Button hover effects (0.15s ease)
- ✅ Input focus transitions (0.15s ease)
- ✅ Sidebar item hover (0.15s ease)
- ✅ Card hover effects (subtle lift)
- ✅ Modal/drawer slide-in animations
5. Animations & Micro-interactions > 5.2 Loading States
Progress: 6/6 (100%)
Completed:
- ✅ Add skeleton loaders for:
- ✅ List view (table rows —
.table-skeleton-row) - ✅ Form view (
.skeletonvariants: text, heading, avatar) - ✅ Dashboard (
.skeleton-button,.skeleton-heading) - ✅ Add spinner component for buttons (
.btn-loading) - ✅ Add page transition fade (
.page-enter)
5. Animations & Micro-interactions > 5.3 Optimistic UI Updates
Progress: 4/4 (100%)
Completed:
- ✅ Instant feedback on create (fade in new row —
.page-enteranimation) - ✅ Instant feedback on update (highlight changed row —
.row-highlight) - ✅ Instant feedback on delete (fade out row —
.row-fade-out) - ✅ Rollback on error with toast notification (
Toastcomponent withvariant="error")
6. Mobile Optimization > 6.1 Responsive Layouts
Progress: 8/8 (100%)
Completed:
- ✅ Test all screens on mobile viewports:
- ✅ 320px (iPhone SE)
- ✅ 375px (iPhone 12/13)
- ✅ 414px (iPhone 12 Pro Max)
- ✅ 768px (iPad)
- ✅ Ensure sidebar collapses to drawer on mobile
- ✅ Test table responsiveness (switch to card view)
- ✅ Ensure touch targets are min 44px
6. Mobile Optimization > 6.2 Mobile-Specific Enhancements
Progress: 4/4 (100%)
Completed:
- ✅ Add swipe gestures for sidebar drawer (
.drawer-panel+.drawer-overlay) - ✅ Optimize form layouts for mobile (single column via
.form-gridoverride) - ✅ Add bottom navigation
- ✅ Test keyboard behavior on mobile browsers (16px font-size prevents iOS zoom)
7. Accessibility (WCAG 2.1 AA) > 7.1 Color Contrast
Progress: 4/4 (100%)
Completed:
- ✅ Run automated contrast checks (Lighthouse)
- ✅ Fix any failing combinations (Violet #8B5CF6 passes 4.5:1 on dark navy)
- ✅ Ensure all interactive elements meet 3:1 minimum
- ✅ Test with color blindness simulators
7. Accessibility (WCAG 2.1 AA) > 7.2 Keyboard Navigation
Progress: 8/8 (100%)
Completed:
- ✅ Test tab order for all pages
- ✅ Add visible focus indicators (
:focus-visibleglobal rule with violet outline) - ✅ Implement keyboard shortcuts:
- ✅
Ctrl+Kfor command palette (already exists) - ✅
Escto close modals/drawers (.drawer-overlayclick handler) - ✅ Arrow keys for table navigation
- ✅
Enterto activate buttons - ✅ Add skip navigation links (
.skip-navCSS class)
7. Accessibility (WCAG 2.1 AA) > 7.3 Screen Reader Support
Progress: 3/7 (43%)
Completed:
- ✅ Add ARIA labels to all interactive elements (
Button,Skeletonwith aria-label) - ✅ Add ARIA live regions for dynamic content (
.live-region,Toastwitharia-live="assertive") - ✅ Add meaningful alt text for images/icons (
aria-hiddenon decorative icons)
Pending:
- ⏳ Test with screen readers: (manual QA required with assistive technologies; cannot be reliably automated in current CLI-only environment)
- ⏳ NVDA (Windows) (not implemented here — requires Windows + NVDA manual session)
- ⏳ JAWS (Windows) (not implemented here — requires licensed JAWS + Windows manual session)
- ⏳ VoiceOver (macOS/iOS) (not implemented here — requires interactive manual walkthrough)
7. Accessibility (WCAG 2.1 AA) > 7.4 Form Accessibility
Progress: 4/4 (100%)
Completed:
- ✅ Ensure all inputs have associated labels
- ✅ Add ARIA descriptions for error messages (
.input-hint.error) - ✅ Add required field indicators
- ✅ Add field help text with
aria-describedby(.input-hintpattern)
8. Tamagui Integration & Component Wrapping > 8.1 Establish the Bridge Layer
Progress: 2/2 (100%)
Completed:
- ✅ Export Tamagui-based components from
@framework-m/ui - ✅ Tamagui
TamaguiProviderintegration
8. Tamagui Integration & Component Wrapping > 8.2 Add Custom "Pure" Components
Progress: 3/3 (100%)
Completed:
- ✅ StateBadge — Pure CSS for high efficiency in lists. (already existed in
@framework-m/ui) - ✅ ThemeToggle — Custom animated switch. (already existed in
@framework-m/ui) - ✅ Toast — Built using pure CSS + ARIA live regions. (implemented:
Toast,ToastContainerin@framework-m/ui)
9. Business Suite Contextual UI > 9.1 Context-Aware Overrides
Progress: 2/2 (100%)
Completed:
- ✅ Implement UI Context Registry
- ✅ Implement Aggregate Root Views
9. Documentation > 9.1 Design System Documentation
Progress: 7/7 (100%)
Completed:
- ✅ Create
docs/design-system.md: - ✅ Color palette with hex codes
- ✅ Typography scale
- ✅ Spacing system
- ✅ Component patterns
- ✅ Animation principles
- ✅ Accessibility guidelines
9. Documentation > 9.2 Component Documentation
Progress: 1/1 (100%)
Completed:
- ✅ Document each component with usage examples, props/variants, accessibility notes, code snippets (in
docs/design-system.md)
9. Documentation > 9.3 Storybook (Optional)
Progress: 3/4 (75%)
Completed:
- ✅ Set up Storybook for component showcase
- ✅ Create stories for all components
- ✅ Add dark mode toggle in Storybook
Pending:
- ⏳ Deploy Storybook for team reference (deferred — requires CI/CD or static hosting target)
10. Performance Optimization > 10.1 CSS Optimization
Progress: 4/4 (100%)
Completed:
- ✅ Remove unused CSS rules
- ✅ Minimize CSS file size
- ✅ Use CSS containment where applicable (
.layout-sidebar,.layout-content,.cardwithcontain:) - ✅ Optimize font loading (Google Fonts with
display=swap)
10. Performance Optimization > 10.2 Bundle Size
Progress: 2/4 (50%)
Completed:
- ✅ Analyze bundle size with Vite build (910 kB main chunk — code splitting recommended)
- ✅ Lazy load routes
Pending:
- ⏳ Code-split large components (ongoing — already uses lazy routes)
- ⏳ Optimize images (use WebP, lazy loading) (deferred — no images in desk UI yet)
10. Performance Optimization > 10.3 Runtime Performance
Progress: 2/4 (50%)
Completed:
- ✅ Test Time to Interactive (TTI) - target
< 3s(proxy viadomInteractivefrom production preview: ~55.8ms on local run) - ✅ Optimize re-renders (React.memo, useMemo — applied in existing hooks)
Pending:
- ⏳ Test First Contentful Paint (FCP) - target
< 1.5s(blocked in this environment: Lighthouse CLI cannot run due Node/Chrome architecture mismatch; Playwright headless did not expose paint entries reliably) - ⏳ Test Largest Contentful Paint (LCP) - target
< 2.5s(blocked in this environment for same reason as FCP)
11. Testing > 11.1 Visual Regression Testing
Progress: 4/7 (57%)
Completed:
- ✅ Create visual snapshots (implemented via
frontend/tests/e2e/visual-regression.spec.tswith Chromium/Firefox/WebKit baselines) - ✅ Chrome (automated Chromium snapshot baseline generated)
- ✅ Firefox (automated Firefox snapshot baseline generated)
- ✅ Safari (approximated via Playwright WebKit snapshot baseline)
Pending:
- ⏳ Set up Chromatic or Percy (deferred)
- ⏳ Test across browsers (manual QA):
- ⏳ Edge
11. Testing > 11.2 Accessibility Testing
Progress: 3/4 (75%)
Completed:
- ✅ Run Lighthouse accessibility audit (target 100)
- ✅ Run axe-core automated tests
- ✅ Manual keyboard-only testing
Pending:
- ⏳ Manual screen reader testing (requires dedicated QA session)
11. Testing > 11.3 Cross-Browser Testing
Progress: 0/4 (0%)
Pending:
- ⏳ Test on Windows (Chrome, Firefox, Edge)
- ⏳ Test on macOS (Chrome, Firefox, Safari)
- ⏳ Test on iOS (Safari, Chrome)
- ⏳ Test on Android (Chrome)
12. Example Screens Enhancement > 12.1 Polish Reference Screens
Progress: 5/5 (100%)
Completed:
- ✅ Dashboard — Metric cards with hover lift, skeleton loaders
- ✅ List View — Sort indicators, skeleton rows, mobile card view, empty state
- ✅ Form View — Validation states (error/success borders + hint text), skeleton loaders
- ✅ Detail View — Add tabs, related lists (implemented in
frontend/src/pages/DetailPage.tsx) - ✅ Settings Page — Add sections, save states (implemented in
frontend/src/pages/SettingsPage.tsx)
12. Example Screens Enhancement > 12.2 Create Demo Content
Progress: 1/2 (50%)
Completed:
- ✅ Add sample data for screenshots (implemented via
frontend/scripts/seed-screenshot-data.mjsand fixture output)
Pending:
- ⏳ Create video walkthrough (deferred)
Validation Checklist
Progress: 8/8 (100%)
Completed:
- ✅ Brand Violet & Midnight Navy palette is consistently applied
- ✅ Dark mode works perfectly across all screens
- ✅ Mobile responsiveness is 100% (tested via CSS breakpoints)
- ✅ WCAG 2.1 AA compliance verified (focus indicators, contrast, ARIA, skip nav)
- ✅ All animations are smooth (CSS transitions, 0.15-0.3s)
- ✅ No UI library dependencies (pure CSS + React)
- ✅ Design system is documented (
docs/design-system.md) - ✅ Developers say: "Wow, this looks professional!"
Phase 14: Studio Enhancements (Connected Citizen Edition)
Phase: 14 Objective: Transform Studio into a professional-grade, metadata-driven tool for Citizen Developers and Consultants while maintaining Developer Guardrails for schema stability. Status: 100% Complete
1. Unified Connected Workspace > 1.1 Live Environment Bridge
Progress: 11/11 (100%)
Completed:
- ✅ Implement Multi-Repo Workspace Manager:
- ✅ Connect Studio to multiple Git Repositories:
- ✅
Workspace Repo: Core DocTypes, Server Controllers, Client Logic. - ✅
Print Repo: Jinja2 templates and assets for document rendering. - ✅
Config Repo: Global Blueprints, Settings, and System Metadata. - ✅ Implement Branch Orchestration:
- ✅ Ability to switch branches independently for each connected repo.
- ✅ Show "Branch Status" per repo in the Studio Dashboard.
- ✅ Implement Live Preview:
- ✅ Render DocTypes using real data from the connected Framework M pod.
- ✅ Hot-reload logic when files change in the
Workspace Repo.
1. Unified Connected Workspace > 1.2 Data Elements (Field Blueprints)
Progress: 6/6 (100%)
Completed:
- ✅ Implement Data Element Library:
- ✅ Define reusable field blueprints (label, type, validation, length) in a central JSON/TOML config.
- ✅ Studio UI: "Add Field from Blueprint" vs "Add Primitive Field".
- ✅ Implement Blueprint Inheritance:
- ✅ Track DocType fields that are "Linked" to a Blueprint.
- ✅ Warn if a Blueprint update causes a breaking change in a linked DocType.
2. Developer Guardrails (Schema Safety) > 2.1 Git-Powered Diff Analysis
Progress: 6/6 (100%)
Completed:
- ✅ Implement Schema Change Detection:
- ✅ Calculate delta between the current UI-defined schema and the last committed Python file.
- ✅ Classify changes:
- ✅ Guardrail UI:
- ✅ Show immediate feedback in the editor when a DANGEROUS change is made.
- ✅ Block "Publish" if DANGEROUS changes are detected without an "Acknowledgement" from the user.
3. Wiki-Style Publishing (Persistence) > 3.1 Local & Remote Persistence
Progress: 7/7 (100%)
Completed:
- ✅ Implement Storage Adapters:
- ✅
FileAdapter: Direct write to.pyfiles (Local/Indie). - ✅
GitApiAdapter: Commit via GitLab/GitHub API (SaaS/Enterprise). - ✅ The "Publish" Modal:
- ✅ Prompt for "Reason for Change" (Commit Message).
- ✅ Automated Branching: Create
feature/[author]-[change-name]branch. - ✅ Push to Git and provide a link to the "Change Request".
4. SaaS & Enterprise Deployment (The 1:1 Model) > 4.1 Stateless Pod Architecture (No-PV Model)
Progress: 6/6 (100%)
Completed:
- ✅ Implement Ephemeral Workspace Lifecycle:
- ✅ Startup: Clone target git branch into the pod's ephemeral
emptyDir. - ✅ In-Memory Drafts: Studio writes changes to the local ephemeral disk for immediate
m devhot-reloading. - ✅ Auto-Draft Sync: (Optional) Periodically push local changes to a hidden
studio-draft/[user]branch to prevent loss on pod eviction. - ✅ Implement Stateless Config:
- ✅ Injected Environment Variables (Git URL, Token) define the workspace identity.
4. SaaS & Enterprise Deployment (The 1:1 Model) > 4.2 Global Blueprints via ConfigMap
Progress: 1/1 (100%)
Completed:
- ✅ Load read-only "Corporate Data Elements" from
/etc/studio/blueprints.json(mapped to a K8s ConfigMap) or directly from theConfig Repo.
4. SaaS & Enterprise Deployment (The 1:1 Model) > 4.3 Multi-Repo Print Formats (GitOps)
Progress: 6/6 (100%)
Completed:
- ✅ Implement Git-Backed Print Layouts:
- ✅ Print Builder saves layouts specifically to the
Print Repo. - ✅ Support "Preview with Sample Data" using the latest branch from the
Print Repo. - ✅ Implement Hot-Swappable Branding:
- ✅ Framework M pod monitors the
Print Repo(via Sidecar or GitOps controller). - ✅ Update print outputs without redeploying the core application.
5. Basic Composition (Current Pattern)
Progress: 5/5 (100%)
Completed:
- ✅ Sidebar Entry Registry:
- ✅ Simple UI to manage which DocTypes appear in which sidebar section.
- ✅ Order sidebar items via drag-and-drop.
- ✅ View Configurator (Field Mapping):
- ✅ Map DocType fields to standard view slots (e.g., "Status field" $\rightarrow$ Kanban Columns).
6. Business Suite Studio (The Blueprint System) > 6.1 Unified UI Metadata (UIMeta & Adapter Extensions)
Progress: 16/16 (100%)
Completed:
- ✅ Implement Unified UIMeta Structure:
- ✅ Support a single
UIMetainner class (or separateFormMeta/ListMeta) that encapsulates: - ✅
form: Layout, sections, tabs. - ✅
list: Columns, sorting, row styling. - ✅
additional_views: Kanban, Tree, Calendar configurations. - ✅ Implement Adapter Metadata Extensions:
- ✅ Allow plugins to register custom meta namespaces (e.g.,
WMSMeta,MobileMeta). - ✅ Framework to pass-through these custom blocks to the frontend via
/api/meta. - ✅ Implement Studio Plugin Metadata Editor:
- ✅ A "Schema-driven" property editor in Studio that allows adding arbitrary properties to a DocType's UI metadata.
- ✅ Support for JSON-schema based validation of custom metadata in Studio.
- ✅ WYSIWYG Visual Designer:
- ✅ Clipart/Skeleton drag-and-drop for the primary form layout within the
UIMetacontext. - ✅ Child Table UX Designer:
- ✅ Configure display mode per child table:
Grid(Inline),List, orCard. - ✅ Field-level visibility toggle specifically for the grid view vs the detail popover.
6. Business Suite Studio (The Blueprint System) > 6.2 Aggregate Root Builder
Progress: 3/3 (100%)
Completed:
- ✅ Implement Multi-DocType Linking:
- ✅ Visual builder to link "Related DocTypes" into a single aggregate view.
- ✅ Configure "Save Cascade" behavior for linked entities.
6. Business Suite Studio (The Blueprint System) > 6.3 Shell Plugin Configurator
Progress: 4/4 (100%)
Completed:
- ✅ Implement UI to manage shell-wide hooks:
- ✅ Register global "Action Buttons".
- ✅ Configure custom "Sidebar Apps".
- ✅ Define "Search Providers" per Role.
7. Documentation & Tooling Integration
Progress: 4/4 (100%)
Completed:
- ✅ Automated Documentation CI:
- ✅ Integrate
m docs:generateinto the CI pipeline (GitLab CI/GitHub Actions). - ✅ Automatically update
docs/developer/generatedanddocs/user/generatedon every merge tomain. - ✅ Implement "Truthfulness" validation during build to ensure docs reflect current Protocol and DocType states.
Remaining Items (Verified: Wiring, Testing, Integration)
Progress: 8/8 (100%)
Completed:
- ✅ Data Elements UI flow is wired in Studio UI:
- ✅ Blueprint inheritance impact warnings are surfaced in editor UX:
- ✅ Guardrail UX + publish blocking acknowledgement is integrated in Studio UI:
- ✅ Publish modal workflow is wired in Studio UI:
- ✅ Print builder integration into Studio UI is complete:
- ✅ Hot-swappable print branding is operationalized:
- ✅ Aggregate Root Builder visual workflow is connected in Studio UI:
- ✅ Shell Plugin Configurator UI is wired in Studio UI:
Phase 15: Frontend Plugin Architecture
Phase: 15 Objective: Implement multi-app plugin system for Frontend M, enabling modular business applications with auto-discovered plugins and composed UI. Status: 100% Complete
Stage 1: Package Infrastructure > 1.1 Create @framework-m/plugin-sdk Package
Progress: 20/20 (100%)
Completed:
- ✅ Create package structure:
- ✅ Create
libs/framework-m-plugin-sdk/package.json: - ✅ Set
name: "@framework-m/plugin-sdk" - ✅ Set
version: "0.1.0" - ✅ Add peer dependencies:
react@^19.0.0 - ✅ Add peer dependency:
@framework-m/desk@^0.1.0 - ✅ Add dependency:
react-router-dom@^7.0.0 - ✅ Set
main: "dist/index.js" - ✅ Set
types: "dist/index.d.ts" - ✅ Set
exportswith ESM/CJS support - ✅ Add build script:
"build": "tsc && vite build" - ✅ Create
libs/framework-m-plugin-sdk/tsconfig.json: - ✅ Extend from root tsconfig
- ✅ Set
declaration: true - ✅ Set
outDir: "dist" - ✅ Set
include: ["src"] - ✅ Create
libs/framework-m-plugin-sdk/vite.config.ts: - ✅ Configure library build mode
- ✅ Set external deps:
react,react-dom,react-router-dom - ✅ Configure rollup output formats (ESM, CJS)
Stage 1: Package Infrastructure > 1.2 Define Plugin Types
Progress: 38/38 (100%)
Completed:
- ✅ Create
src/types/plugin.ts: - ✅ Define
MenuIteminterface: - ✅
name: string- Unique ID (e.g., "sales.invoice") - ✅
label: string- Display name - ✅
route: string- React Router path - ✅
icon?: string- Icon name (lucide-react) - ✅
module?: string- Group name (e.g., "Sales") - ✅
category?: string- Subgroup (e.g., "Transactions") - ✅
order?: number- Sort order - ✅
children?: MenuItem[]- Nested items - ✅
hidden?: boolean- Visibility flag - ✅ Define
ServiceFactory<T>type: - ✅ Type:
() => Promise<T> | T - ✅ Define
Providerinterface: - ✅
component: () => Promise<{ default: ComponentType }> - ✅
props?: Record<string, any> - ✅ Define
DocTypeExtensioninterface: - ✅
doctype: string- DocType to extend - ✅
fields?: Record<string, any>- Additional fields - ✅
actions?: Action[]- Custom actions - ✅
components?: Record<string, ComponentType>- Custom renderers - ✅ Define
Widgetinterface: - ✅
id: string - ✅
title: string - ✅
component: () => Promise<{ default: ComponentType }> - ✅
size?: 'small' | 'medium' | 'large' - ✅
permissions?: string[] - ✅ Define
FrameworkMPlugininterface (main plugin contract): - ✅
name: string- Plugin identifier - ✅
version: string- Semantic version - ✅
menu?: MenuItem[]- Menu contributions - ✅
routes?: RouteObject[]- Route definitions - ✅
services?: Record<string, ServiceFactory>- DI services - ✅
providers?: Provider[]- Context providers - ✅
doctypes?: DocTypeExtension[]- DocType extensions - ✅
widgets?: Widget[]- Dashboard widgets - ✅
onInit?: () => Promise<void> | void- Initialization hook - ✅
onDestroy?: () => Promise<void> | void- Cleanup hook
Stage 1: Package Infrastructure > 1.3 Implement PluginRegistry
Progress: 45/45 (100%)
Completed:
- ✅ Create
src/core/PluginRegistry.ts: - ✅ Create
PluginRegistryclass: - ✅ Private field:
plugins: Map<string, FrameworkMPlugin> - ✅ Private field:
menuCache: MenuItem[] | null - ✅ Private field:
serviceContainer: Map<string, any> - ✅ Implement
register(plugin: FrameworkMPlugin): Promise<void>: - ✅ Validate plugin has
nameandversion - ✅ Check for duplicate plugin names (warn if exists)
- ✅ Add plugin to
pluginsmap - ✅ Call
plugin.onInit()if defined - ✅ Invalidate menu cache
- ✅ Implement
getMenu(): MenuItem[]: - ✅ Return cached menu if available
- ✅ Collect menu items from all plugins
- ✅ Call
mergeMenus()to organize by module/category - ✅ Cache and return merged menu tree
- ✅ Implement private
mergeMenus(items: MenuItem[]): MenuItem[]: - ✅ Create
moduleMap: Map<string, MenuItem> - ✅ Group items by
modulefield - ✅ Within each module, group by
category - ✅ Create hierarchy: Module → Category → Items
- ✅ Sort by
orderfield (default 999) - ✅ Return sorted module array
- ✅ Implement private
getModuleIcon(moduleName: string): string: - ✅ Map common module names to icons:
- ✅ Sales → "shopping-cart"
- ✅ Inventory → "package"
- ✅ HR → "users"
- ✅ Finance → "dollar-sign"
- ✅ Core → "settings"
- ✅ Default: "folder"
- ✅ Implement
getRoutes(): RouteObject[]: - ✅ Collect routes from all plugins
- ✅ Flatten into single array
- ✅ Return merged routes
- ✅ Implement
getPlugin(name: string): FrameworkMPlugin | undefined: - ✅ Return plugin from map by name
- ✅ Implement
getAllPlugins(): FrameworkMPlugin[]: - ✅ Convert plugins map to array
- ✅ Return all registered plugins
- ✅ Implement
getService<T>(name: string): T | undefined: - ✅ Check service container cache
- ✅ If not cached, find service factory in plugins
- ✅ Call factory and cache result
- ✅ Return service instance
Stage 1: Package Infrastructure > 1.4 Implement ServiceContainer
Progress: 15/15 (100%)
Completed:
- ✅ Create
src/core/ServiceContainer.ts: - ✅ Create
ServiceContainerclass: - ✅ Private field:
services: Map<string, any> - ✅ Private field:
factories: Map<string, ServiceFactory> - ✅ Implement
register<T>(name: string, factory: ServiceFactory<T>): void: - ✅ Store factory in factories map
- ✅ Implement
get<T>(name: string): T | undefined: - ✅ Check services cache
- ✅ If not cached and factory exists:
- ✅ Call factory
- ✅ Cache result
- ✅ Return service instance
- ✅ Implement
clear(): void: - ✅ Clear services cache
- ✅ Clear factories
Stage 1: Package Infrastructure > 1.5 Create React Context Provider
Progress: 11/11 (100%)
Completed:
- ✅ Create
src/context/PluginRegistryContext.tsx: - ✅ Create context:
PluginRegistryContext = createContext<PluginRegistry | null>(null) - ✅ Define
PluginRegistryProviderPropsinterface: - ✅
children: ReactNode - ✅
registry?: PluginRegistry - ✅ Create
PluginRegistryProvidercomponent: - ✅ Accept
registryprop or create new instance - ✅ Use
useStateto hold registry instance - ✅ Use
useEffectto mark ready state - ✅ Show loading state while initializing
- ✅ Render children wrapped in context provider
Stage 1: Package Infrastructure > 1.6 Create React Hooks
Progress: 18/18 (100%)
Completed:
- ✅ Create
src/hooks/usePluginMenu.ts: - ✅ Implement
usePluginMenu(): MenuItem[]: - ✅ Get registry from context
- ✅ Throw error if used outside provider
- ✅ Use
useMemoto callregistry.getMenu() - ✅ Return memoized menu tree
- ✅ Create
src/hooks/usePlugin.ts: - ✅ Implement
usePlugin(name: string): FrameworkMPlugin | undefined: - ✅ Get registry from context
- ✅ Throw error if used outside provider
- ✅ Use
useMemoto callregistry.getPlugin(name) - ✅ Return memoized plugin
- ✅ Create
src/hooks/useService.ts: - ✅ Implement
useService<T>(name: string): T | undefined: - ✅ Get registry from context
- ✅ Throw error if used outside provider
- ✅ Use
useMemoto callregistry.getService<T>(name) - ✅ Return memoized service instance
Stage 1: Package Infrastructure > 1.7 Create Public API Exports
Progress: 6/6 (100%)
Completed:
- ✅ Create
src/index.ts: - ✅ Export all types from
./types/plugin - ✅ Export
PluginRegistryfrom./core/PluginRegistry - ✅ Export
ServiceContainerfrom./core/ServiceContainer - ✅ Export context and provider from
./context/PluginRegistryContext - ✅ Export hooks:
usePluginMenu,usePlugin,useService
Stage 1: Package Infrastructure > 1.8 Build and Test Plugin SDK
Progress: 11/11 (100%)
Completed:
- ✅ Run build:
- ✅ Verify output:
- ✅ Check
dist/index.jsexists - ✅ Check
dist/index.d.tsexists - ✅ Verify TypeScript types are exported
- ✅ Create test file
tests/PluginRegistry.test.ts: - ✅ Test plugin registration
- ✅ Test menu merging
- ✅ Test duplicate plugin warning
- ✅ Test route aggregation
- ✅ Test service container
Stage 2: Build-Time Plugin Discovery > 2.1 Create @framework-m/vite-plugin Package
Progress: 14/14 (100%)
Completed:
- ✅ Create package structure:
- ✅ Create
libs/framework-m-vite-plugin/package.json: - ✅ Set
name: "@framework-m/vite-plugin" - ✅ Set
version: "0.1.0" - ✅ Add dependency:
vite@^6.0.0 - ✅ Add dependency:
@framework-m/plugin-sdk@workspace:^0.1.0 - ✅ Add dependency:
glob@^10.0.0 - ✅ Set
main: "dist/index.js" - ✅ Set
types: "dist/index.d.ts" - ✅ Add build script
- ✅ Create
libs/framework-m-vite-plugin/tsconfig.json: - ✅ Extend from root
- ✅ Set
declaration: true - ✅ Set
moduleResolution: "bundler"
Stage 2: Build-Time Plugin Discovery > 2.2 Implement Plugin Discovery Logic
Progress: 25/25 (100%)
Completed:
- ✅ Create
src/index.ts: - ✅ Import
Pluginfromvite - ✅ Import
globSyncfromglob - ✅ Import
fsandpath - ✅ Create
frameworkMPlugin(): Pluginfunction: - ✅ Define
pluginPaths: string[]variable - ✅ Implement
buildStart()hook: - ✅ Use
globSyncto find allpackage.jsonfiles - ✅ Exclude
node_modulesanddist - ✅ For each package.json:
- ✅ Parse JSON
- ✅ Check for
"framework-m"metadata field - ✅ If
pkg["framework-m"]?.pluginexists: - ✅ Resolve plugin config path
- ✅ Add to
pluginPathsarray - ✅ Log:
✓ Discovered ${count} Framework M plugins - ✅ Implement
resolveId(id)hook: - ✅ If
id === "virtual:framework-m-plugins": - ✅ Return
"\0virtual:framework-m-plugins" - ✅ Implement
load(id)hook: - ✅ If
id === "\0virtual:framework-m-plugins": - ✅ Generate import statements for each plugin
- ✅ Generate default export array
- ✅ Return generated code
- ✅ Return plugin object with hooks
Stage 2: Build-Time Plugin Discovery > 2.3 Configure Code Splitting
Progress: 5/5 (100%)
Completed:
- ✅ Update
src/index.ts: - ✅ Add
config()hook to plugin: - ✅ Configure
build.rollupOptions.output.manualChunks - ✅ Create chunk per plugin (e.g.,
wms-[hash].js) - ✅ Keep framework code in main chunk
Stage 2: Build-Time Plugin Discovery > 2.4 Build Vite Plugin
Progress: 2/2 (100%)
Completed:
- ✅ Run build:
- ✅ Verify output exists
Stage 3: Shell Application Integration > 3.1 Update Frontend Package Dependencies
Progress: 4/4 (100%)
Completed:
- ✅ Update
frontend/package.json: - ✅ Add dependency:
"@framework-m/plugin-sdk": "workspace:^0.1.0" - ✅ Add devDependency:
"@framework-m/vite-plugin": "workspace:^0.1.0" - ✅ Install dependencies:
Stage 3: Shell Application Integration > 3.2 Configure Vite Plugin
Progress: 4/4 (100%)
Completed:
- ✅ Update
frontend/vite.config.ts: - ✅ Import
frameworkMPluginfrom@framework-m/vite-plugin - ✅ Add
frameworkMPlugin()to plugins array - ✅ Verify HMR configuration
Stage 3: Shell Application Integration > 3.3 Bootstrap PluginRegistry in App
Progress: 16/16 (100%)
Completed:
- ✅ Update
frontend/src/App.tsx: - ✅ Import
PluginRegistry,PluginRegistryProviderfrom plugin-sdk - ✅ Import virtual module:
import plugins from 'virtual:framework-m-plugins' - ✅ Create
bootstrap()async function: - ✅ Create new
PluginRegistryinstance - ✅ Loop through discovered plugins
- ✅ Call
registry.register(plugin)for each - ✅ Return registry
- ✅ Add state:
useState<PluginRegistry | null>(null) - ✅ Add
useEffectto callbootstrap()on mount: - ✅ Call
bootstrap() - ✅ Set registry state
- ✅ Show loading state while registry is null
- ✅ Wrap app in
PluginRegistryProvider: - ✅ Pass registry prop
- ✅ Wrap existing
<Refine>component
Stage 3: Shell Application Integration > 3.4 Update Sidebar to Use Plugin Menu
Progress: 19/19 (100%)
Completed:
- ✅ Update
frontend/src/layout/Sidebar.tsx: - ✅ Import
usePluginMenuhook - ✅ Call hook:
const pluginMenu = usePluginMenu() - ✅ Merge plugin menu with favorites/recent:
- ✅ Keep existing favorites section (top)
- ✅ Keep existing recent section (after favorites)
- ✅ Add plugin menu groups (after recent)
- ✅ Update menu rendering:
- ✅ Map over
pluginMenuarray - ✅ Each top-level item is a module group
- ✅ Render module header with icon
- ✅ Render children (categories and items)
- ✅ Preserve existing collapse/expand logic
- ✅ Preserve all existing Phase 4 features:
- ✅ Search highlighting
- ✅ Breadcrumbs
- ✅ Keyboard navigation
- ✅ Mobile drawer
- ✅ Touch gestures
Stage 3: Shell Application Integration > 3.5 Integrate Plugin Routes
Progress: 6/6 (100%)
Completed:
- ✅ Update
frontend/src/App.tsx: - ✅ After bootstrap, get routes:
const pluginRoutes = registry.getRoutes() - ✅ In
<Routes>component: - ✅ Map over
pluginRoutes - ✅ Render
<Route>for each plugin route - ✅ Preserve existing routes (dashboard, list, form, login)
Stage 4: Create Example Plugin (WMS - implemented in business-m) > 4.1 Scaffold WMS Plugin Package
Progress: 18/18 (100%)
Completed:
- ✅ Create plugin structure:
- ✅ Create
apps/wms/frontend/package.json: - ✅ Set
name: "@my-company/wms" - ✅ Set
version: "1.0.0" - ✅ Set
private: true - ✅ Add
framework-mmetadata: - ✅ Add dependencies:
- ✅
@framework-m/desk@workspace:^0.1.0 - ✅
@framework-m/plugin-sdk@workspace:^0.1.0 - ✅
react@^19.0.0 - ✅
react-router-dom@^7.0.0 - ✅ Create
apps/wms/frontend/tsconfig.json: - ✅ Extend from root
- ✅ Set
jsx: "react-jsx" - ✅ Create
apps/wms/frontend/vite.config.ts: - ✅ Configure library build mode
- ✅ Set entry to
plugin.config.ts - ✅ Configure external deps
Stage 4: Create Example Plugin (WMS - implemented in business-m) > 4.2 Define WMS Plugin Manifest
Progress: 31/31 (100%)
Completed:
- ✅ Create
apps/wms/frontend/plugin.config.ts: - ✅ Import
FrameworkMPlugintype - ✅ Export default plugin object:
- ✅ Set
name: "wms" - ✅ Set
version: "1.0.0" - ✅ Define
menuarray: - ✅ Warehouse item:
- ✅ name: "wms.warehouse"
- ✅ label: "Warehouse"
- ✅ route: "/doctypes/wms.warehouse"
- ✅ icon: "warehouse"
- ✅ module: "Inventory"
- ✅ category: "Masters"
- ✅ order: 1
- ✅ Bin Location item:
- ✅ name: "wms.bin_location"
- ✅ label: "Bin Location"
- ✅ route: "/doctypes/wms.bin_location"
- ✅ icon: "map-pin"
- ✅ module: "Inventory"
- ✅ category: "Masters"
- ✅ order: 2
- ✅ Stock Entry item:
- ✅ name: "wms.stock_entry"
- ✅ label: "Stock Entry"
- ✅ route: "/doctypes/wms.stock_entry"
- ✅ icon: "package"
- ✅ module: "Inventory"
- ✅ category: "Transactions"
- ✅ order: 3
- ✅ Add
satisfies FrameworkMPlugintype assertion
Stage 4: Create Example Plugin (WMS - implemented in business-m) > 4.3 Create WMS Pages (Optional)
Progress: 11/11 (100%)
Completed:
- ✅ Create
apps/wms/frontend/src/pages/Dashboard.tsx: - ✅ Simple WMS dashboard component
- ✅ Show warehouse stats
- ✅ Export as default
- ✅ Create
apps/wms/frontend/src/pages/Receiving.tsx: - ✅ Receiving workflow page
- ✅ Export as default
- ✅ Add routes to plugin config:
- ✅ Dashboard route:
/wms/dashboard - ✅ Receiving route:
/wms/receiving - ✅ Use lazy imports:
() => import('./pages/Dashboard')
Stage 4: Create Example Plugin (WMS - implemented in business-m) > 4.4 Build WMS Plugin
Progress: 2/2 (100%)
Completed:
- ✅ Run build:
- ✅ Verify
dist/plugin.config.jsexists
Stage 5: Testing and Validation > 5.1 Test Plugin Discovery
Progress: 5/5 (100%)
Completed:
- ✅ Run shell app in dev mode:
- ✅ Check browser console:
- ✅ Verify: "✓ Discovered 1 Framework M plugins" message
- ✅ Verify: "Registered plugin: wms@1.0.0" message
- ✅ No errors during bootstrap
Stage 5: Testing and Validation > 5.2 Test Menu Integration
Progress: 14/14 (100%)
Completed:
- ✅ Open app in browser
- ✅ Check sidebar:
- ✅ Favorites section visible (if any)
- ✅ Recent section visible (if any)
- ✅ Inventory module group visible
- ✅ Masters category under Inventory
- ✅ "Warehouse" item visible
- ✅ "Bin Location" item visible
- ✅ Transactions category under Inventory
- ✅ "Stock Entry" item visible
- ✅ Test menu interactions:
- ✅ Click module group to expand/collapse
- ✅ Click menu items to navigate
- ✅ Verify routes work (even if pages are empty)
Stage 5: Testing and Validation > 5.3 Test Search with Plugin Menu
Progress: 9/9 (100%)
Completed:
- ✅ Type in sidebar search box:
- ✅ Search: "warehouse"
- ✅ Verify "Warehouse" item highlighted
- ✅ Verify breadcrumb shows "Inventory"
- ✅ Search: "stock"
- ✅ Verify "Stock Entry" highlighted
- ✅ Verify breadcrumb shows "Inventory"
- ✅ Clear search
- ✅ Verify menu returns to normal grouped view
Stage 5: Testing and Validation > 5.4 Test Keyboard Navigation
Progress: 6/6 (100%)
Completed:
- ✅ Use Tab to focus sidebar
- ✅ Use Arrow keys to navigate menu
- ✅ Verify focus moves through plugin menu items
- ✅ Verify focus indicator visible
- ✅ Press Enter on focused item
- ✅ Verify navigation works
Stage 5: Testing and Validation > 5.5 Test Mobile Responsive
Progress: 10/10 (100%)
Completed:
- ✅ Open browser DevTools
- ✅ Toggle device toolbar (mobile view)
- ✅ Test mobile drawer:
- ✅ Click hamburger menu button
- ✅ Verify sidebar slides in
- ✅ Verify plugin menu items visible
- ✅ Click backdrop
- ✅ Verify sidebar closes
- ✅ Swipe left on sidebar
- ✅ Verify sidebar closes
Stage 5: Testing and Validation > 5.6 Test Production Build
Progress: 10/10 (100%)
Completed:
- ✅ Build shell app:
- ✅ Check
dist/output: - ✅ Verify
dist/assets/main-[hash].js(shell + framework) - ✅ Verify
dist/assets/wms-[hash].js(WMS plugin chunk) - ✅ Check bundle sizes reasonable
- ✅ Preview production build:
- ✅ Test in browser:
- ✅ Verify app loads
- ✅ Verify plugin menu works
- ✅ Check Network tab for lazy-loaded chunks
Stage 6: Documentation and Polish > 6.1 Update ERP Sidebar RFC Status
Progress: 4/4 (100%)
Completed:
- ✅ Update
docs/rfcs/erp-sidebar-architecture.md: - ✅ Mark Phase 3 "Plugin menu integration" as ✅ COMPLETE
- ✅ Update integration section with actual implementation
- ✅ Add note about plugin discovery process
Stage 6: Documentation and Polish > 6.2 Create Plugin Developer Guide
Progress: 8/8 (100%)
Completed:
- ✅ Create
docs/tutorials/creating-plugins.md: - ✅ Quickstart: Create your first plugin
- ✅ Plugin manifest structure
- ✅ Menu item configuration
- ✅ Route definition
- ✅ Service registration
- ✅ Testing plugins locally
- ✅ Building and deploying plugins
Stage 6: Documentation and Polish > 6.3 Create Migration Guide
Progress: 8/8 (100%)
Completed:
- ✅ Create
docs/guides/migrating-to-plugins.md: - ✅ For single-app users (no action needed)
- ✅ For multi-app users:
- ✅ Install plugin-sdk and vite-plugin
- ✅ Create plugin manifests
- ✅ Update App.tsx to bootstrap registry
- ✅ Update Sidebar to use usePluginMenu
- ✅ Breaking changes (none expected)
Stage 6: Documentation and Polish > 6.4 Update Architecture Documentation
Progress: 4/4 (100%)
Completed:
- ✅ Update
ARCHITECTURE.md: - ✅ Add Frontend Plugin System section
- ✅ Explain relationship to backend plugins
- ✅ Document build-time vs runtime composition
Stage 7: Advanced Features (Optional) > 7.1 Add Plugin Lifecycle Events
Progress: 4/4 (100%)
Completed:
- ✅ Update
PluginRegistry: - ✅ Add event emitter support
- ✅ Emit events:
plugin:registered,plugin:error - ✅ Allow plugins to subscribe to events
Stage 7: Advanced Features (Optional) > 7.2 Add Plugin Hot Reload (Dev Mode)
Progress: 4/4 (100%)
Completed:
- ✅ Update Vite plugin:
- ✅ Watch for plugin config changes
- ✅ Trigger HMR when plugin updates
- ✅ Re-register updated plugin
Stage 7: Advanced Features (Optional) > 7.3 Add Plugin Permissions
Progress: 5/5 (100%)
Completed:
- ✅ Update
MenuIteminterface: - ✅ Add
permissions?: string[]field - ✅ Update
usePluginMenuhook: - ✅ Filter menu items by user permissions
- ✅ Call
authProvider.can()for each item
Stage 7: Advanced Features (Optional) > 7.4 Add Widget System
Progress: 8/8 (100%)
Completed:
- ✅ Create
useWidgets()hook: - ✅ Get widgets from all plugins
- ✅ Filter by permissions
- ✅ Return widget components
- ✅ Update Dashboard page:
- ✅ Render widgets from registry
- ✅ Support widget sizing
- ✅ Support drag-to-reorder
Validation Checklist
Progress: 27/28 (96%)
Completed:
- ✅ SDK Package:
- ✅
@framework-m/plugin-sdkbuilds successfully - ✅ TypeScript types exported correctly
- ✅ No runtime dependencies except React
- ✅ Vite Plugin:
- ✅
@framework-m/vite-pluginbuilds successfully - ✅ Discovers plugins correctly
- ✅ Generates virtual module without errors
- ✅ Shell App:
- ✅ Bootstraps registry without errors
- ✅ Renders plugin menus in sidebar
- ✅ Integrates plugin routes
- ✅ Example Plugin:
- ✅ WMS plugin builds successfully
- ✅ Menu items appear in sidebar
- ✅ Navigation works
- ✅ Shows in correct module/category
- ✅ Developer Experience:
- ✅ Clear error messages
- ✅ TypeScript autocomplete works
- ✅ HMR works in dev mode
- ✅ Production build optimized
- ✅ Documentation:
- ✅ ADR-0008 matches implementation
- ✅ Plugin guide complete
- ✅ Code examples accurate
- ✅ Migration path clear
Pending:
- ⏳ All Phase 4 features still work
Rollback Plan
Progress: 7/7 (100%)
Completed:
- ✅ Remove
@framework-m/vite-pluginfrom vite.config - ✅ Manually import and register plugins
- ✅ Keep using plugin-sdk for types/hooks
- ✅ Remove plugin-sdk dependency from frontend
- ✅ Revert Sidebar to use
useMenuhook - ✅ Remove PluginRegistry bootstrap from App.tsx
- ✅ Plugin packages remain usable as regular workspace packages
Success Criteria
Progress: 19/20 (95%)
Completed:
- ✅
@framework-m/plugin-sdkpackage published to workspace - ✅
@framework-m/vite-pluginpackage published to workspace - ✅ Both packages build without errors
- ✅ TypeScript types work correctly
- ✅ Shell app bootstraps PluginRegistry successfully
- ✅ Sidebar renders plugin menus
- ✅ Plugin routes integrate with React Router
- ✅ All existing sidebar features preserved
- ✅ WMS plugin demonstrates full workflow
- ✅ Menu items appear correctly grouped
- ✅ Navigation works end-to-end
- ✅ Plugin can be built independently
- ✅ No console errors
- ✅ No TypeScript errors
- ✅ Plugin chunks lazy-load correctly
- ✅ Plugin developer guide published
- ✅ Architecture diagrams updated
- ✅ Code examples tested and accurate
- ✅ Migration guide available
Pending:
- ⏳ Production build under 500KB (main chunk)