Agree on the partnership before you commit to it
Find out what you and your business partner are actually agreeing to. Each of you answers on your own, you see where your expectations differ, and you build a shared brief to take to your lawyer.
Quoting software built site-first for trade teams of 1-10. Scope, quote and send before you leave the driveway. Homeowners get free quotes from local tradies.
BusinessTypeScript · PLpgSQLGitHub @BrencoveredOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗AU trade quoting SaaS: build a live quote on site, send it, win the job, run the crew day, push a draft invoice to Xero.
Do not treat supabase/schema.sql as the full live schema. Production evolves through dated files in supabase/migrations/ (apply in order on new environments).
schema.sql is a historical bootstrap snapshot only. Prefer:
If you must bootstrap from SQL editor, run migrations after any base schema, then verify with the latest migration timestamps.
supabase/migrations/ (see above).env.example to .env.local and fill in Supabase keysnpm install && npm run devSign up at resend.com, verify a sending domain, add RESEND_API_KEY and RESEND_FROM_EMAIL. Without these, save still works; send fails with a clear error.
Register a developer app at developer.xero.com. Redirect URI: <deployed-url>/api/xero/callback. Set XERO_CLIENT_ID, XERO_CLIENT_SECRET, XERO_REDIRECT_URI.
Each business connects their own org from Settings. On quote accept, SwiftScope pushes a draft invoice (scope lines when available, otherwise the quote total). Payment status does not sync back from Xero yet - mark jobs paid in SwiftScope when money clears. Variations do not auto-update the Xero invoice yet.
$45/mo or annual (~2 months free), unlimited users, 7-day free trial, no per-seat pricing.
STRIPE_PRICE_MONTHLY, STRIPE_PRICE_ANNUAL, STRIPE_SECRET_KEY/api/stripe/webhook for subscription + checkout events → STRIPE_WEBHOOK_SECRETSUPABASE_SERVICE_ROLE_KEY for webhook writesNEXT_PUBLIC_APP_URL for Checkout redirectsAccess is gated in middleware.ts via trial/subscription status (lib/requireActiveAccess.ts).
npm run dev
npm run build
npm run lint
npm test # vitest unit tests (quote grouping, Xero line builder, trade normalize)
npm run directory:merge # dry-run duplicate plan; add -- --apply to write
npm run directory:abn # free ABN ingest + enrich + MX/ABN verify (local)
npm run directory:verify # re-check ABN status and email MX only
directory_listing feeds SEO pages and outreach. Phone numbers are stored as E.164 (+61…) in phone_e164, websites as a bare hostname in website_domain, and ABNs as 11 digits. Shared call-centre numbers (13 / 1300 / 1800 / 1900) and directory hosts (Facebook, Yellow Pages, supplier sites) are not used as unique identity.
Apply order on an existing database (do this yourself; nothing in CI mutates production):
supabase/migrations/20261021120000_directory_listing_identity.sql. It adds abn, phone_e164, website_domain, verified_at, verification_source, email_valid, and the shared-key flags. It also relabels historical source = 'scraper' rows that have a place_id to google_places. Deploy the app only after this migration: outreach export and claim-invite select email_valid.npx tsx scripts/merge-directory-duplicates.ts (or npm run directory:merge). Read the MERGE, SUPPRESS, and REVIEW lines.npx tsx scripts/merge-directory-duplicates.ts --apply. Same-suburb rows that are the same business are merged (claimed or richer row wins; the loser is snapshotted in directory_listing_merge_log). Different businesses that share a phone or domain keep both rows; the extra row drops the normalised key so the unique index can exist. The displayed phone and website stay. A group with two claimed profiles is left for a person to resolve.supabase/migrations/20261021130000_directory_listing_unique_identity.sql. It refuses to create the unique indexes while any duplicate phone, domain, or ABN group remains in one suburb.Secrets for the weekly GitHub Action .github/workflows/abn-directory.yml (Settings → Secrets and variables → Actions). Do not commit values.
| Name | Where |
|---|---|
SUPABASE_URL | same as NEXT_PUBLIC_SUPABASE_URL |
SUPABASE_SERVICE_ROLE_KEY | Supabase → Project Settings → API |
ABN_LOOKUP_GUID | free registration at https://abr.business.gov.au/Tools/WebServices |
Optional variables: ABN_ENRICH_LIMIT (default 800), DIRECTORY_VERIFY_LIMIT (default 2000). The workflow runs Sundays at 16:00 UTC, or on demand with phase all, ingest, enrich, or verify. It downloads each ABR zip once, stream-parses it, bulk-inserts trade candidates, guesses websites in parallel, then re-checks ABNs (ABN Lookup) and email DNS MX records. It never sends email and it deletes GOOGLE_PLACES_API_KEY from the job environment before it starts. Google Places stays on the manual admin scrape, directory-page scrape, and listing-create screens. The paused expand-directory cron stays out of vercel.json.
ABN bulk ingest from the admin UI returns 409 and points at this workflow. A small enrich batch can still be started from the admin screen; that path does not call Google.
Push to GitHub, import in Vercel, set the env vars above. Standard Next.js app.