Skip to content

Updeus/Online-tools

Repository files navigation

CI

Online Tools

Online Tools is a Next.js 16 application with browser-first utilities for text, developer, image, video, and PDF workflows. Tool processing happens in the browser. The backend is only used for report intake, simple aggregate analytics, and an admin view.

Table of Contents

Current Status

  • Framework: Next.js App Router + TypeScript + React 19.
  • Tools shipped: 78.
  • Tool execution model: client-side only.
  • Backend data storage: Supabase-hosted Postgres for analytics + report intake.
  • Auth + tool state: Supabase auth sessions + cross-device favorites + per-tool upvotes.
  • Bot protection: Cloudflare Turnstile on login/signup.

Recent HEIC + Video + Upvotes Pass (2026-03-09)

  • HEIC to JPG/PNG:
    • Reworked HEIC decode path to avoid headless/browser worker deadlocks and restore reliable selected-file previews plus conversion output/download flow.
    • tests/e2e/heic-to-jpg.spec.ts and tests/e2e/image-thumbnail-regression.spec.ts now pass with existing assertion intent.
  • Video happy-path coverage:
    • Added concrete ACTIONS entries for:
      • mp4-to-mov, mkv-to-mp4, webm-to-mp4, avi-to-mp4
      • mp4-to-mp3, mp4-to-gif
      • video-compressor, video-trimmer, rotate-flip-video, resize-video
    • Added shared tiny-video fixture generation helpers in tests/e2e/tools-happy.spec.ts (real upload + run + output assertions).
  • Tool upvotes (Supabase-backed):
    • Added reusable ToolUpvote component on shared tool pages.
    • Added shared client utility for loading count/state + RPC toggle.
    • Added Supabase migration for tool_upvotes, tool_vote_counts, trigger sync, summary view, and toggle_tool_upvote() RPC with RLS policies.

Recent Intent + SEO Expansion (2026-02-26)

  • New SEO-intent wrappers and pages:
    • Image: webp-to-jpg, webp-to-png, jpg-to-png, png-to-jpg, jpeg-to-png, png-to-ico, compress-image, bulk-image-converter.
    • PDF: pdf-to-jpg, jpg-to-pdf, compress-pdf-online, pdf-crop.
    • Developer: sql-formatter, cron-generator, json-schema-generator.
  • Wrapper architecture:
    • Added shared image-intent converter wiring (batch conversion + ZIP flow) that reuses existing browser conversion logic.
    • Extended pdf-to-images pipeline to support JPG output and wrapper defaults.
  • SEO/content pass:
    • Strengthened unique metadata for image converters and new intent pages (title/description/keywords).
    • Added explicit searchable-PDF CTA/internal linking on relevant OCR/PDF extraction pages instead of introducing unsupported server OCR-to-PDF behavior.
    • Kept structured data pattern consistent (WebApplication + FAQPage) with canonical URLs on all tool pages.

Recent High-ROI Tools Pass (2026-02-26)

  • Added new PDF workflows:
    • edit-pdf (annotation MVP: draw/highlight/text + per-page undo/clear + export).
    • protect-pdf and unlock-pdf using browser-side encryption/decryption (@libpdf/core) with lazy loading.
    • pdf-to-png and png-to-pdf intent wrappers.
    • pdf-to-pptx (one rendered PDF page image per slide).
    • pptx-to-pdf (render slides to images, then package into PDF pages).
    • searchable-pdf (OCR + invisible text layer over image-backed pages).
  • Added image/developer utilities:
    • crop-image (interactive crop rectangle with PNG/JPG export).
    • website-status-checker (browser HTTP reachability + latency probe stats).
  • Added e2e smoke coverage for new tool routes, /llms.txt slug inclusion, and download sanity checks for annotation/OCR PDF output.

Recent UI + SEO Pass (2026-02-18)

  • Header/auth consistency:
    • Normalized Login/Sign up/Logout actions in the top nav and aligned button/link styling.
  • Favorites UX:
    • Improved Favorites filter empty states with sheep-accented copy and clearer sign-in/account CTAs.
    • Added clearer favorite toggle affordance on tool pages (star glyph + explicit labels).
  • Conversion messaging:
    • Added non-intrusive free-account value callouts on home and tool pages (unlimited runs + synced favorites).
  • SEO improvements:
    • Strengthened route metadata for home, tool pages, about, login, and signup.
    • Improved OG/Twitter image text branding.
    • Extended structured data with WebSite + Organization on home/about while keeping tool WebApplication + FAQPage.
  • About page:
    • Added username-only auth disclaimers (no email verification, no password recovery currently, password manager recommendation).
    • Added privacy notes for local browser processing, Supabase account/favorites storage, and Turnstile verification.

Recent Reliability + PPTX Pass (2026-02-18)

  • Word to PDF:
    • Added Visual Render mode (fidelity-first) that includes embedded DOCX images and best-effort HTML layout before PDF export.
    • Kept Text Mode for selectable text output with Unicode-capable font embedding to avoid WinAnsi failures on symbols and smart punctuation.
    • Added fallback glyph replacement with non-blocking warning when unsupported characters are substituted.
    • Updated messaging to clarify Visual Render (image-based PDF) vs Text Mode tradeoffs.
  • PDF Extract:
    • Added first-class thumbnail page selection (click, Shift+click range, Ctrl/Cmd+click additive).
    • Added Select all / Clear selection controls while retaining page-range input support.
    • Shared thumbnail selection logic with PDF Rotate to keep behavior consistent.
  • New tool:
    • pptx-to-images now renders embedded slide images (best effort) in addition to text and exports PNG/WebP with ZIP download.
    • Updated PPTX selected-file UI to the same compact file-chip/card style used in Word to PDF.

Recent PDF UX + Header Pass (2026-02-18)

  • PDF thumbnail-heavy workflows:
    • Added a reusable sticky output/download action bar for long-page thumbnail tools so download CTA remains reachable without scrolling to the bottom.
    • Includes compact output-ready summary and quick navigation actions (scroll to thumbnails / back to top).
  • Header favorites icon:
    • Simplified to a clean professional star icon (removed sheep accent) while keeping active state and accessibility behavior.

Recent OCR + Conversion Pass (2026-02-18)

  • New PDF tool:
    • Added pdf-to-excel with page-thumbnail selection, Shift/Ctrl multi-select, range support, and XLSX export (one sheet per page or single appended sheet).
    • Added best-effort text-grid/table heuristics and warnings when PDFs have no selectable text (with OCR CTA).
  • New image tool:
    • Added heic-to-jpg with HEIC/HEIF batch conversion to JPG or PNG, quality controls, optional resize, metadata stripping, and ZIP export.
  • New OCR tool:
    • Added ocr-to-text for JPG/PNG/WebP and PDFs with in-browser OCR, PDF thumbnail page selection, progress reporting, and TXT/ZIP output modes.

