diff --git a/backend/.env b/backend/.env
new file mode 100644
index 0000000..790f9d9
--- /dev/null
+++ b/backend/.env
@@ -0,0 +1,5 @@
+# VAPID Keys for Push Notifications
+# Generate new keys for production using: cargo run --bin web-push --features web-push -- generate-vapid-keys
+VAPID_PUBLIC_KEY=BEdPj6XQR7MGzM28Nev9wokF5upHoydNDahouJbQ9ZdBJpEFAN1iNfANSEvY0ItasNY5zcvvqN_tjUt64Rfd0gU
+VAPID_PRIVATE_KEY=aUcCYJ7kUd9UClCaWwad0IVgbYJ6svwl19MjSX7GH10
+VAPID_EMAIL=mailto:admin@vibetorrent.app
diff --git a/backend/migrations/001_init.sql b/backend/migrations/001_init.sql
new file mode 100644
index 0000000..8feaa0e
--- /dev/null
+++ b/backend/migrations/001_init.sql
@@ -0,0 +1,16 @@
+-- 001_init.sql
+-- Initial schema for users and sessions
+
+CREATE TABLE IF NOT EXISTS users (
+ id INTEGER PRIMARY KEY,
+ username TEXT NOT NULL UNIQUE,
+ password_hash TEXT NOT NULL,
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE TABLE IF NOT EXISTS sessions (
+ token TEXT PRIMARY KEY,
+ user_id INTEGER NOT NULL,
+ expires_at DATETIME NOT NULL,
+ FOREIGN KEY(user_id) REFERENCES users(id)
+);
diff --git a/backend/migrations/002_push_subscriptions.sql b/backend/migrations/002_push_subscriptions.sql
new file mode 100644
index 0000000..0f0a48f
--- /dev/null
+++ b/backend/migrations/002_push_subscriptions.sql
@@ -0,0 +1,13 @@
+-- 002_push_subscriptions.sql
+-- Push notification subscriptions storage
+
+CREATE TABLE IF NOT EXISTS push_subscriptions (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ endpoint TEXT NOT NULL UNIQUE,
+ p256dh TEXT NOT NULL,
+ auth TEXT NOT NULL,
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
+);
+
+-- Index for faster lookups by endpoint
+CREATE INDEX IF NOT EXISTS idx_push_subscriptions_endpoint ON push_subscriptions(endpoint);
diff --git a/backend/src/db.rs b/backend/src/db.rs
index a53f105..d22ea63 100644
--- a/backend/src/db.rs
+++ b/backend/src/db.rs
@@ -16,35 +16,12 @@ impl Db {
.await?;
let db = Self { pool };
- db.init().await?;
+ db.run_migrations().await?;
Ok(db)
}
- async fn init(&self) -> Result<()> {
- // Create users table
- sqlx::query(
- "CREATE TABLE IF NOT EXISTS users (
- id INTEGER PRIMARY KEY,
- username TEXT NOT NULL UNIQUE,
- password_hash TEXT NOT NULL,
- created_at DATETIME DEFAULT CURRENT_TIMESTAMP
- )",
- )
- .execute(&self.pool)
- .await?;
-
- // Create sessions table
- sqlx::query(
- "CREATE TABLE IF NOT EXISTS sessions (
- token TEXT PRIMARY KEY,
- user_id INTEGER NOT NULL,
- expires_at DATETIME NOT NULL,
- FOREIGN KEY(user_id) REFERENCES users(id)
- )",
- )
- .execute(&self.pool)
- .await?;
-
+ async fn run_migrations(&self) -> Result<()> {
+ sqlx::migrate!("./migrations").run(&self.pool).await?;
Ok(())
}
@@ -59,23 +36,24 @@ impl Db {
Ok(())
}
- pub async fn get_user_by_username(&self, username: &str) -> Result