← Back to lab
ProductIn beta testingProject 08 / 14

Yardsale

A self-hosted online garage sale for one seller: buyers browse used things and send a request, no checkout, no payment, no accounts.

At a glance

  • A request, not a purchase
  • Expectations before the button
  • AI drafts, I decide

Ask for a walkthrough

The question

When you clear out a flat, the hard part isn't finding buyers, it's the back and forth: is it still available, what's wrong with it, can I pick it up on Sunday. Could one calm page answer most of that up front, and turn the rest into a single tidy message instead of a checkout?

What I built

A public catalog in Romanian and English where every item has clear photos, a condition scale, honest notes on defects, what's included and what isn't, and a price in RON with a euro estimate. Buyers add things to a request list and send it with a short message, or ask a question about one item. I confirm availability, pickup and the final total by message.

Behind it, an admin that installs on a phone. I take a photo, write or dictate a quick note, and an AI step drafts the title, description, category, condition and price. Every drafted field shows how sure it is and stays editable, and nothing is published until I press Publish.

Inside

How it looks in use.

Role
Sole designer, developer and owner
Built with
Next.js, TypeScript, Tailwind, Prisma, PostgreSQL
Runs
Built to self-host with Docker Compose; the admin installs on a phone
Status
In beta testing
A buyer adds two items, writes a short note and sends the request, all on a phone.
Adding a product from the phone: a photo, a quick note, then an AI draft to check and edit.
The same catalog on a phone, where most buyers arrive.
The same catalog on a phone, where most buyers arrive.
A product page: condition, price and one button to add it to the request.
A product page: condition, price and one button to add it to the request.
The request list: not a checkout, just the items and a suggested total.
The request list: not a checkout, just the items and a suggested total.
The phone admin: a note, a pricing mode and an AI draft to review.
The phone admin: a note, a pricing mode and an AI draft to review.
The catalog: used items with clear photos, filters and a request button on every card.
The catalog: used items with clear photos, filters and a request button on every card.

Up close

The details that carry it.

Condition at a glance
Condition at a glanceA five-step condition scale, availability and a reduced price, right under the title.
A suggestion, not a bill
A suggestion, not a billThe request list adds up the items and suggests a bundle discount; the final amount comes by message.
Check before publishing
Check before publishingThe AI draft ends with a short list of what to verify and which fields it was least sure about.

Decisions that mattered

  • A request, not a purchaseThere's no payment and no invoice, and the request list says so in its first line. Used goods need a conversation, so the app's job is to make that conversation short.
  • Expectations before the buttonPickup, shipping, payment and invoice are shown on every product, and the buyer ticks that they understand them before sending. Most of the questions I'd otherwise answer by hand are settled there.
  • AI drafts, I decideThe AI fills the form rather than the listing: each field carries a confidence label and a reason, low-confidence fields are flagged in a short checklist, and it runs on a local mock when no key is set, so the app works without any AI at all.

What I learned

Saying what you won't do builds as much trust as what you will. Being plain about no invoice, no transport and slow replies made the page feel more honest, not less helpful.

Project notes

This project is in beta testing, open to invited testers. It keeps changing as I use it and learn from the people who do.

Something similar in mind?

Most of these started as a question I couldn't let go of. If you have one too, let's talk.

To MaxAn ideaWhat would you like to build?I've been wondering whether…I read every message myselfWrite →