simikkk's picture
Upload 36 files
16e1aa7 verified
|
Raw
History Blame Contribute Delete
11 kB
# DEPLOY.md — Etsy Listing Optimizer
This walks through getting every free-tier account, wiring the keys, and
deploying to a Hugging Face Space. Follow it top to bottom the first time.
**Total cost to get running: 0 Kč upfront.** Stripe only takes a cut once you
actually charge someone.
---
## 0. What you'll end up with
- A live app at `https://<your-hf-username>-etsy-listing-optimizer.hf.space`
- Real auth + database (Supabase)
- Real AI generation (Groq, with Gemini as fallback)
- Real subscription billing (Stripe)
Until you add the keys below, the app **runs in demo mode** (in-memory
storage, a mock AI provider) so you can click around and see it work first.
---
## 1. Get every account + API key
### 1.1 Supabase (database + auth) — free, no credit card
1. Go to **https://supabase.com** → sign up → "New Project".
2. Pick an **EU region (Frankfurt)** — this matters for GDPR data residency,
set it now, it can't be changed later without migrating.
3. Set a strong database password (you won't need it day-to-day; Supabase
manages connections for you).
4. Once the project finishes provisioning, go to **Project Settings → API**:
- `Project URL` → this is your `SUPABASE_URL`
- `anon` `public` key → this is your `SUPABASE_ANON_KEY`
- `service_role` `secret` key → this is your `SUPABASE_SERVICE_ROLE_KEY`
(⚠️ never expose this one client-side or commit it — it bypasses every
Row Level Security rule)
5. Go to **Authentication → Providers → Email** and make sure Email auth is
enabled (it is by default).
6. Go to **Authentication → Policies** (or **Auth → Settings** depending on
your dashboard version) and turn on **"Leaked password protection"**.
This is a checkbox, not code — do it now so you don't forget.
7. Go to the **SQL Editor**, paste the entire contents of
`supabase_schema.sql` from this project, and run it. This creates all
tables and Row Level Security policies.
### 1.2 Groq (primary AI provider) — free tier, no credit card
1. Go to **https://console.groq.com/keys**, sign up, click "Create API Key".
2. Copy it → this is your `GROQ_API_KEY`.
3. Free tier has generous rate limits for Llama 3.3 70B; if you ever hit
them, the app automatically falls back to Gemini (see below) — no code
changes needed, just add both keys.
### 1.3 Gemini (fallback AI provider) — free tier, no credit card
1. Go to **https://aistudio.google.com/app/apikey**, sign in with a Google
account, click "Create API key".
2. Copy it → this is your `GEMINI_API_KEY`.
3. This is optional for v1 (Groq alone works), but recommended — it's what
keeps `/generate` working if Groq ever rate-limits you.
### 1.4 Stripe (payments) — free to set up, per-transaction fee only
1. Go to **https://dashboard.stripe.com/register**, sign up.
2. Stay in **Test mode** first (toggle top-right of the dashboard) — you can
test the entire flow with fake card numbers before going live.
3. Go to **Developers → API keys** → copy the **Secret key**
(`sk_test_...`) → this is your `STRIPE_SECRET_KEY`.
4. Go to **Product catalog → Add product**, create three recurring products:
- "Starter" — 149 CZK / month
- "Pro" — 349 CZK / month
- "Business" — 799 CZK / month
For each, copy the **Price ID** (looks like `price_1AbCdE...`) → these
become `STRIPE_PRICE_STARTER`, `STRIPE_PRICE_PRO`, `STRIPE_PRICE_BUSINESS`.
5. Webhook: you'll finish this step *after* deploying (step 3 below), because
Stripe needs your live URL first.
6. When you're ready for real money, flip to **Live mode** in the dashboard
and repeat steps 3–4 to get live keys/price IDs (test and live keys are
different).
### 1.5 Resend (transactional email) — optional for v1, free tier
1. Go to **https://resend.com**, sign up, verify a sending domain (or use
their test domain while developing).
2. **API Keys** → create one → this is your `RESEND_API_KEY`.
3. Not wired into the app yet in v1 (password reset emails currently go
through Supabase's own email delivery, which works out of the box on
the free tier with Supabase's default templates/limits). Add this later
if you want branded emails.
### 1.6 Hugging Face (hosting) — free CPU tier, no credit card
1. Go to **https://huggingface.co/join** if you don't have an account.
2. You'll create the Space in step 2 below.
---
## 2. Create the Hugging Face Space
1. Go to **https://huggingface.co/new-space**.
2. Name: `etsy-listing-optimizer` (or whatever you like).
3. **SDK: choose "Gradio"** and version **5.12.0**. This project's root
`README.md` already contains the metadata block HF Spaces reads
(`sdk: gradio`, `app_file: server.py`) — as long as you keep that file at
the repo root, the Space will run `server.py`, which starts the full
FastAPI app (auth, billing, webhooks, GDPR routes, etc.) with the Gradio
UI mounted on top of it, all on port 7860. No Dockerfile needed.
4. Hardware: **CPU basic** (free).
5. Visibility: your choice (Public is fine and free; Private also works on
the free tier).
6. Click "Create Space".
### 2.1 Push the code
From this project's folder:
```bash
git init
git remote add space https://huggingface.co/spaces/<your-username>/etsy-listing-optimizer
git add .
git commit -m "Initial deploy"
git push space main
```
(Use your HF username/token when prompted for credentials — Hugging Face
will show you a personal access token to use as the password under
**Settings → Access Tokens** if you don't have one yet.)
Once pushed, check the Space's **Logs** tab — you should see uvicorn start
up and, in demo mode, a line noting no LLM provider is configured yet. If
you instead see a build error about `app_file`, double-check `README.md`
is present at the repo root with its metadata block intact (git sometimes
excludes dotfiles/READMEs if you cherry-picked what to push — push the
whole folder).
### 2.2 Add your secrets
In the Space, go to **Settings → Variables and secrets****New secret**
for each of these (values from section 1 above):
```
SUPABASE_URL
SUPABASE_ANON_KEY
SUPABASE_SERVICE_ROLE_KEY
GROQ_API_KEY
GEMINI_API_KEY
STRIPE_SECRET_KEY
STRIPE_WEBHOOK_SECRET (added in step 3 below, after this first deploy)
STRIPE_PRICE_STARTER
STRIPE_PRICE_PRO
STRIPE_PRICE_BUSINESS
APP_BASE_URL (e.g. https://your-username-etsy-listing-optimizer.hf.space)
```
Adding a secret automatically restarts the Space. Leave
`STRIPE_WEBHOOK_SECRET` empty for now — you'll get that value in step 3.
Once `SUPABASE_URL`, a Supabase service role key, at least one of
`GROQ_API_KEY`/`GEMINI_API_KEY`, and `STRIPE_SECRET_KEY` are all set, the
app automatically leaves demo mode and starts using real services — no code
changes required.
---
## 3. Wire up the Stripe webhook
1. Once your Space is live, note its URL, e.g.
`https://your-username-etsy-listing-optimizer.hf.space`.
2. In Stripe, go to **Developers → Webhooks → Add endpoint**.
3. Endpoint URL: `https://your-username-etsy-listing-optimizer.hf.space/billing/webhook`
4. Select these events to listen for:
- `checkout.session.completed`
- `customer.subscription.created`
- `customer.subscription.updated`
- `customer.subscription.deleted`
5. Save, then copy the **Signing secret** (`whsec_...`) shown on the
endpoint's page → set this as `STRIPE_WEBHOOK_SECRET` in your HF Space
secrets (section 2.2). This restarts the Space again.
6. Test it: in Stripe's webhook page, click "Send test webhook" and confirm
your Space logs show `200 received: true` — check the Space's **Logs**
tab.
---
## 4. Verify everything end-to-end
1. Open your Space URL. You should **no longer** see the "Demo mode" banner.
2. Sign up with a real email in the **Account** tab.
3. Generate a listing in the **Generate listing** tab — this now calls Groq
for real.
4. In the **Account** tab, click "Get checkout link" for a paid tier, use a
Stripe **test card** (`4242 4242 4242 4242`, any future expiry, any CVC)
to complete checkout.
5. Confirm your tier updated (try generating more than 5 times — the Free
cap should no longer apply).
6. Test **Export my data** and **Delete my account** — confirm the exported
JSON looks right and that deletion removes the Supabase Auth user (check
**Authentication → Users** in Supabase — the row should be gone).
---
## 5. Going to production (real payments)
- Flip Stripe to **Live mode**, repeat section 1.4 steps 3–4 for live keys
and live Price IDs, update the HF secrets, and set up a **second** webhook
endpoint pointed at the same URL but using your live webhook signing
secret.
- Have a lawyer (or a reputable EU-focused generator) review the draft
Privacy Policy / Terms / Refund Policy at `/legal/privacy`, `/legal/terms`,
`/legal/refunds` before taking real customers — the current text is a
placeholder, not legal advice (see the banner on each page).
- Run `pip-audit` periodically against `requirements.txt` to catch known
vulnerabilities in dependencies (see note in `requirements.txt`).
- Consider setting up log monitoring/alerting on your HF Space (or moving to
a platform with better observability) once you have real users — the free
CPU tier is fine for launch but has no built-in alerting.
---
## Design decisions driven by the "zero upfront cost" constraint
- **Groq over a paid API (OpenAI/Anthropic):** Groq's free tier is generous
and fast (LPU inference); the tradeoff is Llama 3.3 70B is a notch below
GPT-4-class models on nuanced copywriting, which is why the code layers
heavy programmatic validation + a critic pass on top rather than trusting
raw model output.
- **Gemini as fallback, not primary:** Gemini's free tier has stricter
per-minute limits than Groq's, so it's used only when Groq is unavailable.
- **Supabase over a self-hosted Postgres:** free managed Postgres + auth +
RLS in one product, with an EU-region option for GDPR, without paying for
a VPS or a database host.
- **Hugging Face Spaces (Gradio SDK, CPU basic) over a paid PaaS
(Fly.io/Render paid tier):** free forever for a single small instance; the
tradeoff is you're on a single instance with no autoscaling — fine for a
v1 micro-SaaS, but you'll want to move off it if traffic grows (the
in-memory rate limiter and demo-mode fallback both assume single-instance
too).
- **slowapi (in-memory) rate limiting over Redis-backed:** free, zero extra
infra; the tradeoff is limits reset if the Space restarts, and won't work
correctly if you ever scale to multiple instances — swap in a Redis
`storage_uri` at that point.
- **Resend stubbed rather than wired up:** Supabase's built-in auth emails
(confirmation, password reset) work out of the box for free, so Resend
was left as a v2 nice-to-have rather than a v1 requirement, keeping the
initial integration surface smaller.