- 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
275 lines
6.5 KiB
Markdown
275 lines
6.5 KiB
Markdown
# 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`
|
|
|
|
```javascript
|
|
// 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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
simplenote auth status
|
|
```
|
|
→ `GET /auth/verify` → muestra si token es válido.
|
|
|
|
## 4. Comandos CLI Detallados
|
|
|
|
### 4.1 Documents
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# Listar todos los tags
|
|
simplenote tag list
|
|
|
|
# Ver docs con tag
|
|
simplenote tag docs backend
|
|
```
|
|
|
|
### 4.4 Auth
|
|
|
|
```bash
|
|
# Login con token
|
|
simplenote auth login snk_xxxxx
|
|
|
|
# Verificar status
|
|
simplenote auth status
|
|
```
|
|
|
|
## 5. Manejo de Errores
|
|
|
|
```javascript
|
|
// 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
|
|
|
|
```javascript
|
|
// ~/.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:
|
|
```bash
|
|
simplenote --api-url http://custom:3000/api/v1 doc list
|
|
```
|
|
|
|
## 7. Dependencias CLI
|
|
|
|
```json
|
|
// 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
|
|
|
|
```bash
|
|
$ 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
|
|
```
|