[TERMINAL · SKILLS]
> mounting /skills...
> indexing skill manifests...
> linking agents: claude · codex · gemini · cursor
> ready.
[░░░░░░░░░░░░░░░░░░░░░░░░░░░░] 0%
Use Cases/Build an Internal Feature Marketplace for Platform Teams

Build an Internal Feature Marketplace for Platform Teams

Create a self-service portal where product teams discover, request, and enable platform capabilities without filing tickets — reducing platform team toil by 60% and feature delivery time from weeks to hours.

Development#typescript#tsconfig#type-checking#type-safety#javascript-migration
Works with:claude-codeopenai-codexgemini-clicursor

Skills stack · 6 skills

Avg quality 95/100·All SAFE
>

typescript

v1.0.0

Sets up and repairs TypeScript projects: picks tsconfig.json settings for a Node.js service, an npm library or a bundled web app, runs type-checking in CI, and replaces `any` and unsafe casts with types the compiler can verify. Use when someone asks to "set up TypeScript", "fix this tsconfig", "fix a TypeScript error", "upgrade to TypeScript 6 or 7", "migrate JavaScript to TypeScript", "publish types for a package", "run .ts files in Node" or "make this type-safe". Covers the changed defaults in TypeScript 6.0 and 7.0, module and moduleResolution, strict mode, project references, declaration output, narrowing, satisfies and common compiler errors.

93/100 quality
7.30× impact
SAFE· stale score
View skill
>

hono

v1.1.0

Hono is a small web framework built on Web Standards (Request/Response) that runs unchanged on Cloudflare Workers, Deno, Bun, Node.js, AWS Lambda and Vercel. Use it when the user asks to build a Hono API, add Zod validation, JWT auth, CORS or middleware, use the type-safe RPC client (hc), render JSX, stream responses, or deploy one codebase to several runtimes.

100/100 quality
6.20× impact
SAFE· stale score
View skill
>

postgresql

v1.1.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.

100/100 quality
5.15× impact
SAFE· stale score
View skill
>

redis

v1.1.0

Redis is an in-memory data store used as a cache, session store, message broker and counter service. Use when adding a cache layer, storing sessions, rate limiting an API, running pub/sub or Streams with consumer groups, taking a distributed lock, building a leaderboard, or configuring Redis for production (persistence, maxmemory, eviction).

93/100 quality
1.79× impact
SAFE· stale score
View skill
>

zod

v1.1.0

Zod is a TypeScript-first schema library that validates data at runtime and infers static types from the same schema. Use when validating API request bodies, form input, environment variables or config files, parsing untrusted JSON, or migrating from Zod 3 to Zod 4. Covers z.object, safeParse, z.infer, coercion, discriminated unions, refinements, JSON Schema output and the v4 API changes.

93/100 quality
3.87× impact
SAFE· stale score
View skill
>

authjs

v1.1.0

Auth.js (formerly NextAuth.js) is an open-source authentication library that adds OAuth sign-in, magic links, credentials and WebAuthn to Next.js, SvelteKit, Express and other frameworks. Use when a user asks to add login with Google or GitHub, set up NextAuth v5, protect routes with middleware or proxy, add roles to the session, or connect a database adapter such as Drizzle or Prisma. Notes that the project is in maintenance mode under Better Auth.

93/100 quality
1.49× impact
SAFE· stale score
View skill
$

The Problem

A platform team of 5 engineers serves 12 product teams. Every request — new database, feature flag, monitoring dashboard, S3 bucket, API key — requires a Jira ticket, prioritization meeting, and manual provisioning. Average turnaround: 8 days. The platform team spends 70% of their time on repetitive provisioning instead of building reusable infrastructure. Product teams are frustrated: "I just need a Redis instance, why does it take 2 weeks?"

Step 1: Capability Registry

typescript
// src/marketplace/registry.ts
import { z } from 'zod';

export const Capability = z.object({
  id: z.string(),
  name: z.string(),
  description: z.string(),
  category: z.enum(['database', 'cache', 'messaging', 'monitoring', 'storage', 'auth', 'feature-flags', 'ci-cd']),
  tier: z.enum(['self-service', 'approval-required', 'custom']),
  provisioner: z.string(), // function that handles provisioning
  parameters: z.array(z.object({
    name: z.string(),
    type: z.enum(['string', 'number', 'boolean', 'select']),
    required: z.boolean(),
    default: z.unknown().optional(),
    options: z.array(z.string()).optional(),
    description: z.string(),
  })),
  estimatedTimeMinutes: z.number().int(),
  monthlyEstimateCents: z.number().int().optional(),
  owner: z.string().email(),
  docsUrl: z.string().url().optional(),
});

