claude-agent-framework 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -0
- package/bin/claude-framework +3 -0
- package/framework/agents/design-lead.md +240 -0
- package/framework/agents/product-owner.md +179 -0
- package/framework/agents/tech-lead.md +226 -0
- package/framework/commands/ayuda.md +127 -0
- package/framework/commands/a/303/261adir.md +98 -0
- package/framework/commands/backup.md +397 -0
- package/framework/commands/cambiar.md +110 -0
- package/framework/commands/cloud.md +457 -0
- package/framework/commands/code.md +142 -0
- package/framework/commands/debug.md +334 -0
- package/framework/commands/deploy.md +383 -0
- package/framework/commands/deshacer.md +120 -0
- package/framework/commands/estado.md +218 -0
- package/framework/commands/explica.md +227 -0
- package/framework/commands/feature.md +120 -0
- package/framework/commands/git.md +427 -0
- package/framework/commands/historial.md +202 -0
- package/framework/commands/learn.md +408 -0
- package/framework/commands/movil.md +245 -0
- package/framework/commands/nuevo.md +118 -0
- package/framework/commands/plan.md +134 -0
- package/framework/commands/prd.md +113 -0
- package/framework/commands/probar.md +148 -0
- package/framework/commands/revisar.md +208 -0
- package/framework/commands/seeds.md +230 -0
- package/framework/commands/seguridad.md +226 -0
- package/framework/commands/tasks.md +157 -0
- package/framework/skills/architecture/algorithms.md +970 -0
- package/framework/skills/architecture/clean-code.md +1080 -0
- package/framework/skills/architecture/design-patterns.md +1984 -0
- package/framework/skills/architecture/functional-programming.md +972 -0
- package/framework/skills/architecture/solid.md +991 -0
- package/framework/skills/cloud/cloud-aws.md +848 -0
- package/framework/skills/cloud/cloud-azure.md +931 -0
- package/framework/skills/cloud/cloud-gcp.md +848 -0
- package/framework/skills/cloud/message-queues.md +1229 -0
- package/framework/skills/core/accessibility.md +401 -0
- package/framework/skills/core/api.md +474 -0
- package/framework/skills/core/authentication.md +306 -0
- package/framework/skills/core/authorization.md +388 -0
- package/framework/skills/core/background-jobs.md +341 -0
- package/framework/skills/core/caching.md +473 -0
- package/framework/skills/core/code-review.md +341 -0
- package/framework/skills/core/controllers.md +290 -0
- package/framework/skills/core/cua.md +285 -0
- package/framework/skills/core/documentation.md +472 -0
- package/framework/skills/core/file-uploads.md +351 -0
- package/framework/skills/core/hotwire-native.md +296 -0
- package/framework/skills/core/hotwire.md +278 -0
- package/framework/skills/core/i18n.md +334 -0
- package/framework/skills/core/imports-exports.md +750 -0
- package/framework/skills/core/infrastructure.md +337 -0
- package/framework/skills/core/models.md +228 -0
- package/framework/skills/core/notifications.md +672 -0
- package/framework/skills/core/payments.md +581 -0
- package/framework/skills/core/performance.md +361 -0
- package/framework/skills/core/rails-scaffold.md +131 -0
- package/framework/skills/core/search.md +518 -0
- package/framework/skills/core/security.md +565 -0
- package/framework/skills/core/seeds.md +307 -0
- package/framework/skills/core/seo.md +542 -0
- package/framework/skills/core/testing.md +393 -0
- package/framework/skills/core/views.md +260 -0
- package/framework/skills/core/websockets.md +564 -0
- package/framework/skills/data/advanced-sql.md +1204 -0
- package/framework/skills/data/nosql.md +1141 -0
- package/framework/skills/devops/containers-advanced.md +1237 -0
- package/framework/skills/devops/debugging.md +834 -0
- package/framework/skills/devops/git-workflow.md +752 -0
- package/framework/skills/devops/networking.md +932 -0
- package/framework/skills/devops/shell-scripting.md +1132 -0
- package/framework/sub-agents/architecture-patterns-agent.md +1450 -0
- package/framework/sub-agents/cloud-agent.md +677 -0
- package/framework/sub-agents/data.md +504 -0
- package/framework/sub-agents/debugging-agent.md +554 -0
- package/framework/sub-agents/devops.md +483 -0
- package/framework/sub-agents/docs.md +176 -0
- package/framework/sub-agents/frontend-dev.md +349 -0
- package/framework/sub-agents/git-workflow-agent.md +697 -0
- package/framework/sub-agents/integrations.md +630 -0
- package/framework/sub-agents/native-dev.md +434 -0
- package/framework/sub-agents/qa.md +138 -0
- package/framework/sub-agents/rails-dev.md +375 -0
- package/framework/sub-agents/security.md +526 -0
- package/framework/sub-agents/ui.md +437 -0
- package/framework/sub-agents/ux.md +284 -0
- package/framework/templates/api-spec.md +500 -0
- package/framework/templates/component-spec.md +248 -0
- package/framework/templates/feature.json +13 -0
- package/framework/templates/model-spec.md +318 -0
- package/framework/templates/prd-template.md +80 -0
- package/framework/templates/task-plan.md +122 -0
- package/framework/templates/task-user-story.md +52 -0
- package/framework/templates/technical-spec.md +260 -0
- package/framework/templates/user-story.md +95 -0
- package/package.json +42 -0
- package/project-templates/CLAUDE.md +42 -0
- package/project-templates/contexts/architecture.md +25 -0
- package/project-templates/contexts/conventions.md +46 -0
- package/project-templates/contexts/design-system.md +47 -0
- package/project-templates/contexts/requirements.md +38 -0
- package/project-templates/contexts/stack.md +30 -0
- package/project-templates/history/active/models.md +11 -0
- package/project-templates/history/changelog.md +15 -0
- package/project-templates/workspace/.gitkeep +0 -0
- package/src/cli.js +52 -0
- package/src/init.js +104 -0
- package/src/status.js +75 -0
- package/src/update.js +88 -0
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
# API Specification Template
|
|
2
|
+
|
|
3
|
+
## Información General
|
|
4
|
+
|
|
5
|
+
| Campo | Valor |
|
|
6
|
+
|-------|-------|
|
|
7
|
+
| Recurso | [Nombre del recurso] |
|
|
8
|
+
| Base URL | `/api/v1/[recursos]` |
|
|
9
|
+
| Versión | v1 |
|
|
10
|
+
| Estado | Diseño / Implementado |
|
|
11
|
+
|
|
12
|
+
## Autenticación
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
Authorization: Bearer <token>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Todos los endpoints requieren autenticación excepto los marcados como públicos.
|
|
19
|
+
|
|
20
|
+
## Endpoints
|
|
21
|
+
|
|
22
|
+
### Listar [Recursos]
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
GET /api/v1/recursos
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Autenticación:** Requerida
|
|
29
|
+
|
|
30
|
+
**Parámetros de Query:**
|
|
31
|
+
|
|
32
|
+
| Nombre | Tipo | Requerido | Default | Descripción |
|
|
33
|
+
|--------|------|-----------|---------|-------------|
|
|
34
|
+
| `page` | integer | No | 1 | Número de página |
|
|
35
|
+
| `per_page` | integer | No | 20 | Elementos por página (max 100) |
|
|
36
|
+
| `sort` | string | No | created_at | Campo de ordenamiento |
|
|
37
|
+
| `order` | string | No | desc | Dirección (asc/desc) |
|
|
38
|
+
| `status` | string | No | - | Filtrar por estado |
|
|
39
|
+
| `q` | string | No | - | Búsqueda por texto |
|
|
40
|
+
|
|
41
|
+
**Response (200 OK):**
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"recursos": [
|
|
46
|
+
{
|
|
47
|
+
"id": 1,
|
|
48
|
+
"field_name": "valor",
|
|
49
|
+
"status": "active",
|
|
50
|
+
"created_at": "2024-01-15T10:30:00Z",
|
|
51
|
+
"updated_at": "2024-01-15T10:30:00Z",
|
|
52
|
+
"user": {
|
|
53
|
+
"id": 5,
|
|
54
|
+
"name": "Usuario"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
"meta": {
|
|
59
|
+
"current_page": 1,
|
|
60
|
+
"total_pages": 5,
|
|
61
|
+
"total_count": 100,
|
|
62
|
+
"per_page": 20
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
### Obtener [Recurso]
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
GET /api/v1/recursos/:id
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Autenticación:** Requerida
|
|
76
|
+
|
|
77
|
+
**Parámetros de URL:**
|
|
78
|
+
|
|
79
|
+
| Nombre | Tipo | Descripción |
|
|
80
|
+
|--------|------|-------------|
|
|
81
|
+
| `id` | integer | ID del recurso |
|
|
82
|
+
|
|
83
|
+
**Response (200 OK):**
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"recurso": {
|
|
88
|
+
"id": 1,
|
|
89
|
+
"field_name": "valor",
|
|
90
|
+
"description": "Descripción completa",
|
|
91
|
+
"status": "active",
|
|
92
|
+
"created_at": "2024-01-15T10:30:00Z",
|
|
93
|
+
"updated_at": "2024-01-15T10:30:00Z",
|
|
94
|
+
"user": {
|
|
95
|
+
"id": 5,
|
|
96
|
+
"name": "Usuario",
|
|
97
|
+
"email": "user@example.com"
|
|
98
|
+
},
|
|
99
|
+
"related_items": [
|
|
100
|
+
{
|
|
101
|
+
"id": 10,
|
|
102
|
+
"name": "Item relacionado"
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Response (404 Not Found):**
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"error": "Recurso no encontrado"
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
### Crear [Recurso]
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
POST /api/v1/recursos
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Autenticación:** Requerida
|
|
126
|
+
|
|
127
|
+
**Request Body:**
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"recurso": {
|
|
132
|
+
"field_name": "valor",
|
|
133
|
+
"description": "Descripción opcional",
|
|
134
|
+
"status": "draft"
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**Campos del Request:**
|
|
140
|
+
|
|
141
|
+
| Nombre | Tipo | Requerido | Descripción |
|
|
142
|
+
|--------|------|-----------|-------------|
|
|
143
|
+
| `field_name` | string | Sí | Nombre del campo |
|
|
144
|
+
| `description` | string | No | Descripción |
|
|
145
|
+
| `status` | string | No | Estado inicial (default: draft) |
|
|
146
|
+
|
|
147
|
+
**Response (201 Created):**
|
|
148
|
+
|
|
149
|
+
```json
|
|
150
|
+
{
|
|
151
|
+
"recurso": {
|
|
152
|
+
"id": 2,
|
|
153
|
+
"field_name": "valor",
|
|
154
|
+
"description": "Descripción opcional",
|
|
155
|
+
"status": "draft",
|
|
156
|
+
"created_at": "2024-01-15T11:00:00Z",
|
|
157
|
+
"updated_at": "2024-01-15T11:00:00Z"
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**Response (422 Unprocessable Entity):**
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"error": "Validation failed",
|
|
167
|
+
"details": [
|
|
168
|
+
"Field name can't be blank",
|
|
169
|
+
"Field name is too short (minimum is 3 characters)"
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
### Actualizar [Recurso]
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
PATCH /api/v1/recursos/:id
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Autenticación:** Requerida (propietario o admin)
|
|
183
|
+
|
|
184
|
+
**Request Body:**
|
|
185
|
+
|
|
186
|
+
```json
|
|
187
|
+
{
|
|
188
|
+
"recurso": {
|
|
189
|
+
"field_name": "nuevo valor",
|
|
190
|
+
"status": "published"
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Response (200 OK):**
|
|
196
|
+
|
|
197
|
+
```json
|
|
198
|
+
{
|
|
199
|
+
"recurso": {
|
|
200
|
+
"id": 1,
|
|
201
|
+
"field_name": "nuevo valor",
|
|
202
|
+
"status": "published",
|
|
203
|
+
"updated_at": "2024-01-15T12:00:00Z"
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**Response (403 Forbidden):**
|
|
209
|
+
|
|
210
|
+
```json
|
|
211
|
+
{
|
|
212
|
+
"error": "No autorizado para modificar este recurso"
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
### Eliminar [Recurso]
|
|
219
|
+
|
|
220
|
+
```
|
|
221
|
+
DELETE /api/v1/recursos/:id
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**Autenticación:** Requerida (propietario o admin)
|
|
225
|
+
|
|
226
|
+
**Response (204 No Content):**
|
|
227
|
+
|
|
228
|
+
Sin cuerpo de respuesta.
|
|
229
|
+
|
|
230
|
+
**Response (403 Forbidden):**
|
|
231
|
+
|
|
232
|
+
```json
|
|
233
|
+
{
|
|
234
|
+
"error": "No autorizado para eliminar este recurso"
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
### Acción Custom: Publicar
|
|
241
|
+
|
|
242
|
+
```
|
|
243
|
+
POST /api/v1/recursos/:id/publish
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
**Autenticación:** Requerida (propietario o admin)
|
|
247
|
+
|
|
248
|
+
**Response (200 OK):**
|
|
249
|
+
|
|
250
|
+
```json
|
|
251
|
+
{
|
|
252
|
+
"recurso": {
|
|
253
|
+
"id": 1,
|
|
254
|
+
"status": "published",
|
|
255
|
+
"published_at": "2024-01-15T12:30:00Z"
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Códigos de Error
|
|
263
|
+
|
|
264
|
+
| Código | Descripción | Ejemplo de Response |
|
|
265
|
+
|--------|-------------|---------------------|
|
|
266
|
+
| 400 | Bad Request - Parámetros malformados | `{"error": "Invalid JSON"}` |
|
|
267
|
+
| 401 | Unauthorized - Token inválido o ausente | `{"error": "Token inválido"}` |
|
|
268
|
+
| 403 | Forbidden - Sin permisos | `{"error": "No autorizado"}` |
|
|
269
|
+
| 404 | Not Found - Recurso no existe | `{"error": "No encontrado"}` |
|
|
270
|
+
| 422 | Unprocessable Entity - Validación fallida | `{"error": "...", "details": [...]}` |
|
|
271
|
+
| 429 | Too Many Requests - Rate limit | `{"error": "Rate limit", "retry_after": 60}` |
|
|
272
|
+
| 500 | Server Error | `{"error": "Error interno"}` |
|
|
273
|
+
|
|
274
|
+
## Rate Limiting
|
|
275
|
+
|
|
276
|
+
| Endpoint | Límite | Ventana |
|
|
277
|
+
|----------|--------|---------|
|
|
278
|
+
| General | 100 requests | 1 minuto |
|
|
279
|
+
| Creación | 10 requests | 1 minuto |
|
|
280
|
+
| Login | 5 requests | 15 minutos |
|
|
281
|
+
|
|
282
|
+
Headers de respuesta:
|
|
283
|
+
```
|
|
284
|
+
X-RateLimit-Limit: 100
|
|
285
|
+
X-RateLimit-Remaining: 95
|
|
286
|
+
X-RateLimit-Reset: 1705319400
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Paginación
|
|
290
|
+
|
|
291
|
+
Todos los endpoints de listado usan paginación basada en offset.
|
|
292
|
+
|
|
293
|
+
**Parámetros:**
|
|
294
|
+
- `page`: Número de página (empezando en 1)
|
|
295
|
+
- `per_page`: Elementos por página (default: 20, max: 100)
|
|
296
|
+
|
|
297
|
+
**Meta de respuesta:**
|
|
298
|
+
```json
|
|
299
|
+
{
|
|
300
|
+
"meta": {
|
|
301
|
+
"current_page": 2,
|
|
302
|
+
"total_pages": 10,
|
|
303
|
+
"total_count": 195,
|
|
304
|
+
"per_page": 20
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## Filtrado y Ordenamiento
|
|
310
|
+
|
|
311
|
+
### Filtrado
|
|
312
|
+
```
|
|
313
|
+
GET /api/v1/recursos?status=active&user_id=5
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Ordenamiento
|
|
317
|
+
```
|
|
318
|
+
GET /api/v1/recursos?sort=created_at&order=desc
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Búsqueda
|
|
322
|
+
```
|
|
323
|
+
GET /api/v1/recursos?q=texto+de+busqueda
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
## Implementación
|
|
327
|
+
|
|
328
|
+
### Controlador
|
|
329
|
+
|
|
330
|
+
```ruby
|
|
331
|
+
# app/controllers/api/v1/recursos_controller.rb
|
|
332
|
+
module Api
|
|
333
|
+
module V1
|
|
334
|
+
class RecursosController < BaseController
|
|
335
|
+
before_action :set_recurso, only: [:show, :update, :destroy, :publish]
|
|
336
|
+
|
|
337
|
+
def index
|
|
338
|
+
@recursos = policy_scope(Recurso)
|
|
339
|
+
.includes(:user)
|
|
340
|
+
.filter_by(filter_params)
|
|
341
|
+
.order_by(sort_params)
|
|
342
|
+
|
|
343
|
+
@pagy, @recursos = pagy(@recursos, items: per_page)
|
|
344
|
+
|
|
345
|
+
render json: {
|
|
346
|
+
recursos: @recursos.map { |r| recurso_json(r) },
|
|
347
|
+
meta: pagination_meta(@pagy)
|
|
348
|
+
}
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def show
|
|
352
|
+
authorize @recurso
|
|
353
|
+
render json: { recurso: recurso_json(@recurso, full: true) }
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
def create
|
|
357
|
+
@recurso = current_api_user.recursos.build(recurso_params)
|
|
358
|
+
authorize @recurso
|
|
359
|
+
|
|
360
|
+
if @recurso.save
|
|
361
|
+
render json: { recurso: recurso_json(@recurso) }, status: :created
|
|
362
|
+
else
|
|
363
|
+
render_validation_error(@recurso)
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
def update
|
|
368
|
+
authorize @recurso
|
|
369
|
+
|
|
370
|
+
if @recurso.update(recurso_params)
|
|
371
|
+
render json: { recurso: recurso_json(@recurso) }
|
|
372
|
+
else
|
|
373
|
+
render_validation_error(@recurso)
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
def destroy
|
|
378
|
+
authorize @recurso
|
|
379
|
+
@recurso.destroy
|
|
380
|
+
head :no_content
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
def publish
|
|
384
|
+
authorize @recurso
|
|
385
|
+
@recurso.publish!
|
|
386
|
+
render json: { recurso: recurso_json(@recurso) }
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
private
|
|
390
|
+
|
|
391
|
+
def set_recurso
|
|
392
|
+
@recurso = Recurso.find(params[:id])
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
def recurso_params
|
|
396
|
+
params.require(:recurso).permit(:field_name, :description, :status)
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
def filter_params
|
|
400
|
+
params.permit(:status, :user_id, :q)
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
def sort_params
|
|
404
|
+
{
|
|
405
|
+
sort: params[:sort] || 'created_at',
|
|
406
|
+
order: params[:order] || 'desc'
|
|
407
|
+
}
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
def per_page
|
|
411
|
+
[params[:per_page]&.to_i || 20, 100].min
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
def recurso_json(recurso, full: false)
|
|
415
|
+
# Implementación del serializer
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### Rutas
|
|
423
|
+
|
|
424
|
+
```ruby
|
|
425
|
+
# config/routes.rb
|
|
426
|
+
namespace :api do
|
|
427
|
+
namespace :v1 do
|
|
428
|
+
resources :recursos, only: [:index, :show, :create, :update, :destroy] do
|
|
429
|
+
member do
|
|
430
|
+
post :publish
|
|
431
|
+
end
|
|
432
|
+
end
|
|
433
|
+
end
|
|
434
|
+
end
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
## Tests
|
|
438
|
+
|
|
439
|
+
```ruby
|
|
440
|
+
# spec/requests/api/v1/recursos_spec.rb
|
|
441
|
+
require "rails_helper"
|
|
442
|
+
|
|
443
|
+
RSpec.describe "API V1 Recursos", type: :request do
|
|
444
|
+
let(:user) { create(:user) }
|
|
445
|
+
let(:headers) { auth_headers(user) }
|
|
446
|
+
|
|
447
|
+
describe "GET /api/v1/recursos" do
|
|
448
|
+
let!(:recursos) { create_list(:recurso, 3, user: user) }
|
|
449
|
+
|
|
450
|
+
it "returns paginated list" do
|
|
451
|
+
get "/api/v1/recursos", headers: headers
|
|
452
|
+
|
|
453
|
+
expect(response).to have_http_status(:ok)
|
|
454
|
+
expect(json_response["recursos"].size).to eq(3)
|
|
455
|
+
expect(json_response["meta"]).to include("total_count" => 3)
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
it "filters by status" do
|
|
459
|
+
create(:recurso, status: "active")
|
|
460
|
+
create(:recurso, status: "draft")
|
|
461
|
+
|
|
462
|
+
get "/api/v1/recursos?status=active", headers: headers
|
|
463
|
+
|
|
464
|
+
expect(json_response["recursos"].size).to eq(1)
|
|
465
|
+
end
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
describe "POST /api/v1/recursos" do
|
|
469
|
+
let(:valid_params) { { recurso: { field_name: "Test" } } }
|
|
470
|
+
|
|
471
|
+
it "creates recurso" do
|
|
472
|
+
expect {
|
|
473
|
+
post "/api/v1/recursos", params: valid_params, headers: headers
|
|
474
|
+
}.to change(Recurso, :count).by(1)
|
|
475
|
+
|
|
476
|
+
expect(response).to have_http_status(:created)
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
it "returns errors for invalid params" do
|
|
480
|
+
post "/api/v1/recursos",
|
|
481
|
+
params: { recurso: { field_name: "" } },
|
|
482
|
+
headers: headers
|
|
483
|
+
|
|
484
|
+
expect(response).to have_http_status(:unprocessable_entity)
|
|
485
|
+
expect(json_response["details"]).to include(/blank/)
|
|
486
|
+
end
|
|
487
|
+
end
|
|
488
|
+
end
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
## Notas
|
|
492
|
+
|
|
493
|
+
- [Nota adicional 1]
|
|
494
|
+
- [Nota adicional 2]
|
|
495
|
+
|
|
496
|
+
## Changelog
|
|
497
|
+
|
|
498
|
+
| Versión | Fecha | Cambios |
|
|
499
|
+
|---------|-------|---------|
|
|
500
|
+
| v1 | [Fecha] | Versión inicial |
|