Tool Catalog

Text

  • case-converter - Convert text between upper, lower, title, sentence, camel, snake, and kebab cases.
  • whitespace-cleaner - Trim, normalize, and clean whitespace/newline formatting in text.
  • word-counter - Count words, characters, sentences, paragraphs, reading time, and top keywords.
  • lorem-ipsum-generator - Generate placeholder text by words, sentences, or paragraphs with themed presets.
  • ocr-to-text - Extract text from images and scanned PDFs in-browser with thumbnail page selection for PDF mode.

Developer

  • json-formatter - Format, minify, and validate JSON.
  • sql-formatter - Beautify/minify SQL queries with dialect, case, and indent controls.
  • cron-generator - Build cron expressions with presets and human-readable schedule summaries.
  • json-schema-generator - Generate JSON Schema from JSON input with optional required/example fields.
  • url-encode - URL encode/decode text.
  • base64-encode - Base64 encode/decode text.
  • hash-generator - Generate SHA-256, SHA-1, and MD5 hashes.
  • uuid-generator - Generate v4 UUIDs in bulk.
  • password-generator - Generate random passwords with configurable character sets.
  • jwt-decoder - Decode JWT header/payload (no signature verification).
  • csv-json - Convert CSV <-> JSON.
  • yaml-json - Convert YAML <-> JSON.
  • html-css-minifier - Minify HTML and CSS snippets.
  • xml-formatter - Format/minify XML with parse validation and indentation controls.
  • html-formatter - Beautify HTML with configurable indentation and line wrapping.
  • regex-tester - Test JavaScript regex patterns against sample text.
  • timestamp-converter - Convert epoch and date/time strings across UTC, local, and custom offsets.
  • diff-checker - Compare two texts in unified or side-by-side diff modes.
  • url-parser - Parse URL components, edit query parameters, and rebuild URLs.
  • website-status-checker - Run browser-based HTTP reachability probes with latency min/avg/max and jitter stats.
  • qr-generator - Generate downloadable QR codes as PNG/SVG from text or URLs.

Image

  • image-resize - Resize/compress JPG, PNG, and WebP images with EXIF removal.
  • image-convert - Convert JPG/PNG/WebP with optional resize and metadata stripping.
  • crop-image - Interactively crop JPG/PNG/WebP with drag/resize selection and PNG/JPG export.
  • bulk-image-converter - Batch convert JPG/PNG/WebP with resize/quality controls and ZIP export.
  • compress-image - Intent wrapper for fast image compression workflows.
  • avif-to-png - Convert one or many AVIF files to PNG/JPG with single or ZIP download.
  • heic-to-jpg - Convert one or many HEIC/HEIF files to JPG (default) or PNG with optional resize and ZIP download.
  • jfif-to-jpg - Convert one or many JFIF files to JPG/PNG with ZIP download.
  • webp-to-jpg - Convert WEBP files to JPG (default) with batch + ZIP output.
  • webp-to-png - Convert WEBP files to PNG output with batch + ZIP support.
  • jpg-to-png - Convert JPG/JPEG files to PNG in batch.
  • png-to-jpg - Convert PNG files to JPG with quality controls.
  • jpeg-to-png - .jpeg-focused PNG conversion page with distinct SEO intent content.
  • png-to-ico - Convert PNG files into favicon-style ICO output (16/32/48 entries).
  • svg-to-png - Convert one or many SVG files to PNG/JPG/WebP with scale and background controls.
  • favicon-generator - Generate a favicon pack (favicon.ico, PNG icon set, and site.webmanifest) from one source image.
  • pptx-to-images - Convert PPTX slides to PNG/WebP images in-browser with quality scaling and ZIP download.
  • color-picker - Pick image colors, extract dominant palettes, and export HEX/RGB/HSL/CSS variables.
  • exif-viewer - Inspect EXIF/IPTC metadata fields including GPS when available.
  • exif-stripper - Re-encode images to strip metadata and export cleaned files.

Video

  • mov-to-mp4 - Convert .mov to .mp4 locally in-browser using Auto mode (remux first, fallback to H.264/AAC transcode).

PDF

  • pdf-merge - Merge multiple PDFs.
  • pdf-split - Split by range or every N pages.
  • pdf-rotate - Rotate selected pages.
  • pdf-extract - Extract selected pages into a new file.
  • pdf-reorder - Reorder pages with drag-and-drop and export a new PDF.
  • pdf-delete-pages - Remove selected pages by thumbnail/range and export updated PDF.
  • pdf-watermark - Add configurable text watermarks (position/opacity/rotation/range).
  • pdf-page-numbers - Add page numbers with custom format, start index, and placement.
  • pdf-metadata - View/edit/remove metadata fields and save updated PDF.
  • images-to-pdf - Build a PDF from multiple images with page layout options.
  • png-to-pdf - PNG-first wrapper for image-to-PDF conversion (also accepts JPG/WebP).
  • jpg-to-pdf - JPG-first image-to-PDF wrapper (also accepts PNG/WebP).
  • pdf-to-images - Render PDF pages to PNG/WebP and download as ZIP.
  • pdf-to-png - PDF-to-PNG intent wrapper with PNG default and optional WebP output.
  • pdf-to-jpg - PDF to JPG wrapper with JPG-default export intent.
  • pdf-to-pptx - Convert PDF pages to PPTX with one rendered page image per slide.
  • pptx-to-pdf - Convert PPTX slides to an image-based PDF (one slide image per page).
  • pdf-to-word - Convert PDF to DOCX using text-first extraction or page-image mode.
  • word-to-pdf - Convert DOCX to PDF with Visual Render mode (images + layout fidelity) or Text Mode (selectable text).
  • pdf-to-text - Extract selectable text from PDF with per-page and layout-spacing options.
  • searchable-pdf - OCR scanned pages/images and export an image-backed PDF with an invisible text layer.
  • pdf-to-excel - Convert selectable PDF text into XLSX using text-layout or table-heuristic extraction with page selection controls.
  • pdf-compress - Best-effort compression by rasterizing pages at configurable DPI/quality presets.
  • compress-pdf-online - Intent wrapper targeting “compress PDF online” with the same local compression pipeline.
  • pdf-crop - Crop page margins (top/right/bottom/left) and rebuild cropped PDFs client-side.
  • pdf-extract-images - Extract embedded PDF images with page-image fallback and ZIP export.
  • pdf-sign - Place a drawn/uploaded visual signature onto a selected PDF page and export.
  • pdf-flatten - Flatten PDFs by rasterizing pages into a non-editable output document.
  • edit-pdf - Annotate PDFs with draw/highlight/text tools and export a rebuilt annotated PDF.
  • protect-pdf - Add password protection and permissions to a PDF with browser-side encryption.
  • unlock-pdf - Remove PDF protection when credentials allow; includes image-based fallback for hard-to-decrypt files.