export const capabilities: z.infer<typeof Capability>[] = [
  {
    id: 'postgres-db',
    name: 'PostgreSQL Database',
    description: 'Managed PostgreSQL instance with automated backups and monitoring',
    category: 'database',
    tier: 'self-service',
    provisioner: 'provision-postgres',
    parameters: [
      { name: 'name', type: 'string', required: true, description: 'Database name (lowercase, hyphens)' },
      { name: 'size', type: 'select', required: true, options: ['small', 'medium', 'large'], description: 'Instance size', default: 'small' },
      { name: 'environment', type: 'select', required: true, options: ['development', 'staging', 'production'], description: 'Target environment' },
    ],
    estimatedTimeMinutes: 5,
    monthlyEstimateCents: 2500, // $25/mo for small
    owner: 'platform@company.com',
    docsUrl: 'https://wiki.internal/platform/postgres',
  },
  {
    id: 'redis-cache',
    name: 'Redis Cache',
    description: 'Managed Redis instance for caching and sessions',
    category: 'cache',
    tier: 'self-service',
    provisioner: 'provision-redis',
    parameters: [
      { name: 'name', type: 'string', required: true, description: 'Instance name' },
      { name: 'maxMemoryMb', type: 'select', required: true, options: ['256', '512', '1024', '2048'], description: 'Max memory', default: '256' },
      { name: 'environment', type: 'select', required: true, options: ['development', 'staging', 'production'], description: 'Target environment' },
    ],
    estimatedTimeMinutes: 2,
    monthlyEstimateCents: 1500,
    owner: 'platform@company.com',
  },
  {
    id: 'monitoring-dashboard',
    name: 'Grafana Dashboard',
    description: 'Pre-configured monitoring dashboard with alerting',
    category: 'monitoring',
    tier: 'self-service',
    provisioner: 'provision-grafana-dashboard',
    parameters: [
      { name: 'service', type: 'string', required: true, description: 'Service name to monitor' },
      { name: 'template', type: 'select', required: true, options: ['api', 'worker', 'database', 'custom'], description: 'Dashboard template' },
      { name: 'alertChannels', type: 'string', required: false, description: 'Slack channels for alerts (comma-separated)' },
    ],
    estimatedTimeMinutes: 1,
    owner: 'platform@company.com',
  },
  {
    id: 'production-namespace',
    name: 'Production K8s Namespace',
    description: 'Isolated Kubernetes namespace with RBAC, network policies, and resource quotas',
    category: 'ci-cd',
    tier: 'approval-required',
    provisioner: 'provision-k8s-namespace',
    parameters: [
      { name: 'team', type: 'string', required: true, description: 'Team name' },
      { name: 'cpuLimit', type: 'select', required: true, options: ['2', '4', '8', '16'], description: 'CPU cores limit' },
      { name: 'memoryLimitGb', type: 'select', required: true, options: ['4', '8', '16', '32'], description: 'Memory limit' },
    ],
    estimatedTimeMinutes: 15,
    owner: 'platform@company.com',
  },
];

Step 2: Provisioning Engine

typescript
// src/marketplace/provisioner.ts
import { Pool } from 'pg';
import { exec } from 'child_process';
import { promisify } from 'util';

const execAsync = promisify(exec);
const db = new Pool({ connectionString: process.env.DATABASE_URL });

type ProvisionResult = { success: boolean; outputs: Record<string, string>; error?: string };

