@riligar/agents-kit 1.14.0 → 1.16.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.
Files changed (68) hide show
  1. package/.agent/{skills/riligar-dev-clean-code/SKILL.md → rules/clean-code.md} +3 -51
  2. package/.agent/skills/riligar-design-system/SKILL.md +1 -0
  3. package/.agent/skills/riligar-dev-auth-elysia/SKILL.md +2 -2
  4. package/.agent/skills/riligar-dev-dashboard/SKILL.md +582 -0
  5. package/.agent/skills/riligar-dev-dashboard/references/dependencies.md +44 -0
  6. package/.agent/skills/{riligar-dev-backend → riligar-dev-manager}/SKILL.md +13 -9
  7. package/.agent/skills/{riligar-dev-landing-page → riligar-dev-website}/SKILL.md +1 -1
  8. package/.agent/skills/{riligar-dev-seo → riligar-dev-website-seo}/SKILL.md +1 -1
  9. package/.agent/skills/riligar-infra-cloudfare/SKILL.md +437 -0
  10. package/.agent/skills/riligar-infra-cloudfare/references/cloudflare-api.md +139 -0
  11. package/.agent/skills/riligar-infra-cloudfare/references/email-routing.md +262 -0
  12. package/.agent/skills/riligar-infra-cloudfare/references/r2-storage.md +333 -0
  13. package/.agent/skills/{riligar-infrastructure → riligar-infra-fly}/SKILL.md +38 -1
  14. package/.agent/skills/{riligar-dev-stripe → riligar-infra-stripe}/SKILL.md +3 -4
  15. package/.agent/skills/skill-creator/SKILL.md +1 -1
  16. package/package.json +1 -1
  17. package/.agent/skills/riligar-dev-architecture/SKILL.md +0 -54
  18. package/.agent/skills/riligar-dev-architecture/references/context-discovery.md +0 -43
  19. package/.agent/skills/riligar-dev-architecture/references/examples.md +0 -94
  20. package/.agent/skills/riligar-dev-architecture/references/pattern-selection.md +0 -68
  21. package/.agent/skills/riligar-dev-architecture/references/patterns-reference.md +0 -50
  22. package/.agent/skills/riligar-dev-architecture/references/trade-off-analysis.md +0 -77
  23. package/.agent/skills/riligar-dev-autopilot/SKILL.md +0 -59
  24. package/.agent/skills/riligar-dev-code-review/SKILL.md +0 -116
  25. package/.agent/skills/riligar-dev-database/SKILL.md +0 -51
  26. package/.agent/skills/riligar-dev-database/references/database-selection.md +0 -43
  27. package/.agent/skills/riligar-dev-database/references/indexing.md +0 -39
  28. package/.agent/skills/riligar-dev-database/references/migrations.md +0 -48
  29. package/.agent/skills/riligar-dev-database/references/optimization.md +0 -36
  30. package/.agent/skills/riligar-dev-database/references/orm-selection.md +0 -30
  31. package/.agent/skills/riligar-dev-database/references/schema-design.md +0 -56
  32. package/.agent/skills/riligar-dev-database/scripts/schema_validator.py +0 -172
  33. package/.agent/skills/riligar-dev-frontend/SKILL.md +0 -215
  34. package/.agent/skills/riligar-plan-writing/SKILL.md +0 -162
  35. package/.agent/skills/riligar-tech-stack/SKILL.md +0 -110
  36. package/.agent/skills/riligar-tech-stack/references/tech-stack.md +0 -131
  37. /package/.agent/skills/riligar-dev-auth-elysia/assets/{server-snippets.ts → server-snippets.js} +0 -0
  38. /package/.agent/skills/{riligar-dev-backend → riligar-dev-manager}/references/elysia-basics.md +0 -0
  39. /package/.agent/skills/{riligar-dev-backend → riligar-dev-manager}/references/elysia-lifecycle.md +0 -0
  40. /package/.agent/skills/{riligar-dev-backend → riligar-dev-manager}/references/elysia-patterns.md +0 -0
  41. /package/.agent/skills/{riligar-dev-backend → riligar-dev-manager}/references/elysia-plugins.md +0 -0
  42. /package/.agent/skills/{riligar-dev-backend → riligar-dev-manager}/references/elysia-validation.md +0 -0
  43. /package/.agent/skills/{riligar-dev-backend → riligar-dev-manager}/scripts/api_validator.py +0 -0
  44. /package/.agent/skills/{riligar-dev-landing-page → riligar-dev-website}/assets/original-2a03320f967a884fd2ad275d788f32e5.webp +0 -0
  45. /package/.agent/skills/{riligar-dev-landing-page → riligar-dev-website}/assets/original-481d7179109272dcaff2516fef62b718.webp +0 -0
  46. /package/.agent/skills/{riligar-dev-landing-page → riligar-dev-website}/assets/original-56d848520060ca714456601d1a7417cd.webp +0 -0
  47. /package/.agent/skills/{riligar-dev-landing-page → riligar-dev-website}/assets/original-93104cd260129cd6b76dac4119622eaf.webp +0 -0
  48. /package/.agent/skills/{riligar-dev-landing-page → riligar-dev-website}/assets/original-c5d259b0497cec98c36c48fc33ebbde6.webp +0 -0
  49. /package/.agent/skills/{riligar-dev-landing-page → riligar-dev-website}/assets/original-e865b2464fdf5ca567af716e1ed4fd16.webp +0 -0
  50. /package/.agent/skills/{riligar-dev-landing-page → riligar-dev-website}/assets/original-f1459f5315f0045705c2ca4937204146.webp +0 -0
  51. /package/.agent/skills/{riligar-dev-landing-page → riligar-dev-website}/assets/original-f67954754fdc2fc57009369fd3437205.webp +0 -0
  52. /package/.agent/skills/{riligar-dev-landing-page → riligar-dev-website}/assets/screencapture-caddaddy-app-2025-11-03-20_16_14.webp +0 -0
  53. /package/.agent/skills/{riligar-dev-landing-page → riligar-dev-website}/assets/screencapture-ciromaciel-click-2026-01-06-17_08_01.webp +0 -0
  54. /package/.agent/skills/{riligar-dev-landing-page → riligar-dev-website}/assets/screencapture-notionsecondbrain-2026-01-06-16_07_56.webp +0 -0
  55. /package/.agent/skills/{riligar-dev-landing-page → riligar-dev-website}/assets/screencapture-skillsmp-2026-01-16-14_40_22.webp +0 -0
  56. /package/.agent/skills/{riligar-dev-landing-page → riligar-dev-website}/references/conversion-framework.md +0 -0
  57. /package/.agent/skills/{riligar-dev-landing-page → riligar-dev-website}/references/copywriting-guide.md +0 -0
  58. /package/.agent/skills/{riligar-dev-landing-page → riligar-dev-website}/references/section-blueprints.md +0 -0
  59. /package/.agent/skills/{riligar-dev-seo → riligar-dev-website-seo}/references/checklist.md +0 -0
  60. /package/.agent/skills/{riligar-dev-seo → riligar-dev-website-seo}/references/implementation.md +0 -0
  61. /package/.agent/skills/{riligar-dev-seo → riligar-dev-website-seo}/references/structured-data.md +0 -0
  62. /package/.agent/skills/{riligar-infrastructure → riligar-infra-fly}/references/infrastructure.md +0 -0
  63. /package/.agent/skills/{riligar-dev-stripe → riligar-infra-stripe}/assets/stripe-client.js +0 -0
  64. /package/.agent/skills/{riligar-dev-stripe → riligar-infra-stripe}/assets/stripe-server.js +0 -0
  65. /package/.agent/skills/{riligar-dev-stripe → riligar-infra-stripe}/references/stripe-database.md +0 -0
  66. /package/.agent/skills/{riligar-dev-stripe → riligar-infra-stripe}/references/stripe-elysia.md +0 -0
  67. /package/.agent/skills/{riligar-dev-stripe → riligar-infra-stripe}/references/stripe-react.md +0 -0
  68. /package/.agent/skills/{riligar-dev-stripe → riligar-infra-stripe}/references/stripe-webhooks.md +0 -0
