780 lines
15 KiB
Markdown
780 lines
15 KiB
Markdown
# Dokumentasi Folder `scripts/`
|
|
|
|
## Gambaran Umum
|
|
|
|
Folder `scripts/` berisi utility scripts untuk development, testing, dan database management. Scripts ini membantu developer untuk verify functionality, seed data, dan debug issues.
|
|
|
|
---
|
|
|
|
## 📁 Struktur Direktori
|
|
|
|
```
|
|
scripts/
|
|
├── check-links.ts # Check user-coach relationships
|
|
├── check_logs.ts # View recent activity logs
|
|
├── seed_log.ts # Create test activity log
|
|
├── test_har_core.ts # Test activity recognition system
|
|
└── test_rehab_core.ts # Test exercise recognition system
|
|
```
|
|
|
|
**Total Files**: 5 TypeScript scripts
|
|
|
|
---
|
|
|
|
## 📄 Database Management Scripts
|
|
|
|
### **1. `check-links.ts`** 🔗
|
|
|
|
**Path**: `/scripts/check-links.ts`
|
|
|
|
**Fungsi**: Menampilkan semua users dan coach-client relationships
|
|
|
|
**Size**: ~466 bytes
|
|
|
|
**Use Case**:
|
|
|
|
- Verify seeding berhasil
|
|
- Debug coach-client assignments
|
|
- Quick database health check
|
|
|
|
**Code**:
|
|
|
|
```typescript
|
|
import "dotenv/config";
|
|
import { PrismaClient } from "../app/generated/client/client";
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
async function main() {
|
|
const users = await prisma.users.findMany();
|
|
console.log("--- All Users ---");
|
|
users.forEach((u) =>
|
|
console.log(`${u.name} (${u.role}): ID=${u.id}, CoachID=${u.coach_id}`),
|
|
);
|
|
}
|
|
```
|
|
|
|
**How to Run**:
|
|
|
|
```bash
|
|
npx tsx scripts/check-links.ts
|
|
```
|
|
|
|
**Expected Output**:
|
|
|
|
```
|
|
--- All Users ---
|
|
Coach One (COACH): ID=C00001, CoachID=null
|
|
Coach Two (COACH): ID=C00002, CoachID=null
|
|
Client One (CLIENT): ID=U00001, CoachID=C00001
|
|
Client Two (CLIENT): ID=U00002, CoachID=C00001
|
|
Client Three (CLIENT): ID=U00003, CoachID=C00002
|
|
```
|
|
|
|
**Use Cases**:
|
|
|
|
- ✅ Verify after running `prisma db seed`
|
|
- ✅ Check migration success
|
|
- ✅ Debug role assignments
|
|
- ✅ List all registered users
|
|
|
|
---
|
|
|
|
### **2. `check_logs.ts`** 📋
|
|
|
|
**Path**: `/scripts/check_logs.ts`
|
|
|
|
**Fungsi**: Menampilkan 10 activity logs terbaru dari database
|
|
|
|
**Size**: ~887 bytes
|
|
|
|
**Use Case**:
|
|
|
|
- Monitor real-time activity tracking
|
|
- Debug activity logging system
|
|
- Verify fall detection alerts
|
|
- Inspect log details (JSON)
|
|
|
|
**Code**:
|
|
|
|
```typescript
|
|
import { PrismaClient } from "../app/generated/client/client";
|
|
import * as dotenv from "dotenv";
|
|
dotenv.config();
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
async function main() {
|
|
console.log("Checking Activity Logs...");
|
|
const logs = await prisma.activity_logs.findMany({
|
|
take: 10,
|
|
orderBy: { timestamp: "desc" },
|
|
include: {
|
|
user: { select: { name: true } },
|
|
},
|
|
});
|
|
|
|
if (logs.length === 0) {
|
|
console.log("No logs found.");
|
|
} else {
|
|
console.log(`Found ${logs.length} logs:`);
|
|
logs.forEach((log) => {
|
|
console.log(
|
|
`[${log.timestamp?.toISOString()}] ` +
|
|
`User: ${log.user?.name || log.user_id} | ` +
|
|
`Status: ${log.status} | ` +
|
|
`Details: ${JSON.stringify(log.details)}`,
|
|
);
|
|
});
|
|
}
|
|
}
|
|
```
|
|
|
|
**How to Run**:
|
|
|
|
```bash
|
|
npx tsx scripts/check_logs.ts
|
|
```
|
|
|
|
**Expected Output**:
|
|
|
|
```
|
|
Checking Activity Logs...
|
|
Found 3 logs:
|
|
[2025-12-28T10:30:00.000Z] User: Client One | Status: Standing | Details: {"exercise":"bicep_curl","reps":5}
|
|
[2025-12-28T10:25:00.000Z] User: Client Two | Status: Sitting | Details: {}
|
|
[2025-12-28T10:20:00.000Z] User: Client One | Status: Standing | Details: {}
|
|
```
|
|
|
|
**Features**:
|
|
|
|
- ✅ Shows latest 10 logs (configurable via `take`)
|
|
- ✅ Ordered by timestamp (newest first)
|
|
- ✅ Includes user name via join
|
|
- ✅ Pretty-prints JSON details
|
|
|
|
**When to Use**:
|
|
|
|
- After training session untuk verify logs created
|
|
- Debug fall detection alerts
|
|
- Monitor which users are active
|
|
|
|
---
|
|
|
|
### **3. `seed_log.ts`** 🌱
|
|
|
|
**Path**: `/scripts/seed_log.ts`
|
|
|
|
**Fungsi**: Membuat test activity log untuk development
|
|
|
|
**Size**: ~816 bytes
|
|
|
|
**Use Case**:
|
|
|
|
- Populate database dengan sample logs
|
|
- Test log display UI
|
|
- Verify logging system works
|
|
|
|
**Code**:
|
|
|
|
```typescript
|
|
import { PrismaClient } from "../app/generated/client/client";
|
|
import * as dotenv from "dotenv";
|
|
dotenv.config();
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
async function main() {
|
|
console.log("Seeding Mock Log...");
|
|
|
|
// Get a client user
|
|
const user = await prisma.users.findFirst({
|
|
where: { role: "CLIENT" },
|
|
});
|
|
|
|
if (!user) {
|
|
console.error("No client user found to attach log to.");
|
|
return;
|
|
}
|
|
|
|
const log = await prisma.activity_logs.create({
|
|
data: {
|
|
user_id: user.id,
|
|
timestamp: new Date(),
|
|
status: "TEST_LOG",
|
|
confidence: "1.0",
|
|
details: { message: "Manual verification log" },
|
|
},
|
|
});
|
|
|
|
console.log("Created Log ID:", log.id);
|
|
}
|
|
```
|
|
|
|
**How to Run**:
|
|
|
|
```bash
|
|
npx tsx scripts/seed_log.ts
|
|
```
|
|
|
|
**Expected Output**:
|
|
|
|
```
|
|
Seeding Mock Log...
|
|
Created Log ID: 1
|
|
```
|
|
|
|
**Use Cases**:
|
|
|
|
- ✅ Quick test untuk UI development
|
|
- ✅ Verify database schema works
|
|
- ✅ Populate logs tanpa perlu run full app
|
|
|
|
**Customization**:
|
|
|
|
```typescript
|
|
// Modify untuk create specific log
|
|
data: {
|
|
status: 'Fall Detected', // Test fall alert
|
|
confidence: '0.95',
|
|
details: {
|
|
coordinates: { x: 100, y: 200 },
|
|
severity: 'HIGH'
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🧪 Testing Scripts
|
|
|
|
### **4. `test_har_core.ts`** 🤖
|
|
|
|
**Path**: `/scripts/test_har_core.ts`
|
|
|
|
**Fungsi**: Unit test untuk `HARCore` activity recognition system
|
|
|
|
**Size**: ~1 KB
|
|
|
|
**Use Case**:
|
|
|
|
- Test XGBoost model integration
|
|
- Verify exercise detection logic
|
|
- Debug HAR system issues
|
|
- Ensure setExercise() mapping works
|
|
|
|
**Code**:
|
|
|
|
```typescript
|
|
import { HARCore } from "../lib/pose/HARCore";
|
|
import { Landmark } from "../lib/pose/ExerciseRules";
|
|
|
|
const har = new HARCore();
|
|
const mockLandmarks: Landmark[] = Array(33).fill({
|
|
x: 0.5,
|
|
y: 0.5,
|
|
z: 0,
|
|
visibility: 1,
|
|
});
|
|
|
|
console.log("Testing HARCore...");
|
|
|
|
const inputs = ["Bicep Curl", "Squats", "deadlift", "Unknown Exercise"];
|
|
|
|
inputs.forEach((input) => {
|
|
har.setExercise(input);
|
|
console.log(`Set to '${input}'. Invoking process...`);
|
|
|
|
har
|
|
.process(mockLandmarks)
|
|
.then((res) => {
|
|
console.log(
|
|
`[PASS] '${input}' -> Result:`,
|
|
res ? `Exercise: ${res.exercise}, Status: ${res.status}` : "NULL",
|
|
);
|
|
})
|
|
.catch((e) => {
|
|
console.error(`[FAIL] '${input}' -> Error:`, e);
|
|
});
|
|
});
|
|
|
|
setTimeout(() => console.log("Done."), 2000);
|
|
```
|
|
|
|
**How to Run**:
|
|
|
|
```bash
|
|
npx tsx scripts/test_har_core.ts
|
|
```
|
|
|
|
**Expected Output**:
|
|
|
|
```
|
|
Testing HARCore...
|
|
Set to 'Bicep Curl'. Invoking process...
|
|
Set to 'Squats'. Invoking process...
|
|
Set to 'deadlift'. Invoking process...
|
|
Set to 'Unknown Exercise'. Invoking process...
|
|
[PASS] 'Bicep Curl' -> Result: Exercise: bicep_curl, Status: Standing
|
|
[PASS] 'Squats' -> Result: Exercise: squat, Status: Standing
|
|
[PASS] 'deadlift' -> Result: Exercise: deadlift, Status: Standing
|
|
[PASS] 'Unknown Exercise' -> Result: Exercise: null, Status: Standing
|
|
Done.
|
|
```
|
|
|
|
**What It Tests**:
|
|
|
|
- ✅ Exercise name normalization (UI names → config keys)
|
|
- ✅ Activity classification (Standing/Sitting/Fall)
|
|
- ✅ Integration HARCore + RehabCore
|
|
- ✅ Null handling untuk unknown exercises
|
|
|
|
**Debug Use**:
|
|
|
|
```typescript
|
|
// Add this untuk see feature extraction
|
|
const features = har.extractFeatures(mockLandmarks);
|
|
console.log("Extracted Features:", features.length); // Should be 141
|
|
```
|
|
|
|
---
|
|
|
|
### **5. `test_rehab_core.ts`** 💪
|
|
|
|
**Path**: `/scripts/test_rehab_core.ts`
|
|
|
|
**Fungsi**: Unit test untuk `RehabCore` exercise recognition system
|
|
|
|
**Size**: ~1.1 KB
|
|
|
|
**Use Case**:
|
|
|
|
- Test all 7 exercise configs load correctly
|
|
- Verify FSM initialization
|
|
- Debug rep counting issues
|
|
- Ensure config keys match
|
|
|
|
**Code**:
|
|
|
|
```typescript
|
|
import { RehabCore } from "../lib/pose/RehabCore";
|
|
import { Landmark } from "../lib/pose/ExerciseRules";
|
|
|
|
const core = new RehabCore();
|
|
const mockLandmarks: Landmark[] = Array(33).fill({
|
|
x: 0.5,
|
|
y: 0.5,
|
|
z: 0,
|
|
visibility: 1,
|
|
});
|
|
|
|
const exercises = [
|
|
"bicep_curls",
|
|
"hammer_curls",
|
|
"shoulder_press",
|
|
"lateral_raises",
|
|
"squats",
|
|
"deadlifts",
|
|
"lunges",
|
|
];
|
|
|
|
console.log("Testing RehabCore Config Loading...");
|
|
|
|
exercises.forEach((name) => {
|
|
try {
|
|
const result = core.process(name, mockLandmarks);
|
|
|
|
if (result) {
|
|
console.log(`[PASS] ${name} -> Processed successfully.`);
|
|
} else {
|
|
console.error(`[FAIL] ${name} -> Returned null (Config not found?).`);
|
|
}
|
|
} catch (e) {
|
|
console.error(`[FAIL] ${name} -> Exception:`, e);
|
|
}
|
|
});
|
|
```
|
|
|
|
**How to Run**:
|
|
|
|
```bash
|
|
npx tsx scripts/test_rehab_core.ts
|
|
```
|
|
|
|
**Expected Output**:
|
|
|
|
```
|
|
Testing RehabCore Config Loading...
|
|
[PASS] bicep_curls -> Processed successfully.
|
|
[PASS] hammer_curls -> Processed successfully.
|
|
[PASS] shoulder_press -> Processed successfully.
|
|
[PASS] lateral_raises -> Processed successfully.
|
|
[PASS] squats -> Processed successfully.
|
|
[PASS] deadlifts -> Processed successfully.
|
|
[PASS] lunges -> Processed successfully.
|
|
```
|
|
|
|
**What It Tests**:
|
|
|
|
- ✅ Exercise name normalization
|
|
- ✅ Config lookup dari `EXERCISE_CONFIGS`
|
|
- ✅ FSM initialization (`COUNTER_MAP`)
|
|
- ✅ Process loop doesn't crash
|
|
|
|
**Common Failures**:
|
|
|
|
```
|
|
[FAIL] bicep_curls -> Returned null (Config not found?)
|
|
```
|
|
|
|
**Cause**: Typo in exercise name or config key
|
|
|
|
**Fix**: Check `ExerciseRules.ts` dan `RehabCore.ts` COUNTER_MAP
|
|
|
|
---
|
|
|
|
## 🔧 How to Run Scripts
|
|
|
|
### **Prerequisites**:
|
|
|
|
```bash
|
|
# Install tsx (TypeScript executor)
|
|
npm install -g tsx
|
|
|
|
# Or use npx (no global install)
|
|
npx tsx scripts/[script-name].ts
|
|
```
|
|
|
|
### **Environment Setup**:
|
|
|
|
All scripts load `.env` file:
|
|
|
|
```bash
|
|
# .env
|
|
DATABASE_URL="postgresql://user:password@localhost:5432/dbname"
|
|
```
|
|
|
|
### **Package Scripts** (Optional):
|
|
|
|
Add to `package.json`:
|
|
|
|
```json
|
|
{
|
|
"scripts": {
|
|
"check:links": "tsx scripts/check-links.ts",
|
|
"check:logs": "tsx scripts/check_logs.ts",
|
|
"seed:log": "tsx scripts/seed_log.ts",
|
|
"test:har": "tsx scripts/test_har_core.ts",
|
|
"test:rehab": "tsx scripts/test_rehab_core.ts"
|
|
}
|
|
}
|
|
```
|
|
|
|
Then run:
|
|
|
|
```bash
|
|
npm run check:links
|
|
npm run test:har
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 Script Usage Matrix
|
|
|
|
| Script | Purpose | When to Use | Dependencies |
|
|
| -------------------- | -------------------------- | -------------------------------- | --------------------------- |
|
|
| `check-links.ts` | List users & relationships | After seeding, debug assignments | Prisma, DB |
|
|
| `check_logs.ts` | View recent activity logs | After training sessions | Prisma, DB |
|
|
| `seed_log.ts` | Create test log | UI development, testing | Prisma, DB |
|
|
| `test_har_core.ts` | Test activity recognition | After HAR changes, debug | HARCore, XGBoost model |
|
|
| `test_rehab_core.ts` | Test exercise recognition | After config changes, debug | RehabCore, EXERCISE_CONFIGS |
|
|
|
|
---
|
|
|
|
## 🎯 Common Workflows
|
|
|
|
### **Workflow 1: Fresh Database Setup**
|
|
|
|
```bash
|
|
# 1. Reset database
|
|
npx prisma migrate reset
|
|
|
|
# 2. Verify users created
|
|
npx tsx scripts/check-links.ts
|
|
|
|
# 3. Create test log
|
|
npx tsx scripts/seed_log.ts
|
|
|
|
# 4. Verify log saved
|
|
npx tsx scripts/check_logs.ts
|
|
```
|
|
|
|
---
|
|
|
|
### **Workflow 2: Debug Exercise Recognition**
|
|
|
|
```bash
|
|
# 1. Test all exercises load
|
|
npx tsx scripts/test_rehab_core.ts
|
|
|
|
# 2. If FAIL, check config
|
|
cat lib/pose/ExerciseRules.ts | grep -A 5 "bicep_curl"
|
|
|
|
# 3. Fix and re-test
|
|
npx tsx scripts/test_rehab_core.ts
|
|
```
|
|
|
|
---
|
|
|
|
### **Workflow 3: Monitor Production Logs**
|
|
|
|
```bash
|
|
# SSH to server
|
|
ssh user@production-server
|
|
|
|
# Check recent activity
|
|
cd /path/to/app
|
|
npx tsx scripts/check_logs.ts
|
|
|
|
# If fall detected, investigate
|
|
npx tsx scripts/check_logs.ts | grep "Fall Detected"
|
|
```
|
|
|
|
---
|
|
|
|
## 💡 Extending Scripts
|
|
|
|
### **Add New Test Script**:
|
|
|
|
**Example**: `test_form_scoring.ts`
|
|
|
|
```typescript
|
|
import { RehabCore } from "../lib/pose/RehabCore";
|
|
import { Landmark } from "../lib/pose/ExerciseRules";
|
|
|
|
const core = new RehabCore();
|
|
|
|
// Create realistic landmarks (proper squat form)
|
|
const goodSquatLandmarks: Landmark[] = [
|
|
// ... 33 landmarks with correct squat angles
|
|
];
|
|
|
|
const result = core.process("squat", goodSquatLandmarks);
|
|
console.log("Form Score:", result?.scores?.deviation_mae);
|
|
// Expected: < 8 (Excellent)
|
|
```
|
|
|
|
---
|
|
|
|
### **Add Data Export Script**:
|
|
|
|
**Example**: `export_recaps.ts`
|
|
|
|
```typescript
|
|
import { PrismaClient } from "../app/generated/client/client";
|
|
import fs from "fs";
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
async function main() {
|
|
const recaps = await prisma.user_recaps.findMany({
|
|
include: { user: true, training_menus: true },
|
|
});
|
|
|
|
const csv = recaps.map((r) => ({
|
|
user: r.user?.name,
|
|
menu: r.training_menus?.name,
|
|
date: r.completed_at,
|
|
// ... more fields
|
|
}));
|
|
|
|
fs.writeFileSync("export.json", JSON.stringify(csv, null, 2));
|
|
console.log("Exported to export.json");
|
|
}
|
|
|
|
main();
|
|
```
|
|
|
|
---
|
|
|
|
## 🔒 Security Notes
|
|
|
|
### **Safe Scripts**: ✅
|
|
|
|
- `check-links.ts` - Read-only
|
|
- `check_logs.ts` - Read-only
|
|
- `test_har_core.ts` - No DB access
|
|
- `test_rehab_core.ts` - No DB access
|
|
|
|
### **Destructive Scripts**: ⚠️
|
|
|
|
- `seed_log.ts` - **Writes** to database
|
|
- Safe in dev, but be careful in production
|
|
- Consider adding `--dry-run` flag
|
|
|
|
### **Best Practice**:
|
|
|
|
```typescript
|
|
// Add environment check
|
|
if (process.env.NODE_ENV === "production") {
|
|
console.error("This script is not safe to run in production!");
|
|
process.exit(1);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🚀 Advanced Usage
|
|
|
|
### **1. Continuous Testing**:
|
|
|
|
```bash
|
|
# Watch mode for TDD
|
|
npx tsx watch scripts/test_rehab_core.ts
|
|
|
|
# Re-runs on file change
|
|
```
|
|
|
|
---
|
|
|
|
### **2. Automated Checks**:
|
|
|
|
```bash
|
|
# Add to CI/CD pipeline
|
|
# .github/workflows/test.yml
|
|
|
|
- name: Run Unit Tests
|
|
run: |
|
|
npx tsx scripts/test_har_core.ts
|
|
npx tsx scripts/test_rehab_core.ts
|
|
```
|
|
|
|
---
|
|
|
|
### **3. Data Migration**:
|
|
|
|
```typescript
|
|
// scripts/migrate_old_logs.ts
|
|
const oldLogs = await prisma.legacy_logs.findMany();
|
|
|
|
for (const log of oldLogs) {
|
|
await prisma.activity_logs.create({
|
|
data: {
|
|
user_id: log.userId,
|
|
status: transformStatus(log.oldStatus),
|
|
// ... transform logic
|
|
},
|
|
});
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🛠️ Troubleshooting
|
|
|
|
### **Issue**: `Cannot find module 'dotenv'`
|
|
|
|
```bash
|
|
Error: Cannot find module 'dotenv'
|
|
```
|
|
|
|
**Solution**:
|
|
|
|
```bash
|
|
npm install dotenv
|
|
```
|
|
|
|
---
|
|
|
|
### **Issue**: `tsx: command not found`
|
|
|
|
```bash
|
|
bash: tsx: command not found
|
|
```
|
|
|
|
**Solution**:
|
|
|
|
```bash
|
|
# Use npx instead
|
|
npx tsx scripts/check-links.ts
|
|
|
|
# Or install globally
|
|
npm install -g tsx
|
|
```
|
|
|
|
---
|
|
|
|
### **Issue**: Prisma connection error
|
|
|
|
```bash
|
|
Error: Can't reach database server
|
|
```
|
|
|
|
**Solution**:
|
|
|
|
1. Check PostgreSQL running
|
|
2. Verify `DATABASE_URL` in `.env`
|
|
3. Test connection:
|
|
```bash
|
|
npx prisma db pull
|
|
```
|
|
|
|
---
|
|
|
|
### **Issue**: Scripts hang (promises not resolving)
|
|
|
|
```typescript
|
|
// Add timeout
|
|
setTimeout(() => process.exit(0), 5000);
|
|
```
|
|
|
|
---
|
|
|
|
## 📚 References
|
|
|
|
**Tools Used**:
|
|
|
|
- [tsx](https://github.com/esbuild-kit/tsx) - TypeScript executor
|
|
- [Prisma Client](https://www.prisma.io/docs/concepts/components/prisma-client) - Database ORM
|
|
- [dotenv](https://github.com/motdotla/dotenv) - Environment variables
|
|
|
|
**Related Docs**:
|
|
|
|
- `/lib/pose/` - Core AI modules
|
|
- `/prisma/` - Database schema
|
|
- `package.json` - NPM scripts
|
|
|
|
---
|
|
|
|
## ✅ Summary
|
|
|
|
**Total Scripts**: 5
|
|
|
|
**Categories**:
|
|
|
|
- 🗄️ **Database**: 3 scripts (check-links, check_logs, seed_log)
|
|
- 🧪 **Testing**: 2 scripts (test_har_core, test_rehab_core)
|
|
|
|
**When to Use**:
|
|
|
|
- ✅ After database migrations
|
|
- ✅ After modifying exercise configs
|
|
- ✅ Debugging recognition issues
|
|
- ✅ Verifying production data
|
|
|
|
**Quick Commands**:
|
|
|
|
```bash
|
|
# Database health check
|
|
npx tsx scripts/check-links.ts
|
|
|
|
# View recent activity
|
|
npx tsx scripts/check_logs.ts
|
|
|
|
# Test AI systems
|
|
npx tsx scripts/test_har_core.ts
|
|
npx tsx scripts/test_rehab_core.ts
|
|
```
|
|
|
|
Scripts ini adalah **development tools penting** untuk maintain code quality dan debug issues! 🛠️
|