[TERMINAL · SKILLS]
> mounting /skills...
> indexing 295 manifests...
> linking agents: claude · codex · gemini · cursor
> ready.
[░░░░░░░░░░░░░░░░░░░░░░░░░░░░] 0%
Terminal.skills
Use Cases/Build a Config Management Service

Build a Config Management Service

Build a centralized configuration management service with environment-specific overrides, secret encryption, hot-reload, validation, audit logging, and rollback.

#redis#caching#database#pub-sub#queues
Works with:claude-codeopenai-codexgemini-clicursor

Skills stack · 5 skills

Avg quality 93/100·All SAFE
>

typescript

v

Not yet scored
View skill
>

redis

v1.0.0

Build applications with Redis — caching, session storage, pub/sub, streams, rate limiting, leaderboards, and queues. Use when tasks involve in-memory data storage, real-time messaging, distributed locking, or performance optimization with caching layers.

93/100 quality
1.81× impact
SAFE
View skill
>

postgresql

v1.0.0

Assists with designing schemas, writing performant queries, managing indexes, and operating PostgreSQL databases. Use when working with JSONB, full-text search, window functions, CTEs, row-level security, replication, or performance tuning. Trigger words: postgresql, postgres, sql, database, jsonb, rls, window functions, cte.

87/100 quality
1.53× impact
SAFE
View skill
>

hono

v1.0.0

You are an expert in Hono, the ultrafast web framework for the edge. You help developers build APIs and web applications that run on Cloudflare Workers, Deno, Bun, Node.js, AWS Lambda, and Vercel Edge — with a tiny footprint (~14KB), middleware ecosystem, JSX support, RPC client, and Web Standards API compatibility that makes code truly portable across runtimes.

93/100 quality
3.00× impact
SAFE
View skill
>

zod

v1.0.0

You are an expert in Zod, the TypeScript-first schema declaration and validation library. You help developers define schemas that validate data at runtime AND infer TypeScript types at compile time — eliminating the need to write types and validators separately. Used for API input validation, form validation, environment variables, config files, and any data boundary.

100/100 quality
1.21× impact
SAFE
View skill
$

The Problem

Priya leads platform at a 20-person company running 15 microservices. Configuration is scattered: some in .env files, some in Kubernetes ConfigMaps, some hardcoded. Changing a feature flag requires a redeploy. Secrets are in plaintext in environment variables. Nobody knows which service uses which config keys. When someone changed the wrong Redis URL, three services went down simultaneously. They need centralized config: one source of truth, environment-specific overrides, encrypted secrets, hot-reload without redeploy, and audit trail.

Step 1: Build the Config Service

typescript
// src/config/service.ts — Centralized config management with encryption and hot-reload
import { pool } from "../db";
import { Redis } from "ioredis";
import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from "node:crypto";

const redis = new Redis(process.env.REDIS_URL!);

interface ConfigEntry {
  key: string;
  value: any;
  type: "string" | "number" | "boolean" | "json" | "secret";
  environment: string;       // "production", "staging", "development", "*" (all)
  service: string;           // "*" for global, or specific service name
  description: string;
  validationRule?: string;   // JSON schema or regex
  updatedBy: string;
  updatedAt: string;
  version: number;
}

const ENCRYPTION_KEY = scryptSync(process.env.CONFIG_MASTER_KEY || "change-me", "salt", 32);

// Get config for a service/environment
export async function getConfig(
  service: string,
  environment: string
): Promise<Record<string, any>> {
  const cacheKey = `config:${service}:${environment}`;
  const cached = await redis.get(cacheKey);
  if (cached) return JSON.parse(cached);

  // Load configs: global → environment → service → service+environment
  const { rows } = await pool.query(
    `SELECT * FROM config_entries
     WHERE (service = '*' OR service = $1)
       AND (environment = '*' OR environment = $2)
     ORDER BY
       CASE WHEN service = '*' AND environment = '*' THEN 1
            WHEN service = '*' THEN 2
            WHEN environment = '*' THEN 3
            ELSE 4 END`,
    [service, environment]
  );

  const config: Record<string, any> = {};
  for (const row of rows) {
    let value = row.value;
    if (row.type === "secret") value = decrypt(value);
    else if (row.type === "number") value = Number(value);
    else if (row.type === "boolean") value = value === "true";
    else if (row.type === "json") value = JSON.parse(value);
    config[row.key] = value;
  }

  await redis.setex(cacheKey, 30, JSON.stringify(config));  // short TTL for hot-reload
  return config;
}

