# Heygo — Cloudflare Workers shortlinks app # Usage: `just` with no args lists all recipes. # ── Variables ────────────────────────────────────────────── db_name := "heygo-shortlinks" db_name_dev := "heygo-shortlinks-dev" port := "8787" # ── Default: list recipes ────────────────────────────────── _default: @just --list # ── Setup ────────────────────────────────────────────────── # Install npm dependencies install: npm install # ── Local dev ────────────────────────────────────────────── # Apply D1 migrations to local SQLite (run once after install, or after adding migrations) migrate-local: install npx wrangler d1 migrations apply {{db_name}} --local # Build the React SPA into dist/client (needed before dev:worker or deploy) build: npm run build # Start the Cloudflare Worker locally on port 8787 (serves API + built SPA) # Requires: just build && just migrate-local dev: migrate-local npm run dev:worker # Start Vite dev server on port 5173 with hot module replacement (frontend only) dev-ui: npm run dev # Quick smoke test: build, migrate, start worker, curl health endpoint smoke: build migrate-local @echo "Starting worker on :{{port}} …" @npx wrangler dev --port {{port}} & SERVER_PID=$$!; \ sleep 4; \ echo "--- Health ---"; curl -s http://localhost:{{port}}/api/health; echo; \ echo "--- Root (SPA) ---"; curl -sI http://localhost:{{port}}/ | head -1; \ kill $$SERVER_PID 2>/dev/null # ── Local dev auth ───────────────────────────────────────── # Create admin user and sign in locally (prints URL to open in browser) # Requires the worker to be running: `just dev` # Usage: just dev-admin wahyd4@gmail.com dev-admin email="wahyd4@gmail.com": @echo "=== Creating admin user via dev login API ===" @curl -s -X POST http://localhost:{{port}}/api/auth/dev-login \ -H 'content-type: application/json' \ -d '{"email":"{{email}}"}' @echo @echo "Or open http://localhost:{{port}}/#/dev-login in your browser" # Sign out locally (clears session cookie) # Requires the worker to be running: `just dev` dev-logout: @curl -s -X POST http://localhost:{{port}}/api/auth/dev-logout @echo @echo "Signed out." # ── Local D1 helpers ─────────────────────────────────────── # Run an arbitrary SQL query against local D1 (quote the SQL) # Usage: just db-query "SELECT * FROM links" db-query sql: npx wrangler d1 execute {{db_name}} --local --command '{{sql}}' # List all links in local D1 db-links: just db-query "SELECT id, alias, scope, status, link_type, target_url, click_count FROM links ORDER BY created_at DESC" # Show all tables in local D1 db-tables: just db-query "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name" # Insert a test public shortlink (alias + target URL) # Usage: just add-link claude https://claude.ai add-link alias url: npx wrangler d1 execute {{db_name}} --local --command \ "INSERT INTO links (id, alias, scope, status, link_type, target_url, content_markdown, description, owner_user_id, click_count, created_at, updated_at) \ VALUES (lower(hex(randomblob(8))), '{{alias}}', 'public', 'active', 'redirect', '{{url}}', NULL, NULL, NULL, 0, datetime('now'), datetime('now'))" # Delete a link by alias from local D1 # Usage: just rm-link claude rm-link alias: npx wrangler d1 execute {{db_name}} --local --command "DELETE FROM links WHERE alias='{{alias}}'" # Reset local D1 (drop all data, re-apply migrations) db-reset: rm -rf .wrangler/state/v3/d1 just migrate-local # ── Tests ────────────────────────────────────────────────── # Run the full Vitest suite test: npm test # Run tests in watch mode test-watch: npm run test -- --watch # ── Remote: dev environment ──────────────────────────────── # Apply D1 migrations to remote dev database migrate-dev: npm run migrate:dev # Deploy Worker to dev environment (dev.heygo.cc + my.dev.heygo.cc) deploy-dev: build npm run deploy:dev # ── Remote: prod environment ─────────────────────────────── # Apply D1 migrations to remote prod database migrate-prod: npm run migrate:prod # Deploy Worker to prod environment (heygo.cc + my.heygo.cc) deploy-prod: build npm run deploy:prod # ── Terraform infra ──────────────────────────────────────── # terraform init infra-init: terraform -chdir=terraform init # Plan infra for dev (review before apply) infra-plan-dev: terraform -chdir=terraform plan -var-file=environments/dev.tfvars # Apply infra for dev (creates/updates D1, KV, Worker custom domains) infra-apply-dev: terraform -chdir=terraform apply -var-file=environments/dev.tfvars # Plan infra for prod infra-plan-prod: terraform -chdir=terraform plan -var-file=environments/prod.tfvars # Apply infra for prod infra-apply-prod: terraform -chdir=terraform apply -var-file=environments/prod.tfvars # Show Terraform outputs for an environment (dev or prod) # Usage: just infra-output dev infra-output env: terraform -chdir=terraform output -var-file=environments/{{env}}.tfvars # ── Misc ─────────────────────────────────────────────────── # Type-check TypeScript without emitting typecheck: npx tsc --noEmit # Clean build artifacts (keeps node_modules and local D1 state) clean: rm -rf dist