UNPKG

ai-templates

Version:

CLI tool for generating AI templates for different frameworks and tools

578 lines (480 loc) 14 kB
# New Feature Development - Frontend (React) This command guides you through developing new features following best practices and ensuring comprehensive implementation. ## Step 1: Feature Planning ### Create Feature Specification ```bash # Create feature documentation mkdir -p docs/features/<feature-name> touch docs/features/<feature-name>/specification.md ``` Feature specification template: ```markdown # Feature: <Feature Name> ## Overview Brief description of the feature and its business value. ## User Stories - As a [user type], I want to [action] so that [benefit] - As a [user type], I want to [action] so that [benefit] ## Acceptance Criteria - [ ] Criterion 1 - [ ] Criterion 2 - [ ] Criterion 3 ## Technical Requirements ### API Endpoints - POST /api/v1/resource - Create resource - GET /api/v1/resource/:id - Get resource - PUT /api/v1/resource/:id - Update resource - DELETE /api/v1/resource/:id - Delete resource ### Data Models - Resource schema - Validation rules - Relationships ### Business Logic - Core functionality - Edge cases - Error handling ## Non-Functional Requirements - Performance: < 200ms response time - Security: Authentication required - Scalability: Support 1000 concurrent users ``` ## Step 2: Create Feature Branch ```bash # Create feature branch from main git checkout main git pull origin main git checkout -b feature/<feature-name> # Example git checkout -b feature/user-notifications ``` ## Step 3: Database Schema Design ### Create Migration ```bash # Generate migration file npm run migrate:make <feature-name> # Example npm run migrate:make add_notifications_table ``` Example migration: ```typescript export async function up(knex: Knex): Promise<void> { await knex.schema.createTable('notifications', (table) => { table.uuid('id').primary().defaultTo(knex.raw('gen_random_uuid()')); table.uuid('user_id').notNullable().references('id').inTable('users'); table.string('type').notNullable(); table.string('title').notNullable(); table.text('message').notNullable(); table.jsonb('metadata'); table.boolean('is_read').defaultTo(false); table.timestamp('read_at'); table.timestamps(true, true); table.index(['user_id', 'is_read']); table.index('created_at'); }); } export async function down(knex: Knex): Promise<void> { await knex.schema.dropTable('notifications'); } ``` ### Run Migration ```bash # Run migration npm run migrate:latest # Verify migration npm run migrate:status ``` ## Step 4: Model Implementation ### Create Model ```bash # Create model file touch src/models/notification.model.ts ``` Example model: ```typescript // src/models/notification.model.ts import { z } from 'zod'; export const NotificationSchema = z.object({ id: z.string().uuid(), userId: z.string().uuid(), type: z.enum(['info', 'warning', 'error', 'success']), title: z.string().min(1).max(255), message: z.string().min(1), metadata: z.record(z.any()).optional(), isRead: z.boolean().default(false), readAt: z.date().nullable().optional(), createdAt: z.date(), updatedAt: z.date() }); export type Notification = z.infer<typeof NotificationSchema>; export const CreateNotificationSchema = NotificationSchema.omit({ id: true, isRead: true, readAt: true, createdAt: true, updatedAt: true }); export type CreateNotification = z.infer<typeof CreateNotificationSchema>; ``` ## Step 5: Service Layer Implementation ### Create Service ```bash # Create service file touch src/services/notification.service.ts ``` Example service: ```typescript // src/services/notification.service.ts import { FastifyInstance } from 'fastify'; import { Notification, CreateNotification } from '../models/notification.model'; export class NotificationService { constructor(private fastify: FastifyInstance) {} async create(data: CreateNotification): Promise<Notification> { const notification = await this.fastify.db('notifications') .insert(data) .returning('*') .then(rows => rows[0]); // Emit real-time event await this.fastify.io.to(`user:${data.userId}`).emit('notification', notification); return notification; } async findByUser(userId: string, filters?: { isRead?: boolean; limit?: number; offset?: number; }): Promise<Notification[]> { let query = this.fastify.db('notifications') .where('user_id', userId) .orderBy('created_at', 'desc'); if (filters?.isRead !== undefined) { query = query.where('is_read', filters.isRead); } if (filters?.limit) { query = query.limit(filters.limit); } if (filters?.offset) { query = query.offset(filters.offset); } return query; } async markAsRead(id: string, userId: string): Promise<Notification> { const notification = await this.fastify.db('notifications') .where({ id, user_id: userId }) .update({ is_read: true, read_at: new Date() }) .returning('*') .then(rows => rows[0]); if (!notification) { throw new Error('Notification not found'); } return notification; } } ``` ## Step 6: Route Implementation ### Create Route ```bash # Create route file touch src/routes/notifications/index.ts ``` Example route: ```typescript // src/routes/notifications/index.ts import { FastifyPluginAsync } from 'fastify'; import { NotificationService } from '../../services/notification.service'; import { CreateNotificationSchema } from '../../models/notification.model'; const notificationRoutes: FastifyPluginAsync = async (fastify) => { const service = new NotificationService(fastify); // Get notifications for authenticated user fastify.get('/', { onRequest: [fastify.authenticate], schema: { querystring: { type: 'object', properties: { isRead: { type: 'boolean' }, limit: { type: 'number', minimum: 1, maximum: 100, default: 20 }, offset: { type: 'number', minimum: 0, default: 0 } } } } }, async (request, reply) => { const notifications = await service.findByUser( request.user.id, request.query ); return { data: notifications }; }); // Create notification (admin only) fastify.post('/', { onRequest: [fastify.authenticate, fastify.requireRole('admin')], schema: { body: CreateNotificationSchema } }, async (request, reply) => { const notification = await service.create(request.body); reply.code(201).send({ data: notification }); }); // Mark notification as read fastify.patch('/:id/read', { onRequest: [fastify.authenticate] }, async (request, reply) => { const notification = await service.markAsRead( request.params.id, request.user.id ); return { data: notification }; }); }; export default notificationRoutes; ``` ### Register Route ```typescript // src/app.ts app.register(notificationRoutes, { prefix: '/api/v1/notifications' }); ``` ## Step 7: Testing Implementation ### Unit Tests ```bash # Create test files touch tests/unit/services/notification.service.test.ts touch tests/unit/models/notification.model.test.ts ``` Example unit test: ```typescript // tests/unit/services/notification.service.test.ts import { describe, it, expect, beforeEach, jest } from '@jest/globals'; import { NotificationService } from '../../../src/services/notification.service'; describe('NotificationService', () => { let service: NotificationService; let mockFastify: any; beforeEach(() => { mockFastify = { db: jest.fn(), io: { to: jest.fn(() => ({ emit: jest.fn() })) } }; service = new NotificationService(mockFastify); }); describe('create', () => { it('should create a notification', async () => { const mockNotification = { id: 'uuid', userId: 'user-uuid', type: 'info', title: 'Test', message: 'Test message' }; mockFastify.db.mockReturnValue({ insert: jest.fn().mockReturnValue({ returning: jest.fn().mockResolvedValue([mockNotification]) }) }); const result = await service.create({ userId: 'user-uuid', type: 'info', title: 'Test', message: 'Test message' }); expect(result).toEqual(mockNotification); expect(mockFastify.io.to).toHaveBeenCalledWith('user:user-uuid'); }); }); }); ``` ### Integration Tests ```bash # Create integration test touch tests/integration/notifications.test.ts ``` Example integration test: ```typescript // tests/integration/notifications.test.ts import { build } from '../helper'; describe('Notifications API', () => { let app: FastifyInstance; beforeAll(async () => { app = await build(); }); afterAll(async () => { await app.close(); }); describe('GET /api/v1/notifications', () => { it('should return user notifications', async () => { const response = await app.inject({ method: 'GET', url: '/api/v1/notifications', headers: { authorization: 'Bearer valid-token' } }); expect(response.statusCode).toBe(200); expect(response.json()).toHaveProperty('data'); expect(Array.isArray(response.json().data)).toBe(true); }); it('should require authentication', async () => { const response = await app.inject({ method: 'GET', url: '/api/v1/notifications' }); expect(response.statusCode).toBe(401); }); }); }); ``` ## Step 8: API Documentation ### Update OpenAPI Schema ```yaml # docs/openapi.yaml paths: /api/v1/notifications: get: summary: Get user notifications tags: - Notifications security: - bearerAuth: [] parameters: - name: isRead in: query schema: type: boolean - name: limit in: query schema: type: number minimum: 1 maximum: 100 default: 20 - name: offset in: query schema: type: number minimum: 0 default: 0 responses: '200': description: List of notifications content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/Notification' ``` ## Step 9: Feature Flag Implementation (Optional) ```typescript // src/config/features.ts export const features = { notifications: { enabled: process.env.FEATURE_NOTIFICATIONS === 'true', realtime: process.env.FEATURE_NOTIFICATIONS_REALTIME === 'true' } }; // In route registration if (features.notifications.enabled) { app.register(notificationRoutes, { prefix: '/api/v1/notifications' }); } ``` ## Step 10: Performance Optimization ### Add Caching ```typescript // src/services/notification.service.ts async findByUser(userId: string, filters?: any): Promise<Notification[]> { const cacheKey = `notifications:${userId}:${JSON.stringify(filters)}`; // Check cache const cached = await this.fastify.redis.get(cacheKey); if (cached) { return JSON.parse(cached); } // Fetch from database const notifications = await this.fetchFromDb(userId, filters); // Cache for 5 minutes await this.fastify.redis.setex(cacheKey, 300, JSON.stringify(notifications)); return notifications; } ``` ### Add Indexes ```sql -- Performance indexes CREATE INDEX idx_notifications_user_created ON notifications(user_id, created_at DESC); CREATE INDEX idx_notifications_user_unread ON notifications(user_id, is_read) WHERE is_read = false; ``` ## Step 11: Security Considerations ### Input Validation ```typescript // Strict input validation const CreateNotificationSchema = z.object({ userId: z.string().uuid(), type: z.enum(['info', 'warning', 'error', 'success']), title: z.string().min(1).max(255).regex(/^[\w\s\-]+$/), message: z.string().min(1).max(1000), metadata: z.record(z.any()).optional() }).strict(); ``` ### Rate Limiting ```typescript // Apply rate limiting to endpoints fastify.get('/', { onRequest: [fastify.authenticate], preHandler: fastify.rateLimit({ max: 100, timeWindow: '1 minute' }) }, handler); ``` ## Step 12: Monitoring and Logging ### Add Metrics ```typescript // Track feature usage fastify.metrics.increment('notifications.created', { type: notification.type }); fastify.metrics.histogram('notifications.query.duration', duration); ``` ### Structured Logging ```typescript fastify.log.info({ event: 'notification.created', userId: notification.userId, type: notification.type, notificationId: notification.id }, 'Notification created successfully'); ``` ## Final Checklist ```markdown ## Feature Implementation Checklist ### Planning - [ ] Feature specification documented - [ ] User stories defined - [ ] Acceptance criteria clear ### Implementation - [ ] Database schema created - [ ] Models implemented with validation - [ ] Service layer complete - [ ] Routes implemented - [ ] Authentication/authorization added ### Testing - [ ] Unit tests written (>80% coverage) - [ ] Integration tests complete - [ ] E2E tests for critical paths - [ ] Performance tests if needed ### Documentation - [ ] API documentation updated - [ ] Code comments added - [ ] README updated if needed - [ ] Migration guide if breaking changes ### Security - [ ] Input validation strict - [ ] SQL injection prevented - [ ] Rate limiting applied - [ ] Permissions verified ### Performance - [ ] Database indexes added - [ ] Caching implemented where needed - [ ] N+1 queries prevented - [ ] Response times acceptable ### Monitoring - [ ] Logging added - [ ] Metrics tracked - [ ] Alerts configured - [ ] Error handling comprehensive ```