agent-health
Reads production/traces/agent-metrics.jsonl and displays a per-agent performance summary table for the current or a specified session. Highlights agents with…
Applies production backend patterns: middleware, error handling, auth, database integration, and API design. Use when working with backend service files or when the user mentions Express, Fastify, NestJS, backend patterns, or service architecture.
$ npx -y skills add tranhieutt/software_development_department --skill backend-patterns --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/backend-patternsContext preview
The summary Claude sees to decide when to auto-load this skill.
Applies production backend patterns: middleware, error handling, auth, database integration, and API design. Use when working with backend service files or when the user mentions Express, Fastify, NestJS, backend patterns, or service architecture.
name: backend-patterns type: reference description: "Applies production backend patterns: middleware, error handling, auth, database integration, and API design. Use when working with backend service files or when the user mentions Express, Fastify, NestJS, backend patterns, or service architecture." paths: ["**/*.ts", "**/*.js", "**/server.*", "**/app.*", "**/routes/**"] effort: 3 allowed-tools: Read, Glob, Grep, Write, Edit, Bash context: fork agent: backend-developer user-invocable: true when_to_use: "When building Node.js backend services with Express, Fastify, or similar frameworks"
import express from "express";
import "express-async-errors"; // patches async error handling globally
import helmet from "helmet";
import { rateLimit } from "express-rate-limit";
const app = express();
app.use(helmet());
app.use(express.json({ limit: "10kb" }));
app.use(rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }));
// Routes
app.use("/api/v1/users", userRouter);
app.use("/api/v1/products", productRouter);
// 404 handler — must come after all routes
app.use((req, res) => res.status(404).json({ error: "Not found" }));
// Global error handler — must have 4 params
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
const status = err instanceof AppError ? err.statusCode : 500;
res.status(status).json({ error: err.message });
});interface IUserRepository {
findById(id: string): Promise<User | null>;
findByEmail(email: string): Promise<User | null>;
save(user: User): Promise<User>;
delete(id: string): Promise<void>;
}
class PgUserRepository implements IUserRepository {
constructor(private readonly db: Pool) {}
async findById(id: string) {
const { rows } = await this.db.query(
"SELECT * FROM users WHERE id = $1 AND deleted_at IS NULL", [id]
);
return rows[0] ?? null;
}
}class AppError extends Error {
constructor(public message: string, public statusCode: number) { super(message); }
}
class NotFoundError extends AppError { constructor(msg: string) { super(msg, 404); } }
class ForbiddenError extends AppError { constructor(msg: string) { super(msg, 403); } }
class UserService {
async getUser(id: string, requesterId: string): Promise<User> {
const user = await this.repo.findById(id);
if (!user) throw new NotFoundError(`User ${id} not found`);
if (user.id !== requesterId && !isAdmin(requesterId)) throw new ForbiddenError("Access denied");
return user;
}
}import jwt from "jsonwebtoken";
export function authenticate(req: Request, res: Response, next: NextFunction) {
const token = req.headers.authorization?.split(" ")[1];
if (!token) return res.status(401).json({ error: "No token" });
try {
req.user = jwt.verify(token, process.env.JWT_SECRET!) as JWTPayload;
next();
} catch {
res.status(401).json({ error: "Invalid token" });
}
}import { Pool } from "pg";
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 20, // pool size
idleTimeoutMillis: 30_000,
connectionTimeoutMillis: 2_000,
});
// Test connection on startup
async function connectWithRetry(retries = 5, delay = 2000) {
for (let i = 0; i < retries; i++) {
try {
await pool.query("SELECT 1");
console.log("DB connected");
return;
} catch (err) {
if (i === retries - 1) throw err;
await new Promise(r => setTimeout(r, delay * (i + 1))); // exponential backoff
}
}
}const server = app.listen(PORT);
async function shutdown(signal: string) {
console.log(`${signal} received. Shutting down gracefully.`);
server.close(async () => {
await pool.end(); // drain DB connections
process.exit(0);
});
setTimeout(() => process.exit(1), 10_000); // force exit after 10s
}
process.on("SIGTERM", () => shutdown("SIGTERM"));
process.on("SIGINT", () => shutdown("SIGINT"));| Pitfall | Fix | |---|---| | Async handler without try/catch | Use `express-async-errors` package | | `await` inside `forEach` | Use `Promise.all(array.map(async...))` | | Logging raw errors to client | Log internally; return sanitized message to client | | Missing `return` after `res.json()` | Always `return res.json(...)` to stop execution | | Secrets in `config.js` | Use `process.env` + validation on startup |
Repo: tranhieutt/software_development_department
Reads production/traces/agent-metrics.jsonl and displays a per-agent performance summary table for the current or a specified session. Highlights agents with…
Provides the vendored agent-style v0.3.5 prose rule pack as a portable Claude skill. Use when installing, syncing, applying, or auditing SDD Agent-Style…
Provides Angular best practices for components, modules, services, and reactive patterns. Use when working with Angular TypeScript files, component templates,…
Records unexpected API behaviors, undocumented caveats, version bugs, or non-obvious workarounds into .claude/memory/annotations.md. Use immediately when an…
Defines REST and GraphQL API contracts including endpoints, request/response schemas, auth flows, and versioning strategy. Use when designing a new API,…
Manages the ADR (Architecture Decision Record) registry. Use when recording tech-stack choices, design patterns, or infrastructure decisions with context,…