7.3 KiB
GovOPlaN Module Architecture
GovOPlaN is structured as a core platform runner plus installable feature modules. Core owns the runtime shell and cross-cutting primitives. Modules own feature behavior and contribute backend routes, database metadata, permissions, WebUI routes, and navigation metadata.
Core Responsibilities
Core owns:
- the server entry point and platform configuration
- module discovery, registry validation, route aggregation, and platform metadata APIs
- database engine/session primitives and migration orchestration
- auth, tenants, RBAC, governance, audit, CSRF/API helpers, and secret helpers
- shared WebUI shell components such as
AppShell,IconRail,DataGrid,ExplorerTree,MessageDisplayPanel, dialogs, loading frames, access boundaries, and form primitives - centralized mapping from serializable icon names to renderable frontend icons
Core must not import module feature pages or module business logic directly. It should interact with modules through manifests, entry points, metadata, and route contributions.
Module Responsibilities
A module owns one bounded feature area. A module can include both backend and WebUI code in the same repository so feature behavior and frontend integration evolve together.
A module owns:
- backend routers and feature services
- SQLAlchemy models for module-owned tables
- module migrations and migration metadata
- module permissions and role templates
- module-specific schemas, policies, and domain rules
- WebUI pages, feature-specific components, API clients, route contributions, and navigation metadata
A module should not own generic platform UI. If a component is useful outside one module, move it to @govoplan/core-webui and parameterize it there before reusing it.
Backend Contract
Backend modules register through the govoplan.modules entry point and expose a ModuleManifest.
Example:
[project.entry-points."govoplan.modules"]
files = "govoplan_files.backend.manifest:get_manifest"
The manifest should declare:
id,name,version- required
dependenciesandoptional_dependencies - permissions and role templates
- router factory
- migration metadata and script location
- frontend package metadata
- navigation metadata using serializable icon names
Backend nav metadata must use icon-name strings, not frontend components:
NavItem(
path="/files",
label="Files",
icon="folder",
required_any=("files:file:read",),
order=40,
)
Database And Migrations
Core owns the database/session lifecycle. Modules access the database through core session dependencies and register their models/migrations through their manifest.
Rules:
- Do not create independent database engines in modules.
- Use core session dependencies, base metadata, and migration orchestration.
- Keep module-owned tables and migrations in the module repository.
- Keep cross-module foreign-key assumptions explicit and conservative.
- Register module metadata in
MigrationSpecso core can discover it.
WebUI Contract
A WebUI module exports a PlatformWebModule from its package. The object contributes local/fallback metadata and route render functions.
Example:
export const filesModule: PlatformWebModule = {
id: "files",
label: "Files",
version: "1.0.0",
dependencies: ["access"],
navItems: [
{ to: "/files", label: "Files", iconName: "folder", anyOf: ["files:file:read"], order: 40 }
],
routes: [
{ path: "/files", anyOf: ["files:file:read"], order: 40, render: ({ settings, auth }) => createElement(FilesPage, { settings, auth }) }
]
};
WebUI modules receive only the core route context:
settingsauth
A module should call its own API client and module-owned backend routes. Shared API helpers should live in core only when they are truly platform-level concerns.
Icon Rules
Icons are resolved centrally by core.
Modules must provide icon names with iconName in frontend nav contributions and icon in backend manifest metadata. Modules must not import Lucide icons for navigation metadata.
Current core icon names include:
activitycampaigndashboardfilefilesfolderformmailreportsusers
If a module needs a new navigation icon, add the name-to-component mapping in core first, then use the name in backend and frontend metadata.
Shared Component Rules
Use this rule of thumb:
- If it is platform-level or likely reusable by more than one module, define it in
@govoplan/core-webuiwith parameters. - If it is feature-specific and only meaningful inside one bounded module, keep it in that module.
- Modules must not import components from another feature module.
- If one module needs a component currently owned by another module, promote a generic version into core and replace the old usage with the core component.
Examples:
ExplorerTreeis core because files, mailboxes, and future modules can all render hierarchical navigation.MessageDisplayPanelis core because mail, campaign sending, and later audit/review surfaces can display message-like content.MailProfileManagementremains in the mail module because it is specific to mail transport policies and profiles.
Cross-Module Integration
A module can declare required dependencies and optional dependencies. Optional behavior should be enabled by module presence and permissions, not by importing another module's WebUI internals.
Rules:
- Use core module metadata to check whether another module is installed.
- Use backend APIs/events/service contracts for runtime cooperation.
- Keep UI integration declarative where possible: nav items, route contributions, context actions, and explicit extension points.
- Avoid direct imports from one feature module into another feature module unless the imported package is a published API contract designed for that purpose. UI components should be promoted to core instead.
Build And Verification
Backend verification from core:
cd /mnt/DATA/git/govoplan-core
./.venv/bin/python -m compileall src/govoplan_core ../govoplan-files/src/govoplan_files ../govoplan-mail/src/govoplan_mail ../govoplan-campaign/src/govoplan_campaign
Core WebUI host verification:
cd /mnt/DATA/git/govoplan-core/webui
PATH=/home/zemion/.nvm/versions/node/v22.22.3/bin:$PATH /home/zemion/.nvm/versions/node/v22.22.3/bin/npm run build
Wrapper WebUI verification, while the legacy wrapper still exists:
cd /mnt/DATA/git/multi-seal-mail-webui
PATH=/home/zemion/.nvm/versions/node/v22.22.3/bin:$PATH /home/zemion/.nvm/versions/node/v22.22.3/bin/npm run build
Clean generated dist, .vite, and source-tree __pycache__ artifacts after verification unless they are intentionally part of a release artifact.
Release Dependency Rules
Local development may use editable Python installs and local WebUI file: dependencies so sibling module changes reload quickly. Release builds must use tagged git refs or published packages instead. Core provides:
requirements-dev.txtfor local editable backend installsrequirements-release.txtfor tagged backend module installswebui/package.release.jsonfor tagged WebUI module installs
Module repositories include root-level npm manifests for git installs. When cutting a release, update the Python versions, WebUI versions, release dependency refs, and repository tags together.