Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
3b97522
chore(database): add eslint 9 and jest configuration
Zaiidmo Mar 1, 2026
1f81f2c
fix(database): resolve lint errors and code formatting
Zaiidmo Mar 1, 2026
6665276
chore(database): add standardized CI/CD workflows
Zaiidmo Mar 1, 2026
3d1fe0e
chore(database): update dependencies
Zaiidmo Mar 1, 2026
95b769c
fix: resolve npm ci and jest config issues
Zaiidmo Mar 2, 2026
3d7a03d
fix: resolver npmci errors * Jest configs
Zaiidmo Mar 2, 2026
6293b8c
fix: update devDependencies and adjust coverage threshold
Zaiidmo Mar 2, 2026
d759d5e
chore: updated husky pre-configs
Zaiidmo Mar 2, 2026
f3d5738
chore: fixed and added code coverage >80%@
Zaiidmo Mar 2, 2026
92f425b
chore: optimize package.json scripts and lint-staged configuration
Zaiidmo Mar 2, 2026
613438d
chore: add .npmignore to prevent shipping unnecessary files
Zaiidmo Mar 2, 2026
39f63d0
chore: fix pre-push hook shell script header
Zaiidmo Mar 2, 2026
fbe13b2
ci: add npm audit to pr validation workflow
Zaiidmo Mar 2, 2026
a93c0f0
chore: add pull request template with comprehensive checklist
Zaiidmo Mar 2, 2026
90a2e73
chore: add CODEOWNERS for pr review assignment
Zaiidmo Mar 2, 2026
d68f443
chore: configure dependabot for automated dependency updates
Zaiidmo Mar 2, 2026
060bca2
ops: added dependabot config
Zaiidmo Mar 2, 2026
0e293b4
ops: added audit to the release-check workflow
Zaiidmo Mar 2, 2026
18a1a67
1.0.1
Zaiidmo Mar 2, 2026
a4d70a0
ops: updated huskey pre-configs & dependabots pipeline
Zaiidmo Mar 2, 2026
f9f45d7
merged
Zaiidmo Mar 2, 2026
5aabd7c
chore: fixed format errors
Zaiidmo Mar 2, 2026
39cd249
ci: add missing permissions to release-check workflow
Zaiidmo Mar 2, 2026
8d0ffe5
refactor: reduce code duplication in adapters
Zaiidmo Mar 2, 2026
492c5b6
ops: updated audit script
Zaiidmo Mar 2, 2026
9573725
fix(tests): remove duplications
Zaiidmo Mar 2, 2026
34f29a0
test: refactor database.service.spec.ts to use shared createMockAdapt…
Zaiidmo Mar 3, 2026
2f47ff1
refactor: reduce adapter complexity and test duplication
Zaiidmo Mar 3, 2026
c015e81
refactor(tests): eliminate code duplication to fix SonarQube Quality …
Zaiidmo Mar 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 25 additions & 25 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,16 +148,16 @@ constructor(@Inject(DATABASE_TOKEN) private db: DatabaseService) {}

```typescript
// ✅ Use specific NestJS exceptions
throw new NotFoundException("User not found");
throw new BadRequestException("Invalid input");
throw new ConflictException("Email already exists");
throw new InternalServerErrorException("Database error");
throw new NotFoundException('User not found');
throw new BadRequestException('Invalid input');
throw new ConflictException('Email already exists');
throw new InternalServerErrorException('Database error');

// ✅ Log errors with context
try {
await this.operation();
} catch (error) {
this.logger.error("Operation failed", error);
this.logger.error('Operation failed', error);
throw error;
}

Expand All @@ -175,11 +175,11 @@ try {
// ✅ Environment-driven configuration
const uri = process.env.MONGO_URI;
if (!uri) {
throw new Error("MONGO_URI not configured");
throw new Error('MONGO_URI not configured');
}

// ❌ Never hardcode values
const uri = "mongodb://localhost:27017/mydb";
const uri = 'mongodb://localhost:27017/mydb';
```

