feat(auth): add email verification to registration flow
Some checks failed
CI / Test backend (pull_request) Failing after 11s
CI / Check ui (pull_request) Failing after 11s
CI / Docker / backend (pull_request) Has been skipped
CI / Docker / runner (pull_request) Has been skipped
CI / Docker / ui (pull_request) Has been skipped
CI / Docker / caddy (pull_request) Successful in 2m53s
Release / Test backend (push) Successful in 19s
Release / Check ui (push) Successful in 33s
Release / Docker / caddy (push) Failing after 1m26s
Release / Docker / ui (push) Failing after 11s
Release / Docker / backend (push) Successful in 2m2s
Release / Docker / runner (push) Successful in 2m24s
Release / Gitea Release (push) Has been skipped

- Add email/email_verified/verification_token/verification_token_exp fields
  to app_users PocketBase schema (pb-init-v3.sh)
- Add SMTP env vars to UI service in docker-compose.yml
- New email.ts: raw TLS SMTP mailer via Node tls module, sendVerificationEmail()
- createUser() now takes email param, stores verification token (24h TTL)
- loginUser() throws 'Email not verified' when email_verified is false
- New /verify-email route: validates token, verifies user, auto-logs in
- Login page: email field in register form, check-inbox state after register
- /api/auth/register (iOS): returns { pending_verification, email } instead of token
- Add pb.libnovel.cc and storage.libnovel.cc Caddy virtual hosts for homelab runner
- Add homelab runner docker-compose and libnovel.sh helper script
This commit is contained in:
Admin
2026-03-24 20:18:24 +05:00
parent 424f2c5e16
commit 920ac0d41b
13 changed files with 759 additions and 211 deletions

100
scripts/libnovel.sh Normal file
View File

@@ -0,0 +1,100 @@
#!/usr/bin/env bash
set -euo pipefail
# ── LibNovel — production management script ───────────────────────────────────
# Prerequisites on the server:
# - docker + docker compose plugin
# - doppler CLI authenticated (doppler setup run once in the repo directory)
# - docker-compose.yml present in the same directory as this script
#
# Usage: ./libnovel.sh <command> [service]
#
# up Start all services (detached)
# down Stop all services
# restart Stop then start all services
# restart <svc> Restart a single service
# pull Pull latest images from Docker Hub (uses GIT_TAG from Doppler)
# update Pull images then recreate containers
# logs Tail all logs
# logs <svc> Tail a specific service
# ps Show running containers
# shell <svc> Open a shell in a running container
# init Run one-shot init containers
# secrets Print all Doppler secrets (debug)
# ──────────────────────────────────────────────────────────────────────────────
DC="doppler run -- docker compose"
CMD="${1:-help}"
SVC="${2:-}"
case "$CMD" in
up)
$DC up -d
;;
down)
$DC down
;;
restart)
if [[ -n "$SVC" ]]; then
$DC restart "$SVC"
else
$DC down
$DC up -d
fi
;;
pull)
$DC pull backend runner ui caddy
;;
update)
$DC pull backend runner ui caddy
$DC up -d
;;
logs)
if [[ -n "$SVC" ]]; then
$DC logs -f --tail=100 "$SVC"
else
$DC logs -f --tail=50
fi
;;
ps)
$DC ps
;;
shell)
[[ -z "$SVC" ]] && { echo "Usage: $0 shell <service>"; exit 1; }
$DC exec "$SVC" sh
;;
init)
$DC run --rm minio-init
$DC run --rm pb-init
$DC run --rm postgres-init
;;
secrets)
doppler secrets --project libnovel --config prd
;;
help|*)
echo "Usage: $0 <command> [service]"
echo ""
echo " up Start all services"
echo " down Stop all services"
echo " restart Full restart"
echo " restart <svc> Restart one service"
echo " pull Pull latest images from Docker Hub"
echo " update Pull + recreate containers"
echo " logs Tail all logs"
echo " logs <svc> Tail one service"
echo " ps Show running containers"
echo " shell <svc> Shell into a container"
echo " init Run init containers (first-time setup)"
echo " secrets Print Doppler secrets"
;;
esac

View File

@@ -177,11 +177,15 @@ create "audio_jobs" '{
create "app_users" '{
"name":"app_users","type":"base","fields":[
{"name":"username", "type":"text","required":true},
{"name":"password_hash","type":"text"},
{"name":"role", "type":"text"},
{"name":"avatar_url", "type":"text"},
{"name":"created", "type":"text"}
{"name":"username", "type":"text","required":true},
{"name":"password_hash", "type":"text"},
{"name":"role", "type":"text"},
{"name":"avatar_url", "type":"text"},
{"name":"created", "type":"text"},
{"name":"email", "type":"text"},
{"name":"email_verified", "type":"bool"},
{"name":"verification_token", "type":"text"},
{"name":"verification_token_exp","type":"text"}
]}'
create "user_sessions" '{
@@ -240,11 +244,15 @@ create "comment_votes" '{
]}'
# ── 5. Field migrations (idempotent — adds fields missing from older installs) ─
add_field "scraping_tasks" "heartbeat_at" "date"
add_field "audio_jobs" "heartbeat_at" "date"
add_field "progress" "user_id" "text"
add_field "progress" "audio_time" "number"
add_field "progress" "updated" "text"
add_field "books" "meta_updated" "text"
add_field "scraping_tasks" "heartbeat_at" "date"
add_field "audio_jobs" "heartbeat_at" "date"
add_field "progress" "user_id" "text"
add_field "progress" "audio_time" "number"
add_field "progress" "updated" "text"
add_field "books" "meta_updated" "text"
add_field "app_users" "email" "text"
add_field "app_users" "email_verified" "bool"
add_field "app_users" "verification_token" "text"
add_field "app_users" "verification_token_exp" "text"
log "done"