feat: add Next.js, Vue/Nuxt, React, Python (Django/FastAPI) skills and agents

- python-developer agent: Django/FastAPI backend specialist
- nextjs-patterns skill: App Router, Server Components, Server Actions, Auth.js
- vue-nuxt-patterns skill: Composition API, Pinia, Nitro server, SSR
- react-patterns skill: hooks, Context, TanStack Query, React Hook Form
- python-django-patterns skill: DRF, services, repositories
- python-fastapi-patterns skill: async, Pydantic, SQLAlchemy, dependencies
- /nextjs pipeline command for full-stack Next.js apps
- /vue pipeline command for full-stack Vue/Nuxt apps
- Updated frontend-developer with framework-specific skills
- Updated orchestrator, capability-index for Python + frontend routing
- Updated README, STRUCTURE, EVOLUTION_LOG with all new stacks

Total agents: 30. Stacks: PHP, Next.js, Vue/Nuxt, React, Python, Go, Flutter, Node.js
This commit is contained in:
¨NW¨
2026-04-19 10:04:51 +01:00
parent b46a1a20a8
commit 7445e66676
15 changed files with 1942 additions and 9 deletions

View File

@@ -326,3 +326,81 @@ Capability Expansion + Architecture Improvements — 7 evolutionary tasks
- New rules: 4 (atomic-tasks, modular-code, token-optimization, gitea-centric)
- Hardcoded APAW refs fixed: 15+ across 5 files
- Documentation pages updated: 3 (README, STRUCTURE, EVOLUTION_LOG)
---
## Entry: 2026-04-19T10:00:00+01:00
### Type
Capability Expansion — Frontend framework skills + Python development stack
### Gap Analysis
1. No Next.js patterns — most popular full-stack React framework
2. No Vue/Nuxt patterns — major frontend framework
3. No React-only patterns — base for Next.js and many SPAs
4. No Python backend support (Django, FastAPI)
5. Frontend developer had no framework-specific skills
### Implementation
#### New Agent
| Agent | Model | Purpose |
|-------|-------|---------|
| `python-developer` | qwen3-coder:480b | Python/Django/FastAPI backend |
#### New Skills (5)
| Skill | Lines | Purpose |
|-------|-------|---------|
| `nextjs-patterns` | 290 | Next.js 14+ App Router, Server Components, Server Actions, Auth.js, API Routes |
| `vue-nuxt-patterns` | 270 | Vue 3 / Nuxt 3 Composition API, Pinia, Nitro server, SSR |
| `react-patterns` | 240 | React 18+ hooks, Context, TanStack Query, React Hook Form |
| `python-django-patterns` | 200 | Django models, DRF serializers, services, repositories |
| `python-fastapi-patterns` | 230 | FastAPI async, Pydantic schemas, SQLAlchemy, dependencies |
#### New Commands
| Command | Purpose |
|---------|---------|
| `/nextjs` | Full-stack Next.js 14+ app pipeline |
| `/vue` | Full-stack Vue/Nuxt 3 app pipeline |
#### Updated Agent
| Agent | Change |
|-------|--------|
| `frontend-developer` | Added skills: nextjs-patterns, vue-nuxt-patterns, react-patterns |
#### Updated Config
| File | Change |
|------|--------|
| `orchestrator.md` | Added python-developer permission + delegation |
| `capability-index.yaml` | Added python-developer + frontend framework capabilities + routing |
### Files Modified
- `.kilo/agents/orchestrator.md` — python-developer permission + delegation
- `.kilo/agents/frontend-developer.md` — framework skills table
- `.kilo/capability-index.yaml` — python-developer + frontend routing
- `AGENTS.md` — python-developer, frontend update, new commands
### New Files Created
- `.kilo/agents/python-developer.md`
- `.kilo/commands/nextjs.md`
- `.kilo/commands/vue.md`
- `.kilo/skills/nextjs-patterns/SKILL.md`
- `.kilo/skills/vue-nuxt-patterns/SKILL.md`
- `.kilo/skills/react-patterns/SKILL.md`
- `.kilo/skills/python-django-patterns/SKILL.md`
- `.kilo/skills/python-fastapi-patterns/SKILL.md`
### Verification
- [x] Python developer agent created with valid YAML frontmatter
- [x] Orchestrator permissions updated for python-developer
- [x] Capability index updated with python + frontend routing
- [x] Frontend developer has framework-specific skills
- [x] YAML validated (capability-index.yaml)
- [x] README updated with all frameworks
- [x] STRUCTURE updated with all skills
### Metrics
- New agents: 1 (python-developer, total now 30)
- New skills: 5 (3 frontend + 2 Python)
- New commands: 2 (nextjs, vue)
- Supported stacks: PHP, Next.js, Vue/Nuxt, React, Python, Go, Flutter, Node.js

View File

@@ -27,6 +27,7 @@ UI specialist: implement from screenshots/mockups, responsive, accessible, pixel
- Accessibility first: semantic HTML, ARIA labels, keyboard navigation
- Responsive by default: mobile-first approach
- Component composition: build small, reusable parts
- Framework-aware: Next.js App Router, Vue/Nuxt Composition API, React hooks
## Delegates
| Agent | When |
@@ -43,6 +44,14 @@ UI specialist: implement from screenshots/mockups, responsive, accessible, pixel
<files><!-- list: all created/modified files --></files>
</impl>
## Skills
| Skill | When |
|-------|------|
| nextjs-patterns | Next.js 14+ App Router, Server Components, Server Actions |
| vue-nuxt-patterns | Vue 3 / Nuxt 3 Composition API, Pinia, SSR |
| react-patterns | React 18+ hooks, context, TanStack Query |
| flutter-widgets | Flutter widget patterns |
## Handoff
1. Verify visual match to design
2. Check accessibility

View File

@@ -42,6 +42,7 @@ permission:
"memory-manager": allow
"agent-architect": allow
"php-developer": allow
"python-developer": allow
---
# Orchestrator
@@ -72,6 +73,7 @@ Task dispatcher and state machine manager. Route by issue status; enforce workfl
| frontend-developer | UI implementation needed |
| backend-developer | Node.js/Express/API work |
| php-developer | PHP/Laravel/Symfony/WordPress web apps |
| python-developer | Python/Django/FastAPI/API work |
| go-developer | Go backend services |
| flutter-developer | Flutter mobile apps |
| performance-engineer | Review pass: check performance |

View File

@@ -0,0 +1,62 @@
---
description: Python backend specialist for Django, FastAPI, data science, and API development
mode: subagent
model: ollama-cloud/qwen3-coder:480b
variant: thinking
color: "#3776AB"
permission:
read: allow
edit: allow
write: allow
bash: allow
glob: allow
grep: allow
task:
"*": deny
"code-skeptic": allow
"security-auditor": allow
"orchestrator": allow
---
# Python Developer
## Role
Python backend specialist: Django/FastAPI APIs, database integration, async patterns, authentication, modular architecture.
## Behavior
- Security first: validate input, parameterized queries, auth middleware
- RESTful design: proper HTTP methods, status codes, error handling
- Async with FastAPI, sync with Django — follow framework conventions
- Type hints everywhere, Pydantic for validation
- Separate services/repositories from routes/views
- Write tests with pytest before implementation (TDD)
## Delegates
| Agent | When |
|-------|------|
| code-skeptic | After implementation |
| security-auditor | For security review |
## Output
<impl agent="python-developer">
<endpoints><!-- table: method, path, description --></endpoints>
<database><!-- table, columns, indexes --></database>
<files><!-- list: all created/modified files --></files>
<security><!-- checklist: validation, injection protection, auth --></security>
</impl>
## Skills
| Skill | When |
|-------|------|
| python-django-patterns | Django models, DRF, services, repositories |
| python-fastapi-patterns | FastAPI routes, Pydantic, async, dependencies |
| php-security | OWASP common patterns (shared with PHP) |
| php-testing | pytest patterns (adapted for Python) |
## Handoff
1. Run `pytest` with coverage
2. Run `ruff check .` for linting
3. Run `mypy .` for type checking
4. Delegate: code-skeptic
<gitea-commenting required="true" skill="gitea-commenting" />

