eletrotupi / tcc/ api/scripts/seed-demo-report.mjs639638a33f393a399e9112ea8bd95a1d9e34d75c
9.1 KB | 273 lines Raw
1
import pg from 'pg'
2

3
const { Client } = pg
4

5
const dbUrl = process.env.DATABASE_URL ?? 'postgres://user:password@localhost:5430/orbit_dev'
6
const targetEmail = process.env.SEED_EMAIL ?? 'porcellis@eletrotupi.com'
7
const DAYS = 35
8

9
// Reproducible PRNG so the demo dataset is stable between runs.
10
function mulberry32(seed) {
11
  return function () {
12
    seed |= 0
13
    seed = (seed + 0x6d2b79f5) | 0
14
    let t = Math.imul(seed ^ (seed >>> 15), 1 | seed)
15
    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t
16
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296
17
  }
18
}
19
const rand = mulberry32(20261019)
20

21
const pick = (arr) => arr[Math.floor(rand() * arr.length)]
22
const between = (min, max) => Math.floor(rand() * (max - min + 1)) + min
23
const round1 = (n) => Math.round(n * 10) / 10
24

25
function localDateStr(d) {
26
  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
27
}
28

29
// ---- mood ----
30
function pickMood() {
31
  const r = rand()
32
  if (r < 0.15) return 'GREAT'
33
  if (r < 0.5) return 'GOOD'
34
  if (r < 0.75) return 'NEUTRAL'
35
  if (r < 0.9) return 'SAD'
36
  return 'ANGRY'
37
}
38

39
const MOOD_LEVELS = {
40
  GREAT: { energy: [7, 9], stress: [1, 3], anxiety: [1, 3] },
41
  GOOD: { energy: [6, 8], stress: [2, 4], anxiety: [2, 4] },
42
  NEUTRAL: { energy: [4, 6], stress: [3, 5], anxiety: [3, 5] },
43
  SAD: { energy: [2, 4], stress: [4, 6], anxiety: [5, 7] },
44
  ANGRY: { energy: [4, 6], stress: [7, 9], anxiety: [6, 8] },
45
}
46

47
const MOOD_COMPONENTS = {
48
  GREAT: ['JOY', 'GRATITUDE', 'MOTIVATED', 'CALM'],
49
  GOOD: ['CALM', 'FOCUS', 'RELAXED', 'MOTIVATED'],
50
  NEUTRAL: ['CALM', 'TIREDNESS', 'FOCUS', 'RELAXED'],
51
  SAD: ['SADNESS', 'TIREDNESS', 'OVERWHELMED', 'GUILT', 'FEAR'],
52
  ANGRY: ['ANGER', 'FRUSTRATION', 'RESTLESS'],
53
}
54

55
const MOOD_ANNOTATIONS = {
56
  GREAT: ['Dia muito produtivo', 'Acordei bem disposto', 'Me senti leve e animado', null],
57
  GOOD: ['Dia tranquilo', 'Boa noite de sono', 'Trabalho rendeu bem', null],
58
  NEUTRAL: ['Nada de especial hoje', 'Rotina normal', 'Cansado, mas ok', null],
59
  SAD: ['Noite mal dormida', 'Me senti para baixo', 'Sem energia hoje', null],
60
  ANGRY: ['Estresse no trabalho', 'Briga em casa', 'Trânsito me irritou', null],
61
}
62

63
const INTENSITIES = ['LIGHT', 'MODERATE', 'HIGH']
64

65
function componentsFor(mood) {
66
  const pool = MOOD_COMPONENTS[mood]
67
  const count = between(1, Math.min(3, pool.length))
68
  const chosen = new Set()
69
  while (chosen.size < count) chosen.add(pick(pool))
70

71
  return [...chosen].map((component) => {
72
    let intensity = pick(INTENSITIES)
73
    if (['ANGER', 'FEAR', 'OVERWHELMED', 'FRUSTRATION'].includes(component) && intensity === 'LIGHT') {
74
      intensity = 'MODERATE'
75
    }
76
    if (['CALM', 'RELAXED'].includes(component) && intensity === 'HIGH') {
77
      intensity = 'MODERATE'
78
    }
79
    return { component, intensity }
80
  })
81
}
82

