modules/<kebab-name>/ like any other module, but its <name>.yml declares type: "design". That single flag changes how the framework treats it: a design module is a front-end asset library, not a participant in the backend request pipeline.
Why a design module
- One source of UI truth. Buttons, inputs, dialogs, tables, and the rest live in a single module, so every SPA pulls from the same components, icons, and fonts instead of redefining them per screen.
- Front-end, not backend. A design module carries only the React layer. It is never registered into
AppModuleorSharedModule, because it has nothing to do with handling HTTP or WebSocket requests. - Sourced from a skeleton. Its
src/is not a blank local template —ooneex design:createpulls the design system from the upstreamskeleton-designrepository, so you start with a complete, production-ready set of primitives. - Organized by asset kind. Components, hooks, icons, fonts, styles, and utils each get their own folder, so finding and extending a primitive is predictable.
- Consumed by SPAs. The design module is the UI library your SPA imports from — see SPA for how the two connect.
How it differs from other modules
A design module is still a module, but it plays a different role than a regular Module or a microservice.| Concern | Design module | Regular module / microservice |
|---|---|---|
| Contents | React UI assets: components, hooks, icons, fonts, styles, utils | Backend logic: controllers, services, repositories, middleware |
type in <name>.yml | "design" | app, shared, or a microservice type |
| Backend registration | Never registered into AppModule / SharedModule | Wired into the backend request pipeline |
Source of src/ | Pulled from the skeleton-design repository | Scaffolded from local templates |
| Who consumes it | Imported by a SPA as a UI library | Invoked by the request pipeline |
How it works
ooneex design:create scaffolds a base module, marks it type: "design", then pulls the design source from the skeleton-design GitHub repository and installs that design’s dependencies into your project. The result is a module whose src/ mirrors the skeleton — a full design system you can use as-is or extend.
| Folder | What it holds |
|---|---|
components/ | React .tsx UI primitives (~50): accordion, avatar, badge, button, card, dialog, form, input, select, table, tabs, tooltip, and more. |
hooks/ | Reusable React hooks shared across components and screens. |
icons/ | SVG icons in fill and outline variants and multiple sizes. |
fonts/ | Bundled web fonts (Space Grotesk) with their @font-face CSS. |
styles/ | Global stylesheets applied across the design system. |
utils/ | Front-end helpers such as cn for composing class names. |
type is "design", the module is treated as a front-end asset library. Only modules with type: "design" can be removed with ooneex design:remove — the app and shared modules are protected and cannot be deleted this way.
Where to go next
- Structure — the folder layout in detail and what each asset kind contains.
- Usage — importing components, hooks, icons, fonts, and utils into a SPA.
- Create —
ooneex design:createand how the skeleton is pulled. - Remove —
ooneex design:removeand the protection onapp/shared. - Module — how regular backend modules differ from a design module.
- SPA — the Single Page App that consumes the design system.