Limits

  • PDF hard limit: 20 MB max per PDF file.
  • pdf-merge: up to 20 files and 200 pages total.
  • pdf-split, pdf-rotate, pdf-extract, pdf-reorder, pdf-delete-pages, pdf-watermark, pdf-page-numbers, pdf-metadata, pdf-to-images, pdf-to-jpg, pdf-to-png, pdf-to-text, pdf-to-pptx, pdf-compress, compress-pdf-online, pdf-crop, pdf-extract-images, pdf-sign, pdf-flatten, protect-pdf, unlock-pdf: up to 100 pages.
  • edit-pdf: up to 80 pages (annotation-preview performance cap).
  • pdf-to-excel: up to 50 pages (lower cap due extraction cost).
  • images-to-pdf / jpg-to-pdf / png-to-pdf: up to 20 images (10 MB each, max 100 output pages).
  • Image conversion/compression/edit tools (image-resize, image-convert, crop-image, bulk-image-converter, compress-image, avif-to-png, heic-to-jpg, jfif-to-jpg, webp-to-jpg, webp-to-png, jpg-to-png, png-to-jpg, jpeg-to-png, png-to-ico, exif-viewer, exif-stripper): 10 MB max per file (batch converters support up to 20 files unless stated otherwise).
  • ocr-to-text:
    • Images: up to 20 files, 10 MB each.
    • PDF mode: one PDF, 20 MB max, up to 30 pages per run.
  • searchable-pdf:
    • PDF mode: one PDF, 20 MB max, up to 20 pages per run.
    • Image mode: up to 20 images, 10 MB each.
  • pptx-to-images / pptx-to-pdf: 25 MB max per PPTX and up to 80 slides.
  • mov-to-mp4: one .mov per run, 500 MB max on desktop, 100 MB max on mobile. Auto mode attempts remux first, then transcodes to H.264/AAC if remux is incompatible.
  • Typical text-tool limits range from 20,000 to 1,000,000 characters, depending on tool metadata.
  • Usage limits:
    • Guests: NEXT_PUBLIC_GUEST_RUNS_PER_TOOL (default 5) per tool.
    • Authenticated users: NEXT_PUBLIC_AUTH_RUNS_PER_TOOL (default Infinity) per tool.