View File

@@ -32,12 +32,18 @@ agents:
- component_creation
- styling
- responsive_design
- nextjs_development
- vue_nuxt_development
- react_development
receives:
- designs
- wireframes
- api_endpoints
produces:
- vue_components
- react_components
- nextjs_pages
- nuxt_pages
- css_styles
- frontend_tests
forbidden:
@@ -84,6 +90,39 @@ agents:
- security-auditor
- orchestrator
python-developer:
capabilities:
- python_web_development
- django_development
- fastapi_development
- python_api_development
- python_database_design
- python_authentication
- python_async_patterns
- python_testing
- python_security
receives:
- api_specifications
- database_requirements
produces:
- django_views
- fastapi_routers
- python_models
- python_services
- python_schemas
- python_migrations
- python_tests
forbidden:
- frontend_code
- non_python_backend
model: ollama-cloud/qwen3-coder:480b
variant: thinking
mode: subagent
delegates_to:
- code-skeptic
- security-auditor
- orchestrator
backend-developer:
capabilities:
- api_development
@@ -459,6 +498,7 @@ agents:
- frontend-developer
- backend-developer
- php-developer
- python-developer
- go-developer
- flutter-developer
- performance-engineer
@@ -714,6 +754,9 @@ agents:
bug_fixing: the-fixer
git_operations: release-manager
ui_implementation: frontend-developer
nextjs_development: frontend-developer
vue_nuxt_development: frontend-developer
react_development: frontend-developer
e2e_testing: browser-automation
visual_testing: visual-tester
bbox_extraction: visual-tester
@@ -741,6 +784,10 @@ agents:
laravel_development: php-developer
symfony_development: php-developer
wordpress_development: php-developer
# Python Development
python_web_development: python-developer
django_development: python-developer
fastapi_development: python-developer
# DevOps
docker_configuration: devops-engineer
kubernetes_setup: devops-engineer

118
.kilo/commands/nextjs.md Normal file
View File

@@ -0,0 +1,118 @@
---
description: Full-stack Next.js web application pipeline with App Router, SSR, and authentication
mode: nextjs
model: ollama-cloud/qwen3-coder:480b
variant: thinking
color: "#0EA5E9"
permission:
read: allow
edit: allow
write: allow
bash: allow
glob: allow
grep: allow
task:
"*": deny
"frontend-developer": allow
"backend-developer": allow
"system-analyst": allow
"lead-developer": allow
"sdet-engineer": allow
"code-skeptic": allow
"the-fixer": allow
"devops-engineer": allow
"release-manager": allow
"security-auditor": allow
"orchestrator": allow
---
# Next.js Web Application Pipeline
Create a full-stack Next.js 14+ application with App Router, Server Components, API routes, Auth.js, and Docker deployment. Follows atomic task decomposition.
## Parameters
- `project_name`: Application name (required)
- `auth`: Auth provider - 'authjs', 'clerk', 'supabase' (default: 'authjs')
- `database`: Database - 'prisma', 'drizzle' (default: 'prisma')
- `ui`: UI library - 'tailwind', 'shadcn', 'mui' (default: 'shadcn')
- `docker`: Create Docker deployment (default: true)
- `issue`: Gitea issue number for tracking (required)
## Overview
```
Requirements → Architecture → Setup → Pages → API → Auth → Frontend → Tests → Docker
```
## Atomic Task Decomposition
### Step 1: Requirements (1 task)
**Agent**: `@requirement-refiner` — Create issue in TARGET PROJECT
### Step 2: Architecture (1 task)
**Agent**: `@system-analyst` — Design routes, API, database schema
### Step 3: Project Setup (1 task)
**Agent**: `@frontend-developer`
```bash
npx create-next-app@latest {project_name} --typescript --tailwind --eslint --app --src-dir
cd {project_name}
npx shadcn@latest init
```
### Step 4: Database + Models (1 task per model)
**Agent**: `@backend-developer` or `@frontend-developer`
- Prisma schema or Drizzle definitions
- Run `npx prisma migrate dev`
### Step 5: API Routes (1 task per resource)
**Agent**: `@backend-developer` (ONE invocation per resource)
- GET, POST, PUT, DELETE handlers
- Zod validation schemas
### Step 6: Authentication (1 task)
**Agent**: `@frontend-developer`
- Auth.js / Clerk / Supabase setup
- Login/Register pages
- Middleware for protected routes
### Step 7: UI Pages (1 task per page/layout)
**Agent**: `@frontend-developer` (ONE invocation per page)
- Server Components by default
- `'use client'` only for interactivity
- Shadcn UI components
### Step 8: Server Actions (1 task per form)
**Agent**: `@frontend-developer`
- Form validation with Zod
- `revalidatePath` after mutations
### Step 9: Tests (1 task per test suite)
**Agent**: `@sdet-engineer` — Vitest + Playwright
### Step 10: Review → Security → Docker → Release
## Task Sizing
| Task | Agent | Max Tokens |
|------|-------|-----------|
| Setup project | frontend-developer | 5,000 |
| Database schema | backend-developer | 5,000 |
| API route (CRUD) | backend-developer | 5,000 |
| Auth setup | frontend-developer | 8,000 |
| Page + components | frontend-developer | 8,000 |
| Server actions | frontend-developer | 5,000 |
| Tests | sdet-engineer | 8,000 |
| Docker | devops-engineer | 5,000 |
## Quality Gates
| Gate | Criteria |
|------|----------|
| Setup | `npm run build` succeeds |
| API | All endpoints return correct responses |
| Auth | Login/register/logout work |
| Pages | Lighthouse ≥ 90 |
| Tests | Coverage ≥ 80% |
| Docker | Containers build and run |

107
.kilo/commands/vue.md Normal file
View File

@@ -0,0 +1,107 @@
---
description: Full-stack Vue/Nuxt web application pipeline with SSR, Pinia, and Nitro server
mode: vue
model: ollama-cloud/qwen3-coder:480b
variant: thinking
color: "#42B883"
permission:
read: allow
edit: allow
write: allow
bash: allow
glob: allow
grep: allow
task:
"*": deny
"frontend-developer": allow
"backend-developer": allow
"system-analyst": allow
"lead-developer": allow
"sdet-engineer": allow
"code-skeptic": allow
"the-fixer": allow
"devops-engineer": allow
"release-manager": allow
"security-auditor": allow
"orchestrator": allow
---
# Vue/Nuxt Web Application Pipeline
Create a full-stack Nuxt 3 application with Composition API, Pinia, server API routes, and Docker deployment.
## Parameters
- `project_name`: Application name (required)
- `ui`: UI library - 'tailwind', 'vuetify', 'primevue' (default: 'tailwind')
- `auth`: Auth - 'local', 'supabase', 'firebase' (default: 'local')
- `database`: Database - 'prisma', 'drizzle' (default: 'prisma')
- `docker`: Create Docker deployment (default: true)
- `issue`: Gitea issue number for tracking (required)
## Overview
```
Requirements → Architecture → Setup → Pages → Server API → Auth → Components → Tests → Docker
```
## Atomic Task Decomposition
### Step 1: Requirements (1 task)
**Agent**: `@requirement-refiner` — Create issue in TARGET PROJECT
### Step 2: Architecture (1 task)
**Agent**: `@system-analyst` — Design pages, API routes, database schema
### Step 3: Project Setup (1 task)
**Agent**: `@frontend-developer`
```bash
npx nuxi@latest init {project_name}
cd {project_name}
npx nuxi module add @pinia/nuxt
npx nuxi module add @nuxtjs/tailwindcss
```
### Step 4: Server API Routes (1 task per resource)
**Agent**: `@backend-developer` or `@frontend-developer`
- `server/api/products/index.get.ts`
- `server/api/products/[id].get.ts`
- `server/api/products/index.post.ts`
### Step 5: Pinia Stores (1 task per store)
**Agent**: `@frontend-developer`
- `stores/auth.ts`
- `stores/cart.ts`
### Step 6: Composables (1 task per composable)
**Agent**: `@frontend-developer`
- `composables/useAuth.ts`
- `composables/useCart.ts`
### Step 7: Pages + Layouts (1 task per page)
**Agent**: `@frontend-developer` (ONE invocation per page)
- `<script setup lang="ts">` with Composition API
- `useFetch()` for data loading
- NuxtLink for navigation
### Step 8: Components (1 task per component)
**Agent**: `@frontend-developer`
### Step 9: Route Middleware (1 task)
**Agent**: `@frontend-developer`
### Step 10: Tests (1 task per suite)
**Agent**: `@sdet-engineer` — Vitest + Playwright
### Step 11: Review → Security → Docker → Release
## Quality Gates
| Gate | Criteria |
|------|----------|
| Setup | `npm run build` succeeds |
| API | All server routes return correct responses |
| Auth | Login/logout work, middleware protects |
| Pages | SSR renders correctly |
| Tests | Coverage ≥ 80% |
| Docker | Containers build and run |