83
// ---- sleep ----
84
const SLEEP_NOTES = ['Boa noite de sono', 'Acordei de madrugada', 'Demorei para pegar no sono', 'Sono leve', null]
85

86
// ---- triggers ----
87
const TRIGGER_POOL = [
88
  { category: 'WORK', comment: 'Reunião estressante no trabalho' },
89
  { category: 'WORK', comment: 'Prazo apertado no projeto' },
90
  { category: 'FAMILY', comment: 'Discussão em família' },
91
  { category: 'PHYSICAL', comment: 'Noite mal dormida' },
92
  { category: 'PHYSICAL', comment: 'Dor de cabeça forte' },
93
  { category: 'INTERNAL', comment: 'Pensamentos ansiosos' },
94
  { category: 'INTERNAL', comment: 'Sentimento de culpa' },
95
  { category: 'SOCIAL', comment: 'Encontro com amigos' },
96
  { category: 'SOCIAL', comment: 'Evento social no fim de semana' },
97
  { category: 'HEALTH', comment: 'Consulta de rotina' },
98
  { category: 'THERAPY', comment: 'Sessão de terapia' },
99
  { category: 'FAMILY', comment: 'Visita de parentes' },
100
]
101

102
// ---- medicine ----
103
const REGIMENS = [
104
  { name: 'Lítio', dosage: '300 mg', periodicity: 'DAILY', scheduledAt: ['20:00'] },
105
  { name: 'Lamotrigina', dosage: '100 mg', periodicity: 'DAILY', scheduledAt: ['08:00'] },
106
]
107

108
// ---- activities ----
109
const ACTIVITY_POOL = [
110
  { type: 'WALK', duration: 30 },
111
  { type: 'WALK', duration: 45 },
112
  { type: 'MEDITATION', duration: 15 },
113
  { type: 'GYM', duration: 60 },
114
  { type: 'YOGA', duration: 45 },
115
  { type: 'CREATIVE', duration: 60 },
116
  { type: 'SOCIAL', duration: 90 },
117
]
118

