# How Tool Data Is Structured in FckSignups: A Complete Guide to the JSON Schema

> Explore the FckSignups tool data structure. Understand the JSON schema with categories and tools arrays, guided by TypeScript. Learn how your data is organized.

- Repository: [Abdullah/FckSignups](https://github.com/BraveOPotato/FckSignups)
- Tags: deep-dive
- Published: 2026-09-08

---

**FckSignups stores all tool metadata in a single JSON file ([`tools.json`](https://github.com/BraveOPotato/FckSignups/blob/main/tools.json)) following a strict TypeScript schema with two top-level arrays—`categories` and `tools`—defined in [`src/types/index.ts`](https://github.com/BraveOPotato/FckSignups/blob/main/src/types/index.ts).**

The FckSignups repository organizes its entire catalog of sign-up-free tools using a flat JSON structure that prioritizes type safety and runtime flexibility. All public tool information lives in the root-level [`tools.json`](https://github.com/BraveOPotato/FckSignups/blob/main/tools.json) file, while TypeScript interfaces in [`src/types/index.ts`](https://github.com/BraveOPotato/FckSignups/blob/main/src/types/index.ts) enforce compile-time validation across the React application.

## The Core JSON Architecture

At the highest level, [`tools.json`](https://github.com/BraveOPotato/FckSignups/blob/main/tools.json) contains two parallel arrays that drive the entire UI:

```json
{
  "categories": [ ... ],
  "tools": [ ... ]
}

```

- **`categories`** – Defines the navigation taxonomy and filtering options available in the interface.
- **`tools`** – Contains individual tool metadata including URLs, descriptions, GitHub statistics, and UI placement directives.

This bifurcated structure allows the frontend to render category navigation independently from the tool grid, enabling efficient filtering without redundant data duplication.

## TypeScript Schema Definitions

The contract between the JSON source and the React components is enforced through interfaces located in **[src/types/index.ts](https://github.com/BraveOPotato/FckSignups/blob/main/src/types/index.ts)**.

### Category Interface

Each category object follows the `Category` interface:

```typescript
export interface Category {
  id: string;          // e.g. "productivity"
  name: string;        // human-readable label
  icon: string;        // emoji or UI icon
  description: string; // short blurb
}

```

The `id` field serves as the foreign key that links tools to their respective categories.

### Tool Interface

Individual tool entries conform to the `Tool` interface, which includes optional fields for GitHub metadata and editorial status:

```typescript
export interface Tool {
  id: string;                     // stable identifier (used for URLs, keys)
  name: string;                   // display name
  description: string;            // short marketing copy
  url: string;                    // direct link to the app
  category: string;               // matches a Category.id
  tags: string[];                 // free-form keywords for search
  github?: string;                // optional source repo
  license?: string;               // optional license name
  stars?: number;                 // GitHub star count (optional)
  section?: "featured" | "editors-pick" | "meets-criteria"; // UI grouping
  flag?: "new" | "abandoned";     // optional status flag
  addedAt?: string;               // ISO-date string for sorting
  notRecommendedReason?: string; // optional reason to hide from UI
}

```

The **optional chaining** (`?`) on fields like `github`, `stars`, and `section` allows the JSON to remain lean for tools without repository links or those awaiting editorial review.

## Category Metadata Structure

Category objects provide the taxonomy that drives the sidebar navigation and filter chips. A typical category entry looks like this:

```json
{
  "id": "design",
  "name": "Design & Graphics",
  "icon": "🎨",
  "description": "Create visuals right in your browser"
}

```

The UI constructs its category list directly from this array. At runtime, the application automatically injects a special `"all"` category (if missing) that aggregates every tool regardless of classification, ensuring users can always view the complete catalog.

## Tool Entry Field Reference

Each object in the `tools` array represents a single application or utility. Here is a representative entry for Excalidraw:

```json
{
  "id": "excalidraw",
  "name": "Excalidraw",
  "description": "Virtual whiteboard for sketching hand-drawn like diagrams",
  "url": "https://excalidraw.com",
  "category": "design",
  "tags": ["whiteboard", "diagrams", "sketch", "collaboration"],
  "github": "https://github.com/excalidraw/excalidraw",
  "license": "MIT",
  "stars": 131341,
  "addedAt": "2026-05-07",
  "section": "featured"
}

```

### Required vs. Optional Fields

| Field | Type | Purpose |
|-------|------|---------|
| **id** | `string` | Stable React key and URL slug for deep-linking |
| **name** | `string` | Display label rendered in tool cards |
| **description** | `string` | Marketing copy shown beneath the tool name |
| **url** | `string` | Direct external link users click to access the tool |
| **category** | `string` | Foreign key matching a `Category.id`; drives filtering logic |
| **tags** | `string[]` | Searchable keywords used by the tokenization algorithm |
| **github** | `string` (optional) | Repository URL for displaying source availability |
| **license** | `string` (optional) | SPDX identifier or license name |
| **stars** | `number` (optional) | GitHub star count displayed as social proof |
| **section** | `enum` (optional) | Editorial placement: `"featured"`, `"editors-pick"`, or `"meets-criteria"` |
| **flag** | `enum` (optional) | Status indicator: `"new"` or `"abandoned"` |
| **addedAt** | `ISO date` (optional) | Temporal marker for "new" badge logic and sorting |
| **notRecommendedReason** | `string` (optional) | Exclusion note; if present, hides tool from main listings |

## Runtime Loading and Fallback Strategy

The **[src/hooks/useTools.ts](https://github.com/BraveOPotato/FckSignups/blob/main/src/hooks/useTools.ts)** file orchestrates data fetching, caching, and normalization through the `useTools` React hook.

### Environment-Aware Fetching

The hook implements a tiered loading strategy:

1. **Development mode** – Loads from `DEV_JSON_URL` (local [`tools.json`](https://github.com/BraveOPotato/FckSignups/blob/main/tools.json))
2. **Production** – Fetches from `PROD_JSON_URL` (raw GitHub URL for the repository)
3. **Failure fallback** – Returns `FALLBACK_DATA` from **[src/constants/fallbackData.ts](https://github.com/BraveOPotato/FckSignups/blob/main/src/constants/fallbackData.ts)** if both network requests fail

### Data Normalization Pipeline

Once loaded, the hook processes the raw JSON through three transformations:

1. **Hydration** – Guarantees an `"all"` category exists for aggregate viewing
2. **Sectionization** – Normalizes tools into `ToolSections` based on the `section` field for grid layout
3. **Tokenization** – Pre-processes `tags` and `description` fields for fuzzy search matching via `tokenize()` and `matchScore()` utilities

## Practical Implementation Examples

### Accessing Tools in Components

Consume the data layer using the `useTools` hook:

```tsx
import { useTools } from "../hooks/useTools";

export function ToolCatalog() {
  const { tools, loadStatus, errorMessage } = useTools();

  if (loadStatus === "loading") return <p>Loading…</p>;
  if (loadStatus === "error") return <p>{errorMessage}</p>;

  return (
    <ul>
      {tools.map((t) => (
        <li key={t.id}>
          <a href={t.url} target="_blank" rel="noopener">
            {t.name}
          </a>
          {" "}
          – {t.description}
        </li>
      ))}
    </ul>
  );
}

```

The hook automatically merges remote JSON, fallback data, and injects the synthetic "all" category, returning a ready-to-render array.

### Implementing Search and Category Filters

The `useTools` hook exposes state setters and memoized filtered results for building interactive UIs:

```tsx
import { useTools } from "../hooks/useTools";

export function SearchableToolList() {
  const {
    filteredTools,
    categories,
    setActiveCategory,
    setSearchQuery,
    activeCategory,
    searchQuery,
  } = useTools();

  return (
    <>
      <select
        value={activeCategory}
        onChange={(e) => setActiveCategory(e.target.value)}
      >
        {categories.map((c) => (
          <option key={c.id} value={c.id}>
            {c.icon} {c.name}
          </option>
        ))}
      </select>

      <input
        type="search"
        placeholder="Search tools…"
        value={searchQuery}
        onChange={(e) => setSearchQuery(e.target.value)}
      />

      <ul>
        {filteredTools.map((t) => (
          <li key={t.id}>
            <a href={t.url}>{t.name}</a>
            {t.stars && <span>★{t.stars}</span>}
          </li>
        ))}
      </ul>
    </>
  );
}

```

The `filteredTools` array automatically applies both the active category filter and the search-keyword scoring logic defined in [`useTools.ts`](https://github.com/BraveOPotato/FckSignups/blob/main/useTools.ts).

### Adding Static Fallback Data

To ensure a tool appears even when GitHub Pages or the raw JSON endpoint is unreachable, append entries to `FALLBACK_DATA` in **src/constants/fallbackData.ts**:

```typescript
import type { ToolsData } from "../types";

export const FALLBACK_DATA: ToolsData = {
  categories: [
    { id: "utilities", name: "Utilities", icon: "🛠️", description: "Helpful tools" }
  ],
  tools: [
    {
      id: "my-awesome-tool",
      name: "My Awesome Tool",
      description: "A neat utility that requires no signup.",
      url: "https://example.com",
      category: "utilities",
      tags: ["awesome", "demo"],
      github: "https://github.com/example/tool",
      license: "MIT",
      stars: 123,
      addedAt: "2026-09-01",
      section: "featured",
    },
  ],
};

```

After rebuilding, this entry renders immediately without network dependencies.

## Summary

- **FckSignups** maintains all tool metadata in a flat [`tools.json`](https://github.com/BraveOPotato/FckSignups/blob/main/tools.json) structure with `categories` and `tools` arrays.
- **TypeScript interfaces** in [`src/types/index.ts`](https://github.com/BraveOPotato/FckSignups/blob/main/src/types/index.ts) strictly define the `Tool` and `Category` schemas, enforcing type safety across the React codebase.
- **Tool entries** require `id`, `name`, `description`, `url`, `category`, and `tags`, with optional fields for GitHub metadata (`stars`, `license`), editorial placement (`section`), and status flags (`flag`).
- **Runtime loading** employs a resilient strategy via [`useTools.ts`](https://github.com/BraveOPotato/FckSignups/blob/main/useTools.ts), falling back to hardcoded `FALLBACK_DATA` when network requests fail.
- **Automatic normalization** adds an `"all"` category and pre-computes search tokens for client-side filtering.

## Frequently Asked Questions

### Where is the tool data physically stored in the FckSignups repository?

All tool metadata resides in the root-level **[tools.json](https://github.com/BraveOPotato/FckSignups/blob/main/tools.json)** file, which is served directly from the repository and fetched at runtime by the `useTools` hook. TypeScript definitions that validate this structure are located in **src/types/index.ts**.

### What fields are required when adding a new tool to the catalog?

Every tool object must include `id` (unique string), `name` (display label), `description` (UI copy), `url` (external link), `category` (matching a valid category ID), and `tags` (array of search keywords). Optional fields such as `github`, `stars`, `license`, `section`, and `addedAt` enhance the display but are not required for the entry to render.

### How does FckSignups handle data loading failures or offline scenarios?

The application implements a three-tier fallback system in [`useTools.ts`](https://github.com/BraveOPotato/FckSignups/blob/main/useTools.ts): it attempts to load local JSON in development, falls back to the raw GitHub URL in production, and finally returns `FALLBACK_DATA` from **src/constants/fallbackData.ts** if both network requests fail. This ensures the UI remains functional even without connectivity.

### What is the purpose of the `section` field in tool entries?

The optional `section` field controls editorial placement within the UI grid, accepting one of three string values: `"featured"` (highlighted prominently), `"editors-pick"` (curated selections), or `"meets-criteria"` (standard listings). Tools without this field default to the standard grid layout without special visual distinction.