View File

@@ -0,0 +1,301 @@
---
name: nextjs-patterns
description: Next.js 14+ patterns — App Router, Server Components, Server Actions, API Routes, Auth.js, middleware, ISR/SSR/SSG
---
# Next.js Patterns
## Project Structure
```
src/
├── app/ # App Router (Next.js 14+)
│ ├── layout.tsx # Root layout
│ ├── page.tsx # Home page
│ ├── loading.tsx # Loading UI
│ ├── error.tsx # Error boundary
│ ├── not-found.tsx # 404 page
│ ├── globals.css # Global styles
│ ├── (auth)/ # Route group: auth
│ │ ├── login/page.tsx
│ │ └── register/page.tsx
│ ├── (dashboard)/ # Route group: dashboard
│ │ ├── layout.tsx # Dashboard layout (sidebar)
│ │ ├── page.tsx # Dashboard home
│ │ ├── products/
│ │ │ ├── page.tsx # Product list
│ │ │ └── [id]/page.tsx # Product detail
│ │ └── settings/page.tsx
│ └── api/ # API Routes
│ ├── auth/[...nextauth]/route.ts
│ ├── products/route.ts
│ └── webhooks/stripe/route.ts
├── components/
│ ├── ui/ # Base UI (Button, Input, Card, Dialog)
│ ├── forms/ # Form components
│ ├── layouts/ # Layout components
│ └── features/ # Feature-specific components
├── lib/
│ ├── api.ts # API client (fetch wrapper)
│ ├── auth.ts # Auth configuration
│ ├── db.ts # Database client
│ └── utils.ts # Utilities
├── actions/ # Server Actions
│ ├── products.ts
│ └── auth.ts
├── types/ # TypeScript types
└── middleware.ts # Route middleware
```
## App Router Patterns
### Server Component (default)
```tsx
// app/products/page.tsx — Server Component (default in app/)
import { prisma } from '@/lib/db';
export default async function ProductsPage() {
const products = await prisma.product.findMany({
where: { isActive: true },
include: { category: true },
orderBy: { createdAt: 'desc' },
});
return (
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{products.map((product) => (
<ProductCard key={product.id} product={product} />
))}
</div>
);
}
```
### Client Component (interactive)
```tsx
'use client';
import { useState } from 'react';
export function ProductFilters({ categories, onFilter }: Props) {
const [selected, setSelected] = useState<string[]>([]);
return (
<div className="flex flex-wrap gap-2">
{categories.map((cat) => (
<button
key={cat.id}
onClick={() => {
const next = selected.includes(cat.id)
? selected.filter((s) => s !== cat.id)
: [...selected, cat.id];
setSelected(next);
onFilter(next);
}}
className={cn('px-3 py-1 rounded-full text-sm', {
'bg-blue-600 text-white': selected.includes(cat.id),
'bg-gray-100 text-gray-700': !selected.includes(cat.id),
})}
>
{cat.name}
</button>
))}
</div>
);
}
```
### Dynamic Route with Suspense
```tsx
// app/products/[id]/page.tsx
import { Suspense } from 'react';
async function ProductDetail({ id }: { id: string }) {
const product = await getProduct(id);
return <ProductView product={product} />;
}
export default function Page({ params }: { params: { id: string } }) {
return (
<Suspense fallback={<ProductSkeleton />}>
<ProductDetail id={params.id} />
</Suspense>
);
}
```
## Server Actions
```tsx
// actions/products.ts
'use server';
import { revalidatePath } from 'next/cache';
import { prisma } from '@/lib/db';
import { productSchema } from '@/types/product';
export async function createProduct(formData: FormData) {
const raw = Object.fromEntries(formData);
const data = productSchema.parse(raw);
const product = await prisma.product.create({ data });
revalidatePath('/products');
return product;
}
export async function deleteProduct(id: string) {
await prisma.product.delete({ where: { id } });
revalidatePath('/products');
}
```
## API Routes
```ts
// app/api/products/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { prisma } from '@/lib/db';
import { z } from 'zod';
const createSchema = z.object({
name: z.string().min(1).max(255),
price: z.number().positive(),
categoryId: z.string().cuid(),
});
export async function GET(req: NextRequest) {
const { searchParams } = new URL(req.url);
const page = parseInt(searchParams.get('page') || '1');
const limit = parseInt(searchParams.get('limit') || '20');
const [products, total] = await Promise.all([
prisma.product.findMany({
skip: (page - 1) * limit,
take: limit,
include: { category: true },
}),
prisma.product.count(),
]);
return NextResponse.json({
data: products,
meta: { page, limit, total, pages: Math.ceil(total / limit) },
});
}
export async function POST(req: NextRequest) {
const body = await req.json();
const data = createSchema.parse(body);
const product = await prisma.product.create({ data });
return NextResponse.json(product, { status: 201 });
}
```
## Authentication (Auth.js / NextAuth v5)
```ts
// lib/auth.ts
import NextAuth from 'next-auth';
import GitHub from 'next-auth/providers/github';
import Credentials from 'next-auth/providers/credentials';
import { prisma } from '@/lib/db';
export const { handlers, auth, signIn, signOut } = NextAuth({
providers: [
GitHub,
Credentials({
credentials: {
email: { label: 'Email', type: 'email' },
password: { label: 'Password', type: 'password' },
},
async authorize(credentials) {
const user = await prisma.user.findUnique({
where: { email: credentials.email as string },
});
if (!user || !verifyPassword(credentials.password as string, user.password)) {
return null;
}
return user;
},
}),
],
pages: {
signIn: '/login',
signUp: '/register',
},
});
// app/api/auth/[...nextauth]/route.ts
import { handlers } from '@/lib/auth';
export const { GET, POST } = handlers;
```
## Middleware
```ts
// middleware.ts
import { auth } from '@/lib/auth';
import { NextResponse } from 'next/server';
export default auth((req) => {
const isAuth = !!req.auth;
const isAuthPage = req.nextUrl.pathname.startsWith('/login') ||
req.nextUrl.pathname.startsWith('/register');
const isProtected = req.nextUrl.pathname.startsWith('/dashboard');
if (isProtected && !isAuth) {
return NextResponse.redirect(new URL('/login', req.url));
}
if (isAuthPage && isAuth) {
return NextResponse.redirect(new URL('/dashboard', req.url));
}
return NextResponse.next();
});
export const config = {
matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};
```
## Data Fetching Patterns
```tsx
// Parallel data fetching
async function DashboardPage() {
const [stats, recentOrders, topProducts] = await Promise.all([
getDashboardStats(),
getRecentOrders(10),
getTopProducts(5),
]);
return <DashboardView stats={stats} orders={recentOrders} products={topProducts} />;
}
// ISR (Incremental Static Regeneration)
export const revalidate = 3600; // revalidate every hour
// SSG with generateStaticParams
export async function generateStaticParams() {
const products = await prisma.product.findMany({ select: { id: true } });
return products.map((p) => ({ id: p.id }));
}
```
## Checklist
- [ ] App Router (not Pages Router) for new projects
- [ ] Server Components by default, `'use client'` only for interactivity
- [ ] Server Actions for mutations (not API routes for forms)
- [ ] Auth.js v5 for authentication
- [ ] Zod for input validation
- [ ] Suspense boundaries for async components
- [ ] Route groups `(groupName)` for layout organization
- [ ] `next/image` for all images with proper sizing
- [ ] Middleware for auth checks
- [ ] `revalidatePath` / `revalidateTag` after mutations
- [ ] Parallel data fetching with `Promise.all`
- [ ] Error boundaries (`error.tsx`) and loading states (`loading.tsx`)

