133 lines
5.5 KiB
Markdown
133 lines
5.5 KiB
Markdown
# ✨ 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/<token>`) 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 <https://github.com/settings/developers>
|
|
with callback URL `http://localhost:3000/auth/github/callback`.
|
|
|
|
**Google:** create OAuth credentials at
|
|
<https://console.cloud.google.com/apis/credentials> (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.
|