System Docs
How the approval workflow works, end to end.
Workflow Overview
Netlify Forms stores the submission. submission-created saves to Supabase and sends all notification emails via Resend (GYE admin with approve/deny buttons if subsidy, or Gentech + GYE FYI if no subsidy).
admin-action validates the secret, updates Supabase, and sends user & Gentech emails via Resend.
User clicks “still interested” → admin-action updates Supabase and emails Gentech via Resend.
If user opted for uninstall protection: partner email can be provided on the form, or the user receives a link to partner-setup to add it later. If the partner email was already verified on another submission, it’s auto-approved. Otherwise the partner receives an invitation email and must click “I Agree.”
When a tech marks a filter as installed and no partner is set, the user gets a reminder email. For sponsored users, partner-reminder-cron runs daily and sends a warning at 30 days post-install, notifying both the user and admin.
Admin Actions
| Action | Who | Secret | Result |
|---|---|---|---|
approve100 | Admin | ADMIN_SECRET | Approved — 100% subsidy |
approve50 | Admin | ADMIN_SECRET | Approved — 50% subsidy |
deny | Admin | ADMIN_SECRET | Denied — user asked if still interested |
interested | User | USER_ACTION_SECRET | User confirms interest after denial/partial |
partner-approve | Partner | USER_ACTION_SECRET | Partner agrees to be accountability partner |
partner-approve-pause | Partner | USER_ACTION_SECRET | Partner approves 24h pause (72h window) |
partner-approve-removal | Partner | USER_ACTION_SECRET | Partner approves full removal (72h window) |
Action URL Format
/.netlify/functions/admin-action?id={id}&action={action}&email={email}&name={name}&secret={secret}&requested={50|100}
Environment Variables
| Variable | Purpose |
|---|---|
ADMIN_SECRET | Authenticates admin action links |
USER_ACTION_SECRET | Authenticates user “still interested” links |
RESEND_API_KEY | Resend API key for sending emails |
SUPABASE_URL | Supabase project URL |
SUPABASE_SERVICE_ROLE_KEY | Supabase service role key (server-side access) |
Gentech emails are hardcoded in lib/emails.mjs: TO support@gentechsolution.com, CC jperl@gentechsolution.com | |
GYE_ADMIN_EMAIL | GYE admin email for approval notifications (eyes.guard@gmail.com) |
Netlify Functions
| Function | Trigger | What it does |
|---|---|---|
submission-created | Netlify form submission | Saves to Supabase, sends notification emails, sends partner invitation or setup link |
admin-action | Admin/user/partner clicks action link | Updates Supabase, sends user & Gentech emails via Resend |
admin-api | Admin dashboard API calls | CRUD operations, tech updates, partner email management, sends partner reminders on install |
partner-setup | User visits /partner-setup?token=... | Validates HMAC token, lets user enter partner email, sends invitation (or auto-approves if verified) |
partner-reminder-cron | Daily schedule (9 AM ET) | Warns sponsored users & admin if no partner 30+ days post-install |
admin-docs | Manual | This docs page |
admin-emails | Manual | Email templates reference page |
Services
| Service | Role |
|---|---|
| Netlify | Hosting, form submissions, serverless functions |
| Supabase | Database — stores all submissions, updated on every action |
| Resend | Transactional email — sends from hello@kedusha.com |
| No longer used — fully replaced by Supabase + Resend | |
| No longer used — replaced by Supabase | |
| GitHub | Source code (webshadoworg/sponsoredfilter), auto-deploys to Netlify |
Supabase
Project: kiwhkqfepwzacskpvagk
Table: submissions
| Column | Type | Description |
|---|---|---|
id | UUID | Primary key (auto-generated) |
netlify_id | text | Netlify form submission ID (used in action URLs) |
name | text | User’s name |
email | text | User’s email |
phone | text | Phone number |
city | text | City |
device_count | integer | Number of devices |
devices | text | Device types |
guidelines | boolean | Agreed to kedusha.com guidelines |
sponsored | boolean | Requested financial assistance |
discount_level | integer | 50 or 100 (subsidy level requested) |
subsidy_reason | text | Reason for subsidy |
financial_comments | text | Additional financial info |
comments | text | General comments |
uninstall_protection | boolean | Accountability partner required for changes |
partner_email | text | Accountability partner’s email |
partner_status | text | null → approved (set when partner clicks “I Agree” or auto-approved if previously verified) |
status | text | pending → ready / waiting-user / waiting-partner |
decision | text | approve100 / approve50 / deny |
user_response | text | interested (after deny/partial) |
vip_service | boolean | VIP in-person setup requested |
kedusha_account_id | integer | Auto-increment account ID (displayed as KED-XXXX) |
gentech_username | text | Gentech platform username |
tech_status | text | contacted / scheduled / installed / uninstalled / unresponsive / not-interested |
tech_notes | text | Technician notes |
tech_licenses | integer | Number of license installations |
tech_updated_at | timestamptz | Last tech status update |
email_bounced | boolean | Email delivery failed |
created_at | timestamptz | Submission time |
updated_at | timestamptz | Last update time |
Additional Tables
submission_events — activity log (events like tech:installed, partner:invited, partner:auto-approved, partner:30day-warning)
devices — individual devices per submission (type, name, active status, gentech username)
protection_requests — pause/removal requests that require partner approval (72h window)
Supabase Status Lifecycle
| Event | status | decision | user_response |
|---|---|---|---|
| Form submit (no subsidy, no protection) | ready | — | — |
| Form submit (no subsidy, with protection) | waiting-partner | — | — |
| Form submit (subsidy) | pending | — | — |
| Admin: approve100 | ready * | approve100 | — |
| Admin: approve50 (req 50) | ready * | approve50 | — |
| Admin: approve50 (req 100) | waiting-user | approve50 | — |
| Admin: deny | waiting-user | deny | — |
| User: interested | ready * | — | interested |
| Partner: approve | ready | — | — |
— = no change (keep existing value)
* = becomes waiting-partner instead of ready if uninstall protection is enabled
Form Fields
| Field | Type | Description |
|---|---|---|
name | text | User’s name |
email | User’s email | |
phone | tel | Phone number |
city | text | City |
device-count | number | Number of devices |
devices | checkboxes | Device types owned |
daas-torah | checkbox | Agrees to kedusha.com community guidelines |
sponsored | checkbox | Needs financial assistance |
discount-level | radio | 50 or 100 (subsidy level requested) |
subsidy-reason | radio | Reason for subsidy request |
financial-comments | textarea | Additional financial context |
comments | textarea | General comments |
uninstall-protection | checkbox | Wants accountability partner for changes |
partner-email | Accountability partner’s email (optional, validated for format and not same as user email) | |
vip-service | hidden | VIP in-person setup (set by VIP page) |