View File

@@ -0,0 +1,243 @@
---
name: python-django-patterns
description: Django 5+ patterns — models, views, serializers, REST framework, authentication, management commands
---
# Python Django Patterns
## Project Structure
```
project/
├── manage.py
├── config/ # Project settings
│ ├── settings/
│ │ ├── base.py
│ │ ├── development.py
│ │ └── production.py
│ ├── urls.py
│ ├── wsgi.py
│ └── asgi.py
├── apps/
│ ├── products/
│ │ ├── models.py
│ │ ├── views.py # API views (thin)
│ │ ├── serializers.py # DRF serializers
│ │ ├── urls.py
│ │ ├── services.py # Business logic
│ │ ├── repositories.py # Data access
│ │ ├── admin.py
│ │ ├── tasks.py # Celery tasks
│ │ ├── tests/
│ │ │ ├── test_models.py
│ │ │ ├── test_views.py
│ │ │ └── test_services.py
│ │ └── migrations/
│ ├── orders/
│ └── users/
├── shared/
│ ├── pagination.py
│ ├── permissions.py
│ ├── throttling.py
│ └── exceptions.py
├── requirements/
│ ├── base.txt
│ ├── development.txt
│ └── production.txt
└── docker-compose.yml
```
## Model Pattern
```python
# apps/products/models.py
from django.db import models
from django.urls import reverse
class Product(models.Model):
name = models.CharField(max_length=255)
slug = models.SlugField(unique=True)
description = models.TextField(blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
category = models.ForeignKey('Category', on_delete=models.PROTECT, related_name='products')
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-created_at']
indexes = [
models.Index(fields=['slug']),
models.Index(fields=['category', 'is_active']),
]
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('product-detail', kwargs={'slug': self.slug})
```
## Service Pattern (Business Logic in services.py)
```python
# apps/products/services.py
from .repositories import ProductRepository
class ProductService:
def __init__(self, repository=None):
self.repository = repository or ProductRepository()
def list_active(self, page=1, per_page=20, category_id=None, search=None):
return self.repository.list_active(
page=page, per_page=per_page,
category_id=category_id, search=search,
)
def create(self, data: dict):
product = self.repository.create(data)
return product
def update_price(self, product_id: int, new_price):
product = self.repository.get_by_id(product_id)
product.price = new_price
self.repository.save(product)
return product
```
## Repository Pattern
```python
# apps/products/repositories.py
from .models import Product
class ProductRepository:
def list_active(self, page=1, per_page=20, category_id=None, search=None):
qs = Product.objects.filter(is_active=True).select_related('category')
if category_id:
qs = qs.filter(category_id=category_id)
if search:
qs = qs.filter(name__icontains=search)
return qs[(page - 1) * per_page : page * per_page]
def get_by_id(self, product_id: int):
return Product.objects.select_related('category').get(pk=product_id)
def create(self, data: dict):
return Product.objects.create(**data)
def save(self, product):
product.save()
return product
```
## Serializer Pattern (DRF)
```python
# apps/products/serializers.py
from rest_framework import serializers
from .models import Product, Category
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ['id', 'name', 'slug']
class ProductListSerializer(serializers.ModelSerializer):
category = CategorySerializer(read_only=True)
class Meta:
model = Product
fields = ['id', 'name', 'slug', 'price', 'category', 'is_active']
class ProductDetailSerializer(serializers.ModelSerializer):
category = CategorySerializer(read_only=True)
class Meta:
model = Product
fields = '__all__'
class ProductCreateSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ['name', 'description', 'price', 'category', 'is_active']
def validate_price(self, value):
if value <= 0:
raise serializers.ValidationError('Price must be positive')
return value
```
## View Pattern (Thin Views)
```python
# apps/products/views.py
from rest_framework import viewsets, filters, status
from rest_framework.decorators import action
from rest_framework.response import Response
from .models import Product
from .serializers import ProductListSerializer, ProductDetailSerializer, ProductCreateSerializer
from .services import ProductService
from .repositories import ProductRepository
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.filter(is_active=True).select_related('category')
filter_backends = [filters.SearchFilter, filters.OrderingFilter]
search_fields = ['name', 'description']
ordering_fields = ['price', 'created_at']
def get_serializer_class(self):
if self.action == 'list':
return ProductListSerializer
if self.action in ('create', 'update', 'partial_update'):
return ProductCreateSerializer
return ProductDetailSerializer
def get_service(self):
return ProductService(ProductRepository())
def create(self, request):
service = self.get_service()
product = service.create(request.data)
return Response(
ProductDetailSerializer(product).data,
status=status.HTTP_201_CREATED,
)
```
## Authentication (DRF + JWT)
```python
# config/settings/base.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticatedOrReadOnly',
],
'DEFAULT_PAGINATION_CLASS': 'shared.pagination.StandardPagination',
'PAGE_SIZE': 20,
}
```
## Checklist
- [ ] Fat models, thin views, services for business logic
- [ ] Repository pattern for data access
- [ ] DRF serializers for input validation and output transformation
- [ ] Select_related / prefetch_related to prevent N+1
- [ ] JWT (SimpleJWT) for API authentication
- [ ] Environment-specific settings (base/development/production)
- [ ] Django admin for data management
- [ ] pytest-django for testing
- [ ] Celery for async tasks
- [ ] `python manage.py check --deploy` before release

View File