// Set config value
export async function setConfig(params: {
  key: string;
  value: any;
  type: ConfigEntry["type"];
  environment: string;
  service: string;
  description?: string;
  validationRule?: string;
  updatedBy: string;
}): Promise<void> {
  // Validate value
  if (params.validationRule) {
    const valid = validateValue(params.value, params.validationRule);
    if (!valid) throw new Error(`Validation failed for key ${params.key}`);
  }

  // Encrypt secrets
  let storedValue = String(params.value);
  if (params.type === "secret") storedValue = encrypt(String(params.value));

  // Get current version for audit
  const { rows: [current] } = await pool.query(
    "SELECT version, value FROM config_entries WHERE key = $1 AND environment = $2 AND service = $3",
    [params.key, params.environment, params.service]
  );
  const newVersion = current ? current.version + 1 : 1;

  // Save change history
  if (current) {
    await pool.query(
      `INSERT INTO config_history (key, environment, service, old_value, new_value, version, changed_by, changed_at)
       VALUES ($1, $2, $3, $4, $5, $6, $7, NOW())`,
      [params.key, params.environment, params.service, current.value, storedValue, newVersion, params.updatedBy]
    );
  }

  // Upsert config
  await pool.query(
    `INSERT INTO config_entries (key, value, type, environment, service, description, validation_rule, updated_by, version, updated_at)
     VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, NOW())
     ON CONFLICT (key, environment, service) DO UPDATE SET
       value = $2, type = $3, description = COALESCE($6, config_entries.description),
       updated_by = $8, version = $9, updated_at = NOW()`,
    [params.key, storedValue, params.type, params.environment, params.service,
     params.description, params.validationRule, params.updatedBy, newVersion]
  );

  // Invalidate cache and notify services
  await redis.del(`config:${params.service}:${params.environment}`);
  await redis.del(`config:*:${params.environment}`);
  await redis.publish("config:changed", JSON.stringify({
    key: params.key, environment: params.environment, service: params.service, version: newVersion,
  }));
}

// Rollback config to previous version
export async function rollbackConfig(
  key: string, environment: string, service: string, targetVersion: number, userId: string
): Promise<void> {
  const { rows: [history] } = await pool.query(
    "SELECT old_value FROM config_history WHERE key = $1 AND environment = $2 AND service = $3 AND version = $4",
    [key, environment, service, targetVersion]
  );
  if (!history) throw new Error("Version not found");

  const { rows: [current] } = await pool.query(
    "SELECT type FROM config_entries WHERE key = $1 AND environment = $2 AND service = $3",
    [key, environment, service]
  );

  await setConfig({
    key, value: history.old_value, type: current?.type || "string",
    environment, service, updatedBy: userId,
    description: `Rolled back to version ${targetVersion}`,
  });
}

function encrypt(plaintext: string): string {
  const iv = randomBytes(16);
  const cipher = createCipheriv("aes-256-gcm", ENCRYPTION_KEY, iv);
  const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
  const tag = cipher.getAuthTag();
  return iv.toString("hex") + ":" + encrypted.toString("hex") + ":" + tag.toString("hex");
}

function decrypt(ciphertext: string): string {
  const [ivHex, encHex, tagHex] = ciphertext.split(":");
  const decipher = createDecipheriv("aes-256-gcm", ENCRYPTION_KEY, Buffer.from(ivHex, "hex"));
  decipher.setAuthTag(Buffer.from(tagHex, "hex"));
  return decipher.update(Buffer.from(encHex, "hex")) + decipher.final("utf8");
}

function validateValue(value: any, rule: string): boolean {
  try {
    const regex = new RegExp(rule);
    return regex.test(String(value));
  } catch {
    return true;
  }
}

// Get change audit trail
export async function getAuditTrail(
  key: string, environment?: string
): Promise<Array<{ version: number; oldValue: string; newValue: string; changedBy: string; changedAt: string }>> {
  let sql = "SELECT * FROM config_history WHERE key = $1";
  const params: any[] = [key];
  if (environment) { sql += " AND environment = $2"; params.push(environment); }
  sql += " ORDER BY version DESC LIMIT 50";
  const { rows } = await pool.query(sql, params);
  return rows;
}

Results

  • One source of truth — all 15 services read config from one place; no more scattered .env files and hardcoded values
  • Hot-reload without redeploy — change feature flag, services pick it up in 30 seconds via short cache TTL + pub/sub notification; no rolling restart needed
  • Secrets encrypted at rest — AES-256-GCM encryption; database breach doesn't expose API keys; secrets decrypted only in memory at read time
  • Wrong Redis URL incident prevented — validation rules catch invalid URLs before save; environment-specific overrides mean staging changes can't affect production
  • Full audit trail — every config change logged with who, when, old value, new value; rollback to any previous version in one call