# 📐 Plan: n8n Custom Node for Mevspace API

> Built following the [`n8n-node-builder.skill.md`](../n8n-node-builder.skill.md:1) skill.
> Sources: [`dedicateds.json`](../dedicateds.json:1), [`startup-scripts.json`](../startup-scripts.json:1), [`templates.json`](../templates.json:1)

---

## 1. API Analysis

| Item     | Value                                                                    |
| -------- | ------------------------------------------------------------------------ |
| Base URL | `https://api.mevspace.com`                                               |
| Auth     | Query-string param `access-token=<token>` (confirmed from real examples) |
| Format   | JSON (`application/json`)                                                |
| Swagger  | v1.2                                                                     |

### Endpoints to cover

**Dedicated** (`/dedicateds`)
| Operation | Method | Path | Extra params |
|---|---|---|---|
| Get All | GET | `/dedicateds` | — |
| Get Details | GET | `/dedicateds/{hostname}` | `hostname` (path, required) |
| Order KVM | POST | `/dedicateds/{hostname}/order-kvm` | `client_ip` (string, opt), `whitelabel` (boolean, opt) |
| Reinstall | POST | `/dedicateds/{hostname}/reinstall` | `template_id` (int, opt), `raid_value` (string, opt, default `raid1`), `startup_script_id` (int, opt) |
| Restart | POST | `/dedicateds/{hostname}/restart` | — |
| Start | POST | `/dedicateds/{hostname}/start` | — |
| Stop | POST | `/dedicateds/{hostname}/stop` | — |

**Startup Script** (`/startup-scripts`)
| Operation | Method | Path |
|---|---|---|
| Get All | GET | `/startup-scripts` |

**Template** (`/templates`)
| Operation | Method | Path | Extra params |
|---|---|---|---|
| Get All | GET | `/templates` | `type` (query, opt: `dedicated` / `vps` / `vps_cloud`, default `dedicated`) |

---

## 2. Architecture Decision

- **Style:** Declarative (n8n-recommended for HTTP APIs; routing config, no `execute()`).
- **Structure:** Single node `Mevspace` with a `resource` dropdown → `operation` dropdown, because all 3 APIs share the same auth + base URL.
- **Auth:** Query-string `access-token` via `authenticate: { type: 'generic', properties: { qs: { 'access-token': '={{$credentials.accessToken}}' } } }`.

```mermaid
flowchart LR
    A[n8n Workflow] --> B[Mevspace Node]
    B --> C{resource}
    C -->|dedicated| D[Dedicated Ops]
    C -->|startupScript| E[Startup Script Ops]
    C -->|template| F[Template Ops]
    D --> D1[Get All]
    D --> D2[Get Details]
    D --> D3[Order KVM]
    D --> D4[Reinstall]
    D --> D5[Restart]
    D --> D6[Start]
    D --> D7[Stop]
    E --> E1[Get All]
    F --> F1[Get All + type filter]
    B --> G[MevspaceApi Credentials]
    G -->|access-token query param| H[api.mevspace.com]
```

---

## 3. Project Structure

```
n8n-nodes-mevspace/
├── package.json
├── tsconfig.json
├── eslint.config.mjs
├── credentials/
│   └── MevspaceApi.credentials.ts
├── nodes/
│   └── Mevspace/
│       ├── Mevspace.node.ts
│       └── mevspace.svg
├── icons/
│   ├── mevspace-light.svg
│   └── mevspace-dark.svg
└── dist/                      (generated, never edit)
```

---

## 4. File-by-File Build Steps

### Step 1 — `package.json`

- `name`: `n8n-nodes-mevspace`
- `n8n.n8nNodesApiVersion`: 1
- `n8n.credentials`: `["dist/credentials/MevspaceApi.credentials.js"]`
- `n8n.nodes`: `["dist/nodes/Mevspace/Mevspace.node.js"]`
- `keywords`: `["n8n-community-node-package"]`
- scripts: `build`, `dev`, `lint`, `lint:fix` via `@n8n/node-cli`
- devDependency: `@n8n/node-cli`

### Step 2 — `tsconfig.json` + `eslint.config.mjs`

- Standard n8n starter TS config (target ES2017, `outDir: dist`, strict).
- ESLint flat config from starter.

### Step 3 — `credentials/MevspaceApi.credentials.ts`

- `name`: `mevspaceApi`
- `displayName`: `Mevspace API`
- properties: `accessToken` (string, `typeOptions: { password: true }`, required)
- `authenticate`: generic → `qs: { 'access-token': '={{$credentials.accessToken}}' }`
- `test`: GET `https://api.mevspace.com/dedicateds` (expect 200)

### Step 4 — `nodes/Mevspace/Mevspace.node.ts` (declarative)

- `displayName`: `Mevspace`
- `name`: `mevspace`
- `group`: `['transform']`, `usableAsTool: true`
- `credentials`: `[{ name: 'mevspaceApi', required: true }]`
- `requestDefaults`: `baseURL: 'https://api.mevspace.com'`, JSON headers
- `properties`:
  - `resource` (options: Dedicated / Startup Script / Template, `noDataExpression: true`)
  - `operation` (options, `noDataExpression: true`, `displayOptions` per resource)
  - `hostname` (string, required, shown for dedicated get/orderKvm/reinstall/restart/start/stop)
  - Dedicated Order KVM: `client_ip` (string), `whitelabel` (boolean)
  - Dedicated Reinstall: `template_id` (number), `raid_value` (options: raid0/raid1/raid5/raid10, default raid1), `startup_script_id` (number)
  - Template Get All: `type` (options: dedicated/vps/vps_cloud, default dedicated)
- Each operation carries `routing.request` with method + url (using `={{$parameter.hostname}}` expressions) + body where needed.

### Step 5 — Icons

- Create `mevspace-light.svg` + `mevspace-dark.svg` in `icons/`.
- Reference in node: `icon: { light: 'file:mevspace-light.svg', dark: 'file:mevspace-dark.svg' }`.
- Reference in credentials similarly.

### Step 6 — Build & Lint

- `npm install`
- `npm run build` → verify `dist/` populated
- `npm run lint` → zero errors

### Step 7 — Test in n8n

- `npm link` → link in `~/.n8n/custom` → `n8n start`
- Test each resource/operation against real API.

---

## 5. Pre-publish Checklist (from skill)

- [ ] package name starts with `n8n-nodes-`
- [ ] `n8n.nodes` + `n8n.credentials` registered
- [ ] `keywords: ["n8n-community-node-package"]`
- [ ] light + dark icons
- [ ] `usableAsTool: true`
- [ ] `typeOptions: { password: true }` on token field
- [ ] `test` on credentials
- [ ] `requestDefaults.baseURL` set
- [ ] `npm run lint` clean
- [ ] `npm run build` succeeds