@@ -0,0 +1,318 @@
---
name: python-fastapi-patterns
description: FastAPI patterns — async routes, dependency injection, Pydantic, SQLAlchemy, Alembic, background tasks
---
# Python FastAPI Patterns
## Project Structure
```
app/
├── main.py # FastAPI app
├── config.py # Settings (pydantic-settings)
├── database.py # Database session
├── dependencies.py # Shared dependencies (auth, db, pagination)
├── models/ # SQLAlchemy models
│ ├── product.py
│ ├── order.py
│ └── user.py
├── schemas/ # Pydantic schemas
│ ├── product.py
│ ├── order.py
│ └── auth.py
├── routers/ # API routers
│ ├── products.py
│ ├── orders.py
│ ├── auth.py
│ └── admin.py
├── services/ # Business logic
│ ├── product_service.py
│ ├── order_service.py
│ └── auth_service.py
├── repositories/ # Data access
│ ├── product_repository.py
│ └── order_repository.py
├── middleware/
│ ├── auth.py
│ └── logging.py
├── tasks/ # Background tasks
│ └── notifications.py
├── exceptions.py # Custom exceptions
├── migrations/ # Alembic migrations
│ ├── env.py
│ └── versions/
└── tests/
├── conftest.py
├── test_products.py
└── test_auth.py
```
## App Setup
```python
# app/main.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from app.config import settings
from app.routers import products, orders, auth
app = FastAPI(
title=settings.APP_NAME,
version=settings.APP_VERSION,
docs_url='/api/docs',
redoc_url='/api/redoc',
)
app.add_middleware(
CORSMiddleware,
allow_origins=settings.ALLOWED_ORIGINS,
allow_credentials=True,
allow_methods=['*'],
allow_headers=['*'],
)
app.include_router(products.router, prefix='/api/v1', tags=['products'])
app.include_router(orders.router, prefix='/api/v1', tags=['orders'])
app.include_router(auth.router, prefix='/api/v1/auth', tags=['auth'])
@app.get('/health')
async def health_check():
return {'status': 'ok'}
```
## Config
```python
# app/config.py
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
APP_NAME: str = 'My API'
APP_VERSION: str = '1.0.0'
DATABASE_URL: str = 'postgresql+asyncpg://user:pass@localhost/db'
SECRET_KEY: str = 'change-me-in-production'
ALLOWED_ORIGINS: list[str] = ['http://localhost:3000']
ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
model_config = {'env_file': '.env', 'extra': 'ignore'}
settings = Settings()
```
## Database
```python
# app/database.py
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession
from app.config import settings
engine = create_async_engine(settings.DATABASE_URL, echo=False)
AsyncSessionLocal = async_sessionmaker(engine, expire_on_commit=False)
async def get_db() -> AsyncSession:
async with AsyncSessionLocal() as session:
yield session
```
## Pydantic Schemas
```python
# app/schemas/product.py
from pydantic import BaseModel, Field
class ProductBase(BaseModel):
name: str = Field(min_length=1, max_length=255)
price: float = Field(gt=0)
category_id: int
class ProductCreate(ProductBase):
description: str | None = None
class ProductUpdate(BaseModel):
name: str | None = Field(None, min_length=1, max_length=255)
price: float | None = Field(None, gt=0)
class ProductResponse(ProductBase):
id: int
description: str | None
slug: str
model_config = {'from_attributes': True}
class ProductList(BaseModel):
data: list[ProductResponse]
total: int
page: int
pages: int
```
## Repository Pattern
```python
# app/repositories/product_repository.py
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession
from app.models.product import Product
class ProductRepository:
def __init__(self, db: AsyncSession):
self.db = db
async def list(self, page=1, per_page=20, category_id=None, search=None):
query = select(Product).where(Product.is_active.is_(True))
if category_id:
query = query.where(Product.category_id == category_id)
if search:
query = query.where(Product.name.ilike(f'%{search}%'))
total = await self.db.scalar(select(func.count()).select_from(query.subquery()))
items = await self.db.scalars(
query.order_by(Product.created_at.desc())
.offset((page - 1) * per_page)
.limit(per_page)
)
return items.all(), total
async def get_by_id(self, product_id: int):
return await self.db.get(Product, product_id)
async def create(self, data: dict):
product = Product(**data)
self.db.add(product)
await self.db.commit()
await self.db.refresh(product)
return product
```
## Router Pattern (Thin)
```python
# app/routers/products.py
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from app.database import get_db
from app.schemas.product import ProductCreate, ProductResponse, ProductList
from app.services.product_service import ProductService
from app.dependencies import PaginationParams
router = APIRouter()
def get_service(db: AsyncSession = Depends(get_db)) -> ProductService:
return ProductService(db)
@router.get('/products', response_model=ProductList)
async def list_products(
pagination: PaginationParams = Depends(),
category_id: int | None = None,
search: str | None = None,
service: ProductService = Depends(get_service),
):
return await service.list(
page=pagination.page,
per_page=pagination.per_page,
category_id=category_id,
search=search,
)
@router.post('/products', response_model=ProductResponse, status_code=201)
async def create_product(
data: ProductCreate,
service: ProductService = Depends(get_service),
):
return await service.create(data.model_dump())
@router.get('/products/{product_id}', response_model=ProductResponse)
async def get_product(product_id: int, service: ProductService = Depends(get_service)):
product = await service.get(product_id)
if not product:
raise HTTPException(status_code=404, detail='Product not found')
return product
```
## Authentication (JWT)
```python
# app/services/auth_service.py
from datetime import datetime, timedelta, timezone
from jose import jwt, JWTError
from passlib.context import CryptContext
from app.config import settings
pwd_context = CryptContext(schemes=['bcrypt'], deprecated='auto')
class AuthService:
@staticmethod
def hash_password(password: str) -> str:
return pwd_context.hash(password)
@staticmethod
def verify_password(plain: str, hashed: str) -> bool:
return pwd_context.verify(plain, hashed)
@staticmethod
def create_access_token(user_id: int) -> str:
expire = datetime.now(timezone.utc) + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
return jwt.encode({'sub': str(user_id), 'exp': expire}, settings.SECRET_KEY)
@staticmethod
def decode_token(token: str) -> dict:
try:
return jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256'])
except JWTError:
raise ValueError('Invalid token')
```
## Dependencies (Auth + Pagination)
```python
# app/dependencies.py
from fastapi import Depends, HTTPException, Header
from app.services.auth_service import AuthService
class PaginationParams:
def __init__(self, page: int = 1, per_page: int = 20):
self.page = max(1, page)
self.per_page = min(100, max(1, per_page))
async def get_current_user(authorization: str = Header(...)):
if not authorization.startswith('Bearer '):
raise HTTPException(status_code=401, detail='Invalid token format')
token = authorization[7:]
try:
payload = AuthService.decode_token(token)
return int(payload['sub'])
except (ValueError, KeyError):
raise HTTPException(status_code=401, detail='Invalid or expired token')
```
## Checklist
- [ ] Async everywhere (routes, db, external calls)
- [ ] Dependency injection for services and auth
- [ ] Pydantic v2 schemas with `model_config = {'from_attributes': True}`
- [ ] Repository pattern for data access
- [ ] Service layer for business logic
- [ ] Alembic for database migrations
- [ ] JWT for authentication
- [ ] CORS properly configured
- [ ] pytest-asyncio for async tests
- [ ] `alembic upgrade head` before server start
- [ ] Health check endpoint for monitoring

View File

