|
1 | | -# GitHub Copilot Instructions |
2 | | - |
3 | | -> **⚡ Token Efficiency Note**: This is a minimal pointer file (~500 tokens, auto-loaded by Copilot). |
4 | | -> For complete operational details, reference: `#file:AGENTS.md` (~2,500 tokens, loaded on-demand) |
5 | | -> For specialized knowledge, use: `#file:SKILLS/<skill-name>/SKILL.md` (loaded on-demand when needed) |
6 | | -
|
7 | | -## 🎯 Quick Context |
8 | | - |
9 | | -**Project**: Express.js REST API with TypeScript and native ESM |
10 | | -**Stack**: Node.js 24 • Express 5 • TypeScript • Sequelize • SQLite • Docker |
11 | | -**Pattern**: Routes → Controllers → Services → ORM (layered) |
12 | | -**Philosophy**: Learning-focused PoC with modern TypeScript and ESM |
13 | | - |
14 | | -## 📐 Core Conventions |
15 | | - |
16 | | -- **Module System**: Native ESM (require `.js` in imports!) |
17 | | -- **Naming**: camelCase (variables/functions), PascalCase (classes/types) |
18 | | -- **Type Safety**: Strict TypeScript, no `any` without justification |
19 | | -- **Async**: All I/O operations use async/await |
20 | | -- **Testing**: Jest with ESM experimental VM modules |
21 | | -- **Formatting**: Prettier (4 spaces, single quotes, 127 width) |
22 | | -- **Commit Messages**: Follow Conventional Commits with issue number suffix |
23 | | - - Format: `type(scope): description (#issue)` (max 80 chars) |
24 | | - - Types: `feat`, `fix`, `chore`, `docs`, `test`, `refactor` |
25 | | - - Example: `feat(api): add player search endpoint (#123)` |
26 | | - |
27 | | -## 🧪 Test Naming Convention |
28 | | - |
29 | | -Integration tests follow an action-oriented pattern with visual flow: |
30 | | - |
31 | | -**Pattern:** |
32 | | -```typescript |
33 | | -it('Request {METHOD} {/path} {context} → Response {outcome}', async () => { |
34 | | -``` |
35 | | -
|
36 | | -**Components:** |
37 | | -- `Request` / `Response` - Title Case structural keywords |
38 | | -- `METHOD` - ALL CAPS HTTP verbs: `GET`, `POST`, `PUT`, `DELETE` |
39 | | -- `/path` - Actual endpoint with parameters: `/players`, `/players/{id}` |
40 | | -- `context` - Lowercase descriptors: `existing`, `body empty`, `within rate limit` |
41 | | -- `→` - Arrow separator showing cause-effect flow |
42 | | -- `outcome` - What's asserted: `status 200 OK`, `body players`, `header rate limit standard` |
43 | | -- Status codes - Title Case with number: `200 OK`, `201 Created`, `400 Bad Request`, `404 Not Found`, `204 No Content`, `409 Conflict`, `429 Too Many Requests` |
44 | | -
|
45 | | -**Examples:** |
46 | | -```typescript |
47 | | -it('Request GET /health → Response status 200 OK', async () => { |
48 | | -it('Request GET /players → Response body players', async () => { |
49 | | -it('Request GET /players/{id} existing → Response status 200 OK', async () => { |
50 | | -it('Request POST /players body empty → Response status 400 Bad Request', async () => { |
51 | | -it('Request PUT /players/{id} existing → Response status 204 No Content', async () => { |
52 | | -it('Request DELETE /players/{id} nonexistent → Response status 404 Not Found', async () => { |
53 | | -it('Request GET /players exceed rate limit → Response status 429 Too Many Requests', async () => { |
54 | | -``` |
55 | | -
|
56 | | -## 🏗️ Architecture at a Glance |
57 | | -
|
58 | | -``` |
59 | | -Route → Controller → Service → Sequelize → Database |
60 | | - ↓ ↓ ↓ |
61 | | -Cache Validation Transaction |
62 | | -``` |
63 | | -
|
64 | | -- **Routes**: Express router with middleware |
65 | | -- **Controllers**: Request/response handling |
66 | | -- **Services**: Business logic with Sequelize ORM |
67 | | -- **Models**: Sequelize models with TypeScript types |
68 | | -- **Cache**: node-cache (1-hour TTL) |
69 | | -
|
70 | | -## ✅ Copilot Should |
71 | | -
|
72 | | -- Generate TypeScript with proper types and interfaces |
73 | | -- Use ESM imports with `.js` extensions (mandatory!) |
74 | | -- Follow Express async/await patterns correctly |
75 | | -- Write Jest tests with proper ESM configuration |
76 | | -- Apply Sequelize models and migrations correctly |
77 | | -- Use Helmet and CORS for security |
78 | | -- Implement proper error handling with try/catch |
79 | | -
|
80 | | -## 🚫 Copilot Should Avoid |
81 | | -
|
82 | | -- Using `any` type without reason |
83 | | -- Missing `.js` in relative imports (ESM requirement!) |
84 | | -- Mixing CommonJS (`require`) with ESM (`import`) |
85 | | -- Synchronous file operations |
86 | | -- Missing error handling on async operations |
87 | | -- Using `console.log` instead of proper logging |
88 | | -
|
89 | | -## ⚡ Quick Commands |
90 | | -
|
91 | | -```bash |
92 | | -# Run with hot reload |
93 | | -npm run dev |
94 | | - |
95 | | -# Test with coverage |
96 | | -npm test |
97 | | - |
98 | | -# Docker |
99 | | -docker compose up |
100 | | - |
101 | | -# Swagger: http://localhost:9000/api-docs |
102 | | -``` |
103 | | -
|
104 | | -## 📚 Need More Detail? |
105 | | -
|
106 | | -**For operational procedures**: Load `#file:AGENTS.md` |
107 | | -**For Docker expertise**: *(Planned)* `#file:SKILLS/docker-containerization/SKILL.md` |
108 | | -**For testing patterns**: *(Planned)* `#file:SKILLS/testing-patterns/SKILL.md` |
109 | | -
|
110 | | ---- |
111 | | -
|
112 | | -💡 **Why this structure?** Copilot auto-loads this file on every chat (~500 tokens). Loading `AGENTS.md` or `SKILLS/` explicitly gives you deep context only when needed, saving 80% of your token budget! |
| 1 | +# Copilot Instructions |
| 2 | + |
| 3 | +## Stack |
| 4 | + |
| 5 | +- **Runtime**: Node.js 24 LTS (Krypton) |
| 6 | +- **Framework**: Express.js 5 |
| 7 | +- **Language**: TypeScript (strict mode) |
| 8 | +- **Database**: SQLite with Sequelize ORM |
| 9 | +- **Testing**: Jest 30 with Supertest |
| 10 | +- **Containerization**: Docker with multi-stage builds |
| 11 | + |
| 12 | +## Project Patterns |
| 13 | + |
| 14 | +- **Layered Architecture**: Routes → Controllers → Services → Database |
| 15 | +- **Dependency Injection**: Constructor injection with interface-based abstractions |
| 16 | +- **Error Handling**: Try/catch in controllers, centralized error middleware |
| 17 | +- **Caching**: In-memory node-cache (1-hour TTL) at service layer |
| 18 | +- **Logging**: Pino structured logging with request correlation IDs |
| 19 | +- **Security**: Helmet middleware for headers, CORS, express-rate-limit |
| 20 | + |
| 21 | +## Code Conventions |
| 22 | + |
| 23 | +- **Module System**: Native ESM (not CommonJS) - always include `.js` in relative imports |
| 24 | +- **Naming**: camelCase for variables/functions, PascalCase for classes/types/interfaces |
| 25 | +- **File Naming**: kebab-case with suffixes (`player-service.ts`, `player-controller.ts`) |
| 26 | +- **Imports**: Group by external deps → internal modules → types, alphabetically sorted |
| 27 | +- **Type Safety**: Strict TypeScript, avoid `any` unless justified, prefer interfaces over types |
| 28 | +- **Async**: All I/O operations use async/await, never callbacks or synchronous calls |
| 29 | +- **Comments**: JSDoc for public APIs and Swagger annotations, inline comments only when necessary |
| 30 | +- **Formatting**: Prettier (4 spaces, single quotes, 127 width) - enforced pre-commit |
| 31 | +- **Commit Messages**: Conventional Commits format `type(scope): description (#issue)` (max 80 chars) |
| 32 | + |
| 33 | +## Testing |
| 34 | + |
| 35 | +- **Structure**: Integration tests in `/tests/`, focus on controller/service/route layers |
| 36 | +- **Naming Convention**: Action-oriented pattern with visual flow |
| 37 | + |
| 38 | + ```typescript |
| 39 | + it('Request {METHOD} {/path} {context} → Response {outcome}', async () => { |
| 40 | + ``` |
| 41 | +
|
| 42 | + - Example: `it('Request GET /players/{id} existing → Response status 200 OK', async () => {` |
| 43 | + - **Components**: Request/Response (Title Case), METHOD (ALL CAPS), /path (actual endpoint), context (lowercase), outcome (status codes in Title Case like `200 OK`, `404 Not Found`) |
| 44 | +- **Mocking**: Use Jest mocks for external dependencies, avoid mocking internal modules |
| 45 | +- **Coverage**: Maintain existing coverage levels (controllers, services, routes only) |
| 46 | +- **Runner**: Jest with ESM support (`ts-jest` preset), use `--watch` in development |
| 47 | +
|
| 48 | +## Avoid |
| 49 | +
|
| 50 | +- Using `any` type without explicit justification |
| 51 | +- Missing `.js` extensions in relative imports (ESM breaks without them) |
| 52 | +- Mixing CommonJS (`require`/`module.exports`) with ESM (`import`/`export`) |
| 53 | +- Synchronous file operations (`fs.readFileSync`, `fs.writeFileSync`) |
| 54 | +- Missing error handling on async operations (always `try/catch`) |
| 55 | +- Using `console.log` instead of Pino logger |
| 56 | +- Creating files without interfaces when abstraction is needed |
| 57 | +- Ignoring TypeScript errors or using `@ts-ignore` without comments |
| 58 | +- Mocking Sequelize models in tests (use real test database) |
0 commit comments