@@ -0,0 +1,582 @@
1
+ ---
2
+ name: riligar-dev-dashboard
3
+ description: Padrões React específicos do RiLiGar. Zustand, i18n, estrutura de arquivos, composição de componentes. Use quando construindo componentes, gerenciando estado ou implementando UI.
4
+ ---
5
+
6
+ # Front-End — Padrões do RiLiGar
7
+
8
+ > Regras concretas baseadas na arquitetura real dos projetos. Não são genéricas — são do código que existe.
9
+
10
+ ---
11
+
12
+ ## Referências obrigatórias
13
+
14
+ > [!IMPORTANT]
15
+ > Sempre respeite também:
16
+ > - @[.agent/skills/riligar-design-system] — UI exclusivo via Mantine, zero CSS
17
+ > - Rules em `.agent/rules/` — clean-code, naming-conventions, code-style, javascript-only
18
+ > - [references/dependencies.md](references/dependencies.md) — Pacotes e versões do frontend, config Vite
19
+
20
+ ---
21
+
22
+ ## 1. Estrutura de arquivos
23
+
24
+ ```
25
+ src/
26
+ ├── components/ # Componentes reutilizáveis
27
+ │ ├── Sidebar.jsx # PascalCase (SEMPRE)
28
+ │ ├── RichEditor.jsx
29
+ │ └── MediaLibrary.jsx
30
+ ├── pages/ # Uma pasta por página/feature
31
+ │ ├── home.jsx # Arquivo raiz da página: kebab-case
32
+ │ ├── editor/
33
+ │ │ └── index.jsx
34
+ │ └── feeds/
35
+ │ ├── index.jsx
36
+ │ └── FeedConfig.jsx # Sub-componentes: PascalCase
37
+ ├── store/ # Zustand stores — um arquivo por domínio
38
+ │ ├── auth-store.js
39
+ │ ├── feed-store.js
40
+ │ └── post-store.js
41
+ ├── services/ # Chamadas HTTP — um arquivo por domínio
42
+ │ ├── api.js # Instância base do cliente HTTP
43
+ │ ├── feeds.js
44
+ │ └── posts.js
45
+ ├── constants/ # Constantes estáticas do app
46
+ ├── i18n/ # Internacionalização
47
+ │ ├── index.js
48
+ │ └── locales/
49
+ └── hooks/ # Custom hooks compartilhados
50
+ ```
51
+
52
+ ### Regras de naming de arquivos
53
+
54
+ | Tipo | Convenção | Exemplo |
55
+ |---|---|---|
56
+ | Componentes (reutilizáveis) | PascalCase | `MediaLibrary.jsx` |
57
+ | Página raiz | kebab-case | `home.jsx`, `index.jsx` |
58
+ | Sub-componentes de página | PascalCase | `FeedConfig.jsx` |
59
+ | Stores | kebab-case + sufixo `-store` | `feed-store.js` |
60
+ | Services | kebab-case | `feeds.js` |
61
+ | Hooks | camelCase com prefixo `use` | `useDebounce.js` |
62
+
63
+ ---
64
+
65
+ ## 2. Estado — Zustand (não é opcional)
66
+
67
+ Estado global **sempre** Zustand. Sem Context para estado compartilhado. Sem Redux.
68
+
69
+ ### Padrão de store
70
+
71
+ ```javascript
72
+ import { create } from 'zustand'
73
+ import { feedsService } from '../services/feeds'
74
+
75
+ const useFeedStore = create((set, get) => ({
76
+ feeds: [],
77
+ activeFeed: null,
78
+ isLoading: false,
79
+
80
+ fetchFeeds: async () => {
81
+ set({ isLoading: true })
82
+ const feeds = await feedsService.getAll()
83
+ set({ feeds, isLoading: false })
84
+ },
85
+
86
+ setActiveFeed: (feed) => set({ activeFeed: feed }),
87
+ }))
88
+ ```
89
+
90
+ ### Regras
91
+
92
+ - **Sem getters JavaScript** (`get isTrialing() {}`) — não são reativos no Zustand. Derive no componente ou use um selector.
93
+ - **Persistência:** use `persist` middleware apenas quando necessário (ex: `activeFeed`).
94
+ - **Sem lógica de UI** dentro do store. Stores são dados + chamadas de API.
95
+ - **Selectors granulares:** `useStore((state) => state.feeds)` — não `useStore()` inteiro.
96
+
97
+ ### Errado vs Certo
98
+
99
+ ```javascript
100
+ // ❌ Getter não-reativo — nunca vai atualizar o componente
101
+ const useSubscriptionStore = create((set) => ({
102
+ subscription: null,
103
+ get isTrialing() { return this.subscription?.status === 'trialing' }
104
+ }))
105
+
106
+ // ✅ Derive no componente
107
+ const subscription = useSubscriptionStore((s) => s.subscription)
108
+ const isTrialing = subscription?.status === 'trialing'
109
+ ```
110
+
111
+ ---
112
+
113
+ ## 3. i18n — Todas as strings visíveis devem usar `t()`
114
+
115
+ O projeto usa **i18next** com 3 idiomas (pt-BR, en, es). Nenhuma string visível ao usuário pode ser hardcoded.
116
+
117
+ ### Como usar
118
+
119
+ ```javascript
120
+ import { useTranslation } from 'react-i18next'
121
+
122
+ const MyComponent = () => {
123
+ const { t } = useTranslation()
124
+
125
+ return (
126
+ <Button onClick={handleSave}>{t('common.save')}</Button>
127
+ )
128
+ }
129
+ ```
130
+
131
+ ### Regras
132
+
133
+ - **Sempre importar `useTranslation`** antes de usar `t()`. Sem isso, crash em runtime.
134
+ - Strings de UI: `t('namespace.key')` — nunca hardcode.
135
+ - Strings técnicas (logs, variável interna): podem ser em inglês, não precisam de `t()`.
136
+ - Chaves de namespace: domínio da feature (`feeds.`, `posts.`, `media.`) + `common.` para compartilhados.
137
+ - Mensagens de erro da API já vêm traduzidas do backend — não duplique.
138
+
139
+ ### Errado
140
+
141
+ ```javascript
142
+ // ❌ String hardcoded visível ao usuário
143
+ <Button>Salvar Alterações</Button>
144
+ <Text>Nenhuma mídia encontrada.</Text>
145
+
146
+ // ❌ t() sem import — crash
147
+ const handleSave = async () => {
148
+ showNotification({ title: t('common.success') }) // ReferenceError
149
+ }
150
+ ```
151
+
152
+ ### Certo
153
+
154
+ ```javascript
155
+ // ✅
156
+ import { useTranslation } from 'react-i18next'
157
+
158
+ const { t } = useTranslation()
159
+ <Button>{t('common.save')}</Button>
160
+ <Text>{t('media.empty')}</Text>
161
+ ```
162
+
163
+ ---
164
+
165
+ ## 4. Services — camada de HTTP
166
+
167
+ Todas as chamadas de API vão por `services/`. Componentes e stores não chamam HTTP diretamente.
168
+
169
+ ### Padrão
170
+
171
+ ```javascript
172
+ // services/feeds.js
173
+ import { api } from './api'
174
+
175
+ export const feedsService = {
176
+ getAll: () => api.get('feeds').json(),
177
+ getById: (id) => api.get(`feeds/${id}`).json(),
178
+ create: (data) => api.post('feeds', { json: data }).json(),
179
+ update: (id, data) => api.put(`feeds/${id}`, { json: data }).json(),
180
+ remove: (id) => api.delete(`feeds/${id}`).json(),
181
+ }
182
+ ```
183
+
184
+ - `api.js` tem a instância base com token de auth e tratamento de erro.
185
+ - **Não duplique `API_URL`** — já está no `api.js`. Nunca redefina em outro arquivo.
186
+ - Services são funções puras de chamada HTTP. Sem lógica de estado.
187
+
188
+ ---
189
+
190
+ ## 5. Componentes — regras práticas
191
+
192
+ ### Composição
193
+
194
+ - Um componente, uma responsabilidade.
195
+ - Se um componente ultrapassar ~100 linhas, divide.
196
+ - Props down, events up. Sem drilling profundo — usa store.
197
+
198
+ ### Interação com usuário
199
+
200
+ - **Confirmação de exclusão:** sempre usar `HoldButton` / `ButtonDelete` do `components/Buttons.jsx`. Nunca usar `confirm()` nativo.
201
+ - **Hover/focus:** usar props do Mantine (`styles`, `withBorder`, hover via `&:hover` no `styles`). Nunca manipular DOM diretamente via `e.currentTarget.style`.
202
+
203
+ ```javascript
204
+ // ❌ Manipulação direta de DOM
205
+ onMouseEnter={(e) => e.currentTarget.style.background = '#eee'}
206
+
207
+ // ✅ Mantine styles prop
208
+ styles={{ root: { '&:hover': { backgroundColor: 'var(--mantine-color-dimmed)' } } }}
209
+ ```
210
+
211
+ ### Não redefina componentes do Mantine
212
+
213
+ Se você precisa de um `Center`, `TextInput`, `Button` — use o do Mantine. Nunca crie um local com o mesmo nome, isso gera shadow e confusão.
214
+
215
+ ---
216
+
217
+ ## 6. Constantes e valores fixos
218
+
219
+ - Strings de config (phone numbers, mensagens template, URLs externas) vão em `constants/` ou `.env`.
220
+ - Nunca hardcode dentro de componentes.
221
+
222
+ ```javascript
223
+ // ❌
224
+ const message = `Olá, preciso de ajuda com meu plano.`
225
+
226
+ // ✅ constants/whatsapp.js
227
+ export const WHATSAPP_SUPPORT_NUMBER = '...'
228
+ export const WHATSAPP_SUPPORT_MESSAGE = '...' // ou via i18n se traduzível
229
+ ```
230
+
231
+ ---
232
+
233
+ ## 7. Anti-patterns (do código real)
234
+
235
+ | ❌ Problema real encontrado | ✅ Como resolver |
236
+ |---|---|
237
+ | `slugify` duplicado em 2 arquivos | Extrair para `utils/slugify.js` |
238
+ | `stripHtml` duplicado em 2 arquivos | Extrair para `utils/stripHtml.js` |
239
+ | `API_URL` redefinido fora do `api.js` | Importar do `services/api.js` |
240
+ | `t()` usado sem `useTranslation` importado | Sempre verificar import |
241
+ | Componente Mantine shadowed por local | Deletar o local, usar Mantine |
242
+ | Código comentado espalhado | Deletar. Se precisa, usa git. |
243
+ | `confirm()` misturado com HoldButton | Usa HoldButton sempre |
244
+ | `<style>` tag com CSS raw | Usa `styles` prop do Mantine (exceção: libs externas como ProseMirror que precisam de CSS global) |
245
+ | Getters no Zustand store | Derive no componente |
246
+ | `onMouseEnter` manipulando style diretamente | Usa `styles` prop do Mantine |
247
+
248
+ ---
249
+
250
+ ## 8. Padrões reutilizáveis
251
+
252
+ Estruturas que repetem pela codebase. Copie o esqueleto, ajuste apenas o conteúdo domínio-específico.
253
+
254
+ ### 8.1 Page Header
255
+
256
+ Presente em **todas** as pages. Estrutura idêntica sempre:
257
+
258
+ ```javascript
259
+ <Box py="xl">
260
+ <Group justify="space-between" align="flex-end" mb="xl">
261
+ <Stack gap={0}>
262
+ <Text size="xs" fw={700} c="dimmed" tt="uppercase" lts="0.1em">
263
+ {t('namespace.subtitle')}
264
+ </Text>
265
+ <Title order={1} style={{ letterSpacing: '-0.04em' }}>
266
+ {t('namespace.title')}
267
+ </Title>
268
+ </Stack>
269
+ {/* CTA opcional — ex: <Button leftSection={<IconPlus size={16} />}> */}
270
+ </Group>
271
+ {/* Conteúdo da página */}
272
+ </Box>
273
+ ```
274
+
275
+ ### 8.2 Empty State
276
+
277
+ Usado quando uma lista está vazia. Card com borda dashed, icone grande, texto e CTA:
278
+
279
+ ```javascript
280
+ <Card padding="xl" radius="md" withBorder style={{ borderStyle: 'dashed', textAlign: 'center' }}>
281
+ <Stack align="center" py="xl">
282
+ <IconDominio size={48} stroke={1} color="var(--mantine-color-gray-2)" />
283
+ <Text c="dimmed" size="sm">{t('namespace.emptyMessage')}</Text>
284
+ <Button onClick={handleCreate} leftSection={<IconPlus size={16} />}>
285
+ {t('namespace.createFirst')}
286
+ </Button>
287
+ </Stack>
288
+ </Card>
289
+ ```
290
+
291
+ ### 8.3 Loading Guard
292
+
293
+ Loader só aparece quando não há dados ainda (não sobrescreve lista existente):
294
+
295
+ ```javascript
296
+ {loading && data.length === 0 ? (
297
+ <Center style={{ height: 300 }}>
298
+ <Loader />
299
+ </Center>
300
+ ) : (
301
+ /* conteúdo normal */
302
+ )}
303
+ ```
304
+
305
+ ### 8.4 Card Grid
306
+
307
+ Layout responsivo padrão para listas de cards:
308
+
309
+ ```javascript
310
+ <SimpleGrid cols={{ base: 1, sm: 2, md: 3 }}>
311
+ {items.map((item) => (
312
+ <Card key={item.id} padding="lg" radius="md" withBorder>
313
+ {/* conteúdo do card */}
314
+ </Card>
315
+ ))}
316
+ </SimpleGrid>
317
+ ```
318
+
319
+ Para galerias (mais itens pequenos): `cols={{ base: 1, sm: 2, md: 3, lg: 4 }}`
320
+
321
+ ### 8.5 Modal
322
+
323
+ Sempre usa `useDisclosure`. Header com borderBottom específico:
324
+
325
+ ```javascript
326
+ const [opened, { open, close }] = useDisclosure(false)
327
+
328
+ <Modal
329
+ opened={opened}
330
+ onClose={close}
331
+ centered
332
+ radius="md"
333
+ padding="xl"
334
+ title={<Text fw={700}>{t('namespace.modalTitle')}</Text>}
335
+ styles={{ header: { borderBottom: '1px solid var(--mantine-color-gray-2)', marginBottom: 20 } }}
336
+ >
337
+ {/* corpo do modal */}
338
+ </Modal>
339
+ ```
340
+
341
+ Para múltiplos modais na mesma page, renomeia as funções: `{ open: openEdit, close: closeEdit }`
342
+
343
+ ### 8.6 Status Badge
344
+
345
+ Mapeia status → configuração visual via função que recebe `t`:
346
+
347
+ ```javascript
348
+ const getStatusConfig = (t) => ({
349
+ draft: { color: 'gray', icon: <IconCircleDotted size={16} />, label: t('posts.status.draft') },
350
+ scheduled: { color: 'blue', icon: <IconClock size={16} />, label: t('posts.status.scheduled') },
351
+ published: { color: 'green', icon: <IconCircleCheck size={16} />, label: t('posts.status.published') },
352
+ failed: { color: 'red', icon: <IconCircleX size={16} />, label: t('posts.status.failed') },
353
+ })
354
+
355
+ // Uso
356
+ const config = getStatusConfig(t)[status]
357
+ <Badge variant="dot" color={config.color}>{config.label}</Badge>
358
+ ```
359
+
360
+ ### 8.7 Search / Filter
361
+
362
+ Filtro local sem chamada de API — estado local + filter inline:
363
+
364
+ ```javascript
365
+ const [search, setSearch] = useState('')
366
+
367
+ const filtered = items.filter((item) =>
368
+ item.name.toLowerCase().includes(search.toLowerCase())
369
+ )
370
+
371
+ <TextInput
372
+ placeholder={t('common.search')}
373
+ leftSection={<IconSearch size={16} />}
374
+ value={search}
375
+ onChange={(e) => setSearch(e.target.value)}
376
+ />
377
+ ```
378
+
379
+ ---
380
+
381
+ ## 9. Padrões de dados e lógica
382
+
383
+ ### 9.1 Store — async action
384
+
385
+ Template exato que todas as actions seguem. Imports do service como namespace:
386
+
387
+ ```javascript
388
+ import { create } from 'zustand'
389
+ import * as feedsService from '../services/feeds.js'
390
+
391
+ export const useFeedStore = create((set) => ({
392
+ feeds: [],
393
+ loading: false,
394
+ error: null,
395
+
396
+ fetchFeeds: async () => {
397
+ set({ loading: true, error: null })
398
+ try {
399
+ const feeds = await feedsService.getAll()
400
+ set({ feeds, loading: false })
401
+ } catch (error) {
402
+ set({ error: error.message, loading: false })
403
+ throw error
404
+ }
405
+ },
406
+ }))
407
+ ```
408
+
409
+ Nota: services são importados como `import * as service` (namespace), não como objeto exportado.
410
+
411
+ ### 9.2 Store — mutação de listas
412
+
413
+ Atualizações imutáveis via `set(state => ...)` com spread + map/filter:
414
+
415
+ ```javascript
416
+ // Atualizar item na lista
417
+ updateFeed: (id, data) => set((state) => ({
418
+ feeds: state.feeds.map((f) => (f.id === id ? { ...f, ...data } : f))
419
+ })),
420
+
421
+ // Remover item
422
+ removeFeed: (id) => set((state) => ({
423
+ feeds: state.feeds.filter((f) => f.id !== id)
424
+ })),
425
+
426
+ // Adicionar item
427
+ addFeed: (feed) => set((state) => ({
428
+ feeds: [...state.feeds, feed]
429
+ })),
430
+ ```
431
+
432
+ ### 9.3 Notifications
433
+
434
+ Shape e convenção de cores consistente em toda a app:
435
+
436
+ ```javascript
437
+ import { notifications } from '@mantine/notifications'
438
+ import { IconCheck, IconX, IconAlertCircle } from '@tabler/icons-react'
439
+
440
+ // ✅ Sucesso
441
+ notifications.show({
442
+ title: t('common.success'),
443
+ message: t('namespace.savedMessage'),
444
+ color: 'green',
445
+ icon: <IconCheck size={18} />,
446
+ })
447
+
448
+ // ✅ Erro
449
+ notifications.show({
450
+ title: t('common.error'),
451
+ message: error.message,
452
+ color: 'red',
453
+ icon: <IconX size={18} />,
454
+ })
455
+
456
+ // ✅ Warning
457
+ notifications.show({
458
+ title: t('common.warning'),
459
+ message: t('namespace.warningMessage'),
460
+ color: 'yellow',
461
+ icon: <IconAlertCircle size={18} />,
462
+ })
463
+ ```
464
+
465
+ Icones de notification: sempre `size={18}`. Mensagens de erro: usa `error.message` diretamente (já vem traduzido do backend).
466
+
467
+ ### 9.4 dayjs + i18n
468
+
469
+ Locale do dayjs sincroniza com o idioma do i18n:
470
+
471
+ ```javascript
472
+ import dayjs from 'dayjs'
473
+ import relativeTime from 'dayjs/plugin/relativeTime'
474
+ import { useTranslation } from 'react-i18next'
475
+
476
+ dayjs.extend(relativeTime)
477
+
478
+ const MyComponent = () => {
479
+ const { i18n } = useTranslation()
480
+
481
+ useEffect(() => {
482
+ dayjs.locale(i18n.language)
483
+ }, [i18n.language])
484
+
485
+ // Formatos usados no projeto:
486
+ // dayjs(date).format('DD MMM, HH:mm') — compacto com hora
487
+ // dayjs(date).format('DD/MM/YYYY [at] HH:mm') — completo
488
+ // dayjs(date).fromNow() — relativo ("há 2 dias")
489
+ }
490
+ ```
491
+
492
+ ---
493
+
494
+ ## 10. Padrões de fluxo
495
+
496
+ ### 10.1 Route Guard (wrapper)
497
+
498
+ Componente que protege rotas verificando estado do store:
499
+
500
+ ```javascript
501
+ import { Navigate } from 'react-router-dom'
502
+ import { useFeedStore } from '../store/feed-store.js'
503
+
504
+ const RequireFeed = ({ children }) => {
505
+ const activeFeed = useFeedStore((s) => s.activeFeed)
506
+ if (!activeFeed) return <Navigate to="/" />
507
+ return children
508
+ }
509
+ ```
510
+
511
+ Usado na definição de rotas: `<RequireFeed><EditorPage /></RequireFeed>`
512
+
513
+ ### 10.2 Notificação via URL params
514
+
515
+ Após redirects externos (OAuth, Stripe checkout), status vem via query params:
516
+
517
+ ```javascript
518
+ import { useSearchParams } from 'react-router-dom'
519
+
520
+ const SubscriptionPage = () => {
521
+ const [searchParams, setSearchParams] = useSearchParams()
522
+ const { t } = useTranslation()
523
+
524
+ useEffect(() => {
525
+ if (searchParams.get('success')) {
526
+ notifications.show({ title: t('common.success'), message: t('subscription.successMessage'), color: 'green', icon: <IconCheck size={18} /> })
527
+ setSearchParams({})
528
+ } else if (searchParams.get('canceled')) {
529
+ notifications.show({ title: t('common.warning'), message: t('subscription.canceledMessage'), color: 'yellow', icon: <IconAlertCircle size={18} /> })
530
+ setSearchParams({})
531
+ }
532
+ }, [searchParams])
533
+ }
534
+ ```
535
+
536
+ ### 10.3 Autosave
537
+
538
+ Padrão usado no editor — debounce com state machine de status:
539
+
540
+ ```javascript
541
+ const [saveStatus, setSaveStatus] = useState('idle') // 'idle' | 'saving' | 'saved'
542
+
543
+ useEffect(() => {
544
+ if (!content) return
545
+ const timeout = setTimeout(async () => {
546
+ setSaveStatus('saving')
547
+ try {
548
+ await postsService.update(postId, { content })
549
+ setSaveStatus('saved')
550
+ // Reset para idle após 3s
551
+ setTimeout(() => setSaveStatus('idle'), 3000)
552
+ } catch {
553
+ setSaveStatus('idle')
554
+ }
555
+ }, 2000) // debounce de 2s
556
+
557
+ return () => clearTimeout(timeout)
558
+ }, [content, postId])
559
+ ```
560
+
561
+ ---
562
+
563
+ ## 11. Convenção de tamanhos de icones
564
+
565
+ Hierarquia consistente — sempre de `@tabler/icons-react`:
566
+
567
+ | Contexto | Size | Exemplo |
568
+ |---|---|---|
569
+ | Menu items / nav | 14 | Sidebar links |
570
+ | Inline / badges | 16 | Botões, labels, leftSection |
571
+ | Notifications | 18 | Icons nas notifications |
572
+ | Card headers | 20 | Ação principal do card |
573
+ | Feature cards | 24 | Cards de destaque |
574
+ | Empty states | 48 | Icone do empty state (com `stroke={1}`) |
575
+
576
+ Empty states usam `stroke={1}` para parecer mais leve. Icones decorativos genéricos usam `stroke={1.5}`.
577
+
578
+ ---
579
+
580
+ ## Related Skills
581
+
582
+ - @[.agent/skills/riligar-design-system]
@@ -0,0 +1,44 @@
1
+ # Dependências Frontend
2
+
3
+ ## Core
4
+
5
+ | Pacote | Versão | Descrição |
6
+ |---|---|---|
7
+ | `react` | ^19.x | Biblioteca UI |
8
+ | `react-dom` | ^19.x | React DOM renderer |
9
+ | `react-router-dom` | ^7.x | Roteamento |
10
+ | `vite` | ^5.x | Build tool |
11
+ | `zustand` | ^5.x | Gerenciamento de estado |
12
+ | `ky` | ^1.x | HTTP client |
13
+
14
+ ## UI
15
+
16
+ | Pacote | Versão | Descrição |
17
+ |---|---|---|
18
+ | `@mantine/core` | ^8.x | Componentes UI |
19
+ | `@mantine/hooks` | ^8.x | Hooks utilitários |
20
+ | `@mantine/form` | ^8.x | Gerenciamento de formulários |
21
+ | `@mantine/notifications` | ^8.x | Sistema de notificações |
22
+ | `@tabler/icons-react` | ^3.x | Iconografia |
23
+
24
+ > Use apenas Mantine para estilização. Sem CSS Modules, Custom CSS ou CSS In-line.
25
+
26
+ ## Configuração Vite
27
+
28
+ ```javascript
29
+ import { defineConfig } from 'vite'
30
+ import react from '@vitejs/plugin-react'
31
+
32
+ export default defineConfig({
33
+ plugins: [react()],
34
+ build: {
35
+ lib: {
36
+ entry: 'src/index.js',
37
+ formats: ['es', 'cjs'],
38
+ },
39
+ rollupOptions: {
40
+ external: ['react', 'react-dom', '@mantine/core'],
41
+ },
42
+ },
43
+ })
44
+ ```
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: riligar-dev-backend
2
+ name: riligar-dev-manager
3
3
  description: Elysia backend development patterns for Bun. Use when building APIs, routes, plugins, validation, middleware, and error handling with Elysia framework.