@@ -0,0 +1,277 @@
---
name: react-patterns
description: React 18+ patterns — Hooks, composition, context, suspense, concurrent features, component architecture
---
# React Patterns
## Project Structure
```
src/
├── app/ or pages/ # Next.js or Vite pages
├── components/
│ ├── ui/ # Base UI primitives
│ │ ├── Button.tsx
│ │ ├── Input.tsx
│ │ ├── Modal.tsx
│ │ └── Card.tsx
│ ├── forms/ # Form components
│ │ ├── LoginForm.tsx
│ │ └── ProductForm.tsx
│ └── features/ # Feature components
│ ├── product/
│ ├── cart/
│ └── auth/
├── hooks/ # Custom hooks
│ ├── useAuth.ts
│ ├── useCart.ts
│ ├── useDebounce.ts
│ └── useApi.ts
├── context/ # React Context providers
│ ├── AuthContext.tsx
│ └── CartContext.tsx
├── services/ # API services
│ ├── api.ts # Axios/fetch instance
│ ├── authService.ts
│ └── productService.ts
├── types/ # TypeScript types
│ └── index.ts
├── utils/ # Utilities
│ ├── format.ts
│ └── validation.ts
└── lib/ # Third-party config
├── queryClient.ts # TanStack Query
└── supabase.ts
```
## Component Pattern
```tsx
// components/product/ProductCard.tsx
import { useState } from 'react';
import { useCart } from '@/hooks/useCart';
interface ProductCardProps {
product: Product;
showAddToCart?: boolean;
onAddToCart?: (productId: string) => void;
}
export function ProductCard({ product, showAddToCart = true, onAddToCart }: ProductCardProps) {
const [isAdding, setIsAdding] = useState(false);
const { addItem } = useCart();
const handleAdd = async () => {
setIsAdding(true);
await addItem(product.id, 1);
onAddToCart?.(product.id);
setIsAdding(false);
};
const formattedPrice = new Intl.NumberFormat('en-US', {
style: 'currency', currency: 'USD',
}).format(product.price);
return (
<div className="border rounded-lg p-4 hover:shadow-lg transition-shadow">
<a href={`/products/${product.id}`}>
<img src={product.image} alt={product.name} className="w-full h-48 object-cover rounded" />
<h3 className="mt-2 font-semibold">{product.name}</h3>
<p className="text-gray-600">{formattedPrice}</p>
</a>
{showAddToCart && (
<button
onClick={handleAdd}
disabled={isAdding}
className="mt-2 w-full bg-blue-600 text-white py-2 rounded hover:bg-blue-700 disabled:opacity-50"
>
{isAdding ? 'Adding...' : 'Add to Cart'}
</button>
)}
</div>
);
}
```
## Custom Hook Pattern
```ts
// hooks/useCart.ts
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { cartService } from '@/services/cartService';
export function useCart() {
const queryClient = useQueryClient();
const { data: cart } = useQuery({
queryKey: ['cart'],
queryFn: cartService.get,
});
const addItemMutation = useMutation({
mutationFn: cartService.addItem,
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['cart'] }),
});
const removeItemMutation = useMutation({
mutationFn: cartService.removeItem,
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['cart'] }),
});
const total = cart?.items?.reduce((sum, item) => sum + item.price * item.quantity, 0) ?? 0;
const count = cart?.items?.reduce((sum, item) => sum + item.quantity, 0) ?? 0;
return {
cart,
total,
count,
addItem: addItemMutation.mutateAsync,
removeItem: removeItemMutation.mutateAsync,
isAdding: addItemMutation.isPending,
};
}
```
## Context Pattern
```tsx
// context/AuthContext.tsx
import { createContext, useContext, useState, useCallback, type ReactNode } from 'react';
interface AuthContextType {
user: User | null;
isAuthenticated: boolean;
login: (email: string, password: string) => Promise<void>;
logout: () => void;
}
const AuthContext = createContext<AuthContextType | null>(null);
export function AuthProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const login = useCallback(async (email: string, password: string) => {
const response = await authService.login({ email, password });
setUser(response.user);
localStorage.setItem('token', response.token);
}, []);
const logout = useCallback(() => {
setUser(null);
localStorage.removeItem('token');
}, []);
return (
<AuthContext.Provider value={{ user, isAuthenticated: !!user, login, logout }}>
{children}
</AuthContext.Provider>
);
}
export function useAuth() {
const context = useContext(AuthContext);
if (!context) throw new Error('useAuth must be used within AuthProvider');
return context;
}
```
## API Service Pattern
```ts
// services/api.ts
import axios from 'axios';
export const api = axios.create({
baseURL: import.meta.env.VITE_API_URL || '/api',
headers: { 'Content-Type': 'application/json' },
});
api.interceptors.request.use((config) => {
const token = localStorage.getItem('token');
if (token) config.headers.Authorization = `Bearer ${token}`;
return config;
});
api.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
localStorage.removeItem('token');
window.location.href = '/login';
}
return Promise.reject(error);
}
);
// services/productService.ts
import { api } from './api';
export const productService = {
list: (params?: object) => api.get('/products', { params }).then((r) => r.data),
get: (id: string) => api.get(`/products/${id}`).then((r) => r.data),
create: (data: CreateProductDTO) => api.post('/products', data).then((r) => r.data),
update: (id: string, data: UpdateProductDTO) => api.put(`/products/${id}`, data).then((r) => r.data),
delete: (id: string) => api.delete(`/products/${id}`).then((r) => r.data),
};
```
## Form Pattern (React Hook Form + Zod)
```tsx
// components/forms/ProductForm.tsx
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
const schema = z.object({
name: z.string().min(1, 'Name is required').max(255),
price: z.number().positive('Price must be positive'),
categoryId: z.string().min(1, 'Category is required'),
description: z.string().optional(),
});
type ProductFormData = z.infer<typeof schema>;
export function ProductForm({ onSubmit }: { onSubmit: (data: ProductFormData) => Promise<void> }) {
const { register, handleSubmit, formState: { errors, isSubmitting } } = useForm<ProductFormData>({
resolver: zodResolver(schema),
});
return (
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
<div>
<label>Name</label>
<input {...register('name')} className="border rounded px-3 py-2 w-full" />
{errors.name && <p className="text-red-500 text-sm">{errors.name.message}</p>}
</div>
<div>
<label>Price</label>
<input type="number" step="0.01" {...register('price', { valueAsNumber: true })} className="border rounded px-3 py-2 w-full" />
{errors.price && <p className="text-red-500 text-sm">{errors.price.message}</p>}
</div>
<button type="submit" disabled={isSubmitting} className="bg-blue-600 text-white px-4 py-2 rounded">
{isSubmitting ? 'Saving...' : 'Save Product'}
</button>
</form>
);
}
```
## Checklist
- [ ] Functional components with hooks (no class components)
- [ ] TypeScript with strict mode
- [ ] `interface` for props, `type` for unions
- [ ] Custom hooks for reusable logic (data fetching, auth, forms)
- [ ] React Hook Form + Zod for form validation
- [ ] TanStack Query for server state (not useState for API data)
- [ ] Context only for global state (auth, theme)
- [ ] React.memo for expensive renders only
- [ ] Error boundaries for crash recovery
- [ ] Suspense for loading states
- [ ] useCallback/useMemo only when needed (not by default)
- [ ] Clean up effects (return cleanup function)

View File

