Skip to content

Commit 5ee54c5

Browse files
authored
Merge pull request #49 from bwmirek-tsh/copilot-instructions
Add Copilot Instructions
2 parents ea12d3e + a7516c8 commit 5ee54c5

9 files changed

Lines changed: 375 additions & 0 deletions

.github/copilot-instructions.md

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# Coding Guidelines for Serverless TypeScript Application
2+
3+
## Project Overview
4+
5+
This repository is a serverless application boilerplate using AWS Lambda functions, TypeScript, and the Serverless Framework. It follows modern serverless patterns and best practices for building scalable applications on AWS infrastructure.
6+
7+
## Code Architecture
8+
9+
### Key Patterns
10+
- **Serverless Functions**: Individual Lambda functions with specific responsibilities, each in its own directory
11+
- **Microservices approach**: Each function handles a specific business capability
12+
- **Dependency Injection**: Functions receive dependencies as parameters for better testability
13+
- **Middleware-based processing**: Uses Middy middleware for cross-cutting concerns
14+
- **Schema validation**: Zod schemas for input validation and type safety
15+
16+
### Project Structure
17+
```
18+
functions/
19+
├── [function-name]/ # Each function has its own directory
20+
│ ├── handler.ts # Main lambda handler with middleware
21+
│ ├── service.ts # Business logic (optional)
22+
│ ├── service.spec.ts # Unit tests for service
23+
│ ├── event.schema.ts # Zod validation schema
24+
│ ├── function.yml # Serverless configuration
25+
│ └── config/
26+
│ └── index.ts # Environment configuration
27+
shared/
28+
├── config/ # Database and shared configuration
29+
├── errors/ # Custom error classes
30+
├── middleware/ # Reusable middleware functions
31+
├── models/ # TypeORM database models
32+
├── repositories/ # Data access layer
33+
├── utils/ # Shared utility functions
34+
└── logger/ # Winston logging setup
35+
workflows/
36+
├── [workflow-name]/ # Step Functions workflows
37+
│ ├── workflow.yml # Step Function definition
38+
│ └── workflow.asl.yml # Amazon States Language
39+
migrations/ # TypeORM database migrations
40+
```
41+
42+
### Key Libraries and Functionalities
43+
- **TypeScript**: For static typing and modern JavaScript features
44+
- **Serverless Framework**: For deployment and infrastructure management
45+
- **AWS Lambda**: Function compute platform
46+
- **AWS Step Functions**: Workflow orchestration
47+
- **Middy**: Lambda middleware framework for Node.js
48+
- **TypeORM**: ORM for PostgreSQL database interactions
49+
- **Zod**: Schema validation and type inference
50+
- **Winston**: Structured logging
51+
- **AWS SDK v3**: AWS service clients
52+
- **PostgreSQL**: Primary database
53+
- **DynamoDB**: NoSQL database for high-performance data storage
54+
- **Mocha + Sinon**: Testing framework and mocking
55+
56+
### Key Development Guidelines
57+
58+
#### General Guidelines
59+
- Always use TypeScript for type safety
60+
- Follow serverless best practices and patterns
61+
- Use dependency injection for all external dependencies
62+
- All environment variables must be extracted and validated using Zod in function config files
63+
- Use the provided middleware stack for all Lambda functions
64+
- Keep functions focused on single responsibilities
65+
66+
#### Naming Guidelines
67+
- Function directories: Use **kebab-case** (e.g., `create-transaction`, `get-exchange-rates`)
68+
- File names: Use **kebab-case** with appropriate suffixes (e.g., `handler.ts`, `service.ts`)
69+
- Variables and functions: Use **camelCase** (e.g., `getUserById`, `transactionData`)
70+
- Classes and interfaces: Use **PascalCase** (e.g., `TransactionModel`, `PaymentService`)
71+
- Database columns: Use **snake_case** for TypeORM entity properties
72+
- Schema names: Use **camelCase** with "Schema" suffix (e.g., `createTransactionSchema`)
73+
- AWS resources: Use descriptive names with service prefixes
74+
75+
#### Lambda Function Guidelines
76+
- All handlers must use the standard Middy middleware stack
77+
- Initialize database connections and AWS clients outside the handler function
78+
- Use dependency injection - pass all dependencies to service functions
79+
- Validate all inputs with Zod schemas
80+
- Use existing error classes from `shared/errors/`
81+
- Keep handlers thin - move business logic to service functions
82+
- Never create tests for handlers - only test service logic
83+
84+
#### Database Guidelines
85+
- Use **TypeORM** for PostgreSQL interactions
86+
- Use **UUID v4** for primary keys, avoid auto-increment IDs
87+
- Models must have `.model.ts` suffix and include factory methods
88+
- Always generate migrations
89+
- Migrations are auto-executed at application start
90+
- Pass repositories to service functions, never import directly
91+
92+
#### AWS Integration Guidelines
93+
- Use AWS SDK v3 with command pattern
94+
- Initialize AWS clients outside Lambda handlers for connection reuse
95+
- Use Step Functions for complex workflows
96+
- Follow AWS security best practices
97+
98+
#### Testing Guidelines
99+
- Create unit tests for service logic only (`.spec.ts` files)
100+
- Use Sinon for mocking AWS clients and external dependencies
101+
- Mock all external dependencies (databases, APIs, AWS services)
102+
- Test both success and error scenarios
103+
- Place tests next to the files they test
104+
105+
#### Error Handling Guidelines
106+
- Use existing error classes
107+
- Throw errors as exceptions - middleware handles responses
108+
- Include meaningful error messages with context
109+
110+
#### Security Guidelines
111+
- Never expose sensitive information in error messages
112+
- Validate all inputs with Zod schemas
113+
- Use proper IAM roles and permissions
114+
- Store secrets in AWS Parameter Store or Secrets Manager
115+
- Enable CORS only when necessary and configure properly
116+
117+
#### Middleware Guidelines
118+
- Always use the standard middleware stack in correct order
119+
- For non-HTTP triggers, omit HTTP-specific middleware
120+
- Use custom middleware sparingly and document well
121+
122+
#### Workflow Guidelines
123+
- Use Step Functions for complex business processes
124+
- Define workflows in Amazon States Language (ASL)
125+
- Each step should be a focused Lambda function
126+
- Handle errors and retries at the workflow level
127+
- Use Task Tokens for human-in-the-loop processes
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
applyTo: "**/functions/*/config/index.ts"
3+
---
4+
5+
## Configuration Structure
6+
- All functions must have a `config/index.ts` file for environment variable handling
7+
- Always use Zod for configuration validation
8+
- Use the pipeline pattern with `ts-pipe-compose`
9+
10+
## Basic Configuration Template
11+
```typescript
12+
import { z } from "zod";
13+
import { pipeline } from "ts-pipe-compose";
14+
15+
const loadEnvs = (env: any) => ({
16+
appName: env.APP_NAME,
17+
// Add other environment variables here
18+
});
19+
20+
const validateConfig = (config: any) => {
21+
const schema = z.object({
22+
appName: z.string().min(1),
23+
// Add validation for other variables
24+
});
25+
26+
try {
27+
return schema.parse(config);
28+
} catch (error) {
29+
throw new Error(error as string);
30+
}
31+
};
32+
33+
export const createConfig = pipeline(loadEnvs, validateConfig);
34+
```
35+
36+
## Environment Variable Naming
37+
- Use SCREAMING_SNAKE_CASE for environment variable names
38+
- Be descriptive: `EXCHANGE_RATES_API_URL` not `API_URL`
39+
- Include service name: `PAYMENT_SERVICE_API_KEY`
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
applyTo: "**/functions/*/handler.ts"
3+
---
4+
5+
## Lambda Handler Structure
6+
- All handlers must have a `.handler.ts` suffix
7+
- Always use the middy middleware framework with the standard middleware stack (see lambda-middleware.instructions.md)
8+
- Export the handler as `handle`
9+
10+
## Response Format
11+
- Always use `awsLambdaResponse` helper for consistent response formatting:
12+
```typescript
13+
import { awsLambdaResponse } from "../../shared/aws";
14+
import { StatusCodes } from "http-status-codes";
15+
16+
return awsLambdaResponse(StatusCodes.OK, {
17+
success: true,
18+
data: result,
19+
});
20+
```
21+
22+
## Business Logic Separation
23+
- Extract complex business logic into separate service functions
24+
- Pass all dependencies (clients, repositories, config) to service functions
25+
- Keep handlers thin - they should only handle HTTP concerns and orchestration
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
applyTo: "**/functions/*/handler.ts"
3+
---
4+
5+
## Middleware Stack
6+
Always use middleware in this specific order for consistency:
7+
8+
```typescript
9+
import middy from "@middy/core";
10+
import httpEventNormalizer from "@middy/http-event-normalizer";
11+
import httpHeaderNormalizer from "@middy/http-header-normalizer";
12+
import jsonBodyParser from "@middy/http-json-body-parser";
13+
import { inputOutputLoggerConfigured } from "../../shared/middleware/input-output-logger-configured";
14+
import { zodValidator } from "../../shared/middleware/zod-validator";
15+
import { queryParser } from "../../shared/middleware/query-parser";
16+
import { httpCorsConfigured } from "../../shared/middleware/http-cors-configured";
17+
import { httpErrorHandlerConfigured } from "../../shared/middleware/http-error-handler-configured";
18+
19+
export const handle = middy()
20+
.use(jsonBodyParser()) // 1. Parse JSON body
21+
.use(inputOutputLoggerConfigured()) // 2. Log inputs and outputs
22+
.use(httpEventNormalizer()) // 3. Normalize HTTP events
23+
.use(httpHeaderNormalizer()) // 4. Normalize HTTP headers
24+
.use(httpCorsConfigured) // 5. Handle CORS
25+
.use(queryParser()) // 6. Parse query parameters (optional)
26+
.use(zodValidator(yourLambdaSchema)) // 7. Validate input schema
27+
.use(httpErrorHandlerConfigured) // 8. Handle errors (MUST BE LAST)
28+
.handler(lambdaHandler);
29+
```
30+
31+
## Middleware Rules
32+
- `httpErrorHandlerConfigured` must always be the last middleware
33+
- `jsonBodyParser()` should be first for HTTP endpoints that accept JSON
34+
- `queryParser()` is optional - only include if your function uses query parameters
35+
- `zodValidator()` should come after all parsers but before error handler
36+
37+
## Optional Middleware
38+
- Include `queryParser()` only if your event schema includes `queryStringParameters`
39+
- For non-HTTP triggers (SQS, EventBridge), omit HTTP-specific middleware:
40+
- Skip `httpEventNormalizer()`
41+
- Skip `httpHeaderNormalizer()`
42+
- Skip `httpCorsConfigured`
43+
- Skip `queryParser()`
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
applyTo: "**/functions/*/event.schema.ts"
3+
---
4+
5+
## Event Schema Structure
6+
- All event schemas must have a `.event.schema.ts` suffix
7+
- Always use Zod for input validation and type generation
8+
- Export both the schema and the inferred type
9+
10+
## Naming Conventions
11+
- Schema names: `camelCase` with "Schema" suffix (e.g., `createTransactionSchema`)
12+
- Type names: `PascalCase` with "Payload" suffix (e.g., `CreateTransactionPayload`)
13+
- Use descriptive names that match the function purpose
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
applyTo: "**/functions/*/function.yml"
3+
---
4+
5+
## Serverless Function Configuration
6+
Each function must have a `function.yml` file with proper serverless framework configuration.
7+
8+
## Environment Variables
9+
Always include required environment variables:
10+
11+
## Naming Conventions
12+
- Function names: Use `kebab-case` matching the directory name
13+
- Handler path: Always `functions/{function-name}/handler.handle`
14+
- Environment variables: Use `SCREAMING_SNAKE_CASE`
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
applyTo: "**/functions/*/service.ts"
3+
---
4+
5+
## Service Layer Principles
6+
- Extract complex business logic into separate `service.ts` files
7+
- Services should be pure functions that accept all dependencies as parameters
8+
- Never import dependencies directly in services - use dependency injection
9+
10+
## Error Handling
11+
- Use existing error classes from `shared/errors/` (see lambda-error-handling.instructions.md)
12+
- Validate business rules and throw appropriate errors
13+
- Let the middleware handle error responses
14+
15+
## AWS SDK Integration
16+
- Use AWS SDK v3 with command pattern
17+
- Always pass clients as parameters
18+
- Handle AWS SDK errors appropriately:
19+
20+
## Database Operations
21+
- Always pass repositories as parameters
22+
- Use TypeORM query builder for complex queries:
23+
24+
## Business Logic Validation
25+
- Validate business rules before database operations
26+
- Use domain-specific errors for business rule violations:
27+
28+
## Return Values
29+
- Return only the data needed by the handler
30+
- Don't return entire entities if only ID is needed
31+
- Use meaningful return types:
32+
33+
## Utility Integration
34+
- Pass utility classes as parameters when needed:
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
applyTo: "**/functions/*/*.spec.ts"
3+
---
4+
5+
## Testing Lambda Services
6+
- Create unit tests for services in `.spec.ts` files placed next to the service file
7+
- Test file naming: `service.spec.ts` for `service.ts`
8+
- Never create tests for handlers - only test service logic
9+
10+
## What NOT to Test
11+
- Don't test middleware behavior (it's tested separately)
12+
- Don't test AWS SDK internals
13+
- Don't test TypeORM internals
14+
- Don't test validation schemas (Zod handles this)
15+
- Don't test handler functions (keep them thin)
16+
17+
## Test Coverage
18+
Ensure you test:
19+
- Happy path scenarios
20+
- All error conditions
21+
- Edge cases (empty data, boundary values)
22+
- Business rule validations
23+
- External service interactions
24+
- Database operations
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
---
2+
applyTo: "**/functions/**/*"
3+
---
4+
5+
# Serverless Lambda Development Guidelines
6+
7+
This is the main entry point for serverless lambda development instructions. Follow the specific guidelines based on the file you're working with:
8+
9+
## Quick Reference by File Type
10+
11+
### Handler Files (`handler.ts`)
12+
See: [lambda-handlers.instructions.md](lambda-handlers.instructions.md)
13+
- Main lambda entry point with middleware configuration
14+
- Database connection handling
15+
- AWS client initialization
16+
- Response formatting
17+
18+
### Middleware Configuration
19+
See: [lambda-middleware.instructions.md](lambda-middleware.instructions.md)
20+
- Standard middy middleware stack
21+
- Proper middleware ordering
22+
- HTTP vs non-HTTP lambda configurations
23+
24+
### Event Schemas (`event.schema.ts`)
25+
See: [lambda-schemas.instructions.md](lambda-schemas.instructions.md)
26+
- Zod validation schemas
27+
- Type generation
28+
- Common validation patterns
29+
30+
### Configuration (`config/index.ts`)
31+
See: [lambda-configuration.instructions.md](lambda-configuration.instructions.md)
32+
- Environment variable handling
33+
- Configuration validation
34+
- Pipeline pattern implementation
35+
36+
### Service Layer (`service.ts`)
37+
See: [lambda-services.instructions.md](lambda-services.instructions.md)
38+
- Business logic separation
39+
- Dependency injection patterns
40+
- AWS SDK integration
41+
42+
### Testing (`*.spec.ts`)
43+
See: [lambda-testing.instructions.md](lambda-testing.instructions.md)
44+
- Unit testing with Sinon
45+
- Mocking AWS services
46+
- Test structure and patterns
47+
48+
## Development Workflow
49+
50+
1. **Create Function Structure**: Use the plop template or create the required files manually
51+
2. **Define Event Schema**: Start with `event.schema.ts` to define input validation
52+
3. **Configure Environment**: Set up `config/index.ts` with required environment variables
53+
4. **Implement Handler**: Create the main `handler.ts` with middleware stack
54+
5. **Add Business Logic**: If complex, create `service.ts` with business logic
55+
6. **Write Tests**: Create `service.spec.ts` for testing business logic
56+
7. **Configure Serverless**: Set up `function.yml` with proper events and settings

0 commit comments

Comments
 (0)