# Frontend quickstart

> Quickstart: Run the SolidJS app, choose local or remote services, understand app routing, and start Tauri development.

- Repository: macro-inc/macro
- GitHub: https://github.com/macro-inc/macro
- Human docs: https://grok-wiki.com/public/docs/macro-inc-macro-bb988e1a448e
- Complete Markdown: https://grok-wiki.com/public/docs/macro-inc-macro-bb988e1a448e/llms-full.txt

## Source Files

- `js/app/README.md`
- `js/app/package.json`
- `js/app/justfile`
- `js/app/packages/app/index.tsx`
- `js/app/packages/app/component/Root.tsx`
- `js/app/AGENTS.md`

---

---
title: "Frontend quickstart"
description: "Quickstart: Run the SolidJS app, choose local or remote services, understand app routing, and start Tauri development."
---

The Macro frontend is a Bun-managed Vite/SolidJS SPA in `js/app`; the web app serves under `/app`, while Tauri loads the same frontend bundle through native desktop and mobile shells.

## Prerequisites

- Bun
- `just`
- Optional: `nix develop` from the repository root to enter a shell with the expected toolchain
- For Tauri: Rust, Tauri CLI, and platform SDKs for Android or iOS

## Run the web app

<Steps>
  <Step title="Install frontend dependencies">
    ```bash
    cd js/app
    bun i
    ```
  </Step>

  <Step title="Start Vite">
    ```bash
    bun run dev
    ```
  </Step>

  <Step title="Open the app">
    ```text
    http://localhost:3000/app
    ```
  </Step>
</Steps>

`bun run dev` runs `cd packages/app && bun run --bun dev`, which starts Vite with `packages/app/vite.config.ts`. The dev server defaults to port `3000`, binds to `0.0.0.0`, uses strict port mode, and enables HMR over WebSocket.

## Choose remote or local services

In development mode, service endpoints come from `packages/core/constant/servers.ts`.

| Command or environment | Service behavior |
| --- | --- |
| `bun run dev` | Uses remote development Macro services. |
| `VITE_LOCAL_SERVERS=ALL bun run dev` | Uses all registered localhost service URLs. |
| `VITE_LOCAL_SERVERS=document-storage-service,email-service bun run dev` | Uses local URLs for selected services and remote development URLs for the rest. |
| `VITE_LOCAL_SERVERS=document-storage-service:9090 bun run dev` | Uses the selected local service with a port override. |
| `just local` | Starts the app with `VITE_LOCAL_SERVERS=ALL` and `PORT=3000`. |

Useful shortcuts from `js/app/justfile`:

```bash
cd js/app

just local-services
just local
just local-dss
just local-search
just local-email
```

<Warning>
Local backend services require the repository-level local setup. The local stack is documented by `RUNNING_LOCALLY.md`; the frontend command there is `cd js/app && bun i && just local`.
</Warning>

## App routing model

The runtime selects the router by platform:

| Runtime | Router | Base |
| --- | --- | --- |
| Web | `Router` | `/app` |
| Tauri | `HashRouter` | `/` |

The canonical authenticated landing route is:

```text
/component/inbox
```

The root route `/` preloads user info and history, stores known campaign query parameters as short-lived cookies, normalizes short IDs in the URL, then redirects:

| State | Result |
| --- | --- |
| Authenticated | Navigate to `/component/inbox`, preserving query parameters. |
| Unauthenticated | Navigate to `/welcome`, which redirects to `/login`. |
| Native mobile with login cookie and failed user-info query | Show an offline retry fallback. |

The split-layout route decodes URL segments as type/id pairs:

```text
/component/inbox
/<block-or-alias>/<id>
/component/inbox/<block-or-alias>/<id>
```

If no valid pair is present, the layout falls back to the inbox component.

Top-level auth and utility routes include:

| Path | Behavior |
| --- | --- |
| `/login` | Login UI |
| `/signup` | Signup UI |
| `/email-signup-callback` | Email signup callback |
| `/inbox-link-callback` | Email link callback |
| `/login/popup/success` | Broadcasts `login-success` and closes the popup |
| `/team-invite` | Team invite acceptance |
| `*404` | Redirects native mobile to the default route; web navigates to the origin |

## Runtime initialization

`packages/app/index.tsx` performs the browser entrypoint work:

- Imports global CSS and font packages.
- Initializes Lexical markdown support.
- Initializes monochrome icon behavior.
- Sets `document.documentElement.dataset.platform` to `web`, `desktop`, `ios`, or `android`.
- Tracks current input modality as `keyboard`, `mouse`, or `touch`.
- In Tauri, proxies non-localhost `fetch` calls through `@tauri-apps/plugin-http` for native compatibility.
- In development mode, wraps `Root` in a Solid `ErrorBoundary`.
- Outside Vite HMR sessions, lazy-loads observability and listens for `vite:preloadError` to prompt a refresh after deployments.

`Root` mounts global providers for analytics, PostHog, entities, user context, query sync, undo, channels, calls, quick access, search, chat attachments, notifications, split layout routing, onboarding, and toasts.

## Build and preview

```bash
cd js/app

bun run build
bun run preview
```

Build output is emitted from `packages/app` into `packages/app/dist`. Production-style builds use `/app` as the Vite base.

Additional build recipes:

```bash
cd js/app

just build-dev
just build-staging
just build-prod
```

## Local smoke tests

Prefer the repository-level harness for deterministic local E2E:

```bash
just local-e2e
```

That command starts the local service subset with compose overrides, seeds deterministic data, and runs Playwright with `LOCAL_E2E=true`.

For Playwright UI mode:

```bash
just local-e2e-ui
```

## Start Tauri development

The Tauri shell lives under `js/app/tauri` and packages the same `packages/app` frontend.

```bash
cd js/app/tauri

cargo tauri dev
cargo tauri android dev
cargo tauri ios dev
```

Tauri config uses:

| Config key | Value |
| --- | --- |
| `build.devUrl` | `http://localhost:3000` |
| `build.frontendDist` | `../../packages/app/dist` |
| `beforeDevCommand` | `just dev-tauri` from `js/app` |
| `beforeBuildCommand` | `just build-tauri` from `js/app` |

Set `TAURI_DEV_HOST` when a device or emulator needs HMR to connect to a host other than `localhost`.

```bash
TAURI_DEV_HOST=192.168.1.20 cargo tauri android dev
```

## Contributor checks

Common frontend checks from `js/app/AGENTS.md`:

```bash
cd js/app

bun run test
bun run check
bun run lint
bun run format
bun run knip
```

## Next

- Use `RUNNING_LOCALLY.md` for backend stack setup.
- Use `js/app/AGENTS.md` for frontend contribution conventions.
- Use `js/app/tauri/src-tauri/README.md` for native shell development notes.
