feat: adicionar plugin acidaos e skill prompt-refine
Plugin acidaos (novo): - rust-dev: desenvolvimento Core em Rust (Axum, crates, debug compiler) - spoke-dev: desenvolvimento Spokes em Next.js/TypeScript + Storybook - devops: pipelines Gitea Actions CI/CD (adaptado de GitHub para Gitea) - docs: rustdoc, TypeDoc, Outline e ADRs dev-tools: - prompt-refine: skill genérica de engenharia de prompts para agentes IA Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,239 @@
|
||||
---
|
||||
name: spoke-dev
|
||||
description: Desenvolvimento de Spokes do AcidaOS em Next.js/TypeScript — criar aplicações Spoke, componentes React com testes e Storybook. Usar quando "spoke", "dashboard acidaos", "next.js acidaos", "componente react acidaos", "ts-create-spoke", "acidaos ui", "acidaos frontend".
|
||||
allowed-tools: Read, Write, Edit, Bash, mcp__memory-supabase__search_memories, mcp__gitea__get_file_content, mcp__gitea__create_file, mcp__gitea__update_file
|
||||
---
|
||||
|
||||
# AcidaOS Spoke Dev
|
||||
|
||||
Skill para desenvolvimento dos **Spokes do AcidaOS** em Next.js/TypeScript.
|
||||
|
||||
## Contexto do Projecto
|
||||
|
||||
Os Spokes são as aplicações de interface que comunicam com o Core via API interna:
|
||||
|
||||
```
|
||||
acidaos-dashboard (Next.js 15 + App Router)
|
||||
├── src/
|
||||
│ ├── app/ ← App Router pages
|
||||
│ ├── components/ ← Componentes React
|
||||
│ │ ├── ui/ ← Componentes base (shadcn/ui)
|
||||
│ │ └── features/ ← Componentes de funcionalidade
|
||||
│ ├── lib/
|
||||
│ │ ├── api/ ← Client para AcidaOS Core API
|
||||
│ │ └── hooks/ ← React hooks custom
|
||||
│ └── types/ ← TypeScript types partilhados
|
||||
├── __tests__/ ← Jest + Testing Library
|
||||
└── .storybook/ ← Storybook
|
||||
```
|
||||
|
||||
**Stack:** Next.js 15 | TypeScript 5 | React 19 | Tailwind CSS | shadcn/ui | Vercel AI SDK | Vitest | Playwright
|
||||
|
||||
## Protocolo Inicial
|
||||
|
||||
```
|
||||
mcp__memory-supabase__search_memories "acidaos spoke dashboard [componente]"
|
||||
mcp__gitea__get_file_content acidaos-dashboard/package.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Operações
|
||||
|
||||
### 1. Criar nova aplicação Spoke (`/ts-create-spoke-app`)
|
||||
|
||||
**Input:** Nome do Spoke e propósito
|
||||
|
||||
**Estrutura a criar:**
|
||||
```bash
|
||||
# No container dev (Regra #48)
|
||||
cd /root/Dev
|
||||
npx create-next-app@latest acidaos-<nome> \
|
||||
--typescript \
|
||||
--tailwind \
|
||||
--app \
|
||||
--src-dir \
|
||||
--import-alias "@/*" \
|
||||
--no-git
|
||||
```
|
||||
|
||||
**Ficheiros obrigatórios após scaffold:**
|
||||
|
||||
`src/lib/api/core-client.ts` — cliente para o Core:
|
||||
```typescript
|
||||
/**
|
||||
* AcidaOS Core API Client
|
||||
*
|
||||
* @author Descomplicar® Crescimento Digital
|
||||
* @link https://descomplicar.pt
|
||||
*/
|
||||
|
||||
const CORE_API_URL = process.env.ACIDAOS_CORE_URL ?? 'http://localhost:3001';
|
||||
|
||||
export async function coreRequest<T>(
|
||||
endpoint: string,
|
||||
options?: RequestInit
|
||||
): Promise<T> {
|
||||
const res = await fetch(`${CORE_API_URL}${endpoint}`, {
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-AcidaOS-Version': '1',
|
||||
...options?.headers,
|
||||
},
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`Core API error: ${res.status} ${res.statusText}`);
|
||||
}
|
||||
|
||||
return res.json() as Promise<T>;
|
||||
}
|
||||
```
|
||||
|
||||
`src/types/index.ts` — tipos base:
|
||||
```typescript
|
||||
export interface AgentTask {
|
||||
id: string;
|
||||
status: 'pending' | 'running' | 'completed' | 'failed';
|
||||
createdAt: string;
|
||||
completedAt?: string;
|
||||
}
|
||||
|
||||
export interface CoreHealth {
|
||||
status: 'healthy' | 'degraded' | 'down';
|
||||
version: string;
|
||||
uptime: number;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. Criar componente React (`/ts-create-react-component`)
|
||||
|
||||
**Input:** Descrição do componente (nome, props, comportamento)
|
||||
|
||||
**Template base — componente:**
|
||||
|
||||
`src/components/features/<Nome>/<Nome>.tsx`:
|
||||
```typescript
|
||||
/**
|
||||
* <Nome> — <Descrição curta>
|
||||
*
|
||||
* @author Descomplicar® Crescimento Digital
|
||||
*/
|
||||
|
||||
import { type FC } from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
interface <Nome>Props {
|
||||
// props do componente
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const <Nome>: FC<<Nome>Props> = ({ className }) => {
|
||||
return (
|
||||
<div className={cn('', className)}>
|
||||
{/* conteúdo */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
<Nome>.displayName = '<Nome>';
|
||||
```
|
||||
|
||||
**Template — teste (Vitest + Testing Library):**
|
||||
|
||||
`src/components/features/<Nome>/<Nome>.test.tsx`:
|
||||
```typescript
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { <Nome> } from './<Nome>';
|
||||
|
||||
describe('<Nome>', () => {
|
||||
it('renderiza sem erros', () => {
|
||||
render(<<Nome> />);
|
||||
// asserção específica ao componente
|
||||
});
|
||||
|
||||
it('aceita className personalizada', () => {
|
||||
const { container } = render(<<Nome> className="test-class" />);
|
||||
expect(container.firstChild).toHaveClass('test-class');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**Template — Storybook:**
|
||||
|
||||
`src/components/features/<Nome>/<Nome>.stories.tsx`:
|
||||
```typescript
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { <Nome> } from './<Nome>';
|
||||
|
||||
const meta: Meta<typeof <Nome>> = {
|
||||
title: 'Features/<Nome>',
|
||||
component: <Nome>,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof <Nome>>;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
};
|
||||
```
|
||||
|
||||
**Criar index de exportação:**
|
||||
|
||||
`src/components/features/<Nome>/index.ts`:
|
||||
```typescript
|
||||
export { <Nome> } from './<Nome>';
|
||||
export type { <Nome>Props } from './<Nome>';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Padrões Obrigatórios
|
||||
|
||||
### TypeScript
|
||||
- `strict: true` em `tsconfig.json` — sem `any` implícito
|
||||
- Props sempre tipadas com interface exportada
|
||||
- Hooks custom em `src/lib/hooks/use<Nome>.ts`
|
||||
- Server Components por defeito; `'use client'` apenas quando necessário
|
||||
|
||||
### Performance
|
||||
- `next/image` para todas as imagens
|
||||
- `loading="lazy"` em componentes pesados
|
||||
- `Suspense` boundaries em torno de data-fetching
|
||||
- Cache de API calls com `unstable_cache` ou React cache
|
||||
|
||||
### Segurança
|
||||
- Nunca expor `ACIDAOS_CORE_URL` no cliente (apenas server-side)
|
||||
- Sanitizar input do utilizador antes de enviar ao Core
|
||||
- Usar Next.js Server Actions para mutações
|
||||
|
||||
---
|
||||
|
||||
## Quality Gate
|
||||
|
||||
```bash
|
||||
pnpm build # zero erros TypeScript
|
||||
pnpm test # todos os testes passam
|
||||
pnpm lint # zero erros ESLint
|
||||
```
|
||||
|
||||
## Checklist Entrega
|
||||
|
||||
- [ ] Tipos TypeScript sem `any`
|
||||
- [ ] Testes criados (>80% cobertura)
|
||||
- [ ] Story Storybook criada
|
||||
- [ ] `displayName` definido no componente
|
||||
- [ ] `pnpm build` sem erros
|
||||
- [ ] Client/Server components correctamente marcados
|
||||
- [ ] CHANGELOG.md actualizado
|
||||
|
||||
---
|
||||
**Versão**: 1.0.0 | **Autor**: Descomplicar® | **Plugin**: acidaos
|
||||
Reference in New Issue
Block a user