Quickstart
Five minutes from sm new to a running app with a freshly scaffolded module.
1. Install the CLI
uv tool install simple_module_cli(Or pipx install simple_module_cli.) That puts sm on your PATH globally.
2. Scaffold an app
sm new myapp --yes
cd myapp--yes accepts the defaults (SQLite, no multi-tenancy, the standard preset: auth, users, permissions, dashboard, settings, feature_flags). The CLI runs uv sync, npm install, and alembic upgrade head for you.
For an interactive run with prompts, drop the --yes. For a preset + extras: sm new myapp --preset standard --with background_tasks,file_storage --yes.
3. Boot it
make devThe API and Vite dev servers start side by side. Visit:
http://localhost:8000— landing pagehttp://localhost:8000/users/login— sign-in screenhttp://localhost:8000/dashboard— the authenticated home (log in first)http://localhost:8000/settings/modules— the admin settings UI (log in first)
4. Create an admin
In another terminal, from inside myapp:
uv run sm-users create-admin --email admin@example.com --password changemeSign in at /users/login and you land on the dashboard.
5. Scaffold a new module
sm create-module orders --dest modules/orders
uv add ./modules/ordersThis generates modules/orders/ with:
pyproject.toml—[project.entry-points.simple_module]→orders.module:OrdersModulepackage.json+tsconfig.json— JS workspace metadata sotsc --noEmitcovers the module's.tsxpages.orders/module.py—ModuleBasesubclass withmeta = ModuleMeta(name="Orders", ...).orders/models.py—OrderSQLModel table withAuditMixin.orders/contracts/schemas.py—OrderCreate,OrderOutDTOs.orders/service.py— CRUD implementation.orders/services.py— module-scoped state container (stored onapp.state.ordersbyregister_settings).orders/deps.py— FastAPI dependencies.orders/endpoints/api.py— REST endpoints at/api/orders.orders/endpoints/views.py— Inertia endpoints at/orders.orders/pages/Browse.tsx,Create.tsx,Edit.tsx— React pages.orders/locales/en.json— translation namespace.tests/test_orders.py— pytest smoke test.
uv add ./modules/orders adds the package to your app's dependencies; on the next uv sync (which uv add also runs) the entry point is registered and the module becomes discoverable on next boot.
6. Generate a migration
uv run alembic revision --autogenerate -m "add orders tables"
make migrateAlembic's autogenerate picks up the new orders schema (Postgres) or the orders_* tables (SQLite) and writes migrations/versions/XXXX_add_orders_tables.py. Add branch_labels = ("orders",) to that revision so you can later alembic downgrade orders@base to roll the module back in isolation.
7. Hit the module
Restart make dev (modules are discovered at boot). Then:
curl http://localhost:8000/api/orders
# → [] (200)Visit http://localhost:8000/orders — you see the Browse page with an empty list and a "Create" button. The sidebar menu now includes an Orders entry (registered via register_menu_items).
8. Run the tests
uv run pytestSingle file:
uv run pytest modules/orders/tests/test_orders.py -vWhat just happened
- Discovery — the
simple_moduleentry point pointed Python's installer atorders.module:OrdersModule.discover_modules()loaded it, topologically sorted against every other installed module, and invokedregister_*hooks in order. - Routes —
register_routes(api_router, view_router)attached theordersrouters at/api/ordersand/orders. - Menu —
register_menu_itemspushed an entry ontoMenuRegistry; the Inertia shared-props middleware serialized it intomenus.sidebarfor every authenticated request. - Frontend —
modules.generated.ts(rebuilt bymake gen-pages) maps"Orders/Browse"tomodules/orders/orders/pages/Browse.tsx. Vite resolves and HMR-watches that file. - Database —
create_module_base("orders")namespaced theOrdertable under a Postgresordersschema (or theorders_ordertable name under SQLite).
Next steps
- Your first module — extend the scaffold into real domain logic, end-to-end.
- Project structure — the directory tour, so you know where everything lives.
- Framework overview — what happens between
make devand the first HTTP request. - Bundled modules — what's already in the box (auth, users, permissions, settings, …).