# ✨ Spark Slop A small, fast web app for capturing **project ideas** and growing them with **timestamped notes** — like a comment thread for each idea. Ideas are **private to your account** by default, with opt-in sharing. Built with **Bun**, **TypeScript**, and **SQLite** (`bun:sqlite`). No external runtime dependencies — the whole backend is the Bun standard library. ## Stack - **Bun.serve** — HTTP server + static file serving - **bun:sqlite** — embedded database (single `spark_slop.db` file, WAL mode) - **OAuth** sign-in (GitHub and/or Google) with cookie sessions — no passwords stored - **Vanilla TS/JS frontend** — no build step, no framework ## Auth & privacy - **Sign in with GitHub or Google.** Both are optional — the login screen only shows providers you've configured. Sessions are HttpOnly cookies (30 days); no passwords are ever stored. - **Private by default.** Every idea belongs to its owner and is invisible to everyone else. - **Per-idea public toggle.** Flip an idea to public to list it on the Explore feed (`/explore`), browsable by anyone — including logged-out visitors. - **Shareable read-only links.** Generate a secret link (`/share/`) that lets anyone view one idea and its notes without an account. Works independently of public/private status, and can be revoked anytime. ## Setup 1. Install dev types (already done if you cloned with `bun.lock`): ```bash bun install ``` 2. Configure at least one OAuth provider. Copy the example env file and fill in the credentials: ```bash cp .env.example .env ``` **GitHub:** create an OAuth app at with callback URL `http://localhost:3000/auth/github/callback`. **Google:** create OAuth credentials at (Web application) with authorized redirect URI `http://localhost:3000/auth/google/callback`. Bun auto-loads `.env`. If you change `BASE_URL` (e.g. for production), update the callback/redirect URLs in the provider settings to match. ## Run it ```bash bun run dev # auto-reload on file changes # or bun run start # plain run ``` Then open **http://localhost:3000**. Set `PORT` to change the port: ```bash PORT=8080 bun run start ``` The SQLite database file (`spark_slop.db`) is created automatically on first run. (If you ran an older version without auth, the schema self-migrates to add the new columns — existing ideas will have no owner; delete `spark_slop.db` for a clean slate.) ## Project layout ``` src/ db.ts # SQLite schema, migration guard, ownership-scoped queries auth.ts # OAuth (GitHub/Google) flows, sessions, cookies server.ts # Bun.serve: auth routes + JSON API + static files public/ index.html # landing page app.html # the app (auth-gated: idea list, notes, privacy controls) app.js # app logic (login gate, ideas, notes, visibility, sharing) explore.html # public Explore feed explore.js share.html # read-only viewer (shared links + public ideas) share.js common.js # shared helpers (API client, time formatting, rendering) styles.css # modern dark UI ``` ## API ### Public (no auth) | Method | Path | Description | | ------ | ------------------------- | ---------------------------------------- | | GET | `/api/auth/providers` | Which OAuth providers are configured | | GET | `/api/me` | Current user (401 if signed out) | | GET | `/api/explore` | List all public ideas | | GET | `/api/public/ideas/:id` | A public idea + its notes (read-only) | | GET | `/api/shared/:token` | An idea + notes via secret share token | ### Auth | Method | Path | Description | | ------ | -------------------------- | --------------------------------- | | GET | `/auth/github` | Start GitHub OAuth | | GET | `/auth/github/callback` | GitHub redirect target | | GET | `/auth/google` | Start Google OAuth | | GET | `/auth/google/callback` | Google redirect target | | GET | `/auth/logout` | Clear session and sign out | ### Authenticated (owner-scoped) | Method | Path | Description | | ------ | ----------------------------- | ------------------------------------ | | GET | `/api/ideas` | List your ideas (with note counts) | | POST | `/api/ideas` | Create an idea `{title, description}` | | GET | `/api/ideas/:id` | Get one of your ideas | | PUT | `/api/ideas/:id` | Update an idea | | DELETE | `/api/ideas/:id` | Delete an idea (cascades notes) | | PUT | `/api/ideas/:id/visibility` | Set `{visibility: "public"\|"private"}` | | POST | `/api/ideas/:id/share` | Create/rotate a share link | | DELETE | `/api/ideas/:id/share` | Revoke the share link | | GET | `/api/ideas/:id/notes` | List notes for an idea | | POST | `/api/ideas/:id/notes` | Add a note `{body}` | | DELETE | `/api/notes/:id` | Delete a note | All authenticated routes return `401` when signed out and `404` for ideas/notes you don't own — ownership is enforced in the SQL, not just the route layer.