@hed-hog/content 0.0.270 → 0.0.273
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 +397 -0
- package/package.json +5 -5
package/README.md
ADDED
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
# @hed-hog/content
|
|
2
|
+
|
|
3
|
+
## 1. Visão geral do módulo
|
|
4
|
+
|
|
5
|
+
O módulo `@hed-hog/content` é responsável pela gestão de conteúdos multilíngues no sistema HedHog. Ele oferece funcionalidades para criação, leitura, atualização e exclusão (CRUD) de conteúdos, suportando múltiplos idiomas e controle de status (rascunho ou publicado). O módulo integra-se com serviços de paginação, localização e persistência via Prisma.
|
|
6
|
+
|
|
7
|
+
## 2. Escopo e responsabilidades
|
|
8
|
+
|
|
9
|
+
- Gerenciar conteúdos com suporte a múltiplos idiomas.
|
|
10
|
+
- Controlar status dos conteúdos (`draft` ou `published`).
|
|
11
|
+
- Fornecer estatísticas gerais sobre os conteúdos.
|
|
12
|
+
- Aplicar paginação e filtros nas listagens.
|
|
13
|
+
- Garantir validação e integridade dos dados.
|
|
14
|
+
- Restringir acesso via roles específicas.
|
|
15
|
+
|
|
16
|
+
## 3. Endpoints
|
|
17
|
+
|
|
18
|
+
| Método | Path | Autenticação | Descrição |
|
|
19
|
+
|--------|----------------|--------------|--------------------------------------|
|
|
20
|
+
| GET | /content/stats | Autenticada | Retorna estatísticas gerais dos conteúdos. |
|
|
21
|
+
| GET | /content/:id | Autenticada | Retorna conteúdo específico pelo ID, com dados multilíngues. |
|
|
22
|
+
| GET | /content | Autenticada | Lista conteúdos com paginação e filtros. |
|
|
23
|
+
| POST | /content | Autenticada | Cria um novo conteúdo multilíngue. |
|
|
24
|
+
| PATCH | /content/:id | Autenticada | Atualiza conteúdo existente pelo ID. |
|
|
25
|
+
| DELETE | /content/:id | Autenticada | Remove conteúdo pelo ID. |
|
|
26
|
+
|
|
27
|
+
### Detalhes dos endpoints
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
#### GET /content/stats
|
|
32
|
+
|
|
33
|
+
- **Autenticação:** Requer role `admin`.
|
|
34
|
+
- **Descrição:** Retorna estatísticas gerais dos conteúdos, incluindo total, total publicados, total em rascunho e total de idiomas habilitados.
|
|
35
|
+
- **Parâmetros:** Nenhum.
|
|
36
|
+
- **Resposta:**
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"total": number,
|
|
40
|
+
"totalPublished": number,
|
|
41
|
+
"totalDraft": number,
|
|
42
|
+
"totalEnabledLanguages": number
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
- **Erros comuns:** Nenhum específico.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
#### GET /content/:id
|
|
50
|
+
|
|
51
|
+
- **Autenticação:** Requer role `admin`.
|
|
52
|
+
- **Descrição:** Busca um conteúdo pelo seu ID, retornando dados básicos e traduções disponíveis.
|
|
53
|
+
- **Parâmetros:**
|
|
54
|
+
- `id` (path, number): ID do conteúdo.
|
|
55
|
+
- Header `Locale`: Código do idioma para mensagens de erro.
|
|
56
|
+
- **Resposta:**
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"id": number,
|
|
60
|
+
"slug": string,
|
|
61
|
+
"status": "draft" | "published",
|
|
62
|
+
"created_at": string,
|
|
63
|
+
"updated_at": string,
|
|
64
|
+
"locales": {
|
|
65
|
+
"<locale_code>": {
|
|
66
|
+
"title": string,
|
|
67
|
+
"body": string
|
|
68
|
+
},
|
|
69
|
+
...
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
- **Erros:**
|
|
74
|
+
- `404 Not Found`: Conteúdo não encontrado.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
#### GET /content
|
|
79
|
+
|
|
80
|
+
- **Autenticação:** Requer role `admin`.
|
|
81
|
+
- **Descrição:** Lista conteúdos com paginação, filtro por status e busca insensível por slug.
|
|
82
|
+
- **Query Parameters:**
|
|
83
|
+
- `page` (number, opcional): Página atual.
|
|
84
|
+
- `limit` (number, opcional): Itens por página.
|
|
85
|
+
- `status` (string, opcional): Filtra por status (`draft`, `published`, `all`).
|
|
86
|
+
- `search` (string, opcional): Termo para busca insensível no slug.
|
|
87
|
+
- **Header:** `Locale` para idioma das mensagens.
|
|
88
|
+
- **Resposta:**
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"data": [
|
|
92
|
+
{
|
|
93
|
+
"id": number,
|
|
94
|
+
"slug": string,
|
|
95
|
+
"status": "draft" | "published",
|
|
96
|
+
"created_at": string,
|
|
97
|
+
"updated_at": string,
|
|
98
|
+
"title": string,
|
|
99
|
+
"body": string,
|
|
100
|
+
"available_locales": [
|
|
101
|
+
{
|
|
102
|
+
"id": number,
|
|
103
|
+
"code": string,
|
|
104
|
+
"name": string
|
|
105
|
+
},
|
|
106
|
+
...
|
|
107
|
+
]
|
|
108
|
+
},
|
|
109
|
+
...
|
|
110
|
+
],
|
|
111
|
+
"meta": {
|
|
112
|
+
"totalItems": number,
|
|
113
|
+
"itemCount": number,
|
|
114
|
+
"itemsPerPage": number,
|
|
115
|
+
"totalPages": number,
|
|
116
|
+
"currentPage": number
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
- **Erros:**
|
|
121
|
+
- `400 Bad Request`: Locale inválido ou não encontrado.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
#### POST /content
|
|
126
|
+
|
|
127
|
+
- **Autenticação:** Requer role `admin`.
|
|
128
|
+
- **Descrição:** Cria um novo conteúdo com dados multilíngues.
|
|
129
|
+
- **Body:**
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"slug": "string",
|
|
133
|
+
"status": "draft" | "published",
|
|
134
|
+
"locale": {
|
|
135
|
+
"<locale_code>": {
|
|
136
|
+
"title": "string",
|
|
137
|
+
"body": "string"
|
|
138
|
+
},
|
|
139
|
+
...
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
- **Header:** `Locale` para idioma das mensagens.
|
|
144
|
+
- **Resposta:** Objeto do conteúdo criado (id, slug, status, timestamps).
|
|
145
|
+
- **Erros:**
|
|
146
|
+
- `400 Bad Request`: Slug já existe.
|
|
147
|
+
- `400 Bad Request`: Dados de locale ausentes ou inválidos.
|
|
148
|
+
- `400 Bad Request`: Locale não encontrado.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
#### PATCH /content/:id
|
|
153
|
+
|
|
154
|
+
- **Autenticação:** Requer role `admin`.
|
|
155
|
+
- **Descrição:** Atualiza um conteúdo existente, incluindo dados multilíngues.
|
|
156
|
+
- **Parâmetros:**
|
|
157
|
+
- `id` (path, number): ID do conteúdo.
|
|
158
|
+
- **Body:** Campos parciais do conteúdo, exemplo:
|
|
159
|
+
```json
|
|
160
|
+
{
|
|
161
|
+
"slug": "string",
|
|
162
|
+
"status": "draft" | "published",
|
|
163
|
+
"locale": {
|
|
164
|
+
"<locale_code>": {
|
|
165
|
+
"title": "string",
|
|
166
|
+
"body": "string"
|
|
167
|
+
},
|
|
168
|
+
...
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
- **Header:** `Locale` para idioma das mensagens.
|
|
173
|
+
- **Resposta:** Objeto do conteúdo atualizado.
|
|
174
|
+
- **Erros:**
|
|
175
|
+
- `404 Not Found`: Conteúdo não encontrado.
|
|
176
|
+
- `400 Bad Request`: Locale não encontrado.
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
#### DELETE /content/:id
|
|
181
|
+
|
|
182
|
+
- **Autenticação:** Requer role `admin`, `admin-access` ou `admin-content`.
|
|
183
|
+
- **Descrição:** Remove conteúdo pelo ID.
|
|
184
|
+
- **Parâmetros:**
|
|
185
|
+
- `id` (path, number): ID do conteúdo.
|
|
186
|
+
- **Header:** `Locale` para idioma das mensagens.
|
|
187
|
+
- **Resposta:** Objeto do conteúdo deletado.
|
|
188
|
+
- **Erros:**
|
|
189
|
+
- `404 Not Found`: Conteúdo não encontrado.
|
|
190
|
+
|
|
191
|
+
## 4. Regras de autenticação e autorização
|
|
192
|
+
|
|
193
|
+
- Todos os endpoints requerem autenticação.
|
|
194
|
+
- Roles necessárias:
|
|
195
|
+
- `admin` para a maioria das operações.
|
|
196
|
+
- `admin-access` e `admin-content` também autorizados para exclusão.
|
|
197
|
+
- Controle de acesso baseado em roles definido no arquivo `hedhog/data/route.yaml`.
|
|
198
|
+
|
|
199
|
+
## 5. Estruturas de request/response
|
|
200
|
+
|
|
201
|
+
### ContentCreateDTO
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
{
|
|
205
|
+
slug: string; // obrigatório, string
|
|
206
|
+
status: 'draft' | 'published'; // obrigatório, enum
|
|
207
|
+
locale: {
|
|
208
|
+
[localeCode: string]: {
|
|
209
|
+
title: string;
|
|
210
|
+
body: string;
|
|
211
|
+
}
|
|
212
|
+
}; // obrigatório, objeto com dados multilíngues
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### ContentUpdateDTO
|
|
217
|
+
|
|
218
|
+
- Mesma estrutura do `ContentCreateDTO`, porém todos os campos são opcionais (partial).
|
|
219
|
+
|
|
220
|
+
### Resposta de conteúdo individual
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
{
|
|
224
|
+
id: number;
|
|
225
|
+
slug: string;
|
|
226
|
+
status: 'draft' | 'published';
|
|
227
|
+
created_at: string;
|
|
228
|
+
updated_at: string;
|
|
229
|
+
locales: {
|
|
230
|
+
[localeCode: string]: {
|
|
231
|
+
title: string;
|
|
232
|
+
body: string;
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Resposta de listagem paginada
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
{
|
|
242
|
+
data: Array<{
|
|
243
|
+
id: number;
|
|
244
|
+
slug: string;
|
|
245
|
+
status: 'draft' | 'published';
|
|
246
|
+
created_at: string;
|
|
247
|
+
updated_at: string;
|
|
248
|
+
title: string;
|
|
249
|
+
body: string;
|
|
250
|
+
available_locales: Array<{
|
|
251
|
+
id: number;
|
|
252
|
+
code: string;
|
|
253
|
+
name: string;
|
|
254
|
+
}>;
|
|
255
|
+
}>;
|
|
256
|
+
meta: {
|
|
257
|
+
totalItems: number;
|
|
258
|
+
itemCount: number;
|
|
259
|
+
itemsPerPage: number;
|
|
260
|
+
totalPages: number;
|
|
261
|
+
currentPage: number;
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## 6. Erros comuns
|
|
267
|
+
|
|
268
|
+
| Código | Mensagem | Causa comum |
|
|
269
|
+
|--------|---------------------------------|-----------------------------------------|
|
|
270
|
+
| 400 | Locale não encontrado | Código de idioma inválido ou não habilitado. |
|
|
271
|
+
| 400 | Conteúdo com este slug já existe | Tentativa de criar conteúdo com slug duplicado. |
|
|
272
|
+
| 400 | Dados de locale são obrigatórios | Falta de dados multilíngues no payload. |
|
|
273
|
+
| 404 | Conteúdo não encontrado | ID informado não existe no banco. |
|
|
274
|
+
|
|
275
|
+
## 7. Banco de dados (tabelas YAML)
|
|
276
|
+
|
|
277
|
+
### Tabela `content`
|
|
278
|
+
|
|
279
|
+
Finalidade: Armazenar conteúdos multilíngues com status e timestamps.
|
|
280
|
+
|
|
281
|
+
```yaml
|
|
282
|
+
columns:
|
|
283
|
+
- type: pk
|
|
284
|
+
- type: slug
|
|
285
|
+
- name: status
|
|
286
|
+
type: enum
|
|
287
|
+
values: [draft, published]
|
|
288
|
+
- name: title
|
|
289
|
+
type: locale_varchar
|
|
290
|
+
locale:
|
|
291
|
+
en: Title
|
|
292
|
+
pt: Título
|
|
293
|
+
- name: body
|
|
294
|
+
type: locale_text
|
|
295
|
+
locale:
|
|
296
|
+
en: Body
|
|
297
|
+
pt: Corpo
|
|
298
|
+
- type: created_at
|
|
299
|
+
- type: updated_at
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
- **Colunas:**
|
|
303
|
+
- `id` (PK, auto-incremento)
|
|
304
|
+
- `slug` (string, único)
|
|
305
|
+
- `status` (enum: `draft` ou `published`)
|
|
306
|
+
- `title` (campo multilíngue varchar)
|
|
307
|
+
- `body` (campo multilíngue texto)
|
|
308
|
+
- `created_at` (timestamp)
|
|
309
|
+
- `updated_at` (timestamp)
|
|
310
|
+
- **Defaults:** `created_at` e `updated_at` gerenciados automaticamente.
|
|
311
|
+
- **Nulabilidade:** `slug`, `status`, `title` e `body` não nulos.
|
|
312
|
+
- **Integridade:** `slug` único.
|
|
313
|
+
- **Índices:** Índice primário em `id`, índice único em `slug`.
|
|
314
|
+
- **Enums:** `status` com valores `draft` e `published`.
|
|
315
|
+
|
|
316
|
+
## 8. Regras de negócio relevantes
|
|
317
|
+
|
|
318
|
+
- Slug deve ser único para cada conteúdo.
|
|
319
|
+
- Conteúdos podem estar em múltiplos idiomas, cada um com título e corpo.
|
|
320
|
+
- Status controla visibilidade: `draft` para rascunho, `published` para conteúdo ativo.
|
|
321
|
+
- Ao criar ou atualizar, deve-se validar existência dos idiomas informados.
|
|
322
|
+
- Exclusão só é permitida para usuários com roles específicas.
|
|
323
|
+
- Paginação e busca são insensíveis a maiúsculas/minúsculas no campo slug.
|
|
324
|
+
- Mensagens de erro são localizadas conforme o header `Locale`.
|
|
325
|
+
|
|
326
|
+
## 9. Guia rápido de uso (exemplos)
|
|
327
|
+
|
|
328
|
+
### Criar conteúdo
|
|
329
|
+
|
|
330
|
+
```http
|
|
331
|
+
POST /content
|
|
332
|
+
Authorization: Bearer <token>
|
|
333
|
+
Content-Type: application/json
|
|
334
|
+
Locale: pt
|
|
335
|
+
|
|
336
|
+
{
|
|
337
|
+
"slug": "exemplo-conteudo",
|
|
338
|
+
"status": "draft",
|
|
339
|
+
"locale": {
|
|
340
|
+
"pt": {
|
|
341
|
+
"title": "Título Exemplo",
|
|
342
|
+
"body": "Corpo do conteúdo em português."
|
|
343
|
+
},
|
|
344
|
+
"en": {
|
|
345
|
+
"title": "Example Title",
|
|
346
|
+
"body": "Content body in English."
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Atualizar conteúdo
|
|
353
|
+
|
|
354
|
+
```http
|
|
355
|
+
PATCH /content/1
|
|
356
|
+
Authorization: Bearer <token>
|
|
357
|
+
Content-Type: application/json
|
|
358
|
+
Locale: pt
|
|
359
|
+
|
|
360
|
+
{
|
|
361
|
+
"status": "published",
|
|
362
|
+
"locale": {
|
|
363
|
+
"pt": {
|
|
364
|
+
"title": "Título Atualizado",
|
|
365
|
+
"body": "Corpo atualizado."
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### Listar conteúdos com filtro e paginação
|
|
372
|
+
|
|
373
|
+
```http
|
|
374
|
+
GET /content?status=published&page=1&limit=10&search=exemplo
|
|
375
|
+
Authorization: Bearer <token>
|
|
376
|
+
Locale: en
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### Obter conteúdo por ID
|
|
380
|
+
|
|
381
|
+
```http
|
|
382
|
+
GET /content/1
|
|
383
|
+
Authorization: Bearer <token>
|
|
384
|
+
Locale: pt
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### Deletar conteúdo
|
|
388
|
+
|
|
389
|
+
```http
|
|
390
|
+
DELETE /content/1
|
|
391
|
+
Authorization: Bearer <token>
|
|
392
|
+
Locale: pt
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
---
|
|
396
|
+
|
|
397
|
+
Este módulo é fundamental para a gestão de conteúdos multilíngues no HedHog, garantindo flexibilidade, segurança e organização na administração dos textos exibidos nas aplicações.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hed-hog/content",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.273",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
"@nestjs/core": "^11",
|
|
10
10
|
"@nestjs/jwt": "^11",
|
|
11
11
|
"@nestjs/mapped-types": "*",
|
|
12
|
-
"@hed-hog/api-pagination": "0.0.6",
|
|
13
|
-
"@hed-hog/api-locale": "0.0.13",
|
|
14
12
|
"@hed-hog/api": "0.0.4",
|
|
15
|
-
"@hed-hog/
|
|
16
|
-
"@hed-hog/api-prisma": "0.0.5"
|
|
13
|
+
"@hed-hog/api-pagination": "0.0.6",
|
|
14
|
+
"@hed-hog/api-prisma": "0.0.5",
|
|
15
|
+
"@hed-hog/core": "0.0.273",
|
|
16
|
+
"@hed-hog/api-locale": "0.0.13"
|
|
17
17
|
},
|
|
18
18
|
"exports": {
|
|
19
19
|
".": {
|