4
4
  ---
5
5
 
@@ -10,10 +10,7 @@ description: Elysia backend development patterns for Bun. Use when building APIs
10
10
  ## Mandatory Guidelines
11
11
 
12
12
  > [!IMPORTANT]
13
- > All work in this skill MUST adhere to:
14
- >
15
- > - @[.agent/skills/riligar-dev-clean-code] (Clean Code Standards)
16
- > - @[.agent/skills/riligar-tech-stack] (Tech Stack - Bun, Elysia, SQLite, Drizzle)
13
+ > All work in this skill MUST adhere to rules em `.agent/rules/` — clean-code, code-style, javascript-only, naming-conventions.
17
14
 
18
15
  ## Quick Reference
19
16
 
@@ -62,6 +59,16 @@ src/
62
59
  └── logger.js # Request logging
63
60
  ```
64
61
 
62
+ ## Dependencies
63
+
64
+ | Pacote | Versão | Descrição |
65
+ |---|---|---|
66
+ | `bun` | latest | Runtime |
67
+ | `elysia` | latest | Framework HTTP |
68
+ | `bun:sqlite` | builtin | SQLite driver |
69
+ | `drizzle-orm` | latest | ORM |
70
+ | `bun:s3` | latest | S3/R2 Storage |
71
+
65
72
  ## Core Patterns
66
73
 
67
74
  ### Route Plugin
@@ -108,10 +115,7 @@ console.log(`Server running at ${app.server?.url}`)
108
115
  | Need | Skill |
109
116
  | --- | --- |
110
117
  | **Authentication** | @[.agent/skills/riligar-dev-auth-elysia] |
111
- | **Database** | @[.agent/skills/riligar-dev-database] |
112
- | **Tech Stack** | @[.agent/skills/riligar-tech-stack] |
113
- | **Clean Code** | @[.agent/skills/riligar-dev-clean-code] |
114
- | **Infrastructure** | @[.agent/skills/riligar-infrastructure] |
118
+ | **Infrastructure** | @[.agent/skills/riligar-infra-fly] |
115
119
 
116
120
  ## Decision Checklist
117
121
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: riligar-dev-landing-page
2
+ name: riligar-dev-website
3
3
  description: Specialist in High-Conversion Landing Pages using RiLiGar Design System. Use for: (1) Creating marketing/sales pages, (2) Structuring conversion flows (AIDA/PAS), (3) Implementing high-trust components (Hero, Social Proof, Pricing), (4) Writing persuasive copy.
4
4
  ---
5
5
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: riligar-dev-seo
2
+ name: riligar-dev-website-seo
3
3
  description: Implementação de infraestrutura de SEO técnico seguindo a stack RiLiGar (React, Vite, Bun, Elysia). Use para configurar sitemaps, robots.txt, meta tags, OpenGraph, dados estruturados (JSON-LD) e URLs canônicas.
4
4
  ---
5
5