const provisioners: Record<string, (params: Record<string, any>) => Promise<ProvisionResult>> = {
  'provision-postgres': async (params) => {
    const { name, size, environment } = params;
    const sizeMap: Record<string, string> = { small: 'db.t3.micro', medium: 'db.t3.small', large: 'db.t3.medium' };

    // Run Terraform to create the database
    await execAsync(`terraform apply -auto-approve -var="db_name=${name}" -var="instance_class=${sizeMap[size]}" -var="env=${environment}"`, {
      cwd: '/opt/terraform/modules/postgres',
    });

    // Get connection string from Terraform output
    const { stdout } = await execAsync('terraform output -json connection_string', {
      cwd: '/opt/terraform/modules/postgres',
    });

    const connectionString = JSON.parse(stdout);

    return {
      success: true,
      outputs: {
        connectionString,
        host: `${name}.db.internal`,
        port: '5432',
        dashboardUrl: `https://grafana.internal/d/postgres/${name}`,
      },
    };
  },

  'provision-redis': async (params) => {
    const { name, maxMemoryMb, environment } = params;

    await execAsync(`terraform apply -auto-approve -var="name=${name}" -var="memory=${maxMemoryMb}" -var="env=${environment}"`, {
      cwd: '/opt/terraform/modules/redis',
    });

    return {
      success: true,
      outputs: {
        host: `${name}.redis.internal`,
        port: '6379',
        maxMemory: `${maxMemoryMb}MB`,
      },
    };
  },

  'provision-grafana-dashboard': async (params) => {
    const { service, template } = params;

    // Create dashboard from template via Grafana API
    const templateJson = require(`/opt/grafana-templates/${template}.json`);
    templateJson.title = `${service} - ${template}`;

    const res = await fetch(`${process.env.GRAFANA_URL}/api/dashboards/db`, {
      method: 'POST',
      headers: { Authorization: `Bearer ${process.env.GRAFANA_TOKEN}`, 'Content-Type': 'application/json' },
      body: JSON.stringify({ dashboard: templateJson, overwrite: false }),
    });

    const result = await res.json() as any;

    return {
      success: true,
      outputs: { dashboardUrl: `${process.env.GRAFANA_URL}${result.url}` },
    };
  },
};

export async function provision(
  capabilityId: string,
  requestId: string,
  params: Record<string, any>,
  requestedBy: string
): Promise<ProvisionResult> {
  const provisionerFn = provisioners[capabilityId];
  if (!provisionerFn) throw new Error(`No provisioner for ${capabilityId}`);

  await db.query(`UPDATE requests SET status = 'provisioning' WHERE id = $1`, [requestId]);

  try {
    const result = await provisionerFn(params);

    await db.query(`
      UPDATE requests SET status = 'completed', outputs = $1, completed_at = NOW()
      WHERE id = $2
    `, [JSON.stringify(result.outputs), requestId]);

    return result;
  } catch (err: any) {
    await db.query(`UPDATE requests SET status = 'failed', error = $1 WHERE id = $2`, [err.message, requestId]);
    return { success: false, outputs: {}, error: err.message };
  }
}

Step 3: Self-Service API

typescript
// src/api/marketplace.ts
import { Hono } from 'hono';
import { capabilities } from '../marketplace/registry';
import { provision } from '../marketplace/provisioner';
import { Pool } from 'pg';

const app = new Hono();
const db = new Pool({ connectionString: process.env.DATABASE_URL });

app.get('/v1/capabilities', (c) => {
  return c.json({ capabilities });
});

app.post('/v1/capabilities/:id/request', async (c) => {
  const capId = c.req.param('id');
  const cap = capabilities.find(c => c.id === capId);
  if (!cap) return c.json({ error: 'Capability not found' }, 404);

  const params = await c.req.json();
  const requestedBy = c.get('userId');
  const requestId = crypto.randomUUID();

  await db.query(`
    INSERT INTO requests (id, capability_id, params, requested_by, status, created_at)
    VALUES ($1, $2, $3, $4, $5, NOW())
  `, [requestId, capId, JSON.stringify(params), requestedBy, cap.tier === 'self-service' ? 'provisioning' : 'pending_approval']);

  if (cap.tier === 'self-service') {
    // Auto-provision
    const result = await provision(cap.provisioner, requestId, params, requestedBy);
    return c.json({ requestId, status: 'completed', outputs: result.outputs });
  }

  return c.json({ requestId, status: 'pending_approval', estimatedTime: '1-2 business days' });
});

export default app;

Results

  • Provisioning time: 5 minutes for self-service items (was 8 days average)
  • Platform team toil: 60% reduction — automated 80% of repetitive requests
  • Ticket volume: dropped from 50/week to 12/week (only custom/approval items)
  • Product team satisfaction: NPS +62 (was -15)
  • New database creation: click a button, get connection string in 5 minutes
  • Cost visibility: each team sees their infrastructure spend in real-time
  • Onboarding: new teams self-service their entire stack in day 1

Related use cases