### 4. Type Safety
Expand Down Expand Up @@ -235,7 +235,7 @@ export class UserService {
async getUser(id: string): Promise<User> {
const user = await this.users.findById(id);
if (!user) {
throw new NotFoundException("User not found");
throw new NotFoundException('User not found');
}
return user;
}
Expand All @@ -253,7 +253,7 @@ export class UserService {
class MongoAdapter {
async createUser(data: CreateUserDto) {
if (await this.exists({ email: data.email })) {
throw new ConflictException("Email exists"); // Business logic!
throw new ConflictException('Email exists'); // Business logic!
}
return this.model.create(data);
}
Expand All @@ -275,19 +275,19 @@ const poolSize = 10;
const timeout = 5000;

// ✅ GOOD
const poolSize = parseInt(process.env.POOL_SIZE || "10", 10);
const timeout = parseInt(process.env.TIMEOUT || "5000", 10);
const poolSize = parseInt(process.env.POOL_SIZE || '10', 10);
const timeout = parseInt(process.env.TIMEOUT || '5000', 10);
```

### 3. Leaking Internal Types

```typescript
// ❌ BAD - Exporting internal implementation
export { MongoAdapter } from "./adapters/mongo.adapter";
export { MongoAdapter } from './adapters/mongo.adapter';

// ✅ GOOD - Only export public API
export { DatabaseService } from "./services/database.service";
export { Repository } from "./contracts/database.contracts";
export { DatabaseService } from './services/database.service';
export { Repository } from './contracts/database.contracts';
```

### 4. Direct Model Access in Services
Expand Down Expand Up @@ -323,7 +323,7 @@ export class UserService {
### Test Structure

```typescript
describe("DatabaseService", () => {
describe('DatabaseService', () => {
let service: DatabaseService;
let mockAdapter: jest.Mocked<MongoAdapter>;

Expand All @@ -343,8 +343,8 @@ describe("DatabaseService", () => {
service = module.get(DatabaseService);
});

describe("connect", () => {
it("should connect to database", async () => {
describe('connect', () => {
it('should connect to database', async () => {
await service.connect();
expect(mockAdapter.connect).toHaveBeenCalled();
});
Expand All @@ -362,34 +362,34 @@ describe("DatabaseService", () => {
// index.ts - Only these should be exported

// Module (primary)
export { DatabaseKitModule } from "./database-kit.module";
export { DatabaseKitModule } from './database-kit.module';

// Services (for direct injection)
export { DatabaseService } from "./services/database.service";
export { DatabaseService } from './services/database.service';

// Decorators (for DI)
export { InjectDatabase } from "./middleware/database.decorators";
export { InjectDatabase } from './middleware/database.decorators';

// Filters (for app-wide use)
export { DatabaseExceptionFilter } from "./filters/database-exception.filter";
export { DatabaseExceptionFilter } from './filters/database-exception.filter';

// Types (for consumers)
export {
Repository,
PageResult,
DatabaseConfig,
} from "./contracts/database.contracts";
} from './contracts/database.contracts';

// Utilities (for convenience)
export { isValidMongoId } from "./utils/validation.utils";
export { isValidMongoId } from './utils/validation.utils';
```

### ❌ DON'T Export

```typescript
// These should NOT be in index.ts
export { MongoAdapter } from "./adapters/mongo.adapter"; // Internal
export { PostgresAdapter } from "./adapters/postgres.adapter"; // Internal
export { MongoAdapter } from './adapters/mongo.adapter'; // Internal
export { PostgresAdapter } from './adapters/postgres.adapter'; // Internal
```

---
Expand Down
34 changes: 34 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
version: 2
updates:
# npm dependencies
- package-ecosystem: npm
directory: '/'
schedule:
interval: weekly
day: monday
time: '03:00'
open-pull-requests-limit: 5
assignees:
- CISCODE-MA/cloud-devops
labels:
- 'dependencies'
- 'npm'
commit-message:
prefix: 'chore(deps)'
include: 'scope'
rebase-strategy: auto

# GitHub Actions
- package-ecosystem: github-actions
directory: '/'
schedule:
interval: weekly
day: sunday
time: '03:00'
assignees:
- CISCODE-MA/cloud-devops
labels:
- 'dependencies'
- 'github-actions'
commit-message:
prefix: 'ci(deps)'
10 changes: 5 additions & 5 deletions .github/instructions/adapters.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ const model = mongoose.model<T>(name, schema);
} // Direct pass-through
{
status: {
$in: ["active", "pending"];
$in: ['active', 'pending'];
}
}
```
Expand All @@ -126,7 +126,7 @@ try {

```typescript
// MongoDB uses ObjectId
import { Types } from "mongoose";
import { Types } from 'mongoose';
const objectId = new Types.ObjectId(id);
```

Expand Down Expand Up @@ -156,8 +156,8 @@ const table = knex<T>(tableName);
```typescript
// Use Knex transaction
await knex.transaction(async (trx) => {
await trx("users").insert(data);
await trx("orders").insert(orderData);
await trx('users').insert(data);
await trx('orders').insert(orderData);
});
```

Expand All @@ -166,7 +166,7 @@ await knex.transaction(async (trx) => {
```typescript
// PostgreSQL uses auto-increment or UUID
// Return inserted row to get ID
const [inserted] = await knex("users").insert(data).returning("*");
const [inserted] = await knex('users').insert(data).returning('*');
```

---
Expand Down
32 changes: 16 additions & 16 deletions .github/instructions/bugfix.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@ pool: { min: 2, max: 10 }
// MongoDB - Is the filter format correct?
{
status: {
$eq: "active";
$eq: 'active';
}
}

// PostgreSQL - Are operators translated?
{
status: {
eq: "active";
eq: 'active';
}
} // → .where('status', '=', 'active')

Expand All @@ -92,7 +92,7 @@ if (this.softDelete) {
```typescript
// Is session/transaction passed to all operations?
await model.create([data], { session }); // MongoDB
await trx("table").insert(data); // PostgreSQL
await trx('table').insert(data); // PostgreSQL

// Is rollback called on error?
try {
Expand Down Expand Up @@ -149,10 +149,10 @@ await this.hooks.afterCreate(result);
### Step 1: Create Failing Test

```typescript
describe("Bug #123: Description", () => {
it("should handle the edge case correctly", async () => {
describe('Bug #123: Description', () => {
it('should handle the edge case correctly', async () => {
// This test should FAIL initially
const result = await repo.findById("");
const result = await repo.findById('');
expect(result).toBeNull(); // Currently throws
});
});
Expand Down Expand Up @@ -270,13 +270,13 @@ async findById(id: string): Promise<T | null> {

```typescript
// BAD
it.skip("should handle edge case", () => {
it.skip('should handle edge case', () => {
// "I'll fix this later"
});

// GOOD
it("should handle edge case", async () => {
expect(await repo.findById("")).toBeNull();
it('should handle edge case', async () => {
expect(await repo.findById('')).toBeNull();
});
```

Expand Down Expand Up @@ -307,26 +307,26 @@ async findById(id: string): Promise<T | null> {

```typescript
// In test
it("debug test", async () => {
it('debug test', async () => {
// Check actual database state
const allRecords = await repo.findAll({});
console.log("Current records:", allRecords);
console.log('Current records:', allRecords);

// Check what query returns
const result = await repo.findById("123");
console.log("Query result:", result);
const result = await repo.findById('123');
console.log('Query result:', result);
});
```

### Check Mongoose/Knex Debug

```typescript
// MongoDB - Enable Mongoose debug
mongoose.set("debug", true);
mongoose.set('debug', true);

// PostgreSQL - Knex debug
const knex = require("knex")({
client: "pg",
const knex = require('knex')({
client: 'pg',
debug: true,
// ...
});
Expand Down
20 changes: 10 additions & 10 deletions .github/instructions/features.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,12 @@ class PostgresRepository<T> implements Repository<T> {

```typescript
// src/adapters/mongo.adapter.spec.ts
describe("newMethod", () => {
it("should perform expected behavior", async () => {
describe('newMethod', () => {
it('should perform expected behavior', async () => {
// Test implementation
});

it("should handle edge cases", async () => {
it('should handle edge cases', async () => {
// Edge case tests
});
});
Expand All @@ -113,7 +113,7 @@ describe("newMethod", () => {
export {
// ... existing exports
NewReturnType, // If you added new types
} from "./contracts/database.contracts";
} from './contracts/database.contracts';
```

---
Expand Down Expand Up @@ -273,20 +273,20 @@ export function newUtility(input: string): string {

```typescript
// src/index.ts
export { newUtility } from "./utils/new.utils";
export { newUtility } from './utils/new.utils';
```

### Step 3: Add Tests

```typescript
// src/utils/new.utils.spec.ts
describe("newUtility", () => {
it("should transform input correctly", () => {
expect(newUtility("input")).toBe("expected");
describe('newUtility', () => {
it('should transform input correctly', () => {
expect(newUtility('input')).toBe('expected');
});

it("should handle edge cases", () => {
expect(newUtility("")).toBe("");
it('should handle edge cases', () => {
expect(newUtility('')).toBe('');
expect(newUtility(null as any)).toBeNull();
});
});
Expand Down
Loading
Loading