feat: complete M0 — legal pages, consent, tip_views metrics, account deletion UI

- /legal/terms and /legal/privacy pages (linked from sign-in)
- Consent (consentGiven=true) recorded on first Google sign-in
- tip_views table: one row per tip served — enables activation + reaction rate queries
- tip_views purged on account deletion
- Delete account button on /connect (confirm → revoke tokens → purge data → sign out)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-15 09:09:08 +00:00
parent 888f8b9a99
commit f6c890213b
18 changed files with 438 additions and 9 deletions

View File

@@ -88,6 +88,7 @@ export default function TipPage() {
return (
<>
<style>{`
@keyframes breathe {
0%, 100% { opacity: 0.3; }
@@ -100,12 +101,11 @@ export default function TipPage() {
onPointerUp={onPointerUp}
onPointerLeave={onPointerUp}
style={{
minHeight: '100vh',
height: '100dvh',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
padding: '3rem 2rem',
userSelect: 'none',
WebkitUserSelect: 'none',
cursor: state === 'tip' ? 'default' : 'auto',
@@ -127,7 +127,7 @@ export default function TipPage() {
{/* Loading label */}
{(state === 'loading' || state === 'done') && (
<p style={{
marginTop: '1.25rem',
margin: 0,
color: 'rgba(255,255,255,0.55)',
fontSize: '0.7rem',
letterSpacing: '0.18em',
@@ -140,7 +140,7 @@ export default function TipPage() {
{/* Tip */}
{(state === 'tip' || state === 'actions') && tip && (
<Fade visible={visible && state !== 'actions'} style={{ textAlign: 'center', maxWidth: '420px' }}>
<Fade visible={visible && state !== 'actions'} style={{ textAlign: 'center', maxWidth: '420px', padding: '0 2rem' }}>
<p style={{
fontSize: 'clamp(1.25rem, 4vw, 1.75rem)',
fontWeight: 300,