Agree on the partnership before you commit to it
파트너와 실제 합의 내용을 확인하고 각자 답변을 비교해 차이를 파악한 뒤 변호사에게 전달할 공동 요약을 작성합니다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Chuffed Quotes turns rough job notes into a professional, itemised quote. A tradesperson talks or types the job, checks the prices, and sends a link. The customer opens it on their phone, picks a price if they were offered a choice, and accepts by typing their name. A sent or accepted quote can then become an invoice.
Live site: https://www.chuffedquotes.co.uk
The old addresses tradematequotes.co.uk and www.tradematequotes.co.uk permanently redirect (HTTP 308) to the same path on the live site. The product was previously called TradeMate, and before that BuilderBot. The GitHub repository is still named builderbot. The product name itself lives in builderbot-app/lib/brand.mjs.
The app is in a free public beta for UK trades. Card payments are switched off. The first 100 people who join keep it free for 12 months.
/walkthrough. Five recorded clips, all in the same voice, play in order. Together they last about 32 seconds. Sound starts when you tap, each step waits until its clip ends, and it stops after the last clip. The pictures are sample data, not a real customer or business./try. They type notes, or tap a decorating, plumbing, or electrics example, and see Standard, Better, and Premium plus a preview of the customer page. The business name on that preview is “Your Business Name”. It is not saved, and it cannot be sent or emailed. After they create a free account, that quote is waiting in the quote builder.INV-0001 onwards for that account). Invoices can be edited, shared, printed, and marked paid./auth/confirm when the person taps) or by email and password. The email also has a code of 6 to 10 digits, which can be typed on the sign-in page.New quotes get their own reference (BB- plus eight characters). An older shared number such as BB-1041 is left as it is, unless that same id already belongs to another account, in which case it is given a new reference on save.
| Piece | What it is |
|---|---|
| App | Next.js 16 (App Router), React 19, TypeScript |
| Styling | Tailwind CSS 4 |
| Icons | lucide-react |
| Data and sign-in | Supabase (Postgres, Auth, Storage). The live project is in the EU (London). |
| AI | Google Gemini through @google/genai. Default model gemini-3.5-flash, overridable with GEMINI_MODEL. |
| Hosting | Vercel |
| Errors | Sentry, only when NEXT_PUBLIC_SENTRY_DSN is set |
| Usage counts | PostHog, only after the visitor taps Accept on the cookie banner |
| Payments | Stripe code is in the repo. Card payments are switched off in this beta, and the Stripe keys are left blank. |
| Tests and CI | Node’s built-in test runner. GitHub Actions workflow CI, job Lint, Test & Build. |
builderbot-app/ The Next.js app
app/ Pages and API routes
q/[id]/ Public customer quote
i/[token]/ Public invoice
api/quote/ AI generate, AI expand, save, and view counts
components/ Navigation, quote editor pieces, consent banner
lib/ Quote rules, storage, Gemini, Supabase, brand
supabase/schema.sql Full database for a new project
supabase/migrations/ Incremental SQL for a database that already exists
scripts/ Optional local Reddit and X helpers (not part of the website)
test/ Unit tests (node --test)
.github/workflows/ci.yml Lint, Test & Build
The product name, tagline, and owner contact are in builderbot-app/lib/brand.mjs.
You need Node.js 20 (the version CI uses).
cd builderbot-app
cp .env.example .env.local
npm ci
npm run dev
Open http://localhost:3000.
Copy names into .env.local. Put real values only in that file or in the host’s environment settings. .env.example shows placeholders. Do not commit real keys.
| Name | Purpose |
|---|---|
GEMINI_API_KEY | Optional. Blank keeps the app on rough estimates. |
GEMINI_MODEL | Optional model id. Default gemini-3.5-flash. |
NEXT_PUBLIC_SUPABASE_URL | Supabase project URL. |
NEXT_PUBLIC_SUPABASE_ANON_KEY | Supabase anon key (browser). |
SUPABASE_SERVICE_ROLE_KEY | Server only. Used for rate limits and the AI quota. |
NEXT_PUBLIC_APP_URL | Optional public site address, with no trailing slash. |
NEXT_PUBLIC_FEEDBACK_EMAIL | Optional. Blank uses the owner email in lib/brand.mjs. |
STRIPE_SECRET_KEY | Leave blank. Card payments are off. |
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY | Leave blank. |
STRIPE_WEBHOOK_SECRET | Leave blank. |
NEXT_PUBLIC_SENTRY_DSN | Optional. Blank means no error reports. |
SENTRY_ORG | Optional. Needed only to upload source maps. |
SENTRY_PROJECT | Optional. Needed only to upload source maps. |
SENTRY_AUTH_TOKEN | Optional. Server only. Needed only to upload source maps. |
NEXT_PUBLIC_POSTHOG_KEY | Optional. Blank means no usage counts. |
NEXT_PUBLIC_POSTHOG_HOST | Optional. Use the EU host for this site. |
REDDIT_CLIENT_ID | Optional. Only for scripts/reddit-assistant.mjs. |
REDDIT_CLIENT_SECRET | Optional. Only for that script. |
REDDIT_USERNAME | Optional. Only for that script. |
REDDIT_PASSWORD | Optional. Only for that script. |
X_API_KEY | Optional. Only for scripts/x-assistant.mjs. |
X_API_SECRET |
AI quoting runs for signed-in users. Each account can run 30 quote builds and 30 scope rewrites in a rolling hour. A guest on /try can run 5 builds a day from one network address. Those counts live in Supabase. If that database check fails, the same limit is applied in the server’s memory for that address or account. The first requests in the window still go through. The limit still stops the next one. A stored “limit reached” answer still stops the build. It does not leave the helper open with no limit. If Gemini returns an error, times out (20 seconds), or sends unusable JSON, the quote uses the rough estimate.
An AI quote request, including photos, cannot be larger than about 1.8 MB. Each photo must be a real JPEG, PNG, GIF, or WebP, and each one must be smaller than about 350,000 characters. The quote builder shows the plain-English message if a photo is too big or is not a real image. The try-it page does not send photos.
E2E_BASE_URL is read by builderbot-app/test/e2e-live-check.mjs when you point that script at a deployed site. It is not required for npm test.
Run these from builderbot-app/:
| Command | What it does |
|---|---|
npm run dev | Local development server |
npm test | Unit tests (node --test test/*.test.mjs) |
npm run lint | ESLint |
npm run build | Production build |
npm start | Serve the production build |
Two optional local helpers live next to the app and are not started by the website or by CI:
node scripts/reddit-assistant.mjs --help
node scripts/x-assistant.mjs --help
The live site is hosted on Vercel. Merging to main is what ships a new version. Wait until the Vercel deployment says Ready, then use https://www.chuffedquotes.co.uk.
New Supabase project: in the SQL editor, run the whole of builderbot-app/supabase/schema.sql. That file is the current database, including quotes, invoices, templates, rate limits, and view counting.
Database that already exists: run any file in builderbot-app/supabase/migrations/ that has not been applied yet, in filename order. Those files are safe to run more than once. A fresh project that has just run schema.sql does not need them again. The typed-acceptance migration is builderbot-app/supabase/migrations/20261030120000_typed_acceptance_record.sql. Apply it in the Supabase SQL editor when you are ready. Until then, accepting a quote still works. After it is applied, each acceptance is also stored as a row that cannot be edited or deleted.
Set the environment variable names from the table above in Vercel. Leave every Stripe variable blank. Sign-in emails are sent from [email protected]. The privacy notice names Resend as the sender. That mail setup is in Supabase, not in this repository.
A longer click-by-click list for a first deploy is in BETA_SETUP.md.
NEXT_PUBLIC_SENTRY_DSN is set. Tracing is sampled at 10%. Names, email addresses, phone numbers, addresses, and quote wording are removed before the report is sent. Sentry does not record the screen. Source-map upload runs only when SENTRY_ORG, SENTRY_PROJECT, and SENTRY_AUTH_TOKEN are all set. Otherwise the upload is skipped and production stack traces stay minified./q/…) and customer invoice pages (/i/…) are not recorded. A signed-in account is counted by id. The try-it page can count that the page was opened, that Build was tapped (and whether an example was used), that a quote was shown, that a build failed because the notes were empty, the daily limit was hit, or the helper failed, and that sign-up was tapped. It does not send the job notes. The intended host is the EU one (https://eu.i.posthog.com)./privacy on the live site. It names the owner, what is stored, sign-in email, Gemini, Sentry, and PostHog. It is a plain-language beta notice, not legal advice.Dates are the dates on the commits. The same history, in Keep a Changelog form, is in CHANGELOG.md.
builderbot-app/supabase/migrations/20261030120000_typed_acceptance_record.sql in Supabase, the name, time, network address, total, and chosen option are stored in a row that cannot be edited or deleted. Accepting a quote still works before that SQL is applied.price_memory table. The AI is asked to fill in the quantities. The try-it page does not save or send a price list. No database migration./try. A guest gets Standard, Better, and Premium and a customer-page preview under “Your Business Name”. Nothing is saved or sent. Five builds a day are allowed from one network address, using the existing Supabase rate limit. After sign-up, the quote is waiting in the builder. No database migration./walkthrough show a short van demo with recorded narration. It describes speaking the job, checking a priced quote, sending a WhatsApp link, the customer typing their name, and making an invoice. The home page says this takes a couple of minutes. The “quotes stay in this browser” banner is not shown on the demo page./auth/confirm and are used only when the person taps.tradematequotes.co.uk (later redirected).Known follow-ups, in the order they matter:
SENTRY_ORG, SENTRY_PROJECT, and SENTRY_AUTH_TOKEN are set on Vercel. Do not commit the token./quotes. The quote summary prints today’s date with new Date() while the page is rendering (builderbot-app/app/quotes/QuotesClient.tsx). That can make the server HTML and the browser disagree. React reports that mismatch as warning #418.Longer-term notes (supplier price lookups, a native app, tax summaries) are in ROADMAP.md and AGENTS.md. Some older lines in those files still describe card payments as live. The beta behaviour above is the one to trust.
Any change that alters what the product does, how to run it, or what is still to do should update this file’s Progress section and CHANGELOG.md in the same pull request. Coding agents are told to do that in AGENTS.md, GEMINI.md, and .agents/rules/keep-docs-updated.md. Nothing in the repository commits to main by itself.
There is no licence file in this repository. All rights reserved. Ask before you copy or reuse the code.
Chuffed Quotes is run by Michael Boylen, a sole trader in the United Kingdom.
Email: [email protected]
| Optional. Only for that script. |
X_ACCESS_TOKEN | Optional. Only for that script. |
X_ACCESS_SECRET | Optional. Only for that script. |