Skip to content

app polish: hard-gate free trial + PixelVault-branded settings window#3

Merged
facundofarias merged 6 commits into
mainfrom
feat/hard-gate
Jul 11, 2026
Merged

app polish: hard-gate free trial + PixelVault-branded settings window#3
facundofarias merged 6 commits into
mainfrom
feat/hard-gate

Conversation

@facundofarias

Copy link
Copy Markdown
Member

Turns the 5-upload free trial into a real gate. Previously it was a soft nudge that kept uploading after the limit — which means users never had a reason to sign in (the funnel never closed).

Change

Once the 5 free anonymous uploads are used up, further anonymous uploads are blocked: the app shows a "Sign in to keep uploading" notification, opens the Account window, and does not put a URL on the clipboard. Signing in (keyed uploads) removes the limit.

  • upload_and_notify now returns Ok(None) when gated so the watcher/capture callers don't surface a false "Upload failed"; Ok(Some(url)) on a real upload.
  • Watcher leaves the clipboard image in place when gated (retry after sign-in); the per-image dedup prevents notification spam.
  • Signed-in users are unaffected.

Still client-side bypassable by design (reinstall resets the counter) — it presents the wall for the typical user; the server-side anonymous rate limiter remains the real abuse ceiling.

Verified compiling via tauri dev (full build green).

🤖 Generated with Claude Code

facundofarias and others added 2 commits July 11, 2026 11:08
A trial that never blocks converts no one, so once the 5 free anonymous uploads
are used up we now STOP uploading and prompt sign-in (open the Account window)
instead of nudging-and-continuing.

- upload_and_notify returns Ok(None) when gated so callers don't show a false
  "Upload failed"; Ok(Some(url)) on a real upload.
- Watcher keeps the clipboard image in place when gated (retry after sign-in);
  the per-image dedup avoids notification spam.
- Signed-in users are unaffected (keyed uploads, no trial). Still client-side
  bypassable by design — it presents the wall, the server rate limiter is the
  real ceiling.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replaces the generic light/blue Tauri styling with PixelVault's design tokens
(mirrors apps/web global.css): dark bg (#08090c), gold accent (#e4a44c), branded
card/inputs/buttons. Window is now dark-only to match pixelvault.dev.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@facundofarias facundofarias changed the title feat: hard-gate anonymous uploads after the free trial app polish: hard-gate free trial + PixelVault-branded settings window Jul 11, 2026
facundofarias and others added 4 commits July 11, 2026 11:36
Bump window height 540→640 and tighten vertical spacing so the account card +
how-to + footer fit without a scrollbar.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Inline the transparent gold logo SVG above the title; bump height 640→700 and
trim top padding so it still fits without scrolling.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The 'Free & open source · by PixelVault' line already links out, so the separate
pixelvault.dev link was redundant. Height 700→650 to match.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…afety)

Two-model review council (Claude + Codex) on the v0.2.0 diff. Fixes the 5
important findings:

1. Auth fail-open/split → unified cached Session (loaded once at startup,
   fail-CLOSED on real keychain errors vs. 'not found'); uploads read the cache,
   never the keychain. sign_out() now surfaces delete errors. A 401/403 on a
   keyed upload clears the session + prompts re-sign-in (UploadError::Unauthorized)
   instead of spamming raw error bodies.
2. Stale settings window → re-render on window focus (onFocusChanged), not just
   DOMContentLoaded.
3. Background-thread window mutation → open_settings() now runs show()/set_focus()
   via run_on_main_thread.
4. Non-atomic trial admission → try_reserve()/release()/commit_reserved() with a
   compare-exchange loop so concurrent watcher+capture uploads can't exceed 5.
5. Gated image never retried after sign-in → watcher tracks a separate gated_hash
   and lets the exact gated image through once signed in (no re-copy needed).

cargo check + tsc/vite build green, no warnings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@facundofarias
facundofarias merged commit 9372a2f into main Jul 11, 2026
2 checks passed
@facundofarias
facundofarias deleted the feat/hard-gate branch July 11, 2026 10:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant