# Architecture ``` ┌──────────────────────────────────────────────────────┐ │ Browser (React SPA - client/) │ │ │ │ Environments Credentials Snippets │ │ Sessions Scenarios Runs │ └─────────────────────────────┬────────────────────────┘ │ HTTP REST (:13000) │ MCP client (AI agent / VS Code Copilot) │ HTTP /mcp (Streamable MCP) ▼ ┌──────────────────────────────────────────────────────┐ │ NestJS app (server/src/) │ │ │ │ McpService all MCP tools │ │ SessionService session persistence │ │ SessionContextService live browser contexts │ │ EnvironmentService environment CRUD + import │ │ CredentialService credential CRUD + import │ │ SnippetService snippet CRUD + import │ │ BrowserService ad-hoc open/exec │ │ CodeExecutorService sandboxed JS runtime │ │ ScenarioService scenarios/steps/runs CRUD │ │ ScenarioSchedulerService @Interval(1 s) run worker │ └───────────────────────┬──────────────────────────────┘ │ better-sqlite3 (TypeORM) ▼ data/sessions.db ``` - **McpService** registers MCP tools and delegates to session, environment, browser, and scenario services. - **SessionService** persists session records in SQLite. **SessionContextService** manages live Playwright contexts for open sessions. - **EnvironmentService**, **CredentialService**, and **SnippetService** provide CRUD plus import/export upserts. - **BrowserService** handles stateless ad-hoc automation (`/open`, `/exec`) and session-aware browsing. - **CodeExecutorService** validates and executes user JS with `page`, `context`, and helper APIs. - **ScenarioService** manages scenarios, steps, credential aliases, runs, logs, and scenario import/export. - **ScenarioSchedulerService** polls pending runs every second and executes step runs to completion. ## Client (`client/`) A React 19 + TypeScript SPA served separately by Vite during development. In Docker Compose the same build artefacts are served statically alongside the API. The client calls the server REST endpoints directly — there is no separate BFF layer. Routing uses HashRouter so the Vite proxy and server-side routes are never ambiguous. The sidebar footer contains the theme switcher and the app version (injected from the workspace root `package.json` at build time). See [development.md](development.md) for the full client tech stack and directory layout.