Files
simplenote-web/cli-protocol.md
Bulma 90e4dd0807 feat(architecture): add complete technical architecture for SimpleNote
- ARCHITECTURE.md: main architecture document
- api-spec.yaml: full OpenAPI 3.0 spec
- folder-structure.md: detailed folder layout
- data-format.md: JSON schemas for .meta.json, .library.json, .tag-index.json
- env-template.md: environment variables documentation
- cli-protocol.md: CLI-to-API communication protocol
2026-03-28 03:18:25 +00:00

6.5 KiB

SimpleNote CLI - Protocolo de Comunicación

1. Overview

El CLI (simplenote-cli) se comunica con el servidor (simplenote-web) exclusivamente vía HTTP REST usando el API documentado en api-spec.yaml.

No hay comunicación peer-to-peer ni protocolos binarios. Todo es JSON sobre HTTP.

┌──────────────────┐      HTTP/REST       ┌─────────────────┐
│  simplenote-cli  │ ◄──────────────────► │  simplenote-web │
│  (Commander.js)  │   Bearer token auth   │  (Express.js)   │
└──────────────────┘                      └─────────────────┘
         │                                        │
         └──── ~/.config/simplenote/config.json ──┘

2. Cliente HTTP

2.1 Clase SimpleNoteClient

// src/api/client.js
const axios = require('axios');

class SimpleNoteClient {
  constructor({ baseUrl, token }) {
    this.baseUrl = baseUrl.replace(/\/$/, ''); // strip trailing slash
    this.token = token;
    this._axios = axios.create({
      baseURL: this.baseUrl,
      timeout: 10000,
      headers: { 'Content-Type': 'application/json' }
    });
  }

  _authHeaders() {
    return this.token ? { Authorization: `Bearer ${this.token}` } : {};
  }

  async _request(method, path, data) {
    try {
      const res = await this._axios.request({
        method,
        url: path,
        data,
        headers: this._authHeaders()
      });
      return res.data;
    } catch (err) {
      if (err.response) {
        const msg = err.response.data?.error || err.message;
        throw new Error(`API Error ${err.response.status}: ${msg}`);
      }
      throw err;
    }
  }

  // Auth
  async verifyToken() { return this._request('GET', '/auth/verify'); }

  // Documents
  async listDocuments(params) {
    const qs = new URLSearchParams(params).toString();
    return this._request('GET', `/documents${qs ? '?' + qs : ''}`);
  }
  async getDocument(id) { return this._request('GET', `/documents/${id}`); }
  async createDocument(data) { return this._request('POST', '/documents', data); }
  async updateDocument(id, data) { return this._request('PUT', `/documents/${id}`, data); }
  async deleteDocument(id) { return this._request('DELETE', `/documents/${id}`); }
  async exportDocument(id) { return this._request('GET', `/documents/${id}/export`); }

  // Documents > Tags
  async addTagsToDocument(id, tags) {
    return this._request('POST', `/documents/${id}/tags`, { tags });
  }

  // Libraries
  async listLibraries() { return this._request('GET', '/libraries'); }
  async getLibrary(id) { return this._request('GET', `/libraries/${id}`); }
  async createLibrary(data) { return this._request('POST', '/libraries', data); }
  async getLibraryTree(id) { return this._request('GET', `/libraries/${id}/tree`); }
  async listLibraryDocuments(id) {
    return this._request('GET', `/libraries/${id}/documents`);
  }

  // Tags
  async listTags() { return this._request('GET', '/tags'); }
  async getTagDocuments(tag) { return this._request('GET', `/tags/${tag}`); }
}

3. Flujo de Auth

3.1 Login Inicial

simplenote auth login snk_a1b2c3d4e5f6...

Flujo:

  1. CLI guarda token en ~/.config/simplenote/config.json
  2. CLI llama GET /api/v1/auth/verify para validar
  3. Si 200 → login exitoso. Si 401 → token inválido.

3.2 Requests Subsecuentes

Todas las requests incluyen:

Authorization: Bearer <token>

3.3 Verificación de Status

simplenote auth status

GET /auth/verify → muestra si token es válido.

4. Comandos CLI Detallados

4.1 Documents

# Listar con filtros
simplenote doc list --tag backend --library 550e8400... --type requirement
simplenote doc list --tag api --limit 10

# Ver documento
simplenote doc get 770e8400-e29b-41d4-a716-446655440002

# Crear
simplenote doc create \
  --title "API Authentication" \
  --content "# API Authentication\n\n..." \
  --tags "backend,api,auth" \
  --type requirement \
  --priority high \
  --library 550e8400-e29b-41d4-a716-446655440000

# Actualizar
simplenote doc update 770e8400... --title "Nuevo título" --content "..."
simplenote doc update 770e8400... --status approved

# Eliminar
simplenote doc delete 770e8400...

# Exportar como markdown
simplenote doc export 770e8400...

# Agregar tags
simplenote doc add-tags 770e8400... --tags "new-tag,another"

4.2 Libraries

# Listar librerías raíz
simplenote lib list

# Listar con padre
simplenote lib list --parent 550e8400...

# Ver contenido
simplenote lib get 550e8400...

# Crear
simplenote lib create --name "API Specs"
simplenote lib create --name "Sub Librería" --parent 550e8400...

# Ver árbol completo
simplenote lib tree 550e8400...

4.3 Tags

# Listar todos los tags
simplenote tag list

# Ver docs con tag
simplenote tag docs backend

4.4 Auth

# Login con token
simplenote auth login snk_xxxxx

# Verificar status
simplenote auth status

5. Manejo de Errores

// Errores de API se transforman en mensajes claros
try {
  await client.getDocument('non-existent-id');
} catch (err) {
  console.error(err.message);
  // "API Error 404: Document not found"
}

Códigos de error CLI:

  • 1 — Error general (network, parse, etc)
  • 2 — Token inválido / auth fallida
  • 3 — Recurso no encontrado (404)
  • 4 — Validación de input

6. Configuración de Conexión

// ~/.config/simplenote/config.json
{
  "apiUrl": "http://localhost:3000/api/v1",
  "token": "snk_xxxxx",
  "activeLibrary": "550e8400-e29b-41d4-a716-446655440000"
}

Override por línea de comandos:

simplenote --api-url http://custom:3000/api/v1 doc list

7. Dependencias CLI

// package.json
{
  "dependencies": {
    "commander": "^11.1.0",
    "axios": "^1.6.0",
    "chalk": "^5.3.0",
    "inquirer": "^9.2.0"
  }
}

8. Ejemplo de Sesión Completa

$ simplenote auth login snk_a1b2c3d4e5f6
✓ Token verified. Logged in.

$ simplenote lib list
[
  { "id": "550e8400...", "name": "Backend Requirements", "documentCount": 5 }
]

$ simplenote doc create \
  --title "Token Auth" \
  --tags "backend,auth" \
  --type requirement \
  --library 550e8400...
{
  "id": "770e8400...",
  "title": "Token Auth",
  "tags": ["backend", "auth"],
  ...
}

$ simplenote tag docs backend
[
  { "id": "770e8400...", "title": "Token Auth", ... }
]

$ simplenote doc get 770e8400...
# Muestra documento formateado con content + metadata