← Back to list

Stashly - Personal Product Wishlist App

June 1, 2025

Stashly - Personal Product Wishlist App

Stashly

Your personal product wishlist, organized.

Stashly lets you save products you want to buy, organize them into themed lists (stashes), and share them with anyone. Paste a URL and Stashly auto-fills the product name, image, and price. Tag items, drag to reorder, mark purchases, and flip a stash public when you want to share it.

kit.co was shut down. So I built my own.

Free to use · Sign in with Google · Private by default

Check out Website!:

https://stashly-fawn.vercel.app/

Project Repository

https://github.com/Trident09/kitco-alt


Features


Tech Stack

Layer Technology
Framework Next.js 16 (App Router)
Language TypeScript 5
Styling Tailwind CSS 4
Auth Firebase Authentication (Google Sign-In)
Database Cloud Firestore
Drag & drop @dnd-kit
Scraping Brave Search API (server-side)

Getting Started

Prerequisites

1. Clone & install

git clone <repo-url>
cd kitco-alt
npm install

2. Configure environment variables

Copy the example and fill in your values:

cp .env.example .env.local
# Firebase
NEXT_PUBLIC_FIREBASE_API_KEY=
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=
NEXT_PUBLIC_FIREBASE_PROJECT_ID=
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=
NEXT_PUBLIC_FIREBASE_APP_ID=
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID=

# Brave Search API — server-side only
BRAVE_SEARCH_API_KEY=

3. Deploy Firestore rules

firebase deploy --only firestore:rules

4. Run the development server

npm run dev

Open http://localhost:3000.


Project Structure

src/
├── app/
│   ├── layout.tsx          # Root layout (fonts, providers)
│   ├── page.tsx            # Entry point — redirects to /landing or /dashboard
│   ├── landing/            # Marketing / home page
│   ├── about/              # About page
│   ├── login/              # Google Sign-In page
│   ├── dashboard/          # Authenticated dashboard (list of stashes + item view)
│   ├── s/                  # Public share page (/s/[listId])
│   └── api/
│       └── scrape/         # Server-side URL scraping endpoint
├── components/
│   ├── Sidebar.tsx         # Dashboard sidebar — stash list, create/delete
│   ├── ItemModal.tsx       # Add / edit item modal
│   ├── ManageTagsModal.tsx # Rename & delete tags in bulk
│   ├── CoverPickerModal.tsx # Stash cover illustration picker
│   ├── ConfirmModal.tsx    # Generic confirmation dialog
│   ├── KeyboardShortcutsLegend.tsx
│   ├── DashboardFooter.tsx
│   ├── BackToDashboard.tsx
│   └── Footer.tsx
├── lib/
│   ├── firebase.ts         # Firebase app init (auth, db)
│   ├── lists.ts            # Firestore CRUD for StashList
│   ├── items.ts            # Firestore CRUD + real-time subscriptions for StashItem
│   ├── public.ts           # Read-only helpers for the public share page
│   └── stash-covers.tsx    # Cover illustration definitions
├── context/
│   ├── AuthContext.tsx     # Firebase auth state (useAuth hook)
│   └── ToastContext.tsx    # Toast notification system
└── types/
    └── index.ts            # StashList and StashItem interfaces

Available Scripts

Command Description
npm run dev Start development server (Turbopack)
npm run build Production build
npm run start Start production server
npm run lint Run ESLint

Firestore Data Model

lists/{listId}
  uid          string   — owner's Firebase UID
  name         string
  description  string
  isPublic     boolean  — controls public share page access
  cover        string   — cover illustration ID
  tagOrder     string[] — user-defined tag sort order
  itemCount    number   — denormalized count
  createdAt    timestamp
  updatedAt    timestamp

items/{itemId}
  listId       string   — parent list ID
  uid          string   — owner's Firebase UID
  name         string
  url          string
  image        string   — scraped or manually provided URL
  price        string   — free-form, e.g. "$49.99"
  description  string
  notes        string
  tags         string[]
  purchased    boolean
  order        number   — position within list
  createdAt    timestamp
  updatedAt    timestamp

Security rules enforce that only the owner can read/write their own documents, while public lists and their items are readable by anyone (including unauthenticated users).


Contributing

See CONTRIBUTING.md.

Architecture

See docs/ARCHITECTURE.md for a deeper look at how the pieces fit together.

License

MIT © 2025 Rupam Barui