# Techmave Studio — Supabase setup + blog guidelines

The blog CMS lives in `studio.html` (linked from the site footer as "Studio").
It talks to a Supabase project: **email/password auth** for sign-in and a
`posts` table for content. Nothing is hard-coded — when `supabase-config.js`
has no keys, the Studio shows a quiet notice and stays inert. The moment you
paste real values, everything works.

---

## Part 1 — connect Supabase (one-time, ~10 minutes)

1. **Create a project** at [supabase.com](https://supabase.com) → New project.
   Pick any name (e.g. `techmave`); the region closest to your audience.

2. **Create the admin login**
   Project → **Authentication → Users → Add user → Emails**.
   Enter your email and a strong password. That's the Studio sign-in.
   (Disable "Sign up with email" under Authentication → Providers if you want
   only pre-created users to log in.)

3. **Create the `posts` table.** Open Project → **SQL Editor** → New query,
   paste the entire contents of `supabase/schema.sql` (next to this file)
   and run it. It creates the table (including the `excerpt` column the
   journal cards read), the `updated_at` trigger, an index, and the RLS
   policies: anonymous visitors read *published* posts only, signed-in
   admins get full access.

   > `supabase/schema.sql` is the only source of truth for the schema —
   > it matches what `studio.js` / `blog.js` actually read and write.

4. **Paste the credentials.** Project → **Settings → API**, then open
   `supabase-config.js` and fill in the two values:

   ```js
   window.TM_SUPABASE = {
     url: 'https://YOUR-PROJECT.supabase.co',  // "Project URL"
     anonKey: 'eyJ...',                          // "Publishable key" (was anon)
   };
   ```

   No other change is needed — `supabase-config.js` auto-detects the values
   and the Studio enables itself on the next load.

5. **Open `studio.html`** (or the deployed `studio` URL), sign in with your
   email from step 2, and you'll land on an empty posts list. That's it.

> **Security note:** the publishable/anon key is safe to ship in the browser
> — it's meant to be public. All real access control happens in the RLS
> policies above. Don't paste the *service_role* key anywhere in this project.

> **Serving the Studio:** it's a plain static page, so it deploys next to
> `index.html` as-is. It's marked `noindex` so Google won't list the admin
> login publicly.

---

## Part 2 — how to create a blog (writing guidelines)

Every post is written in the Studio editor. The flow is the same each time:

1. **New post** → type the **title** first. The **slug** fills itself from
   the title (e.g. "Why We Ship Fewer Projects" → `why-we-ship-fewer-projects`);
   only edit it if you need to.
2. **Category** — one word: `Product`, `Notes`, `AI`, `Engineering`.
   **Read (min)** — estimate 200 words ≈ 1 minute; it drives the "4 min read"
   line readers expect.
3. **Write the body in the rich text box:**
   - **B / I** — selection formatting, H2 for section breaks, H3 for
     sub-points. One H2 per major idea; H3s underneath.
   - **Lists** — bullets for "things", numbered for "steps".
   - **" " (blockquote)** — pull-quotes and outside references.
   - **Link** — select text, then Link → paste URL. Always https, external
     links open in a new tab automatically.
   - **Image** — host the image somewhere public (e.g. your static site's
     `/img/` or a CDN), paste the URL, and *always* give alt text (one short
     sentence describing the image).
4. **Voice** — plain, specific, no jargon dumps. Lead with the takeaway, not
   a throat-clearing intro. 400–900 words is the house length; if a post
   needs 2000 words, split it.
5. **Save** — creates the post as a **draft**. You can save any number of
   times; the title/slug/meta fields only become final when you publish.
6. **Publish** — tick the *Published* box in the editor and Save (or use
   *Publish* in the posts list). This stamps `published_at` and makes the
   post visible to the site's blog reader. *Unpublish* clears the stamp and
   shelves it without deleting.
7. **Slug rule:** slug + title together are the reader-facing identity.
   Change the slug only if the post is unlinked anywhere (RSS, socials).

**Sanitization:** on every save the editor content is stripped of `<script>`,
event attributes (`on*`), and `javascript:`/`data:` URLs before hitting
Supabase. Write normal content and none of this is ever visible to you.

---

## Troubleshooting

| Symptom | Fix |
| --- | --- |
| Notice "Supabase not connected yet" | Keys missing in `supabase-config.js` — do Part 1, step 4. |
| "Email or password is incorrect." | The user wasn't created in Authentication → Users, or password differs. |
| `relation "posts" does not exist` | Part 1, step 3 SQL not run in that project. |
| `failed to fetch` | Wrong project URL, or CORS/region issue — check Settings → API for the exact URL. |
| New users can sign themselves up | Authentication → Providers → Email → disable "Sign up". |
