From 64de5f287a5b077a85e2a4ede0052850a8a8c851 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Feb 2026 04:53:46 +0000 Subject: [PATCH 1/3] Initial plan From cc2761cb5fc5a12e34777409ad6e4818e98f44ad Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Feb 2026 04:57:48 +0000 Subject: [PATCH 2/3] Add Copilot instructions for repository, API, and Frontend Co-authored-by: thomasiverson <12767513+thomasiverson@users.noreply.github.com> --- .github/copilot-instructions.md | 181 +++++++++ .github/instructions/API.instructions.md | 194 ++++++++++ .github/instructions/Frontend.instructions.md | 347 ++++++++++++++++++ 3 files changed, 722 insertions(+) create mode 100644 .github/copilot-instructions.md create mode 100644 .github/instructions/API.instructions.md create mode 100644 .github/instructions/Frontend.instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..95d8a6c --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,181 @@ +# OctoCAT Supply Chain Management System - Copilot Instructions + +## Project Overview + +This is a demonstration application showcasing GitHub Copilot capabilities. The OctoCAT Supply Chain Management System is a full-stack TypeScript application that manages supply chain operations including products, suppliers, orders, deliveries, and branches. + +**Purpose:** Demo/training application to showcase GitHub Copilot, GHAS, and AI-assisted development features. + +**Target Audience:** Developers learning about GitHub Copilot capabilities, including Agent Mode, Vision, MCP Server Integration, and custom instructions. + +## Tech Stack + +### Backend (API) +- **Language:** TypeScript +- **Runtime:** Node.js (>=18) +- **Framework:** Express.js +- **API Documentation:** Swagger/OpenAPI (swagger-jsdoc, swagger-ui-express) +- **Testing:** Vitest with Supertest +- **Build:** TypeScript Compiler (tsc) + +### Frontend +- **Language:** TypeScript +- **Framework:** React 18+ +- **Build Tool:** Vite +- **Styling:** Tailwind CSS +- **Routing:** React Router DOM v7 +- **State Management:** React Query (v3) +- **HTTP Client:** Axios + +### DevOps +- **Containerization:** Docker/Docker Compose +- **Package Manager:** npm workspaces + +## Project Structure + +``` +/ +├── .github/ # GitHub-specific configurations +│ ├── agents/ # Custom Copilot agents (Chat Mode) +│ ├── prompts/ # Copilot prompt files for automation +│ ├── workflows/ # GitHub Actions workflows +│ └── instructions/ # Path-specific Copilot instructions +├── api/ # Backend API workspace +│ ├── src/ +│ │ ├── index.ts # Main entry point +│ │ ├── models/ # Data models with Swagger schemas +│ │ ├── routes/ # Express routes with Swagger docs +│ │ └── seedData.ts # Sample data initialization +│ └── package.json +├── frontend/ # React frontend workspace +│ ├── src/ +│ │ ├── components/ # React components (organized by feature) +│ │ ├── context/ # React context providers +│ │ └── api/ # API configuration +│ └── package.json +├── docs/ # Project documentation +└── package.json # Root workspace configuration +``` + +## Coding Standards + +### General +- Use TypeScript for all code (strict mode enabled) +- Use ES6+ features (async/await, arrow functions, destructuring) +- Prefer functional programming patterns where appropriate +- Keep files focused and modular (single responsibility) +- Use meaningful, descriptive variable and function names + +### TypeScript +- Always define interfaces for data structures +- Use explicit return types for functions +- Avoid `any` type; use `unknown` if type is truly unknown +- Use optional chaining (`?.`) and nullish coalescing (`??`) + +### API Development (Express.js) +- Use Swagger/OpenAPI JSDoc comments for all routes and models +- Follow RESTful conventions: + - GET for retrieval + - POST for creation + - PUT for full updates + - PATCH for partial updates + - DELETE for removal +- Structure routes consistently: + ```typescript + /** + * @swagger + * /api/resource: + * get: + * summary: Description + * tags: [TagName] + * responses: + * 200: + * description: Success response + */ + router.get('/api/resource', (req, res) => { ... }); + ``` +- Use express.Router() for modular route definitions +- Enable CORS appropriately for frontend communication + +### Frontend Development (React) +- Use functional components with hooks (no class components) +- Prefer named exports for components +- Use React Query for data fetching and caching +- Implement loading and error states for async operations +- Use Tailwind CSS utility classes for styling +- Organize components by feature/entity in subdirectories +- Use TypeScript interfaces for component props and data structures +- Implement responsive design patterns + +### Testing +- Use Vitest for all tests +- Use Supertest for API route testing +- Include describe/it blocks with clear descriptions +- Test both success and error cases +- Mock external dependencies appropriately +- Reset state between tests using beforeEach/afterEach +- Run tests with: `npm run test:api` (API) or `npm test` (all workspaces) + +### Documentation +- Use JSDoc comments for functions and complex logic +- Keep Swagger documentation in sync with API implementation +- Update README.md when adding new features or changing setup +- Document non-obvious decisions and workarounds + +## Build and Development Commands + +### Development +```bash +npm install # Install all workspace dependencies +npm run dev # Start both API and frontend in dev mode +npm run dev:api # Start only API (port 3000) +npm run dev:frontend # Start only frontend (port 5137) +``` + +### Building +```bash +npm run build # Build all workspaces +npm run build --workspace=api # Build API only +npm run build --workspace=frontend # Build frontend only +``` + +### Testing +```bash +npm run test # Run all tests +npm run test:api # Run API tests (Vitest) +npm run test:frontend # Run frontend tests +``` + +### Linting +```bash +npm run lint # Lint frontend code (ESLint) +``` + +## Data Model + +The application follows an entity-relationship model for a supply chain system: + +- **Headquarters** (1) → (N) **Branch** +- **Branch** (1) → (N) **Order** +- **Order** (1) → (N) **OrderDetail** +- **OrderDetail** (1) → (N) **OrderDetailDelivery** +- **OrderDetail** (N) → (1) **Product** +- **Delivery** (1) → (N) **OrderDetailDelivery** +- **Supplier** (1) → (N) **Delivery** + +See `/api/ERD.png` for visual representation. + +## Important Notes + +- The API runs on port 3000, frontend on port 5137 +- In Codespaces, set API port visibility to "public" to avoid CORS issues +- This is a demo application - prioritize clarity and demonstration value over production optimizations +- The entire project was created using AI and GitHub Copilot +- Sample data is seeded on API startup for demonstration purposes + +## Resources + +- [Full Architecture Documentation](./docs/architecture.md) +- [Build Instructions](./docs/build.md) +- [Demo Script](./docs/demo-script.md) +- [API Swagger Documentation](http://localhost:3000/api-docs) (when running) diff --git a/.github/instructions/API.instructions.md b/.github/instructions/API.instructions.md new file mode 100644 index 0000000..ed4163b --- /dev/null +++ b/.github/instructions/API.instructions.md @@ -0,0 +1,194 @@ +--- +applyTo: 'api/**/*.ts' +--- + +# API-Specific Copilot Instructions + +These instructions apply specifically to the backend API code in the `/api` directory. + +## API Architecture + +The API follows a modular Express.js architecture with clear separation of concerns: +- **Routes** (`src/routes/`): Define HTTP endpoints and request handling +- **Models** (`src/models/`): Define TypeScript interfaces and Swagger schemas +- **Main Entry** (`src/index.ts`): Express app configuration and middleware setup +- **Seed Data** (`src/seedData.ts`): Sample data for demonstration purposes + +## Swagger/OpenAPI Documentation + +**ALWAYS** include comprehensive Swagger JSDoc comments for: + +1. **Models** (`src/models/*.ts`): +```typescript +/** + * @swagger + * components: + * schemas: + * ModelName: + * type: object + * required: + * - requiredField + * properties: + * fieldName: + * type: string + * description: Clear description of the field + */ +export interface ModelName { + fieldName: string; +} +``` + +2. **Routes** (`src/routes/*.ts`): +```typescript +/** + * @swagger + * /api/resource: + * get: + * summary: Brief summary of what the endpoint does + * tags: [ResourceName] + * responses: + * 200: + * description: Success response description + * content: + * application/json: + * schema: + * type: array + * items: + * $ref: '#/components/schemas/ModelName' + */ +router.get('/api/resource', (req, res) => { ... }); +``` + +3. **Path Parameters**: +```typescript +/** + * @swagger + * /api/resource/{id}: + * get: + * summary: Get resource by ID + * tags: [ResourceName] + * parameters: + * - in: path + * name: id + * required: true + * schema: + * type: integer + * description: Resource identifier + */ +``` + +## RESTful Conventions + +- Use plural nouns for resource endpoints (`/api/products`, not `/api/product`) +- Implement standard HTTP methods: + - `GET /api/resources` - List all resources + - `GET /api/resources/:id` - Get single resource + - `POST /api/resources` - Create new resource + - `PUT /api/resources/:id` - Update resource (full replacement) + - `DELETE /api/resources/:id` - Delete resource +- Return appropriate HTTP status codes: + - 200 OK - Successful GET, PUT, DELETE + - 201 Created - Successful POST + - 404 Not Found - Resource doesn't exist + - 400 Bad Request - Invalid input + +## In-Memory Data Storage + +The API uses in-memory arrays for data storage (this is a demo app): +- Data is stored in module-level variables (e.g., `let products: Product[] = [];`) +- Data persists only during the API process lifetime +- Seed data is initialized on startup from `seedData.ts` +- Use array methods for CRUD operations: + - `find()` for single retrieval + - `filter()` for multiple retrieval + - `push()` for creation + - `splice()` or `filter()` for deletion + - Direct assignment or `map()` for updates + +## Error Handling + +- Always validate input parameters +- Return meaningful error messages +- Use try-catch for operations that might fail +- Example: +```typescript +if (!id) { + return res.status(400).json({ error: 'ID is required' }); +} +const resource = resources.find(r => r.id === parseInt(id)); +if (!resource) { + return res.status(404).json({ error: 'Resource not found' }); +} +``` + +## Testing Standards + +- Tests live alongside route files (e.g., `branch.test.ts` next to `branch.ts`) +- Use Vitest and Supertest for API route testing +- Structure tests with clear describe/it blocks: +```typescript +import { describe, it, expect, beforeEach } from 'vitest'; +import request from 'supertest'; +import app from '../index'; + +describe('Resource API', () => { + beforeEach(() => { + // Reset state if needed + resetResourceData(); + }); + + it('should return all resources', async () => { + const response = await request(app).get('/api/resources'); + expect(response.status).toBe(200); + expect(response.body).toBeInstanceOf(Array); + }); +}); +``` +- Test both successful operations and error cases +- Use `resetBranchData()` or similar functions to reset in-memory data between tests +- Run tests with: `npm run test:api` + +## CORS Configuration + +- CORS is enabled for frontend communication +- Development frontend typically runs on port 5137 +- In Codespaces, ensure API port visibility is set to "public" + +## Common Patterns + +### ID Generation +Use `Math.max(...items.map(i => i.id), 0) + 1` for generating new IDs + +### Route Module Export +Export an Express Router instance: +```typescript +import express from 'express'; +const router = express.Router(); +// ... define routes ... +export default router; +``` + +### Importing Routes in Main +```typescript +import resourceRoutes from './routes/resource'; +app.use(resourceRoutes); +``` + +## Development Workflow + +1. Define the model interface with Swagger schema (`src/models/`) +2. Create route handlers with Swagger docs (`src/routes/`) +3. Add sample seed data if needed (`src/seedData.ts`) +4. Write tests for the routes (`src/routes/*.test.ts`) +5. Run tests: `npm run test:api` +6. Start dev server: `npm run dev:api` +7. Verify in Swagger UI: http://localhost:3000/api-docs + +## Key Files + +- `src/index.ts` - Express app setup, middleware, Swagger configuration +- `src/routes/*.ts` - Individual resource route handlers +- `src/models/*.ts` - TypeScript interfaces with Swagger schemas +- `src/seedData.ts` - Sample data initialization +- `vitest.config.ts` - Test configuration +- `tsconfig.json` - TypeScript configuration diff --git a/.github/instructions/Frontend.instructions.md b/.github/instructions/Frontend.instructions.md new file mode 100644 index 0000000..83cd9e2 --- /dev/null +++ b/.github/instructions/Frontend.instructions.md @@ -0,0 +1,347 @@ +--- +applyTo: 'frontend/**/*.{ts,tsx}' +--- + +# Frontend-Specific Copilot Instructions + +These instructions apply specifically to the React frontend code in the `/frontend` directory. + +## Frontend Architecture + +The frontend is a modern React application with the following structure: +- **Components** (`src/components/`): React components organized by feature/entity +- **Context** (`src/context/`): React Context providers for shared state +- **API Config** (`src/api/`): API endpoint configuration and utilities +- **Entry Point** (`src/main.tsx`): React app initialization and routing setup + +## Component Structure + +### Functional Components with Hooks +Always use functional components with React Hooks (never class components): + +```typescript +import { useState, useEffect } from 'react'; + +interface ComponentProps { + title: string; + onAction?: () => void; +} + +export default function ComponentName({ title, onAction }: ComponentProps) { + const [state, setState] = useState(''); + + useEffect(() => { + // Effect logic here + }, []); + + return ( +
+ {/* Component JSX */} +
+ ); +} +``` + +### Component Organization +- Place entity-specific components in `components/entity/[entityName]/` +- Examples: `components/entity/product/Products.tsx`, `components/entity/product/ProductForm.tsx` +- Shared/common components go in `components/` root +- Admin components go in `components/admin/` + +## TypeScript Interfaces + +Always define TypeScript interfaces for: + +1. **Component Props**: +```typescript +interface ProductCardProps { + product: Product; + onAddToCart: (productId: number) => void; +} +``` + +2. **Data Models** (matching API models): +```typescript +interface Product { + productId: number; + name: string; + description: string; + price: number; + imgName: string; + sku: string; + unit: string; + supplierId: number; + discount?: number; +} +``` + +3. **Component State**: +```typescript +interface FormState { + email: string; + password: string; + errors: Record; +} +``` + +## Data Fetching with React Query + +Use React Query (v3) for all data fetching: + +```typescript +import { useQuery, useMutation } from 'react-query'; +import axios from 'axios'; +import { api } from '../../api/config'; + +// Fetch function +const fetchProducts = async (): Promise => { + const { data } = await axios.get(`${api.baseURL}${api.endpoints.products}`); + return data; +}; + +// In component +export default function Products() { + const { data: products, isLoading, error } = useQuery('products', fetchProducts); + + if (isLoading) return
Loading...
; + if (error) return
Error loading products
; + + return
{/* Render products */}
; +} +``` + +### Mutations +```typescript +const mutation = useMutation( + (newProduct: Product) => axios.post(`${api.baseURL}${api.endpoints.products}`, newProduct), + { + onSuccess: () => { + // Invalidate and refetch + queryClient.invalidateQueries('products'); + }, + } +); +``` + +## Styling with Tailwind CSS + +- Use Tailwind utility classes for all styling (no CSS files for component styles) +- Follow responsive design patterns: `sm:`, `md:`, `lg:` breakpoints +- Use theme-aware classes for dark mode support +- Common patterns: + - Containers: `container mx-auto px-4` + - Cards: `bg-white dark:bg-gray-800 rounded-lg shadow-md p-6` + - Buttons: `bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded` + - Forms: `w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2` + +## Theme Context + +Use the ThemeContext for dark mode support: + +```typescript +import { useTheme } from '../../context/ThemeContext'; + +export default function Component() { + const { darkMode, toggleTheme } = useTheme(); + + return ( +
+ {/* Component content */} +
+ ); +} +``` + +## State Management + +### Local State +Use `useState` for component-local state: +```typescript +const [searchTerm, setSearchTerm] = useState(''); +const [isOpen, setIsOpen] = useState(false); +const [items, setItems] = useState([]); +``` + +### Derived State +Use React Query for server state and `useMemo` for expensive computed values: +```typescript +const filteredProducts = useMemo(() => + products?.filter(p => p.name.toLowerCase().includes(searchTerm.toLowerCase())), + [products, searchTerm] +); +``` + +### Context +Use React Context for app-wide state (auth, theme): +```typescript +// In context provider +export const AuthContext = createContext(undefined); + +// In components +const { user, isAuthenticated } = useContext(AuthContext); +``` + +## Routing + +Use React Router v7 for navigation: + +```typescript +import { BrowserRouter, Routes, Route, Link, useNavigate } from 'react-router-dom'; + +// Navigation +Products + +// Programmatic navigation +const navigate = useNavigate(); +navigate('/products'); + +// Route definition + + } /> + } /> + +``` + +## Error Handling + +Always implement loading and error states: + +```typescript +export default function DataComponent() { + const { data, isLoading, error } = useQuery('key', fetchFunction); + + if (isLoading) { + return ( +
+
Loading...
+
+ ); + } + + if (error) { + return ( +
+
Error: {error.message}
+
+ ); + } + + return
{/* Render data */}
; +} +``` + +## Forms + +Use controlled components for forms: + +```typescript +export default function FormComponent() { + const [formData, setFormData] = useState({ + name: '', + email: '', + }); + + const handleChange = (e: React.ChangeEvent) => { + const { name, value } = e.target; + setFormData(prev => ({ ...prev, [name]: value })); + }; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + // Handle form submission + }; + + return ( +
+ + +
+ ); +} +``` + +## Image Handling + +- Images are stored in `public/` directory +- Reference images using `/imageName.png` path +- Product images use `imgName` property from API +- Example: `{product.name}` + +## API Configuration + +API endpoints are centralized in `src/api/config.ts`: + +```typescript +export const api = { + baseURL: 'http://localhost:3000', + endpoints: { + products: '/api/products', + suppliers: '/api/suppliers', + // ... other endpoints + } +}; +``` + +## Testing + +- Tests use Vitest with React Testing Library +- Test files are typically `*.test.tsx` alongside components +- Focus on user interactions and component behavior +- Run tests with: `npm run test:frontend` + +## Common Patterns + +### Modal/Dialog +```typescript +const [showModal, setShowModal] = useState(false); + +return ( + <> + + {showModal && ( +
+
+ {/* Modal content */} + +
+
+ )} + +); +``` + +### Search/Filter +```typescript +const [searchTerm, setSearchTerm] = useState(''); +const filteredItems = items?.filter(item => + item.name.toLowerCase().includes(searchTerm.toLowerCase()) +); +``` + +## Development Workflow + +1. Create component in appropriate directory +2. Define TypeScript interfaces for props and data +3. Implement component with hooks +4. Add Tailwind CSS styling +5. Handle loading and error states +6. Test in browser: `npm run dev:frontend` +7. Build for production: `npm run build --workspace=frontend` + +## Key Files + +- `src/main.tsx` - App entry point, routing configuration +- `src/App.tsx` - Root component +- `src/components/` - All React components +- `src/context/` - Context providers (Auth, Theme) +- `src/api/config.ts` - API configuration +- `vite.config.ts` - Vite build configuration +- `tailwind.config.js` - Tailwind CSS configuration From f431ddb8821ae35a16da28dc5ca8458127662399 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Feb 2026 04:58:58 +0000 Subject: [PATCH 3/3] Clarify React Query version in frontend instructions Co-authored-by: thomasiverson <12767513+thomasiverson@users.noreply.github.com> --- .github/instructions/Frontend.instructions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/instructions/Frontend.instructions.md b/.github/instructions/Frontend.instructions.md index 83cd9e2..94d3ab0 100644 --- a/.github/instructions/Frontend.instructions.md +++ b/.github/instructions/Frontend.instructions.md @@ -86,7 +86,7 @@ interface FormState { ## Data Fetching with React Query -Use React Query (v3) for all data fetching: +Use React Query (v3.39.3) for all data fetching. Note: This project uses React Query v3 for demonstration purposes. For new projects, consider using TanStack Query v5+ which offers improved features and TypeScript support. ```typescript import { useQuery, useMutation } from 'react-query';