Skip to content
KiranRajeev-KVPublic

About

A self-hosted shared idea archive for small groups—save, discover and revisit useful thoughts.

Topics

Resources

Stars

8 stars

Watchers

0 watching

Forks

Latest commit

 

History

73 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Stashed app icon

Stashed

Save ideas worth coming back to.

Stashed is a self-hosted, shared idea archive designed for small groups. Members can save their own ideas, discover what others are thinking, and return to useful thoughts later.

Anyone can read public ideas. Authors can also keep ideas unlisted (available only by URL) or private (available only to themselves), and are the only members who can edit or delete their ideas.

Stashed is a full-stack web app: the React frontend and Hono API run together on a single Cloudflare Worker, backed by Cloudflare D1 and Drizzle ORM.

Screenshots

Landing Browse ideas
Stashed landing page with product introduction and interactive archive preview Public Ideas archive showing searchable idea cards
Read an idea Explore a collection
Public Idea detail with author, status, tags, and formatted notes Public Collection detail with collaborators and curated Ideas

Current Features

  • GitHub authentication and registration
  • Public, unlisted, and private idea visibility
  • Collaborative Collections for organizing Ideas without changing their access rules
  • A shared public idea feed, ordered by recently updated ideas
  • Author-owned idea creation, editing, and deletion
  • Idea statuses for tracking how thoughts develop
  • Searchable tags created as ideas are saved
  • Full-text search across idea titles and content
  • Markdown editing and rendering
  • Responsive light and dark appearances

Important

Registration is currently open through GitHub. Anyone who can reach a deployed instance and authenticate with GitHub can register; Stashed does not currently include invitations or an approved-members list.

Tech Stack

  • Frontend: React 19, Vite, TypeScript, Tailwind CSS v4, TanStack Router, TanStack Query, TanStack Form, Plate
  • Backend: Hono on Cloudflare Workers (serves the SPA and the API from one Worker)
  • Database: Cloudflare D1 + Drizzle ORM
  • Tooling: pnpm, just, Oxlint, Knip, Prettier, Wrangler

Architecture Decisions

Significant technical decisions are recorded as Architecture Decision Records.

Prerequisites

  • Node.js 22+
  • pnpm
  • just (optional — you can use the npm scripts directly)
  • A Cloudflare account (only needed for deploying and db:remote)

Quickstart

pnpm install
pnpm db:local
pnpm dev

Open http://127.0.0.1:5173. Confirm the server is up with:

curl http://127.0.0.1:5173/api/health
# {"ok":true,"app":"Stashed"}

Scripts

Run just to list every recipe. The ones you'll use most:

Command What it does
just dev Start the dev server (SPA + Worker) at 127.0.0.1:5173
just build Type-check + production build
just check lint + format-check + typecheck + build (pre-commit gate)
just knip Find unused code/dependencies in all and production code
just deploy Build, then deploy to Cloudflare
just db-generate Generate Drizzle migrations from the schema
just db-local Apply migrations to the local D1 database
just db-remote Apply migrations to the remote D1 database
just screenshots Regenerate committed README/documentation screenshots
just clean Remove build artifacts (dist, .wrangler, tsbuildinfo)

Screenshots

Screenshot assets are committed under docs/assets/screenshots/. Install Playwright's Chromium once, then regenerate all of them with:

pnpm exec playwright install chromium
pnpm screenshots

The capture is read-only against the public production site and uses a fixed desktop viewport, dark-primary/light-secondary themes, reduced motion, and UTC locale. The two detail routes are explicit public records in scripts/screenshots.mjs; the command fails rather than silently substituting another record if either changes. Because it captures public production content, the copy and public avatars can legitimately change between regenerations.

To capture only specific assets, pass their stable names:

pnpm screenshots -- --only ideas,collection-detail

Set STASHED_SCREENSHOT_BASE_URL to capture the same public routes from a different deployment.

Knip runs in both comprehensive and production modes. Its project patterns in knip.json mark the React and Worker trees as shipped code while keeping local maintenance scripts in the comprehensive pass. Configuration hints fail the command so new entry-point gaps are fixed rather than silently ignored.

Production deployment

Stashed deploys the React frontend, Hono API, and static assets together as a single Cloudflare Worker. The Worker uses the stashed-db D1 database declared in wrangler.jsonc.

Production releases are branch-gated:

  • Pull requests and pushes to main or prod run the CI workflow.
  • Only a push to prod can run the production deployment workflow.
  • The deployment applies pending D1 migrations before publishing the Worker.
  • Production seed data is never applied automatically.

Some schema migrations also require a one-time data migration for existing production records. See the migration guide for release-specific instructions.

The current production origin is:

https://stashed.kiranrajeevkv.workers.dev

Create a GitHub environment named production, restrict it to the prod branch, and add these environment secrets:

Secret Purpose
CLOUDFLARE_ACCOUNT_ID Selects the Cloudflare account
CLOUDFLARE_API_TOKEN Deploys Workers and applies D1 migrations

Scope the API token to this Cloudflare account. It needs Workers Scripts: Write and D1: Edit. The GitHub App client ID, client secret, and Stashed session secret and TypeSafe API key are Worker secrets stored directly in Cloudflare; they do not need to be duplicated in GitHub.

The intended release flow is to work normally on main, then open a pull request from main into the protected prod branch when the current state is ready for production.

For the initial Worker deployment, set the Worker secrets without committing the local .env file:

pnpm exec wrangler secret bulk .env
pnpm db:remote
pnpm run deploy

Keep the local callback (http://127.0.0.1:5173/api/auth/github/callback) and add this exact production callback to the GitHub App:

https://stashed.kiranrajeevkv.workers.dev/api/auth/github/callback

About

A self-hosted shared idea archive for small groups—save, discover and revisit useful thoughts.

Topics

Resources

Stars

8 stars

Watchers

0 watching

Forks

Contributors

Languages