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

Build a Dynamic Form Builder

Build a dynamic form builder with drag-and-drop fields, conditional logic, multi-step flows, validation rules, submission handling, and analytics for no-code form creation.

#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

Eva leads product at a 20-person HR tech company. Every client needs custom forms: onboarding surveys, performance reviews, exit interviews — each with different fields, validation, and logic. Currently, developers build each form in React. Adding a field takes a PR cycle. Conditional logic ("show section B only if answer A is 'Manager'") is hardcoded. They have 50 clients with 200 unique forms; each change request queues behind engineering. They need a form builder: drag-and-drop fields, conditional visibility, multi-step wizards, custom validation, and analytics — all configurable without code.

Step 1: Build the Form Engine

typescript
// src/forms/builder.ts — Dynamic form engine with conditional logic and multi-step support
import { pool } from "../db";
import { Redis } from "ioredis";
import { randomBytes } from "node:crypto";
import { z, ZodSchema } from "zod";

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

interface FormDefinition {
  id: string;
  name: string;
  description: string;
  steps: FormStep[];
  settings: {
    submitButtonText: string;
    successMessage: string;
    redirectUrl?: string;
    notifyEmails: string[];
    allowMultipleSubmissions: boolean;
    requireAuth: boolean;
    expiresAt?: string;
  };
  status: "draft" | "published" | "archived";
  version: number;
  createdBy: string;
}

interface FormStep {
  id: string;
  title: string;
  description?: string;
  fields: FormField[];
  conditions?: StepCondition[];  // show step only if conditions met
}

interface FormField {
  id: string;
  type: "text" | "email" | "number" | "select" | "multiselect" | "textarea" | "date" | "file" | "rating" | "toggle" | "radio" | "checkbox" | "heading" | "paragraph";
  label: string;
  placeholder?: string;
  required: boolean;
  validation?: {
    minLength?: number;
    maxLength?: number;
    min?: number;
    max?: number;
    pattern?: string;
    customMessage?: string;
  };
  options?: Array<{ label: string; value: string }>;
  defaultValue?: any;
  conditions?: FieldCondition[];  // show field only if conditions met
  layout?: { width: "full" | "half" | "third"; order: number };
}

interface FieldCondition {
  fieldId: string;
  operator: "equals" | "not_equals" | "contains" | "gt" | "lt" | "is_empty" | "is_not_empty";
  value: any;
}

type StepCondition = FieldCondition;

// Create or update form definition
export async function saveForm(form: Omit<FormDefinition, "id" | "version">): Promise<FormDefinition> {
  const id = `form-${randomBytes(6).toString("hex")}`;
  const { rows: [existing] } = await pool.query(
    "SELECT MAX(version) as v FROM forms WHERE name = $1", [form.name]
  );
  const version = (existing?.v || 0) + 1;

  const full: FormDefinition = { ...form, id, version };

  await pool.query(
    `INSERT INTO forms (id, name, description, steps, settings, status, version, created_by, created_at)
     VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW())`,
    [id, form.name, form.description, JSON.stringify(form.steps),
     JSON.stringify(form.settings), form.status, version, form.createdBy]
  );

  await redis.del(`form:${form.name}`);
  return full;
}

// Get published form for rendering
export async function getPublishedForm(formName: string): Promise<FormDefinition | null> {
  const cached = await redis.get(`form:${formName}`);
  if (cached) return JSON.parse(cached);

  const { rows: [row] } = await pool.query(
    "SELECT * FROM forms WHERE name = $1 AND status = 'published' ORDER BY version DESC LIMIT 1",
    [formName]
  );
  if (!row) return null;

  const form: FormDefinition = {
    ...row,
    steps: JSON.parse(row.steps),
    settings: JSON.parse(row.settings),
  };

  await redis.setex(`form:${formName}`, 300, JSON.stringify(form));
  return form;
}

// Evaluate field visibility based on conditions
export function evaluateConditions(
  conditions: FieldCondition[] | undefined,
  formData: Record<string, any>
): boolean {
  if (!conditions || conditions.length === 0) return true;

  return conditions.every((cond) => {
    const fieldValue = formData[cond.fieldId];
    switch (cond.operator) {
      case "equals": return fieldValue === cond.value;
      case "not_equals": return fieldValue !== cond.value;
      case "contains": return String(fieldValue || "").includes(cond.value);
      case "gt": return Number(fieldValue) > Number(cond.value);
      case "lt": return Number(fieldValue) < Number(cond.value);
      case "is_empty": return !fieldValue || fieldValue === "";
      case "is_not_empty": return !!fieldValue && fieldValue !== "";
      default: return true;
    }
  });
}