119
async function main() {
120
  const db = new Client({ connectionString: dbUrl })
121
  await db.connect()
122

123
  try {
124
    const { rows } = await db.query(
125
      'SELECT id, first_name, last_name FROM users WHERE email = $1',
126
      [targetEmail],
127
    )
128
    if (rows.length === 0) {
129
      console.error(`User ${targetEmail} not found`)
130
      process.exitCode = 1
131
      return
132
    }
133

134
    const user = rows[0]
135
    const userId = user.id
136

137
    // Wipe existing demo data, children first (FK-safe order).
138
    await db.query('DELETE FROM care_actions WHERE user_id = $1', [userId])
139
    await db.query('DELETE FROM medicine_regimens WHERE user_id = $1', [userId])
140
    await db.query('DELETE FROM triggers WHERE user_id = $1', [userId])
141
    await db.query('DELETE FROM sleep_records WHERE user_id = $1', [userId])
142
    await db.query('DELETE FROM moods WHERE user_id = $1', [userId])
143
    await db.query('DELETE FROM insights WHERE user_id = $1', [userId])
144

145
    const now = new Date()
146
    const dayAt = (offset) => {
147
      const d = new Date(now)
148
      d.setDate(now.getDate() - offset)
149
      return d
150
    }
151

152
    const counts = { moods: 0, sleep: 0, triggers: 0, medicine: 0, activities: 0 }
153

154
    // moods
155
    for (let d = DAYS; d >= 0; d--) {
156
      const r = rand()
157
      const count = r < 0.05 ? 0 : r < 0.5 ? 1 : r < 0.85 ? 2 : 3
158

159
      for (let i = 0; i < count; i++) {
160
        const mood = pickMood()
161
        const levels = MOOD_LEVELS[mood]
162

163
        const moment = new Date(dayAt(d))
164
        moment.setHours(pick([9, 12, 15, 18, 21]) + between(0, 2), between(0, 59), 0, 0)
165

166
        const res = await db.query(
167
          `INSERT INTO moods
168
             (user_id, selected_mood, energy_level, stress_level, anxiety_level, annotation, moment)
169
           VALUES ($1, $2, $3, $4, $5, $6, $7)
170
           RETURNING id`,
171
          [
172
            userId,
173
            mood,
174
            between(...levels.energy),
175
            between(...levels.stress),
176
            between(...levels.anxiety),
177
            pick(MOOD_ANNOTATIONS[mood]),
178
            moment,
179
          ],
180
        )
181

182
        for (const c of componentsFor(mood)) {
183
          await db.query(
184
            'INSERT INTO mood_components (mood_id, component, intensity) VALUES ($1, $2, $3)',
185
            [res.rows[0].id, c.component, c.intensity],
186
          )
187
        }
188
        counts.moods++
189
      }
190
    }
191

192
    // sleep records — one per night
193
    for (let d = DAYS; d >= 0; d--) {
194
      const day = dayAt(d)
195
      const average = round1(5.5 + rand() * 3)
196
      const note = pick(SLEEP_NOTES)
197
      await db.query(
198
        'INSERT INTO sleep_records (user_id, average, date, annotations, updated_at) VALUES ($1, $2, $3, $4, NOW())',
199
        [userId, average, localDateStr(day), note],
200
      )
201
      counts.sleep++
202
    }
203

204
    // triggers
205
    for (let i = 0; i < TRIGGER_POOL.length; i++) {
206
      const t = TRIGGER_POOL[i]
207
      const moment = new Date(dayAt(between(0, DAYS)))
208
      moment.setHours(between(8, 21), between(0, 59), 0, 0)
209
      await db.query(
210
        'INSERT INTO triggers (user_id, category, moment, comment, updated_at) VALUES ($1, $2, $3, $4, NOW())',
211
        [userId, t.category, moment, t.comment],
212
      )
213
      counts.triggers++
214
    }
215

216
    // medicine regimens + logs
217
    for (const r of REGIMENS) {
218
      const reg = await db.query(
219
        `INSERT INTO medicine_regimens (user_id, name, dosage, periodicity, scheduled_at, active, updated_at)
220
         VALUES ($1, $2, $3, $4, $5, true, NOW())
221
         RETURNING id`,
222
        [userId, r.name, r.dosage, r.periodicity, r.scheduledAt],
223
      )
224
      const regimenId = reg.rows[0].id
225

226
      for (let d = DAYS; d >= 0; d--) {
227
        if (rand() < 0.25) continue
228

229
        const moment = new Date(dayAt(d))
230
        const [h, m] = pick(r.scheduledAt).split(':').map(Number)
231
        moment.setHours(h, m, 0, 0)
232

233
        const ca = await db.query(
234
          "INSERT INTO care_actions (user_id, type, moment, updated_at) VALUES ($1, 'MEDICINE', $2, NOW()) RETURNING id",
235
          [userId, moment],
236
        )
237
        await db.query(
238
          'INSERT INTO medicine_logs (care_action_id, regimen_id, taken_at) VALUES ($1, $2, $3)',
239
          [ca.rows[0].id, regimenId, moment],
240
        )
241
        counts.medicine++
242
      }
243
    }
244

245
    // activities
246
    for (let i = 0; i < 10; i++) {
247
      const a = pick(ACTIVITY_POOL)
248
      const moment = new Date(dayAt(between(0, DAYS)))
249
      moment.setHours(between(7, 20), between(0, 59), 0, 0)
250

251
      const ca = await db.query(
252
        "INSERT INTO care_actions (user_id, type, moment, updated_at) VALUES ($1, 'ACTIVITY', $2, NOW()) RETURNING id",
253
        [userId, moment],
254
      )
255
      await db.query(
256
        'INSERT INTO activities (care_action_id, type, duration) VALUES ($1, $2, $3)',
257
        [ca.rows[0].id, a.type, a.duration],
258
      )
259
      counts.activities++
260
    }
261

262
    const name = [user.first_name, user.last_name].filter(Boolean).join(' ')
263
    console.log(`Seeded demo data for ${targetEmail} (id ${user.id}, ${name})`)
264
    console.log(counts)
265
  } finally {
266
    await db.end()
267
  }
268
}
269

270
main().catch((err) => {
271
  console.error(err)
272
  process.exit(1)
273
})