V Ranadheer

Product & Design

V Ranadheer
Projects

CaseCraft

3 October, 2026

CaseCraft turns a one-line product flow into a prioritized checklist of the UX states that flow needs: default, loading, success, empty, error, recovery, and the awkward edge cases that usually show up late.

The goal was not to wrap an AI response in a chat UI. I wanted the output to become something a designer, PM, or frontend engineer could actually work through: grouped, checkable, copyable, and honest about what was generated versus what fell back safely.

0:00
Play

A product film showing CaseCraft turning a rough flow into a structured UX state checklist.

The Product Shape

A screen is rarely one screen. Password reset includes invalid emails, expired links, repeated submits, empty fields, slow requests, unavailable inboxes, and people returning halfway through. CaseCraft treats those moments as the product surface, not as cleanup work after the happy path.

The interface starts with a single prompt and returns a working state matrix. Each item has a category, a Must / Should / Could priority, and a short note. As states are checked off, the coverage percentage updates, making the list feel less like generated text and more like a design-readiness tool.

Making AI Useful, Not Loose

The important product decision was to distrust the model just enough. CaseCraft asks the AI for structured output, but the app still validates, normalizes, orders, de-duplicates, and repairs the result before it reaches the screen.

If the model returns garbage, times out, or the API is unavailable, the user does not hit a dead end. They get a clearly labelled starter checklist instead. That keeps the tool usable during a demo and makes the reliability boundary visible instead of pretending the AI is always correct.

schema.ts
1export function normalizeSuggestedGroups(groups) {
2 if (!Array.isArray(groups) || !groups.length) {
3 return starterGroups;
4 }
5
6 const byCategory = new Map();
7 const seenTitles = new Set();
8
9 for (const group of groups) {
10 const states = Array.isArray(group?.states) ? group.states : [];
11
12 for (const state of states) {
13 const title = typeof state?.title === "string" ? state.title.trim() : "";
14 const titleKey = title.toLowerCase();
15
16 if (!title || seenTitles.has(titleKey)) continue;
17 seenTitles.add(titleKey);
18
19 const category = normalizeCategory(state.category || group.category);
20 const note = typeof state.note === "string" ? state.note.trim() : "";
21
22 byCategory.set(category, [
23 ...(byCategory.get(category) ?? []),
24 {
25 title,
26 category,
27 priority: normalizePriority(state.priority),
28 note: note || undefined,
29 },
30 ]);
31 }
32 }
33
34 const normalized = stateCategories
35 .filter((category) => byCategory.has(category))
36 .map((category) => ({ category, states: byCategory.get(category) }));
37
38 return normalized.length ? normalized : starterGroups;
39}

This normalizer is the quiet core of the project. It turns model output into a stable interface contract: categories are forced into known buckets, invalid priorities become safe defaults, duplicate titles are dropped, empty results fall back to starter states, and the final groups render in a consistent order.

The Workflow Layer

The checklist can be filtered by priority, sections can collapse, individual states can be copied, and the whole artifact exports as Markdown with the current checkmarks intact. That makes the output portable: it can move into a product doc, a Linear ticket, a design review, or directly into a coding agent as implementation context.

There is also a second pass called “Check for missed states.” It sends the original flow plus the titles already covered, then asks only for gaps. Suggestions can be accepted into the existing list, which keeps the flow iterative without turning it into an endless chat thread.

Built For A Public URL

Since the app is public, the server routes include request-size checks, per-visitor rate limits, and a global ceiling to protect the model budget. The frontend also persists the thread locally, so a refresh keeps the generated states and check-offs without needing a database or account system.

The result is a small product with a clear boundary: CaseCraft does not claim to replace product thinking. It gives the team a stronger starting point, especially before handoff, when missing states are still cheap to catch.

Try it here: usecasecraft-delta.vercel.app