Key Features

  • Registry-driven tool system (src/tools/registry.ts) with lazy loading (src/tools/loader.ts).
  • Shared reusable UI components for tool screens (src/components/*).
  • Search + category filtering on the home page (Text / Developer / Image / Video / PDF).
  • Favorites filter in the home explorer for signed-in users.
  • Per-tool metadata for SEO and discoverability.
  • Username-only Supabase auth (/login, /signup) with cookie-backed sessions via @supabase/ssr.
  • Cloudflare Turnstile verification on signup/login before Supabase auth calls (with official deterministic test keys for local dev).
  • Optional server-side auth rate limiting (/api/auth/signup and /api/auth/login) with Upstash Redis (disabled by default).
  • Shared usage limiter boundary for tool runs (src/lib/usageLimiter.ts + shared run buttons).
  • Report flow at /report backed by server-side validation.
  • Admin dashboard at /admin for reports and usage counters.

Local Development

Requirements

  • Node.js 20+ recommended.
  • npm (project uses package-lock.json).

Install and run

npm install
npm run dev

Open http://localhost:3000.

Scripts

npm run dev     # start dev server
npm run build   # production build
npm run build:secure  # production build + sourcemap/env-exposure assertions
npm run assert:env-safety  # fail on client/service-role env exposure patterns
npm run start   # run production build
npm run lint    # lint codebase
npm run test    # run unit/integration tests (Jest)
npm run test:watch
npm run test:e2e  # run Playwright browser tests
npm run test:all  # run unit + e2e
npm run seed:test-users  # create and validate 10 dev auth users via API (no deletion)
npm run test:rls:dev  # verify cross-user favorite isolation in dev

Production Build Security (Source Maps + Env Guardrails)

  • Production browser source maps are explicitly disabled in next.config.ts.
  • Server source maps are explicitly disabled in next.config.ts.
  • Production client webpack config is hardened (devtool = false) so source maps are not emitted in non-dev client builds.
  • Production builds remain minified via Next.js defaults (no heavy obfuscation tooling added).
  • CI and local hardening command: npm run build:secure (npm run build + scripts/assert-no-sourcemaps.mjs + scripts/assert-env-safety.mjs).
  • scripts/assert-env-safety.mjs fails if:
    • a NEXT_PUBLIC_*SERVICE_ROLE* env name exists,
    • SUPABASE_SERVICE_ROLE_KEY appears in a client component,
    • a service-role key name/value appears in .next/static client bundle output.
  • No custom legacy-polyfill/browserslist target overrides are applied; keeping Next.js defaults avoids risky compatibility regressions.
  • Requests for *.map should return 404 by default because map files are not generated/deployed.
  • If error-tracking integration is added later, source maps must be uploaded privately only and never served publicly. Remove local map files before deployment.

Testing

  • Unit/integration tests: npm run test
  • Watch mode: npm run test:watch
  • E2E browser tests: npm run test:e2e
  • Full suite: npm run test:all
  • Vercel Analytics sanity check: deploy to Vercel, visit the live site, then confirm traffic appears in the project Analytics tab.
  • Vercel Speed Insights sanity check: deploy to Vercel, generate real traffic, then confirm data appears in the project Speed Insights tab.

SEO

  • App Router Metadata API is used for global metadata defaults and per-route canonical URLs.
  • src/app/robots.ts and src/app/sitemap.ts expose crawl directives and tool-page discovery.
  • Every tool page includes visible "About this tool" content, FAQ content, related internal links, and matching JSON-LD (WebApplication + FAQPage).
  • Home page includes server-rendered category sections and crawlable tool links.

Validation workflow:

  1. Run Lighthouse against / and a few /<slug> pages.
  2. Validate rich snippets with Google's Rich Results Test.
  3. Inspect canonical/metadata tags in page source and browser devtools.

Notes:

  • E2E fixtures are generated automatically in tests/fixtures by Playwright global setup.
  • If Playwright browsers are missing, run npx playwright install chromium.

Environment Variables

Set these in .env.local for local development and in Vercel Project Settings -> Environment Variables for production.

Core App

  • ADMIN_USERNAME - Admin login username. Default: admin.
  • ADMIN_PASSWORD - Admin login password. Default: admin.
  • ADMIN_SESSION_SECRET - HMAC secret used to sign admin cookie.
  • NEXT_PUBLIC_SITE_URL - Canonical public site URL (metadata, robots.txt, and sitemap.xml), for example https://tools.baabaasheep.party.
  • CANONICAL_HOST - Optional canonical host redirect target (middleware 308 host redirects), for example tools.baabaasheep.party.
  • NEXT_PUBLIC_COMMIT_SHA - Optional commit SHA shown on home page footer.
  • NEXT_PUBLIC_COMMIT_MESSAGE - Optional commit message shown on home page footer.

Auth, Favorites, Turnstile, and Limits

  • NEXT_PUBLIC_SUPABASE_URL - Supabase project URL.
  • NEXT_PUBLIC_SUPABASE_ANON_KEY - Supabase anon/public key.
  • SUPABASE_SERVICE_ROLE_KEY - Server-only key. Required for server-side analytics writes (/api/analytics) and report writes/admin report reads (/api/reports, /api/admin/reports). Also used for optional signup rollback cleanup.
  • NEXT_PUBLIC_TURNSTILE_SITE_KEY - Cloudflare Turnstile site key (public).
  • TURNSTILE_SECRET_KEY - Cloudflare Turnstile secret key (server-only; never expose).
  • TURNSTILE_ENABLED - Optional toggle (true/false). Default: true.
  • AUTH_RATE_LIMIT_ENABLED - Optional toggle for auth endpoint rate limiting. Default: false.
  • UPSTASH_REDIS_REST_URL - Upstash Redis REST URL for auth endpoint rate limiting.
  • UPSTASH_REDIS_REST_TOKEN - Upstash Redis REST token for auth endpoint rate limiting.
  • NEXT_PUBLIC_GUEST_RUNS_PER_TOOL - Guest limit per tool. Default: 5.
  • NEXT_PUBLIC_AUTH_RUNS_PER_TOOL - Logged-in limit per tool. Default: Infinity.
  • NEXT_PUBLIC_GOOGLE_AUTH_ENABLED - Optional toggle for Google OAuth button. Default: false.

Vercel Environment Variables Checklist (copy/paste)

Canonical + SEO:

  • NEXT_PUBLIC_SITE_URL (required)
  • CANONICAL_HOST (optional but recommended)
  • NEXT_PUBLIC_COMMIT_SHA (optional)
  • NEXT_PUBLIC_COMMIT_MESSAGE (optional)

Admin:

  • ADMIN_USERNAME
  • ADMIN_PASSWORD
  • ADMIN_SESSION_SECRET

Supabase:

  • NEXT_PUBLIC_SUPABASE_URL
  • NEXT_PUBLIC_SUPABASE_ANON_KEY
  • SUPABASE_SERVICE_ROLE_KEY (server-only; required for analytics writes and report write/admin-read paths)

Turnstile:

  • NEXT_PUBLIC_TURNSTILE_SITE_KEY
  • TURNSTILE_SECRET_KEY
  • TURNSTILE_ENABLED

Optional auth rate limiting:

  • AUTH_RATE_LIMIT_ENABLED
  • UPSTASH_REDIS_REST_URL
  • UPSTASH_REDIS_REST_TOKEN

Limits:

  • NEXT_PUBLIC_GUEST_RUNS_PER_TOOL
  • NEXT_PUBLIC_AUTH_RUNS_PER_TOOL
  • NEXT_PUBLIC_GOOGLE_AUTH_ENABLED

Changing Usage Limits

  1. Set NEXT_PUBLIC_GUEST_RUNS_PER_TOOL and/or NEXT_PUBLIC_AUTH_RUNS_PER_TOOL in .env.local.
  2. Restart the dev server.
  3. Limits are parsed from src/lib/config.ts and enforced through src/lib/usageLimiter.ts.

How limits are resolved in code:

  • src/lib/config.ts parses public run-limit flags and defaults.
  • src/lib/config.server.ts holds server-only secrets.
  • Shared limiter logic lives in src/lib/usageLimiter.ts.

Important: change default admin credentials and set a strong ADMIN_SESSION_SECRET before any shared deployment.

Supabase Setup

  1. Create a Supabase project.
  2. In Supabase project settings, copy:
    • Project URL -> NEXT_PUBLIC_SUPABASE_URL
    • Project API anon key -> NEXT_PUBLIC_SUPABASE_ANON_KEY
    • Service role key -> SUPABASE_SERVICE_ROLE_KEY
  3. Add values to .env.local (local) and Vercel env vars (production).
  4. Restart the dev server.

Apply migrations with Supabase CLI (remote hosted project)

This repository includes:

  • supabase/config.toml
  • supabase/migrations/20260218123000_create_auth_profiles_and_tool_favorites.sql
  • supabase/migrations/20260219094000_create_tool_usage_analytics.sql
  • supabase/migrations/20260220103000_create_reports.sql
  • supabase/migrations/20260309093000_create_tool_upvotes.sql

Use the Supabase CLI against your hosted project:

  1. Install CLI (either option):
    • npm i -D supabase (then use npx supabase ...)
    • Install Supabase CLI globally from official Supabase docs.
  2. Authenticate:
    • npx supabase login
  3. Link this repo to your hosted project:
    • npx supabase link --project-ref <ref>
  4. Apply migrations:
    • npx supabase db push
  5. Optional alternative:
    • npx supabase migration up --linked

<ref> is your Supabase project reference from the hosted project dashboard.

Auth/Favorites SQL (tables + RLS + policies)

If you are not using CLI migrations, run this SQL manually in Supabase SQL Editor:

create extension if not exists pgcrypto;

create table if not exists public.profiles (
  user_id uuid primary key references auth.users(id) on delete cascade,
  username text not null unique,
  created_at timestamptz default now()
);

create table if not exists public.tool_favorites (
  id uuid primary key default gen_random_uuid(),
  user_id uuid not null references auth.users(id) on delete cascade,
  tool_id text not null,
  created_at timestamptz default now(),
  unique (user_id, tool_id)
);

alter table public.profiles enable row level security;
alter table public.tool_favorites enable row level security;

drop policy if exists "profiles_select_own" on public.profiles;
create policy "profiles_select_own"
  on public.profiles
  for select
  using (user_id = auth.uid());

drop policy if exists "profiles_insert_own" on public.profiles;
create policy "profiles_insert_own"
  on public.profiles
  for insert
  with check (user_id = auth.uid());

drop policy if exists "profiles_update_own" on public.profiles;
create policy "profiles_update_own"
  on public.profiles
  for update
  using (user_id = auth.uid())
  with check (user_id = auth.uid());

drop policy if exists "tool_favorites_select_own" on public.tool_favorites;
create policy "tool_favorites_select_own"
  on public.tool_favorites
  for select
  using (user_id = auth.uid());

drop policy if exists "tool_favorites_insert_own" on public.tool_favorites;
create policy "tool_favorites_insert_own"
  on public.tool_favorites
  for insert
  with check (user_id = auth.uid());

drop policy if exists "tool_favorites_delete_own" on public.tool_favorites;
create policy "tool_favorites_delete_own"
  on public.tool_favorites
  for delete
  using (user_id = auth.uid());

Do not create public policies on either auth/favorites table.

Tool Upvotes SQL (tables + RLS + RPC)

Tool upvotes are defined in:

  • supabase/migrations/20260309093000_create_tool_upvotes.sql

That migration adds:

  • public.tool_upvotes (one vote per tool_slug + user_id)
  • public.tool_vote_counts (materialized counts)
  • trigger sync function (sync_tool_vote_count) for inserts/deletes
  • public.toggle_tool_upvote(text) RPC (authenticated toggle)
  • public.tool_upvote_summary view (anon/auth readable counts)
  • RLS policies so authenticated users can only read/write their own rows in tool_upvotes

No new environment variables are required beyond existing Supabase variables:

  • NEXT_PUBLIC_SUPABASE_URL
  • NEXT_PUBLIC_SUPABASE_ANON_KEY
  • SUPABASE_SERVICE_ROLE_KEY

Tool Upvotes Local Verification

  1. Apply latest Supabase migrations:
    • npx supabase db push
  2. Start the app:
    • npm run dev
  3. Unauthenticated check:
    • Open any tool page.
    • Confirm data-testid="tool-upvote-count" and data-testid="tool-upvote-button" render.
    • Click upvote and confirm sign-in prompt/error appears.
  4. Authenticated toggle check:
    • Sign in as user A and click upvote once (count increments, button becomes active).
    • Click again (count decrements, vote removed).
  5. Persistence + isolation check:
    • Sign in as user B on the same tool and verify user B sees independent upvote state.
    • Switching back to user A should preserve user A's vote state only.
  6. Optional SQL checks in Supabase SQL editor:
    • select tool_slug, upvotes_count from public.tool_vote_counts order by updated_at desc limit 20;
    • select tool_slug, user_id, created_at from public.tool_upvotes order by created_at desc limit 20;

Reports SQL (table + constraints + RLS)

Reports persistence is defined in:

  • supabase/migrations/20260220103000_create_reports.sql

That migration creates public.reports with:

  • category check constraint (Bug/Feature/Security/Other)
  • title/description length checks (120/4000)
  • optional tool_id, page_path, user_id, and user_agent columns (with length caps)
  • indexes on created_at desc and tool_id
  • RLS enabled with anon/authenticated revoked for select/insert/update/delete
  • service_role granted insert + select for server-only report writes and admin reads

Supabase Analytics Setup (tables + indexes + policies + RPC increment)

Analytics schema in this repo is intentionally minimal and does not store tool input content.

Security model used by the app:

  • RLS is enabled on analytics tables.
  • anon and authenticated can SELECT totals/daily rows only.
  • Public writes are blocked.
  • /api/analytics writes server-side using SUPABASE_SERVICE_ROLE_KEY and the increment_tool_usage RPC.

Security notes (service-role usage)

SUPABASE_SERVICE_ROLE_KEY is required for privileged server-side analytics writes, report writes, admin report reads, and optional auth rollback cleanup. It must never be available to browser code.

Current server-only usage in this repo:

  • src/lib/config.server.ts reads SUPABASE_SERVICE_ROLE_KEY (server-only module).
  • src/lib/supabase/admin.ts creates the admin Supabase client.
  • src/lib/server/analyticsStore.ts calls increment_tool_usage and reads analytics totals.
  • src/lib/server/reportsStore.ts writes and reads public.reports.
  • src/app/api/analytics/route.ts is the write/read API boundary for aggregate analytics.
  • src/app/api/reports/route.ts is the report write API boundary.
  • src/app/api/admin/reports/route.ts is the admin report read API boundary.
  • src/app/api/auth/signup/route.ts optionally uses admin client for rollback cleanup only.

Why this is safe:

  • Service-role access is only instantiated from server-only modules (server-only guarded imports).
  • Client components do not import config.server or admin Supabase client modules.
  • Analytics POST validates slug against the canonical tool registry and enforces server-side rate limiting.
  • Database permissions restrict privileged report/analytics writes (and report reads) to service_role; anon/authenticated do not have report-table access.

How to confirm it is not exposed:

  1. rg -n "SUPABASE_SERVICE_ROLE_KEY" src scripts tests
  2. rg -n "NEXT_PUBLIC_[A-Z0-9_]*SERVICE_ROLE" src scripts tests
  3. Check .env* files do not define any NEXT_PUBLIC_*SERVICE_ROLE* variable names.
  4. Run npm run build:secure and confirm scripts/assert-env-safety.mjs passes.
  5. (Optional) manually inspect .next/static output to ensure no SUPABASE_SERVICE_ROLE_KEY / sb_secret_ tokens appear.

Run this SQL in Supabase SQL Editor (or apply it as a migration file):

create table if not exists public.tool_usage_totals (
  tool_id text primary key,
  total_runs bigint not null default 0,
  updated_at timestamptz not null default now(),
  constraint tool_usage_totals_total_runs_nonnegative check (total_runs >= 0)
);

create table if not exists public.tool_usage_daily (
  tool_id text not null,
  day date not null,
  runs bigint not null default 0,
  updated_at timestamptz not null default now(),
  primary key (tool_id, day),
  constraint tool_usage_daily_runs_nonnegative check (runs >= 0)
);

create index if not exists tool_usage_daily_day_idx on public.tool_usage_daily (day);

alter table public.tool_usage_totals enable row level security;
alter table public.tool_usage_daily enable row level security;

grant select on table public.tool_usage_totals to anon, authenticated;
grant select on table public.tool_usage_daily to anon, authenticated;
revoke insert, update, delete on table public.tool_usage_totals from anon, authenticated;
revoke insert, update, delete on table public.tool_usage_daily from anon, authenticated;

drop policy if exists "tool_usage_totals_select_public" on public.tool_usage_totals;
create policy "tool_usage_totals_select_public"
  on public.tool_usage_totals
  for select
  using (true);

drop policy if exists "tool_usage_daily_select_public" on public.tool_usage_daily;
create policy "tool_usage_daily_select_public"
  on public.tool_usage_daily
  for select
  using (true);

create or replace function public.increment_tool_usage(p_tool_id text, p_day date default current_date)
returns void
language plpgsql
security definer
set search_path = public
as $$
declare
  normalized_tool_id text;
  target_day date;
begin
  normalized_tool_id := nullif(trim(p_tool_id), '');
  if normalized_tool_id is null then
    raise exception 'p_tool_id is required';
  end if;

  target_day := coalesce(p_day, current_date);

  insert into public.tool_usage_totals (tool_id, total_runs, updated_at)
  values (normalized_tool_id, 1, now())
  on conflict (tool_id) do update
    set total_runs = public.tool_usage_totals.total_runs + 1,
        updated_at = now();

  insert into public.tool_usage_daily (tool_id, day, runs, updated_at)
  values (normalized_tool_id, target_day, 1, now())
  on conflict (tool_id, day) do update
    set runs = public.tool_usage_daily.runs + 1,
        updated_at = now();
end;
$$;

revoke all on function public.increment_tool_usage(text, date) from public;
revoke all on function public.increment_tool_usage(text, date) from anon;
revoke all on function public.increment_tool_usage(text, date) from authenticated;
grant execute on function public.increment_tool_usage(text, date) to service_role;

How to apply:

  • Option 1 (recommended): keep SQL in migration files under supabase/migrations/ and run npx supabase db push.
  • Option 2: paste SQL into Supabase SQL Editor and run once per environment.

Supabase Auth Settings (username-only mode)

  1. Open Authentication -> Sign In / Providers.
  2. Set Confirm email to OFF.
  3. Save.

If this remains enabled, username-only signup cannot complete and the API returns email_confirmation_enabled.

Authentication URL Configuration

In Authentication -> URL Configuration:

  • Set Site URL to your production domain.
  • Add allowed redirect URLs:
    • http://localhost:3000
    • https://your-production-domain
  • Do not use wildcard redirects in production.

How to Verify RLS Is Active

  1. In SQL editor, confirm RLS flags:
    select tablename, rowsecurity
    from pg_tables
    where schemaname = 'public'
      and tablename in ('profiles', 'tool_favorites', 'tool_usage_totals', 'tool_usage_daily', 'reports');
  2. In Authentication -> Policies, confirm owner-scoped policies for auth/favorites, read-only public policies for analytics tables, and no anon/authenticated access policies on public.reports.
  3. Run the dev script npm run test:rls:dev to validate favorites cross-user isolation end-to-end.

Cloudflare Turnstile Setup

  1. Create a Turnstile widget in Cloudflare.
  2. Add allowed hostnames:
    • localhost
    • 127.0.0.1
    • your production hostname
  3. Set keys in .env.local:
    • NEXT_PUBLIC_TURNSTILE_SITE_KEY
    • TURNSTILE_SECRET_KEY
  4. Keep TURNSTILE_ENABLED=true (default) unless intentionally disabling for local debugging.

Local deterministic testing (official Cloudflare test keys):

  • Always-pass site key: 1x00000000000000000000AA
  • Always-pass secret key: 1x0000000000000000000000000000000AA
  • Optional always-fail site key: 2x00000000000000000000AB
  • Optional always-fail secret key: 2x0000000000000000000000000000000AB

Example .env.local test-key block:

NEXT_PUBLIC_TURNSTILE_SITE_KEY=1x00000000000000000000AA
TURNSTILE_SECRET_KEY=1x0000000000000000000000000000000AA
TURNSTILE_ENABLED=true

Deterministic dev behavior:

  • In non-production only, when TURNSTILE_SECRET_KEY equals Cloudflare's official always-pass test secret, server validation accepts any non-empty turnstileToken.
  • Production remains strict and always calls Cloudflare verification.
  • Turnstile remains the primary bot protection while auth rate limiting is disabled by default.

Auth Rate Limiting (Optional, Disabled by Default)

Current default:

  • AUTH_RATE_LIMIT_ENABLED=false
  • /api/auth/signup and /api/auth/login do not enforce rate limits.

To enable in a future deployment:

  1. Set AUTH_RATE_LIMIT_ENABLED=true.
  2. Set UPSTASH_REDIS_REST_URL.
  3. Set UPSTASH_REDIS_REST_TOKEN.

When enabled, limits are:

  • Signup: 3 requests/hour/IP.
  • Login: 10 requests/15 minutes/IP.

If enabled without Upstash env vars, auth endpoints fail closed with error.code = "rate_limit_unavailable".

Enable Google Sign-In (Optional)

Google OAuth is scaffolded and disabled by default.

  1. In Supabase Auth -> Providers, enable Google.
  2. Configure Google client ID/secret in Supabase provider settings.
  3. Add redirect URLs to Supabase and Google console allowlists:
    • Local: http://localhost:3000/auth/callback
    • Production: https://your-domain/auth/callback
    • Vercel previews: allow your preview domain pattern and callback path.
  4. Set NEXT_PUBLIC_GOOGLE_AUTH_ENABLED=true.

Code path:

  • Client button uses supabase.auth.signInWithOAuth({ provider: "google" }).
  • Callback handler: src/app/auth/callback/route.ts.

Seeding test users (dev only)

This project includes a dev-only API-driven seed script:

  • Command: npm run seed:test-users
  • Script: scripts/seed-test-users.mjs
  • API endpoint used: POST /api/auth/signup

Expected behavior:

  • Attempts to create usernames testuser01 through testuser10 with strong deterministic passwords.
  • Existing users are treated as non-fatal (user_already_exists).
  • At end, script verifies each username can log in via POST /api/auth/login.
  • Script exits non-zero if any signup/login operation fails unexpectedly.

Requirements:

  • Dev server must be running at http://localhost:3000.
  • Supabase URL/anon key configured in .env.local.
  • Supabase Confirm Email disabled (username-only flow).
  • Turnstile either disabled or configured with local/test keys.

Troubleshooting:

  • If the script reports missing env vars, verify .env.local and restart npm run dev.
  • If the API returns email_confirmation_enabled, disable Supabase Confirm Email.
  • If the API returns profiles_missing, apply Supabase migrations with npx supabase db push before rerunning.
  • If logins fail unexpectedly, inspect server logs and Supabase Auth -> Users for account state.

Security note:

  • Intended for local/dev only. Do not run against production datasets.
  • Created auth users remain in Supabase Auth -> Users for manual inspection.

Dev RLS Security Test

The repository includes a lightweight script to validate user-level favorites isolation in development.

Command:

npm run test:rls:dev

What it does:

  1. Creates/logs into two test users.
  2. Adds favorite tools for each user.
  3. Asserts each user only reads their own favorites from /api/favorites.
  4. Exits non-zero on any isolation failure.

Use this when changing auth/favorites policies or API logic.

Local Verification Steps

  1. Set .env.local with Supabase + Turnstile keys (use always-pass test keys for Turnstile in local dev).
  2. Run:
    npm install
    npm run dev
  3. Seed and validate auth flow end-to-end:
    npm run seed:test-users
  4. Verify signup/login:
    • /signup should complete immediately (Confirm Email disabled).
    • /login should authenticate with username + password.
  5. Verify usage limits:
    • As guest, run a tool 5 times.
    • The 6th run is blocked and shows login CTA.
  6. Verify favorites:
    • Login, favorite a tool from the tool page action bar.
    • Reload and confirm it remains favorited.
    • Open another browser/device with same account and confirm sync.
  7. (Optional) Verify auth endpoint rate limiting after setting AUTH_RATE_LIMIT_ENABLED=true and Upstash env vars:
    • Signup: max 3 requests/hour/IP.
    • Login: max 10 requests/15 minutes/IP.
  8. Verify RLS isolation:
    npm run test:rls:dev
  9. Verify analytics:
    • Confirm /api/analytics increments only when runs succeed.
    • Confirm home page totals/per-tool counts increase after running tools.

Production Data Persistence

Current production persistence model:

  • Analytics: Supabase-backed (public.tool_usage_totals and optional public.tool_usage_daily) via /api/analytics.
  • Reports: Supabase-backed (public.reports) via /api/reports and /api/admin/reports.

Important Vercel behavior:

  • Vercel serverless/runtime filesystem is non-durable and may be read-only.
  • Reports and analytics no longer depend on the local filesystem.
  • /api/reports and /api/admin/reports return reports_unconfigured when Supabase admin configuration/migration is missing.
  • /api/reports and /api/admin/reports can return reports_unavailable on transient Supabase failures.

Deploy to Vercel + Cloudflare (Custom Domain)

1) Local pre-deploy gate

Run this before creating or promoting a production deployment:

npm run lint
npm run test
npm run build:secure
npm run test:e2e

2) Create Vercel project and import repo

  1. In Vercel, choose Add New... -> Project and import this Git repository.
  2. Vercel auto-detects Next.js settings for this repo.
  3. Set Node.js version to 20.x (project baseline is Node.js 20+).
  4. Trigger the first deployment.

3) Add production environment variables in Vercel

Use the checklist in Environment Variables -> Vercel Environment Variables Checklist (copy/paste) above.

4) Attach custom domain in Vercel

  1. Open Project -> Settings -> Domains.
  2. Add your production domain.
  3. For apex + www, accept Vercel prompts to add both and choose your preferred redirect direction.

5) Configure Cloudflare DNS (Cloudflare manages DNS, Vercel hosts app)

Prefer the exact DNS values shown in the Vercel Domains UI; do not assume static targets.

Recommended apex + www pattern:

  1. Add apex domain to the Vercel project and accept Vercel's www suggestion/redirect preference.
  2. In Cloudflare DNS:
    • Apex (@): add an A record pointing to Vercel (commonly 76.76.21.21) or whatever Vercel currently shows.
    • www: add a CNAME pointing to the Vercel target (commonly cname.vercel-dns.com or a project-specific vercel-dns-### target).
  3. If Vercel shows an absolute CNAME value with a trailing dot (.), copy it exactly, including the dot.

Subdomain-only pattern (for example tools.example.com):

  1. Add tools.example.com in Vercel project domains.
  2. In Cloudflare DNS, add CNAME record: tools -> Vercel-provided target.

6) Cloudflare SSL/TLS and proxy guidance

  • SSL/TLS mode: use Full (strict) where possible. If strict validation is temporarily blocked, use Full while resolving certificate issues.
  • Proxy (orange cloud) tradeoff:
    • Start DNS-only (Proxy status: DNS only) until Vercel verifies the domain and issues SSL certs.
    • After cert issuance, you can enable proxy if desired.
    • If proxy is enabled and you hit certificate/redirect issues, temporarily switch back to DNS-only during troubleshooting.

7) Troubleshooting domain/cert issues

Invalid configuration:

  • Re-check Cloudflare records against the exact Vercel Domains UI values.
  • Remove conflicting DNS records (especially stale/incorrect AAAA records; Vercel does not support IPv6 origin records for this setup).
  • Ensure only the intended apex/CNAME records exist.

Cert not issuing / failed to generate cert:

  • Set the related DNS record(s) to DNS-only temporarily.
  • Confirm CNAME target exactly matches Vercel (including trailing dot when shown).
  • Remove and re-add the domain in Vercel Domains settings.
  • Wait for DNS propagation before rechecking.

Redirect loops:

  • Check middleware canonical host behavior (CANONICAL_HOST) in middleware.ts.
  • Check Cloudflare Always Use HTTPS and other redirect rules.
  • Avoid double-forcing redirects in both Cloudflare and app middleware with conflicting host/protocol targets.

Security header baseline:

  • HSTS, nosniff, referrer policy, permissions policy, and clickjacking protection are enabled globally.
  • CSP is enforced via Content-Security-Policy (not report-only).
  • CSP uses a per-request nonce for inline scripts (script-src 'nonce-<value>') so theme init and JSON-LD inline scripts remain allowed without unsafe-inline.
  • script-src does not use unsafe-inline; it allows 'self', nonce scripts, blob:, Turnstile (https://challenges.cloudflare.com), and 'wasm-unsafe-eval' for WASM-heavy browser tools.
  • style-src 'unsafe-inline' is intentionally retained for App Router styling compatibility.
  • Turnstile sources are allowlisted in CSP (https://challenges.cloudflare.com) for script/frame/connect.

CSP verification and troubleshooting:

  1. Open DevTools -> Network -> document request and inspect response headers.
  2. Confirm Content-Security-Policy exists and script-src includes 'nonce-...'.
  3. Confirm script-src does not include 'unsafe-inline'; unsafe-eval should also be absent.
  4. If a feature breaks, check the browser CSP console violation and add only the specific missing source/directive instead of broad unsafe fallbacks.

Production Checklist

Deployment configuration checks

  • Vercel env vars are set (see checklist above).
  • Cloudflare SSL/TLS mode is Full (strict).
  • DNS records point to Vercel using exact Vercel-provided targets.
  • Canonical host config is aligned:
    • NEXT_PUBLIC_SITE_URL uses the intended canonical URL.
    • CANONICAL_HOST matches canonical host when host redirects are desired.

Post-go-live verification (copy/paste)

Route and SEO checks:

  • https://<domain>/robots.txt
  • https://<domain>/sitemap.xml
  • Canonical tags match NEXT_PUBLIC_SITE_URL.
  • Apex <-> www redirects behave as intended.
  • /tools/<slug> redirects to /<slug>.
  • Run tools and confirm analytics totals/per-tool counters update on home.

DNS verification commands:

dig +short <domain> A
dig +short <domain> AAAA
dig +short www.<domain> CNAME
dig +short tools.<domain> CNAME

Notes:

  • AAAA should generally be empty for Vercel-hosted records in this setup.
  • DNS propagation can take time; allow for TTL before concluding a record is incorrect.

SEO sanity checklist:

  1. Run Lighthouse on / and several high-traffic tool routes.
  2. Run Google Rich Results Test on home and at least one tool page.
  3. Confirm generated metadata/OG tags reflect production canonical host.

Routes

Pages

  • / - Tool directory with search/filter and usage counter display.
  • /<slug> - Dynamic tool page (canonical).
  • /tools/[slug] - Legacy route that permanently redirects to /<slug>.
  • /login - User login page (Turnstile-protected).
  • /signup - User signup page (Turnstile-protected).
  • /auth/callback - Supabase OAuth callback handler (Google scaffolding).
  • /report - User report form.
  • /admin - Admin login + reports + analytics view.
  • /tester - Internal registry/routing sanity page.

API

All API responses use a JSON envelope:

  • Success: { ok: true, ... }
  • Error: { ok: false, error: { code, message } }

Endpoints:

Method Path Purpose
POST /api/reports Validate payload and insert a report into public.reports (Supabase, server-side service-role client).
GET /api/admin/reports Return up to 1000 newest reports from public.reports (admin cookie required).
POST /api/admin/login Validate credentials and set signed ot_admin httpOnly cookie (24h TTL).
POST /api/admin/logout Expire admin cookie.
POST /api/auth/signup Verify Turnstile, create Supabase auth user, insert profile, and rollback partial failures when possible (optional rate-limiting scaffold can be enabled).
POST /api/auth/login Verify Turnstile and sign in Supabase user session (optional rate-limiting scaffold can be enabled).
POST /api/auth/logout End Supabase auth session.
GET /api/auth/session Return current Supabase auth user (if logged in).
GET /api/favorites Return logged-in user's favorite tool IDs.
POST /api/favorites Add tool favorite for logged-in user.
DELETE /api/favorites Remove tool favorite for logged-in user.
POST /api/analytics Increment tool usage counter by slug (server-side Supabase write via service-role RPC).
GET /api/analytics Return aggregate usage snapshot from Supabase analytics tables.

Validation highlights:

  • Reports: category must be Bug, Feature, Security, or Other.
  • Reports: title max 120 chars, description max 4000 chars.
  • Reports request size: 50 KB max (based on content-length).
  • Reports storage errors: reports_unconfigured (missing Supabase admin config/migration) and reports_unavailable (transient DB failure).
  • Analytics increment: slug must be non-empty and <= 80 chars.
  • Auth: login/signup validates username + password and requires Turnstile token when enabled.
  • Auth: username policy is lowercase ^[a-z0-9_]{3,20}$ with reserved-name blocklist.
  • Auth: signup requires Supabase Confirm Email to be disabled for username-only flow.
  • Auth: optional rate limiting returns { ok: false, error: { code: "rate_limited", message } } on limit breaches when AUTH_RATE_LIMIT_ENABLED=true.
  • Favorites: tool IDs are validated against canonical registry slugs.

Project Structure

src/
  app/
    page.tsx
    login/page.tsx
    signup/page.tsx
    auth/callback/route.ts
    report/page.tsx
    admin/page.tsx
    tester/page.tsx
    tools/[slug]/
    api/auth/*
    api/favorites/route.ts
  components/
    providers/
  lib/
    config.ts
    config.server.ts
    analytics.ts
    usageLimiter.ts
    supabase/
    server/
      adminAuth.ts
      analyticsStore.ts
      reportsStore.ts
      http.ts
      turnstile.ts
  tools/
    _shared/
    registry.ts
    loader.ts
    <tool-slug>/

Adding a New Tool

  1. Create src/tools/<slug>/meta.ts, Tool.tsx, and index.ts.
  2. Export metadata + component from index.ts.
  3. Add the tool meta to src/tools/registry.ts.
  4. Add a loader case in src/tools/loader.ts.
  5. Enforce input limits in the tool UI before processing.

Roadmap Phases

Phase 0 - Foundation (Local Dev First)

  • Next.js app scaffolded with TypeScript + ESLint.
  • Tool contract, registry, and lazy loader implemented.
  • Home route lists tools from the registry.
  • Dynamic route /<slug> renders tools by slug.
  • User-safe error handling pattern is in place.
  • Input/file limits are enforced per tool metadata.
  • Security headers baseline (CSP enforced with script nonces/HSTS/nosniff/referrer policy).

Phase 1 - MVP v0.1 (Browser-Only Tools)

  • JSON Formatter/Minifier + validation.
  • URL Encode/Decode.
  • Base64 Encode/Decode.
  • Case Converter.
  • Image Resize + Compress with EXIF stripping.
  • Global tool search.
  • Category filtering (Text/Developer/Image/PDF).
  • Per-tool SEO metadata.
  • Privacy messaging for local processing.

Phase 2 - MVP v0.2 (Client-Side PDF Basics)

  • PDF Merge.
  • PDF Split.
  • PDF Rotate.
  • PDF Extract.
  • Strict PDF file/page limits.
  • Clear local-processing messaging.

Phase 3 - Quality + Scale (UX + Reliability)

  • Shared UI components (Dropzone, FileList, OutputPanel, OptionsPanel, ErrorMessage, EmptyState).
  • Better empty/error states across tool pages.
  • Basic accessibility improvements (labels, keyboard focus, visible focus styles).
  • Lightweight analytics without tool-input logging.
  • Report intake + admin dashboard for reports and analytics.
  • Unit/integration tests for tool logic, registry/loader contract, and API validation.
  • Playwright E2E coverage across all tools, including PDF/Image download flows.

Phase 3.5 - Tool Expansion Sprint

  • JSON Formatter + Validator.
  • Base64 Encode/Decode.
  • URL Encode/Decode.
  • Hash Generator.
  • UUID Generator.
  • Case Converter.
  • Timestamp Converter.
  • CSV <-> JSON Converter.
  • Whitespace Cleaner.
  • Password Generator.
  • YAML <-> JSON Converter.
  • HTML/CSS Minifier.
  • Regex Tester.
  • JWT Decoder.
  • PDF Merge/Split/Rotate/Extract.
  • Image Resize + Compress.
  • PDF Reorder tool.
  • Standalone EXIF viewer/stripper tool.

Phase 4 - Deployment + Hardening

  • Production deployment playbook (Vercel + Cloudflare baseline) documented.
  • Production security headers baseline verified.
  • CI checks and dependency automation (Dependabot/audit pipeline).

Phase 5 - Server-Side Heavy Tools (Optional, Carefully)

  • Retention policy and auto-delete for uploaded content.
  • Malware scanning for uploads.
  • Rate limiting and abuse prevention.
  • Ephemeral object storage + queue/worker model.
  • OCR and Office conversion tools.

Security and Privacy Notes

  • Tool content is processed in-browser, not uploaded by tool pages.
  • Reports and analytics are intentionally minimal and avoid logging tool input payloads.
  • Admin auth uses a signed cookie with timing-safe signature checks.
  • API validation returns safe user-facing errors and does not expose stack traces.
  • Vulnerability reporting process is documented in SECURITY.md.

Licensing and Anti-Theft Reality

  • This project is proprietary and distributed under an "All Rights Reserved" license (LICENSE).
  • Client-side code can still be reverse engineered in compiled/minified form.
  • Real protection for proprietary algorithms requires moving sensitive logic to server-side execution.
  • A placeholder route exists at /pro for future server-side/premium tools, but no logic has been moved yet.

License

All Rights Reserved. See LICENSE. Terms of use: TERMS.md.

About

Resources

License

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors