This commit is contained in:
payacom
2026-09-13 21:32:36 +03:30
parent 90c5f94b57
commit c302aea177
49 changed files with 4063 additions and 920 deletions

View File

@@ -0,0 +1,59 @@
const jwt = require('jsonwebtoken')
const AnalyticsEvent = require('../../../models/AnalyticsEventModel')
const MAX_BATCH_SIZE = 50
const VALID_TYPES = new Set(['session_start', 'page_view', 'click'])
const VALID_PLATFORMS = new Set(['web', 'android', 'ios'])
function decodeUserId(req) {
const token = req.header('Authorization')?.split(' ')[1]
if (!token) return null
try {
const decoded = jwt.verify(token, process.env.APP_SECRET)
return decoded?.id || null
} catch {
return null
}
}
// ورودیِ خام و کوتاه (بدون توکن الزامی — کاربر مهمون هم ردیابی می‌شه)؛ از هر دو کلاینت
// وب (sendBeacon موقع بستن تب) و اپلیکیشن اندروید/iOS به‌صورت دسته‌ای ارسال می‌شه
const trackEvents = async (req, res, next) => {
try {
const userId = decodeUserId(req)
const events = Array.isArray(req.body?.events) ? req.body.events : []
if (!events.length) return res.status(204).end()
const docs = events.slice(0, MAX_BATCH_SIZE).reduce((acc, e) => {
if (!e || !VALID_TYPES.has(e.type) || !VALID_PLATFORMS.has(e.platform)) {
return acc
}
if (!e.sessionId || typeof e.sessionId !== 'string') return acc
acc.push({
userId,
sessionId: e.sessionId,
type: e.type,
path: typeof e.path === 'string' ? e.path.slice(0, 500) : null,
durationMs:
typeof e.durationMs === 'number' && e.durationMs >= 0
? Math.min(e.durationMs, 24 * 60 * 60 * 1000)
: null,
label: typeof e.label === 'string' ? e.label.slice(0, 200) : null,
platform: e.platform,
device: typeof e.device === 'string' ? e.device.slice(0, 100) : null,
browser: typeof e.browser === 'string' ? e.browser.slice(0, 100) : null,
os: typeof e.os === 'string' ? e.os.slice(0, 100) : null
})
return acc
}, [])
if (docs.length) await AnalyticsEvent.insertMany(docs, { ordered: false })
res.status(204).end()
} catch (error) {
next(error)
}
}
module.exports = { trackEvents }