GGP

Master ledger — every system, one page.
Owner: Will (mindfulcrumb@gmail.com) · Updated 2026-04-25 · Vault: ~/.claude/.env
9 live 1 built · not deployed 1 vendor 1 retired

Status board tap a row to jump to detail

Daily ops five systems · the employee operations stack

01 Clock App live

Employee clock-in/out, geofenced to two shop locations.

URL
clock.gadgetgeekspro.com
Code
/root/clock-app/index.html on Hetzner; APIs at /opt/kimai/public/*.php in kimai container.
Stack
Vanilla JS + Kimai PHP APIs + MySQL.
Vault keys
None on client. Server reads KIMAI_DB_PASSWORD from /Users/research/payroll-setup/.env.
Last touched
2026-04-23 (leave-balance UI added)
Issues / next
Steady. Next: pay-stub PDF emailer; time-off request workflow.

Geofence radii 200 m around (32.229003, −110.876589) and (32.220943, −110.839048). Auto clock-out cron every 15 min closes any entry >12 h. Pay period 14 days, OT FLSA per-week >40 h at 1.5×, timezone America/Phoenix −07:00.

02 Timesheet (Kimai) live

Full timesheet admin UI — view, edit, export, audit time entries. Source of record for hours.

URL
time.gadgetgeekspro.com/en/timesheet/
Code
kimai container, /opt/kimai/
Stack
Kimai 2 (PHP / Symfony)
Vault keys
KIMAI_ADMIN_EMAIL, KIMAI_ADMIN_PASSWORD, KIMAI_DB_PASSWORD in /Users/research/payroll-setup/.env
Last touched
2026-03 (steady)
Issues / next
Steady. Watch DB size; backup cadence already set in payroll-backups/.

03 Payroll Admin live

Pay-period summaries, payroll readiness, NACHA generation, tax liability view, employee onboarding status.

URL
clock.gadgetgeekspro.com/admin.html
Code
/root/clock-app/admin.html + APIs /opt/kimai/public/clock-admin-api.php, clock-generate-nacha.php, clock-leave-log.php, clock-leave-balance.php
Stack
PHP + MySQL + ERPNext API. bcrypt + 24h session tokens. CORS locked to gadgetgeekspro.com.
Vault keys
ERPNEXT_URL, ERPNEXT_API_KEY, ERPNEXT_API_SECRET. Static admin token ggp_admin_dashboard_2026 accepted only from 127.0.0.1 / ::1.
Last touched
2026-04-23 (leave system verified live)
Issues / next
None. Next: MFA for admin, pay-stub PDF emailer, "Adjust Balance" UI on Leave card (currently API-only).

Federal 2026 brackets per IRS Rev Proc 2025-32 / OBBBA. AZ flat 2.5% with optional A-4 election (8 rates 0%–5.1%). SS 6.2% (cap $184,500), Medicare 1.45% (no cap). Employer FUTA 0.6% on first $7,000, AZ SUTA 2.0% on first $8,000, AZ Job Training 0.1% on first $7,000.

04 Onboarding live

New-hire flow — W-4 wizard, AZ A-4 election, direct deposit, address, emergency contact, e-sig + perjury cert.

URL
onboard.gadgetgeekspro.com
Code
/root/onboard-app/index.html + /opt/kimai/public/onboard/save.php
Stack
Vanilla JS + PHP. Audit log at /data/onboarding/audit.log (IP + timestamp per change).
Vault keys
ERPNEXT_URL, ERPNEXT_API_KEY, ERPNEXT_API_SECRET. Email alerts via RESEND_API_KEY, RESEND_FROM_EMAIL.
Last touched
2026-03-25 (server-side auth hardened)
Issues / next
None. Next: mobile signature capture, document upload (proof of address, ID), annual W-4 refresh prompt.

PII storage: per-employee JSON at /data/onboarding/{employee_id}.json in the kimai container; directory chmod 750, owner www-data. Save endpoint uses merge logic — never overwrites.

05 ERPNext live

Backend of record — employees, salary structure, GL accounts, journal entries, leave ledger config.

URL
erp.gadgetgeekspro.com
Code
Compose at /Users/research/payroll-setup/; container payroll-setup-backend-1; bench at /home/frappe/frappe-bench/ inside.
Stack
ERPNext + Frappe + MariaDB.
Vault keys
ERPNEXT_URL, ERPNEXT_API_KEY, ERPNEXT_API_SECRET. Compose-only: DB_ROOT_PASSWORD, ADMIN_PASSWORD, TAXBANDITS_*.
Last touched
2026-04-23
Issues / next
None. Next: evaluate move of ACH/tax filing to QuickBooks or Gusto (~$88/mo); keep this stack as employee-management layer.

Company Gadget geeks pro (abbr GGP). Salary Structures: Standard Hourly + Standard Salaried. GL accounts 2310/2320/2330/2340/2350/2360/2120/5120/5130. Leave: sick 1h per 30h worked (annual cap 24h), PTO 40h annual grant, both carry forward, 90-day waiting period; ledger at leave_ledger (append-only).

docker exec -w /home/frappe/frappe-bench payroll-setup-backend-1 \
  bench --site erp.gadgetgeekspro.com execute <module.function>

Storefront & customer three systems

06 Refresh Theme live

Online Store 2.0 storefront for gadgetgeekspro.myshopify.com.

URL
gadgetgeekspro.myshopify.com · admin
Code
/Users/research/refresh-theme/
Stack
Shopify Liquid (Dawn 15.2.0 fork). Theme ID 157805740283. Breakpoints 750/990 px.
Vault keys
SHOPIFY_STORE, SHOPIFY_ACCESS_TOKEN (24h refresh), SHOPIFY_CLIENT_ID, SHOPIFY_CLIENT_SECRET. Plus DEVICEPLUG_STORE, DEVICEPLUG_ACCESS_TOKEN.
Last touched
2026-03-16
Issues / next
None. Next: continue CWV polish (LCP <2.5 s, CLS <0.1, INP <200 ms, Lighthouse ≥90).

API 2026-01 GraphQL Admin only. Bulk ops via bulkOperationRunQuery for >250 records. Theme push discipline: theme dev MUST run, strip JSON comments after pull, full-theme push always.

07 Transactional Emails built · not deployed

Order confirmations, shipping, refunds, review requests via Shopify webhooks → Resend. Code complete, never deployed — verified 2026-04-25 (no process on port 4000, no launchd, no autostart). Render deploy chosen.

URL
Not deployed. After Render: *.onrender.com. Shopify webhook URLs need updating once live.
Code
/Users/research/gadget-geeks-emails/ — Procfile + nixpacks.toml staged.
Stack
Express + React Email + Resend SDK. HMAC-SHA256 webhook sig verification present.
Vault keys
RESEND_API_KEY, RESEND_DOMAIN, RESEND_FROM_EMAIL, RESEND_FROM_NAME, SHOPIFY_ACCESS_TOKEN, SHOPIFY_WEBHOOK_SECRET.
Last touched
2026-03-09 (1 commit total)
Pre-deploy gaps
idempotency on Shopify retries · structured logging (Pino) · smoke tests · rate limit · doc LOGO_URL/STORE_URL defaults.

⚠ kimai container has resend-webhook.php + dwolla-webhook.php handlers (audit 2026-04-25). Investigate overlap before deploying the Express server — server-side may already handle some webhook flows.

08 The Hub (Financial OS) live

Financial dashboard — invoice OCR, payments, AR/AP, journal entries against ERPNext.

URL
app.gadgetgeekspro.com · fallback the-hub-4og.pages.dev
Code
/Users/research/ggp-hub/
Stack
Next.js 16 + Tailwind + Framer Motion → Cloudflare Pages. Auth: passkeys (SimpleWebAuthn). Offline: service worker + IndexedDB queue.
Vault keys
ANTHROPIC_API_KEY, ERPNEXT_*, CLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_TUNNEL_API_TOKEN. CF Pages secrets: WEBAUTHN_RP_ID, WEBAUTHN_ORIGIN, NEXT_PUBLIC_APP_URL.
Last touched
2026-04-09 (Day 1 launch)
Issues / next
Day-1 leftovers: enter opening balances with brother; register passkey on his iPhone; Add to Home Screen.
cd /Users/research/ggp-hub
npx @cloudflare/next-on-pages
CLOUDFLARE_ACCOUNT_ID=99b9624f8d6c3f6410a36d19db9a39fd \
  npx wrangler pages deploy .vercel/output/static \
  --project-name the-hub --branch main --commit-dirty=true

Inventory one system

09 Inventory Intake (PWA) live

Shop-floor IMEI scanning, auto-detect device specs, create ERPNext Item Variant + Serial No + Stock Entry.

URL
intake.gadgetgeekspro.com
Code
Frontend /Users/research/ggp-inventory/frontend/src/; backend /Users/research/ggp-inventory/ggp-intake-app/server/server.py (~1900 lines, deployed to /root/ggp-intake-app/server/).
Stack
Vite + React + TypeScript (Quagga2 barcode) + FastAPI + ERPNext + unlock4less + 248K-entry TAC database.
Vault keys
Server /root/ggp-intake-app/server/.env: ERP_URL, ERP_TOKEN; u4l creds (username Tradeingadgets, key) live only on the server. u4l account email accounts@gadgetgeekspro.com. Top-level vault has ERPNEXT_* for cross-system use.
Last touched
2026-04-23 (auto-print labels after submit, grade+tester on label)
Issues / next
TS build errors in lots system — ship via npx vite build, fix types as tech debt. Color auto-fill flake on re-tested IMEIs (DHRU 24-48h cache).

u4l health: /api/health returns unlock4less: ok | ip_blocked | auth_failed | down. Per-path egress IPs at /api/u4l/whoami. If ip_blocked, refresh the IPv6 whitelist at unlock4less.com → Profile → API Access.

phone → intake.gadgetgeekspro.com
      → nginx (payroll-setup-proxy-1) on 94.130.58.243
      → FastAPI (server-ggp-intake-api-1) :8080
      → ERPNext (erp.gadgetgeekspro.com)
      → unlock4less (direct from server via IPv6 2a01:4f8:1c19:4c00::1)

Marketing one system · listed but pending Will's confirmation

11 Marketing Org live per memory

Repo of 26+ AI agents on GitHub Actions for content / social / research. Listed as an active workstream in _projects/ggp/context.md; Will did not recognize the name in chat — confirm familiarity before relying on it.

URL
github.com/mindfulcrumb/gadgetgeeks-marketing-org
Code
Local clone /Users/research/gadgetgeeks-marketing-org/
Stack
GitHub Actions + Claude API; cron schedules 2h/3h/6h.
Vault keys
ANTHROPIC_API_KEY, OPENROUTER_API_KEY, OPENAI_API_KEY, plus per-platform social tokens stored as GitHub Actions secrets.
Last touched
2026-03-19 (last commit)
Issues / next
Run gh run list -R mindfulcrumb/gadgetgeeks-marketing-org to confirm active runs; promote to LIVE once Will confirms ownership.

Vendor & dormant two entries · not part of daily ops

10 Hi-Tek Nova testPod vendor

Phone diagnostics, grading, ADISA-certified data erasure. Vendor SaaS — not built by Will.

URL
cloud.hiteknova.com
Code
N/A (third-party)
Stack
Hi-Tek Nova cloud testPod — ~50–200 devices/day, 45 simultaneous tests, <3 min cycle.
Vault keys
None in ~/.claude/.env. Login lives in Hi-Tek's portal — keep in 1Password.
Last touched
2026-04-21 (decision: stay on Hi-Tek, request on-prem/factory edition + custom dashboard wrapper)
Issues / next
Awaiting on-prem quote and REST/webhook API spec from Hi-Tek sales.

12 u4l Proxy retired

Cloudflare Worker that proxied unlock4less DHRU calls because Hetzner IPv4 was blocked. Replaced.

URL
Former — u4l.gadgetgeekspro.com
Code
/Users/research/u4l-proxy/ + local Mac proxy /Users/research/u4l-local-proxy.py + tunnel config ~/.cloudflared/u4l-config.yml
Stack
Cloudflare Worker + Wrangler.
Vault keys
None — retired.
Last touched
~2026-04 (replaced)
Issues / next
Hetzner now calls unlock4less directly via IPv6 (2a01:4f8:1c19:4c00::1 whitelisted). Local Mac files can be archived.

Hetzner host map

Host 94.130.58.243 · IPv6 2a01:4f8:1c19:4c00::1 · SSH ssh -i ~/.ssh/erp-deploy root@94.130.58.243

ContainerRoleNotes
payroll-setup-proxy-1Nginx — terminates :80/:443, routes by Host:Only public ingress
payroll-setup-frontend-1ERPNext frontend (nginx)Serves static, proxies to backend
payroll-setup-backend-1ERPNext + Frappe (bench)API at erp.gadgetgeekspro.com
payroll-setup-queue-short-1Frappe RQ worker (short)Email sends, light async
payroll-setup-queue-long-1Frappe RQ worker (long)Reports, bulk ops
payroll-setup-scheduler-1Frappe schedulerCron-like ERPNext jobs
payroll-setup-websocket-1Frappe websocketRealtime UI updates
payroll-setup-redis-cache-1Redis (cache)App cache
payroll-setup-redis-queue-1Redis (queue)RQ job queue
payroll-setup-db-1MariaDB 10.11ERPNext + Kimai DBs
payroll-setup-kimai-1Kimai 2 (apache) + clock/onboard PHP APIsHosts time.*, container OS in CEST — see TZ note
payroll-setup-n8n-1n8n automationHosts auto.gadgetgeekspro.com
server-ggp-intake-api-1FastAPI intake :8080Reads ERPNext + unlock4less
ggp-cloudflaredCloudflare tunnel clientInvestigate purpose — likely legacy u4l

TZ: payroll-setup-kimai-1 container OS is CEST. Kimai PHP, ERPNext containers, MariaDB, host are UTC. Mismatch only matters if anything reads container date instead of PHP. Set TZ=America/Phoenix on the kimai container to align with the user-facing timezone.

Host file layout

/root/clock-app/index.htmlClock app frontend
/root/clock-app/admin.htmlPayroll Admin frontend
/root/onboard-app/index.htmlOnboarding frontend
/root/ggp-intake-app/Intake PWA static + server
/root/payroll-scripts/Tax reminder cron, NACHA helpers
/data/onboarding/*.jsonPer-employee PII (chmod 750)
/data/company_info.jsonCompany bank info + EIN
/data/admin_password.hashAdmin bcrypt hash
/data/admin_sessions.jsonActive admin sessions
/data/tax_liability_*.jsonPer-period tax liability snapshots
/opt/kimai/public/*.phpAll Kimai-container PHP APIs

Cloudflare DNS

Account Will@mindfulcrumb.com (99b9624f8d6c3f6410a36d19db9a39fd) · Zone gadgetgeekspro.com (521107c5ff9225d0f4b03df30818ee00) · Pages project the-hubthe-hub-4og.pages.dev

SubdomainTypeTargetProxied
app.gadgetgeekspro.comCNAMEthe-hub-4og.pages.devyes
clock.gadgetgeekspro.comA94.130.58.243yes
time.gadgetgeekspro.comA94.130.58.243yes
onboard.gadgetgeekspro.comA94.130.58.243yes
erp.gadgetgeekspro.comA94.130.58.243yes
intake.gadgetgeekspro.comA94.130.58.243yes
auto.gadgetgeekspro.comA94.130.58.243 (n8n)yes
u4l.gadgetgeekspro.comretired
hub.gadgetgeekspro.comMXroute{1,2,3}.mx.cloudflare.net (future email)

Vault index tap to expand · key names only, never values

Shopify Theme + Emails + Inventory
SHOPIFY_STORE · SHOPIFY_ACCESS_TOKEN · SHOPIFY_CLIENT_ID · SHOPIFY_CLIENT_SECRET · DEVICEPLUG_STORE · DEVICEPLUG_ACCESS_TOKEN
Webhook only: SHOPIFY_WEBHOOK_SECRET in /Users/research/gadget-geeks-emails/.env
Retrieve: grep '^SHOPIFY_' ~/.claude/.env
ERPNext Hub + Payroll + Onboarding + Inventory + ERP itself
ERPNEXT_URL · ERPNEXT_API_KEY · ERPNEXT_API_SECRET
Compose-only (/Users/research/payroll-setup/.env): SITE_NAME · DB_ROOT_PASSWORD · ADMIN_PASSWORD
Intake server-only (/root/ggp-intake-app/server/.env): ERP_URL · ERP_TOKEN
Retrieve: grep '^ERPNEXT_' ~/.claude/.env
Kimai / Payroll compose-only
In /Users/research/payroll-setup/.env: KIMAI_DB_PASSWORD · KIMAI_ADMIN_EMAIL · KIMAI_ADMIN_PASSWORD
Tax filing Payroll Admin · TaxBandits
In /Users/research/payroll-setup/.env: TAXBANDITS_CLIENT_ID · TAXBANDITS_CLIENT_SECRET · TAXBANDITS_USER_TOKEN
Cloudflare Hub deploy + DNS + Tunnels
CLOUDFLARE_ACCOUNT_ID · CLOUDFLARE_ZONE_ID · CLOUDFLARE_TUNNEL_API_TOKEN
Wrangler OAuth: ~/.wrangler/config/default.toml
Retrieve: grep '^CLOUDFLARE_' ~/.claude/.env
Resend Emails + Onboarding alerts
RESEND_API_KEY · RESEND_DOMAIN · RESEND_FROM_EMAIL · RESEND_FROM_NAME
Retrieve: grep '^RESEND_' ~/.claude/.env
AI providers Hub OCR + Marketing Org
ANTHROPIC_API_KEY · OPENROUTER_API_KEY · OPENAI_API_KEY · GOOGLE_AI_API_KEY · FAL_KEY · ELEVENLABS_API_KEY
Marketing Org / agents
TWITTER_CONSUMER_KEY · TWITTER_CONSUMER_SECRET · TWITTER_BEARER_TOKEN · TWITTER_ACCESS_TOKEN · TWITTER_ACCESS_TOKEN_SECRET · TELEGRAM_BOT_TOKEN · TELEGRAM_LUMINARY_BOT_TOKEN · FIRECRAWL_API_KEY · MODAL_TOKEN_ID · MODAL_TOKEN_SECRET · WANDB_API_KEY · TINKER_API_KEY
Adjacent projects not GGP, kept in same vault
D'Lux Space: DLUX_SPACE_*
Lotshare: GITHUB_TOKEN_LOTSHARE · VERCEL_TOKEN_LOTSHARE · SUPABASE_TOKEN_LOTSHARE · CLAUDE_CODE_OAUTH_TOKEN_LOTSHARE · DATABASE_URL_LOTSHARE

Cross-system data flows

A. Time → Pay → ACH out
   Employee phone
     → clock.gadgetgeekspro.com (Clock App)
       → kimai PHP APIs → MySQL kimai2_timesheet
         → time.gadgetgeekspro.com (Kimai admin)
           → admin.html (Payroll Admin) reads pay-period
             → clock-generate-nacha.php → NACHA file
               → bank ACH (manual today)
               → ERPNext salary structure + journal entry
                 → The Hub displays + reconciles
B. Sale → Invoice → Reconcile
   Shopify (gadgetgeekspro.myshopify.com) order
     → webhook → ERPNext sales order + item
       → Hub displays order + payment status
         → Hub OCR (Claude) extracts invoice → ERPNext journal entry
           → Hub closes loop with payment settlement
C. Phone in → Inventory → Storefront
   Shop floor IMEI scan
     → intake.gadgetgeekspro.com (PWA)
       → FastAPI :8080 → TAC lookup + unlock4less enrichment
         → ERPNext Item Variant + Serial No + Stock Entry
           → (future) sync → Shopify catalog

Daily operations playbook

1. Run a payroll for the current pay period

  1. Open clock.gadgetgeekspro.com/admin.html.
  2. Verify Live Status, then Pay Period Summary — confirm hours per employee (use hours_override when owner-confirmed differs from raw clock).
  3. Review Payroll Readiness Checklist — every employee green (W-4, A-4, direct deposit, address).
  4. Click Generate Payroll → downloads NACHA + CSV + payment sheet.
  5. Upload NACHA at the bank portal; mark deposit dates in /data/tax_liability_<period>.json.

2. Add a new employee

  1. Create the user in ERPNext (employee record + salary structure).
  2. Send onboarding URL: https://onboard.gadgetgeekspro.com?token=<kimai_token>.
  3. Confirm green on the Payroll Admin "Onboarding" panel.

3. Fix a stuck clock-in

  1. ssh -i ~/.ssh/erp-deploy root@94.130.58.243
  2. docker exec -it kimai bash
  3. mysql -u root -p"$KIMAI_DB_PASSWORD" kimaiUPDATE kimai2_timesheet SET end = ... WHERE id = ...;

4. Deploy intake frontend

cd /Users/research/ggp-inventory/frontend && rm -rf dist && npx vite build
ssh -i ~/.ssh/erp-deploy root@94.130.58.243 "rm -rf /root/ggp-intake-app/assets/*"
scp -i ~/.ssh/erp-deploy dist/index.html root@94.130.58.243:/root/ggp-intake-app/index.html
scp -i ~/.ssh/erp-deploy dist/assets/* root@94.130.58.243:/root/ggp-intake-app/assets/
curl -s -o /dev/null -w "%{http_code}\n" https://intake.gadgetgeekspro.com

5. Deploy intake backend

scp -i ~/.ssh/erp-deploy /Users/research/ggp-inventory/ggp-intake-app/server/server.py \
  root@94.130.58.243:/root/ggp-intake-app/server/server.py
ssh -i ~/.ssh/erp-deploy root@94.130.58.243 \
  "cd /root/ggp-intake-app/server && docker compose down && \
   docker compose build --quiet && docker compose up -d"
curl -s https://intake.gadgetgeekspro.com/api/health

6. Rotate the Shopify access token (24h cycle)

  1. Refresh via flow in ~/.claude/CLAUDE.md knowledge router (shopify-token-flow.md).
  2. Update ~/.claude/.env (SHOPIFY_ACCESS_TOKEN=...).
  3. Update ~/.claude/mcp.json if Shopify MCP is configured there.
  4. Restart any webhook listeners that read the env (Transactional Emails server :4000).

7. Restart a Hetzner container

ssh -i ~/.ssh/erp-deploy root@94.130.58.243
docker ps -a
docker restart kimai
docker logs --tail 100 -f kimai

8. Check ERPNext logs

docker exec -it payroll-setup-backend-1 \
  tail -f /home/frappe/frappe-bench/sites/erp.gadgetgeekspro.com/logs/web.log

9. Push refresh-theme to Shopify

  1. Ensure shopify theme dev is running; visually verify at 1280 px AND 375 px.
  2. After any shopify theme pull, strip /* */ blocks from JSON template files.
  3. Push the FULL theme: shopify theme push --live=false --theme <id> (never --only).

10. Send a test transactional email

cd /Users/research/gadget-geeks-emails
node -e "require('./send.js').sendTest('order_confirmation', 'will@example.com')"

Adjust to whatever entrypoint the repo exposes — check package.json scripts.

Open issues & next up

Immediate · this week

2–4 weeks

1–3 months