J&H WEB SOLUTIONS — WEBSITE + PRIVATE LEAD WORKSPACE Your public site is at /. Your lead workspace is at /admin/. This package adds a real Cloudflare database backend and server login. It does not contain a password, a demo account, or any made-up leads. ONE-TIME CLOUDFLARE SETUP (about 10–15 minutes) 1. DOWNLOAD AND UNZIP Download JH-Web-Solutions-Leads-Cloudflare.zip. Unzip it so you can open schema.sql and this guide. The ZIP itself can be uploaded to Pages. 2. CREATE THE DATABASE In the Cloudflare dashboard, find Storage & Databases > D1 SQL Database. Create a database named jh-leads (or another name you prefer). Open that database's Console. Open schema.sql from this package in a text editor, copy its contents, and run the SQL in the D1 Console. If the console accepts one statement at a time, run each semicolon-separated statement. CREATE TABLE IF NOT EXISTS is safe to rerun; do not delete an existing DB. 3. CONNECT THE DATABASE TO YOUR EXISTING PAGES SITE Open Workers & Pages > your J&H Pages project > Settings > Bindings. Add a D1 database binding. Variable/binding name: DB (uppercase, exactly) Select the database from step 2. Set this for the Production environment. Bindings require a new deployment. 4. SET TWO ENCRYPTED SECRETS In the same Pages project's Settings > Variables and Secrets, select Production and add these values using the encrypted/secret type: TEAM_PASSWORD: A unique password of at least 16 characters. Share it only with your teammate. A long password-manager-generated value is recommended. This is what you type on the login screen. AUTH_SECRET: A separate random value of at least 32 characters. Generate it with a password manager. Nobody needs to type it when signing in. Keep it in Cloudflare only. Do not put either secret into the HTML, JavaScript, schema, CSV, or ZIP. Do not reuse a personal email or banking password for the team password. 5. UPLOAD THE UPDATED SITE In your existing Cloudflare Pages Direct Upload project, choose Create a new deployment, select Production, and upload this entire ZIP. Deploy. index.html and _worker.js are already at the ZIP root; keep the admin folder. Uploading only index.html will omit the private workspace and backend. No build command or npm installation is needed for this dashboard upload. Use Pages, not an empty Worker project. Dashboard uploads support _worker.js. 6. SIGN IN Open your normal website URL with /admin/ at the end. For example: https://YOUR-PROJECT.pages.dev/admin/ Sign in with TEAM_PASSWORD. Your teammate uses the same password on their device. The session lasts 12 hours; the browser cookie is Secure and HttpOnly. Leads and changes are stored in the shared D1 database, not in localStorage. If a setup message appears, check the exact DB binding name, both secret names and lengths, and whether schema.sql ran successfully. Redeploy after changing the binding or secrets. The public site works while database setup is pending. The login page now identifies each missing or too-short setting separately. It never displays a secret value. If a setting exists in Cloudflare but the page says it is missing, check Production versus Preview and confirm a new deployment was created after saving the setting. Use the main production URL for this setup. DAILY WORKFLOW 1. Import a CSV or Add lead manually. Only Business name is required. 2. Record the business's type, city, website, contact details and source URL. 3. Mark its website condition and write the specific improvement you could offer. 4. Assign the lead, choose its priority and update its sales stage. 5. Add a follow-up date and the next action after every conversation. 6. Open Follow-ups due when deciding who to contact. Dates use America/Chicago. 7. Use Export filtered CSV to download a backup or share a selected set. STAGES New / Qualified / Contacted / Interested / Call booked / Proposal sent / Won / Lost / Do not contact Won, Lost and Do not contact are excluded from the Follow-ups due count. No email, SMS, calls, or automatic reminders are sent by this workspace. Priority is your team's manual judgment; the app does not invent a lead score. IMPORTING SCRAPER CSVs - The first row must be column names. Download the blank template inside the app or use lead-import-template.csv from this ZIP. - The importer guesses common column names; review its mapping before importing. - Unneeded columns can be skipped. There is no need to fill every field. - Use dates as YYYY-MM-DD. Deal value is dollars, not cents. - Website values may be complete URLs or domains; stored links use http(s). - Default values: Stage = New, Priority = Normal, Website condition = Not reviewed. - Maximum per file: 5 MB, 5,000 data rows, 100 columns. Split larger scrapes. - The preview shows invalid rows. Correct them or explicitly choose to skip them. - Duplicates are matched on business name + city, ignoring case, punctuation and spacing. Always include city when available. Branches in different cities are separate leads; same-name branches within one city need distinguishing names. - Duplicate imports NEVER replace existing notes, assignments or outreach stages. - Imports save in batches of 25. Completed batches remain saved if interrupted. Rerunning a file skips matches, including a batch saved before a network error. - Export supports up to 10,000 filtered leads at once. Narrow the filters if needed. - Exported cells are escaped to reduce spreadsheet-formula injection risk. PASSWORDS, ACCESS AND BACKUPS - Share the team password privately. This first version uses a shared team account, not separate user accounts. Assigned to is a label, not a permission boundary. - Every API read/write/export requires a valid server session. The login page and static app code contain no lead records or credentials. - Password guessing is limited to 8 attempts per 15 minutes per Cloudflare IP. - Signing out deletes that browser session on the server. - Change TEAM_PASSWORD or AUTH_SECRET and redeploy to invalidate old sessions. - Edits check the record version so one teammate cannot silently overwrite another teammate's newer edit. Reopen a changed record before retrying. - Delete lead is permanent and asks for confirmation. Export backups regularly. - Keep the D1 database when replacing the site ZIP. Redeploys preserve database data. - Cloudflare service quotas or charges depend on your plan and usage. PUBLIC QUOTE FORM The existing quote form still submits to your Formspree endpoint: https://formspree.io/f/mnpjgown It was not redirected to the lead database. Quote inquiries are not automatically CRM records in this version; add a lead manually when you want to track one. WHAT WAS CHECKED The package is tested with real SQLite-compatible SQL for login/session expiry, rate limiting, CSRF checks, lead creation/editing, duplicate imports, stale edits, deletion, filtering, CSV parsing/export and input validation. Frontend DOM workflow checks are also run. A supported live browser preview was unavailable here, and this ZIP has not been deployed to your account. Complete steps 2–6 to activate it. OFFICIAL CLOUDFLARE REFERENCES https://developers.cloudflare.com/pages/get-started/direct-upload/ https://developers.cloudflare.com/pages/functions/advanced-mode/ https://developers.cloudflare.com/pages/functions/bindings/ https://developers.cloudflare.com/d1/