diff --git a/apps/backend/server.js b/apps/backend/server.js
index a461e0c..74d7480 100644
--- a/apps/backend/server.js
+++ b/apps/backend/server.js
@@ -253,34 +253,70 @@ async function initDatabase() {
`);
}
- await dbRun(`
- CREATE TABLE IF NOT EXISTS push_subscriptions (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- medicine_nregistro TEXT NOT NULL,
- medicine_name TEXT,
- endpoint TEXT NOT NULL,
- p256dh TEXT NOT NULL,
- auth TEXT NOT NULL,
- created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
- UNIQUE(medicine_nregistro, endpoint)
- )
- `);
- await dbRun(`CREATE INDEX IF NOT EXISTS idx_push_subscriptions_med ON push_subscriptions(medicine_nregistro)`);
+ // Push subscription tables — PG when available, SQLite fallback
+ if (pgPool) {
+ await pgPool.query(`
+ CREATE TABLE IF NOT EXISTS push_subscriptions (
+ id SERIAL PRIMARY KEY,
+ user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
+ medicine_nregistro TEXT NOT NULL,
+ medicine_name TEXT,
+ endpoint TEXT NOT NULL,
+ p256dh TEXT NOT NULL,
+ auth TEXT NOT NULL,
+ created_at TIMESTAMPTZ DEFAULT NOW(),
+ UNIQUE(user_id, medicine_nregistro, endpoint)
+ )
+ `);
+ await pgPool.query(`CREATE INDEX IF NOT EXISTS idx_push_subscriptions_med ON push_subscriptions(medicine_nregistro)`);
+ await pgPool.query(`CREATE INDEX IF NOT EXISTS idx_push_subscriptions_user ON push_subscriptions(user_id)`);
- await dbRun(`
- CREATE TABLE IF NOT EXISTS push_subscriptions_pharmacy (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- medicine_nregistro TEXT NOT NULL,
- medicine_name TEXT,
- pharmacy_id INTEGER NOT NULL,
- endpoint TEXT NOT NULL,
- p256dh TEXT NOT NULL,
- auth TEXT NOT NULL,
- created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
- UNIQUE(medicine_nregistro, pharmacy_id, endpoint)
- )
- `);
- await dbRun(`CREATE INDEX IF NOT EXISTS idx_push_subs_pharm ON push_subscriptions_pharmacy(medicine_nregistro, pharmacy_id)`);
+ await pgPool.query(`
+ CREATE TABLE IF NOT EXISTS push_subscriptions_pharmacy (
+ id SERIAL PRIMARY KEY,
+ user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
+ medicine_nregistro TEXT NOT NULL,
+ medicine_name TEXT,
+ pharmacy_id INTEGER NOT NULL,
+ endpoint TEXT NOT NULL,
+ p256dh TEXT NOT NULL,
+ auth TEXT NOT NULL,
+ created_at TIMESTAMPTZ DEFAULT NOW(),
+ UNIQUE(user_id, medicine_nregistro, pharmacy_id, endpoint)
+ )
+ `);
+ await pgPool.query(`CREATE INDEX IF NOT EXISTS idx_push_subs_pharm ON push_subscriptions_pharmacy(medicine_nregistro, pharmacy_id)`);
+ await pgPool.query(`CREATE INDEX IF NOT EXISTS idx_push_subs_pharm_user ON push_subscriptions_pharmacy(user_id)`);
+ } else {
+ await dbRun(`
+ CREATE TABLE IF NOT EXISTS push_subscriptions (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ medicine_nregistro TEXT NOT NULL,
+ medicine_name TEXT,
+ endpoint TEXT NOT NULL,
+ p256dh TEXT NOT NULL,
+ auth TEXT NOT NULL,
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
+ UNIQUE(medicine_nregistro, endpoint)
+ )
+ `);
+ await dbRun(`CREATE INDEX IF NOT EXISTS idx_push_subscriptions_med ON push_subscriptions(medicine_nregistro)`);
+
+ await dbRun(`
+ CREATE TABLE IF NOT EXISTS push_subscriptions_pharmacy (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ medicine_nregistro TEXT NOT NULL,
+ medicine_name TEXT,
+ pharmacy_id INTEGER NOT NULL,
+ endpoint TEXT NOT NULL,
+ p256dh TEXT NOT NULL,
+ auth TEXT NOT NULL,
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
+ UNIQUE(medicine_nregistro, pharmacy_id, endpoint)
+ )
+ `);
+ await dbRun(`CREATE INDEX IF NOT EXISTS idx_push_subs_pharm ON push_subscriptions_pharmacy(medicine_nregistro, pharmacy_id)`);
+ }
if (!pgPool) {
// SQLite-only migrations for existing deployments
@@ -307,9 +343,11 @@ if (!pgPool) {
try { await dbRun('ALTER TABLE users ADD COLUMN city TEXT'); } catch {}
}
-// Add user_id to push tables (SQLite — no cross-DB FK)
- try { await dbRun('ALTER TABLE push_subscriptions ADD COLUMN user_id INTEGER'); } catch {}
- try { await dbRun('ALTER TABLE push_subscriptions_pharmacy ADD COLUMN user_id INTEGER'); } catch {}
+// Add user_id to push tables (SQLite only — PG tables already have it)
+ if (!pgPool) {
+ try { await dbRun('ALTER TABLE push_subscriptions ADD COLUMN user_id INTEGER'); } catch {}
+ try { await dbRun('ALTER TABLE push_subscriptions_pharmacy ADD COLUMN user_id INTEGER'); } catch {}
+ }
// Create alerts table for persistent Avisos data
try {
@@ -1733,35 +1771,35 @@ app.post('/api/notifications/subscribe', requireAuth, async (req, res) => {
}
if (pharmacy_id) {
- const existing = await dbGet(
- 'SELECT id FROM push_subscriptions_pharmacy WHERE medicine_nregistro = ? AND pharmacy_id = ? AND endpoint = ?',
- [medicine_nregistro, pharmacy_id, endpoint]
+ const existing = await userDbGet(
+ 'SELECT id FROM push_subscriptions_pharmacy WHERE user_id = ? AND medicine_nregistro = ? AND pharmacy_id = ? AND endpoint = ?',
+ [userId, medicine_nregistro, pharmacy_id, endpoint]
);
if (existing) {
- await dbRun(
- 'UPDATE push_subscriptions_pharmacy SET medicine_name = ?, p256dh = ?, auth = ?, user_id = ? WHERE id = ?',
- [medicine_name || null, p256dh, auth, userId, existing.id]
+ await userDbRun(
+ 'UPDATE push_subscriptions_pharmacy SET medicine_name = ?, p256dh = ?, auth = ? WHERE id = ? AND user_id = ?',
+ [medicine_name || null, p256dh, auth, existing.id, userId]
);
} else {
- await dbRun(
- 'INSERT INTO push_subscriptions_pharmacy (medicine_nregistro, medicine_name, pharmacy_id, endpoint, p256dh, auth, user_id) VALUES (?, ?, ?, ?, ?, ?, ?)',
- [medicine_nregistro, medicine_name || null, pharmacy_id, endpoint, p256dh, auth, userId]
+ await userDbRun(
+ 'INSERT INTO push_subscriptions_pharmacy (user_id, medicine_nregistro, medicine_name, pharmacy_id, endpoint, p256dh, auth) VALUES (?, ?, ?, ?, ?, ?, ?)',
+ [userId, medicine_nregistro, medicine_name || null, pharmacy_id, endpoint, p256dh, auth]
);
}
} else {
- const existing = await dbGet(
- 'SELECT id FROM push_subscriptions WHERE medicine_nregistro = ? AND endpoint = ?',
- [medicine_nregistro, endpoint]
+ const existing = await userDbGet(
+ 'SELECT id FROM push_subscriptions WHERE user_id = ? AND medicine_nregistro = ? AND endpoint = ?',
+ [userId, medicine_nregistro, endpoint]
);
if (existing) {
- await dbRun(
- 'UPDATE push_subscriptions SET medicine_name = ?, p256dh = ?, auth = ?, user_id = ? WHERE id = ?',
- [medicine_name || null, p256dh, auth, userId, existing.id]
+ await userDbRun(
+ 'UPDATE push_subscriptions SET medicine_name = ?, p256dh = ?, auth = ? WHERE id = ? AND user_id = ?',
+ [medicine_name || null, p256dh, auth, existing.id, userId]
);
} else {
- await dbRun(
- 'INSERT INTO push_subscriptions (medicine_nregistro, medicine_name, endpoint, p256dh, auth, user_id) VALUES (?, ?, ?, ?, ?, ?)',
- [medicine_nregistro, medicine_name || null, endpoint, p256dh, auth, userId]
+ await userDbRun(
+ 'INSERT INTO push_subscriptions (user_id, medicine_nregistro, medicine_name, endpoint, p256dh, auth) VALUES (?, ?, ?, ?, ?, ?)',
+ [userId, medicine_nregistro, medicine_name || null, endpoint, p256dh, auth]
);
}
}
@@ -1776,21 +1814,22 @@ app.post('/api/notifications/subscribe', requireAuth, async (req, res) => {
app.delete('/api/notifications/unsubscribe', requireAuth, async (req, res) => {
try {
const { medicine_nregistro, endpoint, pharmacy_id } = req.body || {};
+ const userId = req.session.userId;
if (!endpoint) {
return res.status(400).json({ error: 'endpoint is required' });
}
if (pharmacy_id) {
- await dbRun(
- 'DELETE FROM push_subscriptions_pharmacy WHERE medicine_nregistro = ? AND pharmacy_id = ? AND endpoint = ?',
- [medicine_nregistro, pharmacy_id, endpoint]
+ await userDbRun(
+ 'DELETE FROM push_subscriptions_pharmacy WHERE user_id = ? AND medicine_nregistro = ? AND pharmacy_id = ? AND endpoint = ?',
+ [userId, medicine_nregistro, pharmacy_id, endpoint]
);
} else if (medicine_nregistro) {
- await dbRun(
- 'DELETE FROM push_subscriptions WHERE medicine_nregistro = ? AND endpoint = ?',
- [medicine_nregistro, endpoint]
+ await userDbRun(
+ 'DELETE FROM push_subscriptions WHERE user_id = ? AND medicine_nregistro = ? AND endpoint = ?',
+ [userId, medicine_nregistro, endpoint]
);
} else {
- await dbRun('DELETE FROM push_subscriptions WHERE endpoint = ?', [endpoint]);
+ await userDbRun('DELETE FROM push_subscriptions WHERE user_id = ? AND endpoint = ?', [userId, endpoint]);
}
res.status(204).end();
} catch (error) {
@@ -1803,14 +1842,14 @@ app.delete('/api/notifications/unsubscribe', requireAuth, async (req, res) => {
app.get('/api/notifications/mine', requireAuth, async (req, res) => {
try {
const userId = req.session.userId;
- const globalRows = await dbAll(
+ const globalRows = await userDbAll(
`SELECT id, medicine_nregistro, medicine_name, created_at
FROM push_subscriptions
WHERE user_id = ?
ORDER BY created_at DESC`,
[userId]
);
- const pharmacyRows = await dbAll(
+ const pharmacyRows = await userDbAll(
`SELECT ps.id, ps.medicine_nregistro, ps.medicine_name, ps.pharmacy_id,
ps.created_at, p.name AS pharmacy_name, p.address AS pharmacy_address
FROM push_subscriptions_pharmacy ps
@@ -1839,12 +1878,12 @@ app.delete('/api/notifications/mine', requireAuth, async (req, res) => {
return res.status(400).json({ error: 'id must be a positive integer' });
}
if (scope === 'pharmacy') {
- await dbRun(
+ await userDbRun(
'DELETE FROM push_subscriptions_pharmacy WHERE id = ? AND user_id = ?',
[rowId, userId]
);
} else if (scope === 'global') {
- await dbRun(
+ await userDbRun(
'DELETE FROM push_subscriptions WHERE id = ? AND user_id = ?',
[rowId, userId]
);
@@ -1861,11 +1900,11 @@ app.delete('/api/notifications/mine', requireAuth, async (req, res) => {
async function sendPushForMedicine({ medicine_nregistro, medicine_name, pharmacy }) {
if (!PUSH_ENABLED) return { sent: 0, failed: 0, pruned: 0 };
- const globalSubs = await dbAll(
+ const globalSubs = await userDbAll(
'SELECT id, endpoint, p256dh, auth FROM push_subscriptions WHERE medicine_nregistro = ?',
[medicine_nregistro]
);
- const pharmacySubs = pharmacy?.id ? await dbAll(
+ const pharmacySubs = pharmacy?.id ? await userDbAll(
'SELECT id, endpoint, p256dh, auth FROM push_subscriptions_pharmacy WHERE medicine_nregistro = ? AND pharmacy_id = ?',
[medicine_nregistro, pharmacy.id]
) : [];
@@ -1907,7 +1946,7 @@ async function sendPushForMedicine({ medicine_nregistro, medicine_name, pharmacy
const deleteQuery = sub._pharmSub
? 'DELETE FROM push_subscriptions_pharmacy WHERE id = ?'
: 'DELETE FROM push_subscriptions WHERE id = ?';
- await dbRun(deleteQuery, [sub.id]);
+ await userDbRun(deleteQuery, [sub.id]);
pruned++;
} catch {}
} else {
diff --git a/apps/frontend-mobile/.idea/caches/deviceStreaming.xml b/apps/frontend-mobile/.idea/caches/deviceStreaming.xml
index ddfd7af..95dc662 100644
--- a/apps/frontend-mobile/.idea/caches/deviceStreaming.xml
+++ b/apps/frontend-mobile/.idea/caches/deviceStreaming.xml
@@ -1,8 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -171,6 +190,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -531,6 +562,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1681,6 +1724,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1785,23 +1840,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -2186,5 +2224,6 @@
+
\ No newline at end of file
diff --git a/apps/frontend-mobile/.idea/vcs.xml b/apps/frontend-mobile/.idea/vcs.xml
index 6c0b863..64713b8 100644
--- a/apps/frontend-mobile/.idea/vcs.xml
+++ b/apps/frontend-mobile/.idea/vcs.xml
@@ -1,6 +1,7 @@
+
\ No newline at end of file