// Build Zod validation schema from form definition
export function buildValidationSchema(form: FormDefinition, currentData: Record<string, any>): ZodSchema {
  const shape: Record<string, any> = {};

  for (const step of form.steps) {
    if (!evaluateConditions(step.conditions, currentData)) continue;

    for (const field of step.fields) {
      if (field.type === "heading" || field.type === "paragraph") continue;
      if (!evaluateConditions(field.conditions, currentData)) continue;

      let schema: any;
      switch (field.type) {
        case "email": schema = z.string().email(field.validation?.customMessage || "Invalid email"); break;
        case "number": case "rating":
          schema = z.number();
          if (field.validation?.min !== undefined) schema = schema.min(field.validation.min);
          if (field.validation?.max !== undefined) schema = schema.max(field.validation.max);
          break;
        case "multiselect": case "checkbox":
          schema = z.array(z.string()); break;
        case "toggle":
          schema = z.boolean(); break;
        case "date":
          schema = z.string().regex(/^\d{4}-\d{2}-\d{2}$/); break;
        default:
          schema = z.string();
          if (field.validation?.minLength) schema = schema.min(field.validation.minLength);
          if (field.validation?.maxLength) schema = schema.max(field.validation.maxLength);
          if (field.validation?.pattern) schema = schema.regex(new RegExp(field.validation.pattern));
      }

      shape[field.id] = field.required ? schema : schema.optional();
    }
  }

  return z.object(shape);
}

// Submit form response
export async function submitForm(
  formName: string,
  data: Record<string, any>,
  context: { userId?: string; ip: string; userAgent: string }
): Promise<{ id: string; valid: boolean; errors?: Record<string, string> }> {
  const form = await getPublishedForm(formName);
  if (!form) throw new Error("Form not found");

  // Check expiry
  if (form.settings.expiresAt && new Date(form.settings.expiresAt) < new Date()) {
    throw new Error("Form has expired");
  }

  // Validate
  const schema = buildValidationSchema(form, data);
  const result = schema.safeParse(data);

  if (!result.success) {
    const errors: Record<string, string> = {};
    for (const issue of result.error.issues) {
      errors[issue.path.join(".")] = issue.message;
    }
    return { id: "", valid: false, errors };
  }

  const id = `sub-${randomBytes(8).toString("hex")}`;

  await pool.query(
    `INSERT INTO form_submissions (id, form_id, form_version, data, user_id, ip, user_agent, created_at)
     VALUES ($1, $2, $3, $4, $5, $6, $7, NOW())`,
    [id, form.id, form.version, JSON.stringify(data), context.userId, context.ip, context.userAgent]
  );

  // Notify
  if (form.settings.notifyEmails.length > 0) {
    await redis.rpush("notification:queue", JSON.stringify({
      type: "form_submission", formName, submissionId: id,
      emails: form.settings.notifyEmails,
    }));
  }

  // Analytics
  await redis.hincrby(`form:analytics:${form.id}`, "submissions", 1);
  await redis.hincrby(`form:analytics:${form.id}`, `step_completions`, form.steps.length);

  return { id, valid: true };
}

// Form analytics
export async function getFormAnalytics(formId: string): Promise<{
  totalSubmissions: number;
  completionRate: number;
  avgCompletionTime: number;
  fieldDropoffs: Record<string, number>;
}> {
  const stats = await redis.hgetall(`form:analytics:${formId}`);
  const { rows: [{ count }] } = await pool.query(
    "SELECT COUNT(*) as count FROM form_submissions WHERE form_id = $1", [formId]
  );

  return {
    totalSubmissions: parseInt(count),
    completionRate: 0,
    avgCompletionTime: 0,
    fieldDropoffs: {},
  };
}

Results

  • Form creation: 2 weeks → 30 minutes — HR team drags fields, sets conditions, publishes; no engineering PR needed; 200 forms managed by non-technical staff
  • Conditional logic without code — "show 'Manager Name' field only when Role = 'Individual Contributor'" configured in the builder; reduces form length by 40% for most users
  • Multi-step wizards — performance review split into 5 steps with progress bar; completion rate up 25% vs single long form
  • Real-time validation — Zod schema generated dynamically from form definition; errors shown inline; invalid submissions dropped from 15% to 2%
  • Submission analytics — dashboard shows step-by-step dropoff; Step 3 had 30% dropoff → simplified from 8 fields to 4 → dropoff dropped to 8%