Builder Showcase Phase 3 Validation + Anti-Spam Test Checklist

Working context: DataInsideData™ Builder Showcase / ProofMe intake pipeline.

Goal: confirm the new frontend preview flow, backend validation, duplicate detection, honeypot, metadata logging, and deployment path all work before moving deeper into Phase 3 hardening.


0. Pre-Test Setup

Local repo / branch

  • [✔️] Confirm you are on the correct branch.
git branch --show-current
git status
  • [✔️] Confirm there are no unexpected old submit pages or duplicate routes.
Get-ChildItem -Recurse -File | Select-String "submit-a-builder-project"
Get-ChildItem -Recurse -File | Select-String "Test payload created successfully"
  • Confirm the canonical submit page is:
/projects/builder-showcase/submit/

1. Backend Database Prep

Required metadata columns

Run in pgAdmin or the SQL runner:

alter table public.builder_project_submissions
add column if not exists user_agent text,
add column if not exists request_origin text,
add column if not exists request_referer text,
add column if not exists client_ip_hash text;

Helpful indexes

create index if not exists idx_builder_project_submissions_readme_url
on public.builder_project_submissions(readme_url);

create index if not exists idx_builder_project_submissions_email_repo_title_created_at
on public.builder_project_submissions(
  submitter_email,
  repo_url,
  project_title,
  created_at desc
);

create index if not exists idx_builder_project_submissions_client_ip_hash
on public.builder_project_submissions(client_ip_hash);

2. Supabase Secrets

Confirm required Edge Function secrets

  • SUPABASE_URL
  • DID_SUPABASE_WRITE_KEY
  • DID_PUBLIC_FORM_KEY
  • DID_IP_HASH_SALT

Check secrets:

npx supabase secrets list

Set IP salt if needed:

python -c "import secrets; print(secrets.token_hex(32))"

Then:

npx supabase secrets set DID_IP_HASH_SALT="PASTE_RANDOM_HEX_STRING_HERE"

3. Deno + Function Validation

From the function folder:

cd supabase/functions/submit-builder-project
deno check index.ts

Expected:

  • No TypeScript errors.
  • No "public" is not assignable to type "never" error.
  • No missing import errors.

Deploy:

npx supabase functions deploy submit-builder-project

Expected:

  • Function deploys successfully.
  • Supabase CLI is logged in.
  • Correct Supabase project is linked/selected.

4. Frontend Preview Flow

Start Jekyll cleanly:

bundle exec jekyll clean
bundle exec jekyll serve --livereload --trace

Open:

http://localhost:4000/projects/builder-showcase/submit/

Preview behavior

  • [✔️] Fill a valid form.
  • [✔️] Click Preview Submission.
  • [✔️] Confirm preview panel appears.
  • [✔️] Confirm cleaned email is lowercased.
  • [✔️] Confirm tags are trimmed and comma-split.
  • [✔️] Confirm long README URL wraps inside the preview box.
  • [✔️] Confirm Confirm & Submit is visible and left-aligned.
  • [✔️] Confirm Make Edits is visible and not white-on-white.
  • [✔️] Click Make Edits.
  • [✔️] Confirm page scrolls/focuses back to the first form field.
  • [✔️] Confirm form values remain editable.

5. Frontend Required Field Tests

Try submitting with each missing field:

  • [✔️] Missing first name fails.
  • [✔️] Missing last name fails.
  • [✔️] Missing email fails.
  • [✔️] Missing repo URL fails.
  • [✔️] Missing project title fails.
  • [✔️] Blank category fails.
  • [✔️] Missing description fails.
  • [✔️] Blank tags/tools fails.
  • [✔️] Unchecked ownership/permission checkbox fails.
  • [✔️] Unchecked public showcase acknowledgement fails.

Expected:

Browser validation or preview validation blocks submission before database insert.

6. Backend Validation Tests

These should fail even if someone bypasses browser validation.

Bad repo URL

Use:

https://google.com/test

Expected:

  • Backend returns 400.
  • Message says repository URL must be a valid GitHub repository URL.
  • No row inserted.

Bad README URL

Use a normal GitHub page URL instead of raw URL:

https://github.com/user/repo/blob/main/README.md

Expected:

  • Backend returns 400.
  • Message says README URL must be raw.githubusercontent.com and end in README.md.
  • No row inserted.

Valid GitHub repo URL

Use:

https://github.com/user/repo

Expected:

  • Backend accepts if all other fields are valid.
  • Row inserted.

Valid raw README URL

Use:

https://raw.githubusercontent.com/user/repo/main/README.md

Expected:

  • Backend accepts if all other fields are valid.

7. Honeypot Test

Use DevTools or temporarily unhide the honeypot field and enter a value for:

website

Expected:

  • Backend returns 400.
  • Message says invalid submission.
  • No row inserted.

8. Duplicate Submission Tests

Same README URL already active

Submit a project using a README URL that already exists in an active workflow status:

submitted
reviewing
approved
published
needs_changes

Expected:

  • Backend returns 409.
  • Message says a submission using this README URL is already in the review/publishing workflow.
  • No duplicate row inserted.

Same email + repo URL + project title within 10 minutes

Submit the same exact:

  • email
  • repo URL
  • project title

within 10 minutes.

Expected:

  • Backend returns 409.
  • Message says similar submission was received recently.
  • No duplicate row inserted.

Same email + same repo + different project title

Submit:

  • same email
  • same repo URL
  • different project title

Expected:

  • Submission is allowed.
  • Row inserted.

Same email + same monorepo + different README URL

Submit:

  • same email
  • same repo URL
  • different raw README URL

Expected:

  • Submission is allowed.
  • Row inserted.

9. Metadata Logging Tests

After successful submission, query:

select
    id,
    project_title,
    submitter_email,
    user_agent,
    request_origin,
    request_referer,
    client_ip_hash,
    created_at
from public.builder_project_submissions
order by created_at desc
limit 5;

Expected:

  • user_agent is populated.
  • request_origin is populated when submitted from browser.
  • request_referer may be populated depending on browser/request context.
  • client_ip_hash is populated if the Edge Function sees an IP header and DID_IP_HASH_SALT is set.
  • Raw IP address is not stored.

10. Frontend Browser Cooldown

After one successful submission:

  • Try submitting again immediately from the same browser.

Expected:

  • Frontend blocks rapid resubmission for around 60 seconds.
  • User sees a friendly message.
  • Backend duplicate rules still protect the database if frontend is bypassed.

11. Admin Workflow Retest

After a successful valid submission:

View submissions

python scripts/view_submissions.py
python scripts/view_submissions.py --status submitted
python scripts/view_submissions.py --submission-id YOUR_SUBMISSION_UUID

Expected:

  • New row appears.
  • Exact lookup works.
  • Status count/reporting still works.

Update status

python scripts/update_submission_status.py --submission-id YOUR_SUBMISSION_UUID --status approved

Expected:

  • Status updates successfully.

Promote to builder_projects

python scripts/promote_builder_project.py --submission-id YOUR_SUBMISSION_UUID --public

Expected:

  • Row inserts/updates in builder_projects.
  • Submission status becomes published.

Export

python scripts/export_builder_projects.py --slug YOUR_PROJECT_SLUG

Expected:

  • _data/builder_projects.yml updates.
  • Detail page is generated.
  • README rendering still works.

12. Final Acceptance Criteria

Phase 3B first-layer hardening is ready when:

  • Valid form submission succeeds.
  • Preview-before-submit works.
  • Make Edits returns focus to the form.
  • Frontend required field validation works.
  • Backend validation blocks bad payloads.
  • Honeypot blocks bot-like submissions.
  • Duplicate README URL is blocked.
  • Recent exact duplicate is blocked.
  • Productive multiple-project submissions are allowed.
  • Metadata columns populate.
  • Raw IP address is not stored.
  • Admin scripts still work.
  • Publish/export workflow still works.