@@ -0,0 +1,327 @@
---
name: vue-nuxt-patterns
description: Vue 3 + Nuxt 3 patterns — Composition API, Pinia, SSR/ISR, auto-imports, middleware, Nitro server
---
# Vue/Nuxt Patterns
## Project Structure
```
src/ or ~/
├── app.vue # Root app
├── layouts/
│ ├── default.vue # Main layout (header, footer)
│ └── admin.vue # Admin layout (sidebar)
├── pages/
│ ├── index.vue # Home
│ ├── products/
│ │ ├── index.vue # Product list
│ │ └── [id].vue # Product detail
│ ├── cart.vue
│ ├── checkout.vue
│ └── admin/
│ ├── index.vue
│ └── products.vue
├── components/
│ ├── ui/ # Base UI (Button, Input, Modal)
│ ├── product/
│ │ ├── ProductCard.vue
│ │ ├── ProductGrid.vue
│ │ └── ProductFilters.vue
│ ├── cart/
│ │ ├── CartItem.vue
│ │ └── CartSummary.vue
│ └── layout/
│ ├── AppHeader.vue
│ └── AppSidebar.vue
├── composables/ # Auto-imported
│ ├── useCart.ts
│ ├── useAuth.ts
│ ├── useProducts.ts
│ └── useApi.ts
├── stores/ # Pinia stores
│ ├── cart.ts
│ ├── auth.ts
│ └── products.ts
├── server/
│ ├── api/
│ │ ├── products/index.get.ts
│ │ ├── products/[id].get.ts
│ │ ├── products/index.post.ts
│ │ ├── cart/index.get.ts
│ │ └── auth/login.post.ts
│ ├── middleware/
│ │ └── auth.ts
│ └── utils/
│ └── db.ts
├── middleware/ # Route middleware
│ └── auth.ts
├── types/
│ └── index.ts
├── utils/
│ └── format.ts
└── nuxt.config.ts
```
## Page Component Pattern
```vue
<!-- pages/products/index.vue -->
<script setup lang="ts">
const { data: products, pending, error } = await useFetch('/api/products', {
query: { page: 1, limit: 20 },
default: () => [],
})
const filters = ref({ category: null, search: '' })
const filtered = computed(() =>
products.value.filter((p) => {
if (filters.value.category && p.categoryId !== filters.value.category) return false
if (filters.value.search && !p.name.toLowerCase().includes(filters.value.search.toLowerCase())) return false
return true
})
)
useHead({ title: 'Products' })
</script>
<template>
<div class="container mx-auto px-4">
<ProductFilters
v-model:category="filters.category"
v-model:search="filters.search"
/>
<ProductGrid :products="filtered" :loading="pending" />
</div>
</template>
```
## Composable Pattern
```ts
// composables/useCart.ts
export const useCart = () => {
const cart = useState<CartItem[]>('cart', () => [])
const items = useCookie<CartItem[]>('cart-items', { default: () => [] })
const total = computed(() =>
items.value.reduce((sum, item) => sum + item.price * item.quantity, 0)
)
const count = computed(() =>
items.value.reduce((sum, item) => sum + item.quantity, 0)
)
async function addItem(productId: string, quantity = 1) {
const { data, error } = await useFetch('/api/cart/items', {
method: 'POST',
body: { productId, quantity },
})
if (!error.value) {
items.value = data.value?.items || items.value
}
}
async function removeItem(itemId: string) {
await useFetch(`/api/cart/items/${itemId}`, { method: 'DELETE' })
items.value = items.value.filter((i) => i.id !== itemId)
}
return { items, total, count, addItem, removeItem }
}
```
## Pinia Store
```ts
// stores/auth.ts
import { defineStore } from 'pinia'
export const useAuthStore = defineStore('auth', () => {
const user = ref<User | null>(null)
const token = useCookie('auth-token')
const isAuthenticated = computed(() => !!token.value)
async function login(email: string, password: string) {
const { data, error } = await useFetch('/api/auth/login', {
method: 'POST',
body: { email, password },
})
if (!error.value && data.value) {
token.value = data.value.token
user.value = data.value.user
}
return { data, error }
}
function logout() {
token.value = null
user.value = null
navigateTo('/login')
}
return { user, token, isAuthenticated, login, logout }
})
```
## Server API (Nitro)
```ts
// server/api/products/index.get.ts
import { defineEventHandler, getQuery } from 'h3'
export default defineEventHandler(async (event) => {
const { page = '1', limit = '20', category, search } = getQuery(event)
const where: any = {}
if (category) where.categoryId = category
if (search) where.name = { contains: search, mode: 'insensitive' }
const [products, total] = await Promise.all([
prisma.product.findMany({
where,
skip: (Number(page) - 1) * Number(limit),
take: Number(limit),
include: { category: true },
orderBy: { createdAt: 'desc' },
}),
prisma.product.count({ where }),
])
return {
data: products,
meta: { page: Number(page), limit: Number(limit), total, pages: Math.ceil(total / Number(limit)) },
}
})
```
```ts
// server/api/products/index.post.ts
import { defineEventHandler, readBody, createError } from 'h3'
import { z } from 'zod'
const schema = z.object({
name: z.string().min(1).max(255),
price: z.number().positive(),
categoryId: z.string().cuid(),
})
export default defineEventHandler(async (event) => {
const body = await readBody(event)
const parsed = schema.safeParse(body)
if (!parsed.success) {
throw createError({ statusCode: 422, message: parsed.error.flatten() })
}
const product = await prisma.product.create({ data: parsed.data })
return product
})
```
## Route Middleware
```ts
// middleware/auth.ts
export default defineNuxtRouteMiddleware((to) => {
const { isAuthenticated } = useAuthStore()
if (!isAuthenticated && to.path.startsWith('/admin')) {
return navigateTo('/login')
}
})
```
## Component Pattern (Composition API)
```vue
<!-- components/product/ProductCard.vue -->
<script setup lang="ts">
interface Props {
product: Product
showAddToCart?: boolean
}
const props = withDefaults(defineProps<Props>(), {
showAddToCart: true,
})
const emit = defineEmits<{
addToCart: [productId: string]
}>()
const { addItem } = useCart()
const isAdding = ref(false)
async function handleAdd() {
isAdding.value = true
await addItem(props.product.id)
isAdding.value = false
emit('addToCart', props.product.id)
}
const formattedPrice = computed(() =>
new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(props.product.price)
)
</script>
<template>
<div class="border rounded-lg p-4 hover:shadow-lg transition-shadow">
<NuxtLink :to="`/products/${product.id}`">
<img :src="product.image" :alt="product.name" class="w-full h-48 object-cover rounded" />
<h3 class="mt-2 font-semibold">{{ product.name }}</h3>
<p class="text-gray-600">{{ formattedPrice }}</p>
</NuxtLink>
<button
v-if="showAddToCart"
:disabled="isAdding"
@click="handleAdd"
class="mt-2 w-full bg-blue-600 text-white py-2 rounded hover:bg-blue-700 disabled:opacity-50"
>
{{ isAdding ? 'Adding...' : 'Add to Cart' }}
</button>
</div>
</template>
```
## Nuxt Config
```ts
// nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@pinia/nuxt',
'@nuxtjs/tailwindcss',
'@nuxt/image',
],
runtimeConfig: {
public: { apiBase: process.env.NUXT_PUBLIC_API_BASE || '/api' },
private: { dbUrl: process.env.DATABASE_URL },
},
app: {
head: {
title: 'My App',
meta: [{ name: 'description', content: 'My Nuxt app' }],
},
},
})
```
## Checklist
- [ ] Composition API with `<script setup lang="ts">`
- [ ] Auto-imports (composables, components, utils)
- [ ] Pinia for state (not Vuex)
- [ ] Server API routes (Nitro) for backend logic
- [ ] `useFetch` / `useLazyFetch` for data fetching
- [ ] `useState` for shared client state
- [ ] `useCookie` for persistent state
- [ ] Route middleware for auth checks
- [ ] `useHead` for SEO meta
- [ ] `defineNuxtConfig` with modules
- [ ] SSR-friendly code (no `window` in composables)
- [ ] `useAsyncData` for server-side data

View File

@@ -16,6 +16,12 @@ Agent: Runs full pipeline for issue #42 with Gitea logging
| Command | Description | Usage |
|---------|-------------|-------|
| `/pipeline <issue>` | Run full agent pipeline for issue | `/pipeline 42` |
| `/nextjs` | Next.js 14+ full-stack app pipeline | `/nextjs my-app` |
| `/vue` | Vue/Nuxt 3 full-stack app pipeline | `/vue my-app` |
| `/laravel` | Laravel full-stack app pipeline | `/laravel my-app` |
| `/wordpress` | WordPress plugin/site pipeline | `/wordpress my-plugin` |
| `/feature` | Feature development pipeline | `/feature` |
| `/commerce` | E-commerce site pipeline | `/commerce` |
| `/status <issue>` | Check pipeline status for issue | `/status 42` |
| `/evolve` | Run evolution cycle with fitness scoring | `/evolve --issue 42` |
| `/evaluate <issue>` | Generate performance report | `/evaluate 42` |
@@ -41,9 +47,10 @@ These agents are invoked automatically by `/pipeline` or manually via `@mention`
| `@system-analyst` | Designs specifications | glm-5.1 | thinking | sdet-engineer, orchestrator |
| `@sdet-engineer` | Writes tests (TDD) | qwen3-coder:480b | thinking | lead-developer, orchestrator |
| `@lead-developer` | Implements code | qwen3-coder:480b | thinking | code-skeptic, orchestrator |
| `@frontend-developer` | UI implementation | qwen3-coder:480b | — | code-skeptic, orchestrator |
| `@frontend-developer` | UI (Next.js, Vue/Nuxt, React) | qwen3-coder:480b | — | code-skeptic, visual-tester, orchestrator |
| `@backend-developer` | Node.js/Express/APIs | qwen3-coder:480b | — | code-skeptic, orchestrator |
| `@php-developer` | PHP/Laravel/Symfony/WordPress | qwen3-coder:480b | thinking | code-skeptic, security-auditor, orchestrator |
| `@python-developer` | Python/Django/FastAPI | qwen3-coder:480b | thinking | code-skeptic, security-auditor, orchestrator |
| `@go-developer` | Go backend services | qwen3-coder:480b | — | code-skeptic, orchestrator |
| `@flutter-developer` | Flutter mobile apps | qwen3-coder:480b | — | code-skeptic, orchestrator |

