> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ooneex.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a spa

> Scaffold a standalone Vite single-page app module wired to a design module, with a free dev port and the spa dependencies installed.

A spa module is a standalone Vite single-page application that lives inside your project but runs on its own dev server — it is **not** part of the backend. The `spa:create` generator pulls the spa source from the upstream skeleton repository, marks the module as a `spa` in its yml config, links it to a [design module](/design-system/overview), assigns a free dev port, and installs the spa dependencies. After it finishes you have a working frontend you can start with one command.

If you are new to spa modules, read the [spa overview](/spa/overview) first. This page is the friendly walkthrough; for the terse flag reference see [spa:create](/cli/commands/spa-create).

## CLI command

```bash theme={null}
ooneex spa:create [options]
```

Run it with no flags and it prompts for everything it needs — the spa name and the design module.

### Examples

```bash theme={null}
# Interactive: prompts for the spa name and design module
ooneex spa:create

# Provide the name as a flag
ooneex spa:create --name=dashboard

# Link the spa to a design module
ooneex spa:create --name=dashboard --design=ui
```

### Options

| Option     | Description                                                                                                         | Default                   |
| ---------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------- |
| `--name`   | Spa name. Normalized to PascalCase with any trailing `Module` stripped; the module folder uses its kebab-case form. | Prompted if omitted       |
| `--design` | Design module the spa uses. An existing design can be chosen interactively, or a new name is scaffolded.            | Prompted if omitted       |
| `--cwd`    | Project directory the spa is created in.                                                                            | Current working directory |
| `--silent` | Suppress prompts, spinners, and output.                                                                             | `false`                   |

<Note>
  The command clones the spa source and installs packages, so it needs **`git`**
  and **network access**. If either is unavailable the create will not complete.
</Note>

## The design link

Every spa composes a **design module** — a `type: "design"` module that holds the shared UI building blocks. During create you choose which one:

* **Pick an existing design.** If your project already has `type: "design"` modules, you choose one interactively (or pass it with `--design`).
* **Name a new one.** Give a name that does not exist yet and the generator scaffolds it for you with [`design:create`](/design-system/overview).

The choice is recorded as `design:` in the spa's yml config, so the link between the spa and its design module is explicit and persistent.

## What happens

When you run `spa:create`, the generator works through these steps in order:

<Steps>
  <Step title="Scaffold the base module">
    A base module is scaffolded under `modules/<kebab-name>/`, using the kebab-case form of the name you gave.
  </Step>

  <Step title="Detach it from the backend">
    A spa is a frontend, not part of the backend — so it is un-registered from `AppModule` and `SharedModule`, and its root `tsconfig` path alias is removed.
  </Step>

  <Step title="Remove the backend module class">
    The scaffolded `<Pascal>Module.ts` and its spec file are deleted; a spa does not ship a backend module class.
  </Step>

  <Step title="Mark it as a spa">
    The module yml is marked `type: "spa"` and records `design: "<kebab>"` for the design module you chose.
  </Step>

  <Step title="Add Vite scripts and assign a port">
    Vite `dev`, `build`, and `preview` scripts are added to the module `package.json`. The `dev` script gets a free dev port — `5000` by default, or the next free port if `5000` is taken (the generator scans other modules' `--port` usage to find a free one).
  </Step>

  <Step title="Clone the spa source">
    The upstream [`skeleton-spa`](https://github.com/ooneex/skeleton-spa.git) repo is cloned (shallow) into the module's `src/`, and every `shared/` sub-layer is ensured to exist via `.gitkeep`: `assets`, `components`, `hooks`, `layouts`, `services`, `store`, `styles`, `types`, and `utils`.
  </Step>

  <Step title="Install dependencies">
    The spa's `dependencies` and `devDependencies` are installed into the project.
  </Step>

  <Step title="Scaffold the design module if needed">
    If the design module you chose does not exist yet, it is scaffolded via `design:create`.
  </Step>
</Steps>

## What you get

You end up with a self-contained spa module under `modules/<kebab-name>/` — its own Vite setup, a `src/` populated from the skeleton, the full `shared/` layer in place, a dedicated dev port, and a recorded link to its design module. See the [spa structure](/spa/structure) for a tour of the generated layout.

## Start and stop the spa

Run the spa from the project root with `app:start`. The `--spa` flag narrows the run to spa modules, so only the dev servers come up:

```bash theme={null}
# Start every spa module on its assigned port
ooneex app:start --spa

# Start just one spa by name
ooneex app:start --spa=dashboard

# Run the spa alongside the api modules it talks to
ooneex app:start --api --spa
```

Vite serves the spa on the port assigned at create time. The spa is a frontend dev server, not a Docker service, so to stop it you interrupt the running process with <kbd>Ctrl</kbd>+<kbd>C</kbd>.

<Tip>
  Running `ooneex app:start` with no flag starts the spa together with every
  `api` and `microservice` module — handy when the spa needs a live backend.
</Tip>

## Next steps

<CardGroup cols={2}>
  <Card title="Run the dev server" icon={<Icon icon="play" size={16} />}>
    Start the spa from the project root with `ooneex app:start --spa` — Vite
    serves it on the assigned port.
  </Card>

  <Card title="Add features" icon={<Icon icon="puzzle-piece" size={16} />} href="/spa/features">
    Build out pages and flows with
    [`spa:feature:create`](/cli/commands/spa-feature-create).
  </Card>
</CardGroup>

To take the spa back out, see [remove a spa](/spa/remove).

## Use with Claude and Codex

The generator ships a matching `spa:create` skill. It runs the scaffold and then guides your AI agent through what comes next — choosing or naming the design module, starting the dev server, and adding the first features. Initialize the skills once for your agent:

<Tabs>
  <Tab title="Claude">
    ```bash theme={null}
    ooneex claude:init
    ```

    Then ask Claude in natural language — it maps the request to the generator and runs it:

    ```text Prompt icon="terminal" wrap theme={null}
    Create a spa called dashboard that uses the ui design module.
    ```
  </Tab>

  <Tab title="Codex">
    ```bash theme={null}
    ooneex codex:init
    ```

    Then ask Codex in natural language — it maps the request to the generator and runs it:

    ```text Prompt icon="terminal" wrap theme={null}
    Create a spa called dashboard that uses the ui design module.
    ```
  </Tab>
</Tabs>

For example, the prompt above maps to `spa:create --name=dashboard --design=ui`.

For the full command reference, see [spa:create](/cli/commands/spa-create).
