# How to Handle User Data with FckSignups: A Privacy-First, Stateless Architecture

> Learn how to handle user data with FckSignups. Discover its privacy-first, stateless architecture that never stores personal data, offering secure and account-free submission processing.

- Repository: [Abdullah/FckSignups](https://github.com/BraveOPotato/FckSignups)
- Tags: how-to-guide
- Published: 2026-09-07

---

**FckSignups** (now branded **NoSignups**) processes user submissions—new tool suggestions and problem reports—through a three-layer pipeline that never stores personal data, requires no accounts, and persists only as GitHub issues for maintainer review.

This React + TypeScript project demonstrates how to build **accountless contribution flows** that respect user privacy while maintaining data integrity. The entire system is **stateless**: no databases, no cookies, no tracking—just validated payloads flowing from browser to Cloudflare Worker to GitHub API.

---

## The Three-Layer Data Flow Overview

User data handling in FckSignups follows a strict path:

1. **Client-side modal** – Dynamic forms in [`src/hooks/useModal/useModal.tsx`](https://github.com/BraveOPotato/FckSignups/blob/main/src/hooks/useModal/useModal.tsx) collect and POST JSON payloads
2. **Cloudflare Worker validation** – Serverless handlers sanitize input and enforce schema rules
3. **GitHub Issue creation** – Validated data becomes trackable issues via REST API

Each layer serves a distinct purpose: capture, validate, persist. Nothing is retained on intermediate servers.

---

## Layer 1: Client-Side Form Capture

### Modal System Architecture

The [`useModal.tsx`](https://github.com/BraveOPotato/FckSignups/blob/main/useModal.tsx) hook manages all user interactions. When visitors click **"Submit a Tool"** or **"Report a Tool"**, the `<ModalRenderer>` component:

- Reads configuration from [`src/constants/ModalConfigs.tsx`](https://github.com/BraveOPotato/FckSignups/blob/main/src/constants/ModalConfigs.tsx)
- Renders form fields based on `ModalConfig` JSON schema
- Posts to Cloudflare Worker endpoints via `fetch()`

```tsx
// src/hooks/useModal/useModal.tsx – handleSubmit implementation
async function handleSubmit(e: FormEvent) {
  e.preventDefault();
  const formData = new FormData(e.target as HTMLFormElement);
  const payload = Object.fromEntries(formData);
  
  const response = await fetch(submitURL, {
    method: 'POST',
    body: JSON.stringify(payload)
  });
  
  // Response handling triggers success/error UI states
}

```

The `submitURL` values are configured in [`ModalConfigs.tsx`](https://github.com/BraveOPotato/FckSignups/blob/main/ModalConfigs.tsx), pointing to:
- `https://fcksignups-submit.abdullahalkafajy.workers.dev/submit-tool`
- `https://fcksignups-submit.abdullahalkafajy.workers.dev/report-tool`

**Key privacy feature**: The client never sends cookies, headers, or fingerprinting data beyond the form contents.

---

## Layer 2: Server-Side Validation

The Cloudflare Worker acts as a **stateless gatekeeper**. All incoming payloads pass through a shared `validate()` function that:

- Checks required field presence
- Validates URL formats
- Enforces length limits
- Trims and sanitizes strings

Validation failures return **HTTP 400** with descriptive JSON errors. Valid payloads proceed to GitHub integration.

### Tool Submission Handler

[`handleSubmitTool.ts`](https://github.com/BraveOPotato/FckSignups/blob/main/handleSubmitTool.ts) processes new tool suggestions:

```ts
// cloudflare-worker/urlHandlers/handleSubmitTool.ts
export async function handleSubmitTool(request: Request, env: Env, origin: string) {
  const sub = validate(await request.json()); // Throws on malformed data
  
  const issueBody = `

## Tool Submission

| Field | Value |
|-------|-------|
| **Name** | ${sub.name} |
| **Description** | ${sub.description} |
| **URL** | ${sub.url} |
| **Tags** | ${sub.tags.join(", ")} |
| **GitHub** | ${sub.github || "—"} |
| **Category** | ${sub.category} |
`;

  const res = await fetch(
    `https://api.github.com/repos/${env.GITHUB_REPO_OWNER}/${env.GITHUB_REPO_NAME}/issues`,
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${env.GITHUB_TOKEN}`,
        "Content-Type": "application/json",
        Accept: "application/vnd.github+json",
        "User-Agent": "fcksignups-worker/1.0",
      },
      body: JSON.stringify({
        title: `[Tool Submission Request] ${sub.name}`,
        body: issueBody,
        labels: ["tool-submission", ...(sub.github ? [] : ["no-repo-link"])],
      }),
    }
  );

  if (!res.ok) throw new Error("GitHub issue creation failed");
  return jsonResponse({ok: true}, 200, origin);
}

```

### Tool Report Handler

[`handleReportTool.ts`](https://github.com/BraveOPotato/FckSignups/blob/main/handleReportTool.ts) handles problem reports for existing tools:

```ts
// cloudflare-worker/urlHandlers/handleReportTool.ts
export async function handleReportTool(request: Request, env: Env, origin: string) {
  const report = validate(await request.json());
  
  const issueBody = `

## Tool Suggestion

| Field | Value |
|-------|-------|
| **ID** | ${report.toolId} |
| **Issue** | ${report.report} |
`;

  const res = await fetch(
    `https://api.github.com/repos/${env.GITHUB_REPO_OWNER}/${env.GITHUB_REPO_NAME}/issues`,
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${env.GITHUB_TOKEN}`,
        "Content-Type": "application/json",
        Accept: "application/vnd.github+json",
      },
      body: JSON.stringify({
        title: `[Tool Report] ${report.toolId}`,
        body: issueBody,
        labels: ["tool-report"],
      }),
    }
  );

  if (!res.ok) throw new Error("GitHub issue creation failed");
  return jsonResponse({ok: true}, 200, origin);
}

```

---

## Layer 3: GitHub as Persistent Store

Rather than operating a database, FckSignups **externalizes persistence to GitHub Issues**. This design choice provides:

- **Auditability** – All submissions are publicly reviewable
- **Workflow integration** – Maintainers use familiar GitHub tooling
- **Zero data retention** – The worker holds no state between requests
- **Spam resistance** – GitHub's abuse systems provide secondary filtering

The `GITHUB_TOKEN` environment variable authenticates API requests. Labels like `tool-submission` and `tool-report` enable automatic triage.

---

## Data Loading: The Read Path

For displaying tools, [`src/hooks/useTools.ts`](https://github.com/BraveOPotato/FckSignups/blob/main/src/hooks/useTools.ts) fetches a public JSON catalogue:

```ts
// src/hooks/useTools.ts
async function loadTools(JSON_URL: string): Promise<ToolsData | null> {
  const res = await fetch(JSON_URL);
  if (!res.ok) return null;
  return (await res.json()) as ToolsData;
}

```

When the network fails, [`src/constants/fallbackData.ts`](https://github.com/BraveOPotato/FckSignups/blob/main/src/constants/fallbackData.ts) supplies static tool definitions—ensuring the site remains functional offline.

---

## Key Architectural Decisions

| Decision | Implementation | Privacy Impact |
|----------|---------------|--------------|
| No account system | Email/identity never collected | Eliminates PII storage |
| Stateless workers | No sessions, cookies, or KV storage | Request isolation |
| Validation at edge | `validate()` runs in Cloudflare Worker | Rejects malformed input before persistence |
| GitHub Issues as backend | REST API for issue creation | Public audit trail, no proprietary database |
| Client-side form generation | `ModalConfig` JSON drives UI | Flexible without server templating |

---

## Summary

- **FckSignups handles user data** through a three-stage pipeline: client capture → server validation → GitHub persistence
- **[`useModal.tsx`](https://github.com/BraveOPotato/FckSignups/blob/main/useModal.tsx)** renders dynamic forms and POSTs JSON to Cloudflare Workers
- **[`handleSubmitTool.ts`](https://github.com/BraveOPotato/FckSignups/blob/main/handleSubmitTool.ts)** and **[`handleReportTool.ts`](https://github.com/BraveOPotato/FckSignups/blob/main/handleReportTool.ts)** validate payloads and create issues via GitHub REST API
- **No accounts, cookies, or databases** are required—the architecture is fully stateless
- **Validation occurs at the edge**, rejecting bad data before any persistence attempt
- **GitHub Issues serve as the sole data store**, providing transparency and maintainer workflow integration

---

## Frequently Asked Questions

### What happens to user data after form submission?

Submitted data is validated by the Cloudflare Worker, then immediately posted as a GitHub Issue. No intermediate storage occurs—the worker is stateless and discards the request context after responding. The only persistent copy exists as a publicly visible issue in the repository.

### Can users edit or delete their submissions after sending?

No. Because FckSignups requires no authentication, there is no mechanism to link subsequent requests to original submissions. Users receive immediate confirmation of successful delivery, but modifications require maintainer intervention via GitHub issue comments.

### How does FckSignups prevent spam or abuse?

Three mechanisms operate in sequence: client-side form validation, server-side schema enforcement in `validate()`, and GitHub's native abuse detection on the final API call. The stateless design also prevents automated session exploitation, as no user state exists to hijack.

### Is any personal information collected automatically?

No. The `fetch()` calls in [`useModal.tsx`](https://github.com/BraveOPotato/FckSignups/blob/main/useModal.tsx) deliberately exclude credentials and custom headers. Only form field values are transmitted. IP addresses and user agents are processed by Cloudflare's infrastructure but not logged or retained by the application code.