View File

@@ -1,6 +1,8 @@
# APAW — Automatic Programmers Agent Workflow
**Self-Improving Agent Pipeline** — автономная система из 29+ специализированных ИИ-агентов с автоматической эволюцией промптов, мониторингом выполнения и модульной архитектурой.
**Self-Improving Agent Pipeline** — автономная система из 30+ специализированных ИИ-агентов с автоматической эволюцией промптов, мониторингом выполнения и модульной архитектурой.
Поддерживаемые стеки: **PHP/Laravel/Symfony/WordPress**, **Next.js**, **Vue/Nuxt**, **React**, **Python/Django/FastAPI**, **Go**, **Flutter**, **Node.js/Express**.
---
@@ -9,8 +11,8 @@
```
APAW/
├── .kilo/ # KiloCode конфигурация
│ ├── agents/ # 29 агентов (YAML frontmatter)
│ ├── commands/ # Workflow команды (/pipeline, /laravel, /wordpress, etc.)
│ ├── agents/ # 30 агентов (YAML frontmatter)
│ ├── commands/ # Workflow команды (/pipeline, /laravel, /nextjs, /vue, etc.)
│ ├── rules/ # Правила кодирования (атомарные задачи, модульность, токены)
│ ├── skills/ # Специализированные навыки (PHP, Go, Node, Docker, Gitea)
│ ├── shared/ # Общие модули (gitea-api, gitea-commenting, self-evolution)
@@ -74,7 +76,7 @@ bun run agent:stats --project UniqueSoft/my-shop
---
## Команда агентов (29+)
## Команда агентов (30+)
### Планирование и Анализ
@@ -95,6 +97,7 @@ bun run agent:stats --project UniqueSoft/my-shop
| `@frontend-developer` | Qwen3-Coder 480B | UI компоненты |
| `@backend-developer` | Qwen3-Coder 480B | Node.js/Express APIs |
| `@php-developer` | Qwen3-Coder 480B | PHP/Laravel/Symfony/WordPress |
| `@python-developer` | Qwen3-Coder 480B | Python/Django/FastAPI |
| `@go-developer` | Qwen3-Coder 480B | Go/Gin/Echo APIs |
| `@flutter-developer` | Qwen3-Coder 480B | Flutter mobile apps |
| `@devops-engineer` | Nemotron-3-Super | Docker, K8s, CI/CD |
@@ -219,6 +222,11 @@ Subagent модели определены в `.md` файлах агентов.
- `php_web_development``php-developer`
- `laravel_development``php-developer`
- `wordpress_development``php-developer`
- `python_web_development``python-developer`
- `django_development``python-developer`
- `fastapi_development``python-developer`
- `nextjs_development``frontend-developer`
- `vue_nuxt_development``frontend-developer`
- `security``security-auditor`
- и т.д.
@@ -258,6 +266,15 @@ bun run agent:stats
- `php-testing` — PHPUnit, Pest, Dusk
- `php-modular-architecture` — Modules, packages, service separation
### Frontend (Next.js / Vue / React)
- `nextjs-patterns` — Next.js 14+ App Router, Server Components, Server Actions, Auth.js
- `vue-nuxt-patterns` — Vue 3 / Nuxt 3 Composition API, Pinia, Nitro, SSR
- `react-patterns` — React 18+ hooks, Context, TanStack Query, React Hook Form
### Python
- `python-django-patterns` — Django models, DRF, services, repositories
- `python-fastapi-patterns` — FastAPI async, Pydantic, SQLAlchemy, dependencies
### Инфраструктура
- `gitea-workflow` — Gitea интеграция (автодетекция проекта)
- `gitea-commenting` — Автоматические комментарии
@@ -338,7 +355,7 @@ bun run agent:stats:project --project UniqueSoft/my-shop
| Runtime | TypeScript / Node.js / Bun |
| Agent Runtime | KiloCode VS Code Extension |
| Version Control | Gitea + Git Flow |
| Languages | TypeScript / PHP / Go / Dart |
| Languages | TypeScript / PHP / Python / Go / Dart |
| Testing | TDD (Red-Green-Refactor), PHPUnit, Pest |
| Containerization | Docker / Docker Compose |
@@ -347,12 +364,14 @@ bun run agent:stats:project --project UniqueSoft/my-shop
## Статус проекта
✅ Production Ready
29 агентов
30 агентов
✅ Self-improving pipeline с fitness scoring
✅ Gitea интеграция с автодетекцией проекта
✅ Agent Evolution Dashboard
✅ Мониторинг выполнения агентов
✅ PHP/Laravel/Symfony/WordPress поддержка
✅ Next.js / Vue/Nuxt / React поддержка
✅ Python/Django/FastAPI поддержка
✅ Атомарные задачи и модульная архитектура
---

View File

@@ -7,15 +7,18 @@ This document describes the organized structure of the APAW project.
```
APAW/
├── .kilo/ # Kilo Code configuration
│ ├── agents/ # 29 agent definitions (YAML frontmatter)
│ ├── agents/ # 30 agent definitions (YAML frontmatter)
│ │ ├── orchestrator.md # Main dispatcher
│ │ ├── php-developer.md # PHP/Laravel/Symfony/WordPress
│ │ ├── python-developer.md # Python/Django/FastAPI
│ │ ├── lead-developer.md # Primary code writer
│ │ ├── code-skeptic.md # Adversarial review
│ │ └── ... (25 more)
│ ├── commands/ # Slash commands
│ │ ├── pipeline.md # Full agent pipeline
│ │ ├── laravel.md # Laravel web app pipeline
│ │ ├── nextjs.md # Next.js app pipeline
│ │ ├── vue.md # Vue/Nuxt app pipeline
│ │ ├── wordpress.md # WordPress development pipeline
│ │ ├── feature.md # Feature development
│ │ ├── commerce.md # E-commerce site
@@ -137,7 +140,7 @@ Rules in `.kilo/rules/` are loaded globally for all agents:
Skills are capability modules agents reference:
### PHP Development (NEW)
### PHP Development
| Skill | Lines | Purpose |
|-------|-------|---------|
@@ -148,6 +151,21 @@ Skills are capability modules agents reference:
| `php-testing` | 242 | PHPUnit, Pest, Dusk browser tests |
| `php-modular-architecture` | 242 | Module separation, interfaces, events |
### Frontend Frameworks
| Skill | Lines | Purpose |
|-------|-------|---------|
| `nextjs-patterns` | 290 | Next.js 14+ App Router, Server Components, Server Actions, Auth.js |
| `vue-nuxt-patterns` | 270 | Vue 3 / Nuxt 3 Composition API, Pinia, Nitro, SSR |
| `react-patterns` | 240 | React 18+ hooks, Context, TanStack Query, React Hook Form |
### Python Development
| Skill | Lines | Purpose |
|-------|-------|---------|
| `python-django-patterns` | 200 | Django models, DRF, services, repositories |
| `python-fastapi-patterns` | 230 | FastAPI async, Pydantic, SQLAlchemy, dependencies |
### Infrastructure
| Skill | Purpose |