# Dokumentasi Folder `prisma/`

## Gambaran Umum

Folder `prisma/` berisi semua konfigurasi dan migration files untuk database management menggunakan Prisma ORM. Folder ini adalah "blueprint" dari database schema aplikasi.

---

## 📁 Struktur Direktori

```
prisma/
├── migrations/                                    # Database Migration History
│   ├── 20251228085634_add_users_model/
│   │   └── migration.sql                          # Initial database schema
│   ├── 20251228091450_add_menu_client_assignment/
│   │   └── migration.sql                          # Menu assignment feature
│   └── migration_lock.toml                        # Migration lock file
├── schema.prisma                                  # Database Schema Definition
└── seed.ts                                        # Database Seeder Script
```

---

## 📄 File Utama

### **`schema.prisma`** ⭐

**Fungsi**: Schema definition file - Blueprint utama database

**Location**: `/prisma/schema.prisma`

**Size**: ~2.6 KB

#### **Generator Configuration**:

```prisma
generator client {
  provider = "prisma-client"
  output   = "../app/generated/client"
}
```

- Generate Prisma Client TypeScript
- Output ke `app/generated/client/` untuk import di aplikasi

#### **Datasource Configuration**:

```prisma
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}
```

- Database: PostgreSQL
- Connection string dari environment variable `DATABASE_URL`

---

## 📊 Database Models

### **1. Model `users`** 👥

**Fungsi**: Menyimpan data pengguna (Coach & Client)

**Fields**:
| Field | Type | Description | Constraint |
|-------|------|-------------|------------|
| `id` | String | User ID unik | Primary Key, default: cuid() |
| `name` | String | Nama lengkap | VARCHAR, NOT NULL |
| `role` | String | Role pengguna | VARCHAR, "COACH" atau "CLIENT" |
| `coach_id` | String? | ID coach (untuk client) | Foreign Key → users.id |
| `created_at` | DateTime? | Waktu registrasi | Default: now() |

**Relations**:

- `coach` → Self-relation ke `users` (Many-to-One)
  - Client memiliki 1 coach
- `clients` → Self-relation ke `users` (One-to-Many)
  - Coach memiliki banyak clients
- `created_menus` → `training_menus[]` (One-to-Many)
  - Coach dapat membuat banyak menu
- `assigned_menus` → `training_menus[]` (One-to-Many)
  - Client dapat memiliki banyak assigned menus
- `recaps` → `user_recaps[]` (One-to-Many)
  - User dapat memiliki banyak workout recaps
- `activity_logs` → `activity_logs[]` (One-to-Many)
  - User dapat memiliki banyak activity logs

**Indexes**:

- `ix_users_id` on `id` (Primary)
- `ix_users_coach_id` on `coach_id` (Query optimization)

**ID Format**:

- Coach: `C00001`, `C00002`, etc.
- Client: `U00001`, `U00002`, etc.

**Business Logic**:

```typescript
// Coach can have multiple clients
Coach (C00001)
  └─> Clients: [U00001, U00002]

// Client belongs to one coach
Client (U00001)
  └─> Coach: C00001
```

---

### **2. Model `activity_logs`** 📝

**Fungsi**: Log aktivitas real-time (Standing/Sitting/Fall detection)

**Fields**:
| Field | Type | Description |
|-------|------|-------------|
| `id` | Int | Auto-increment ID (Primary Key) |
| `timestamp` | DateTime? | Waktu log dibuat |
| `status` | String? | "Standing", "Sitting", "Fall Detected" |
| `confidence` | String? | Confidence score dari XGBoost |
| `details` | Json? | Additional metadata |
| `user_id` | String? | Foreign Key → users.id |

**Relations**:

- `user` → `users` (Many-to-One)

**Indexes**:

- `ix_activity_logs_id` on `id`
- `ix_activity_logs_user_id` on `user_id`

**Use Case**:

- Real-time monitoring di `/client/monitor`
- Historical activity tracking
- Fall detection alerts

**Example Data**:

```json
{
	"id": 1,
	"timestamp": "2025-12-28T10:30:00Z",
	"status": "Standing",
	"confidence": "0.95",
	"details": {
		"exercise": "bicep_curl",
		"reps": 5
	},
	"user_id": "U00001"
}
```

---

### **3. Model `training_menus`** 📋

**Fungsi**: Menyimpan workout programs/menus yang dibuat coach

**Fields**:
| Field | Type | Description |
|-------|------|-------------|
| `id` | Int | Auto-increment ID (Primary Key) |
| `name` | String? | Nama menu (e.g., "Upper Body Day 1") |
| `exercises` | Json? | Array of exercise objects |
| `created_at` | DateTime? | Waktu pembuatan |
| `author_id` | String? | Foreign Key → users.id (Coach yang buat) |
| `client_id` | String? | Foreign Key → users.id (Client assigned) |

**Relations**:

- `author` → `users` (Many-to-One, relation: "CreatedMenus")
  - Menu dibuat oleh 1 coach
- `assigned_client` → `users` (Many-to-One, relation: "AssignedMenus")
  - Menu ditugaskan kepada 1 client
- `user_recaps` → `user_recaps[]` (One-to-Many)
  - Menu bisa memiliki banyak recap results

**Indexes**:

- `ix_training_menus_id` on `id`
- `ix_training_menus_name` on `name`
- `ix_training_menus_author_id` on `author_id`

**JSON Structure untuk `exercises` field**:

```json
[
	{
		"name": "Bicep Curl",
		"set_index": 1,
		"reps": 10,
		"weight": 15,
		"rest": 60
	},
	{
		"name": "Hammer Curl",
		"set_index": 1,
		"reps": 12,
		"weight": 12,
		"rest": 60
	}
]
```

**Business Logic**:

```typescript
// Coach creates menu
Coach (C00001)
  └─> Creates Menu (id: 1, "Upper Body")
      └─> Assigns to Client (U00001)

// Client sees assigned menu
Client (U00001)
  └─> Assigned Menu: "Upper Body" (id: 1)
```

---

### **4. Model `user_recaps`** 📈

**Fungsi**: Menyimpan hasil latihan (training recap) setelah workout selesai

**Fields**:
| Field | Type | Description |
|-------|------|-------------|
| `id` | Int | Auto-increment ID (Primary Key) |
| `menu_id` | Int? | Foreign Key → training_menus.id |
| `user_id` | String? | Foreign Key → users.id |
| `summary` | Json? | Workout summary data |
| `completed_at` | DateTime? | Waktu workout selesai |

**Relations**:

- `training_menus` → `training_menus` (Many-to-One)
  - Recap terkait dengan 1 menu
- `user` → `users` (Many-to-One)
  - Recap milik 1 user

**Indexes**:

- `ix_user_recaps_id` on `id`
- `ix_user_recaps_user_id` on `user_id`

**JSON Structure untuk `summary` field**:

```json
{
	"completed": true,
	"exercises": [
		{
			"name": "Bicep Curl",
			"set_index": 1,
			"reps": 10,
			"weight": 15,
			"rest": 60
		}
	],
	"timestamp": "2025-12-28T11:00:00Z",
	"results": [
		{
			"name": "Bicep Curl",
			"set": 1,
			"reps": 10,
			"weight": 15,
			"score": 12.5,
			"repDetails": [
				{
					"rep": 1,
					"score": 8.2,
					"feedback": "Perfect"
				},
				{
					"rep": 2,
					"score": 14.5,
					"feedback": "Elbow moving forward"
				}
			]
		}
	]
}
```

**Key Features di Summary**:

- ✅ Overall workout stats
- ✅ Per-set average form scores
- ✅ **Per-rep breakdown** dengan:
  - Rep number
  - MAE score
  - Specific feedback text

---

## 🔄 Database Relationships Diagram

```mermaid
erDiagram
    users ||--o{ users : "coach-client"
    users ||--o{ training_menus : "creates (author)"
    users ||--o{ training_menus : "assigned to (client)"
    users ||--o{ user_recaps : "performs workout"
    users ||--o{ activity_logs : "generates logs"
    training_menus ||--o{ user_recaps : "tracked in recap"

    users {
        string id PK
        string name
        string role
        string coach_id FK
    }

    training_menus {
        int id PK
        string name
        json exercises
        string author_id FK
        string client_id FK
    }

    user_recaps {
        int id PK
        int menu_id FK
        string user_id FK
        json summary
    }

    activity_logs {
        int id PK
        string status
        string user_id FK
    }
```

---

## 📁 Folder `migrations/`

### **Gambaran Umum**

Folder yang berisi history semua perubahan database schema.

### **Migration Files**:

#### **1. `20251228085634_add_users_model/migration.sql`**

**Tanggal**: 28 Desember 2025, 08:56:34

**Fungsi**: Initial database schema creation

**Changes**:

- ✅ Create table `users` dengan self-referencing foreign key
- ✅ Create table `activity_logs` dengan JSONB details
- ✅ Create table `training_menus` dengan JSONB exercises
- ✅ Create table `user_recaps` dengan JSONB summary
- ✅ Create indexes untuk optimization:
  - User ID index
  - Coach ID index
  - Menu name index
  - Author ID index
  - User recap user_id index
- ✅ Add foreign key constraints dengan proper ON DELETE/UPDATE actions

**Key SQL**:

```sql
CREATE TABLE "users" (
    "id" TEXT NOT NULL,
    "name" VARCHAR NOT NULL,
    "role" VARCHAR NOT NULL,
    "coach_id" TEXT,
    "created_at" TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT "users_pkey" PRIMARY KEY ("id")
);

-- Self-referencing foreign key
ALTER TABLE "users"
  ADD CONSTRAINT "users_coach_id_fkey"
  FOREIGN KEY ("coach_id") REFERENCES "users"("id")
  ON DELETE SET NULL ON UPDATE CASCADE;
```

**Size**: ~2.7 KB

---

#### **2. `20251228091450_add_menu_client_assignment/migration.sql`**

**Tanggal**: 28 Desember 2025, 09:14:50

**Fungsi**: (Merged into previous migration)

**Status**: ⚠️ Skipped/No-op migration

**Reason**:

- Original purpose: Add `client_id` to `training_menus`
- Already included in first migration to fix type mismatches
- File kept untuk preserve migration history order

**Content**:

```sql
-- This migration is skipped because its changes (adding client_id)
-- were manually merged into the previous migration to fix type mismatches
-- This file is kept to preserve migration history order.
```

---

#### **`migration_lock.toml`**

**Fungsi**: Lock file untuk ensure consistent database provider

**Content**:

```toml
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "postgresql"
```

**Purpose**:

- Mencegah accidental switch ke database provider lain
- Ensure semua developer/environment menggunakan PostgreSQL
- Auto-generated oleh Prisma CLI

---

## 📄 File `seed.ts`

**Fungsi**: Database seeder untuk populate initial test data

**Location**: `/prisma/seed.ts`

**Size**: ~1.6 KB

### **Seed Data**:

**2 Coaches**:

1. `C00001` - "Coach One"
2. `C00002` - "Coach Two"

**3 Clients**:

1. `U00001` - "Client One" (assigned to Coach One)
2. `U00002` - "Client Two" (assigned to Coach One)
3. `U00003` - "Client Three" (assigned to Coach Two)

### **Script Logic**:

```typescript
import { PrismaClient } from "../app/generated/client/client";

const prisma = new PrismaClient();

async function main() {
	// Upsert coaches
	const coach1 = await prisma.users.upsert({
		where: { id: "C00001" },
		update: {},
		create: {
			id: "C00001",
			name: "Coach One",
			role: "COACH",
		},
	});

	// Upsert clients with coach_id
	const client1 = await prisma.users.upsert({
		where: { id: "U00001" },
		update: {},
		create: {
			id: "U00001",
			name: "Client One",
			role: "CLIENT",
			coach_id: coach1.id,
		},
	});
}
```

### **Run Seeder**:

```bash
npx prisma db seed
```

**Use Case**:

- Development/testing data
- Demo accounts
- Quick reset database dengan data awal

---

## 🛠️ Prisma Commands

### **Essential Commands**:

#### **1. Generate Prisma Client**

```bash
npx prisma generate
```

- Regenerate TypeScript client dari schema
- Run setelah setiap perubahan `schema.prisma`
- Output ke `app/generated/client/`

#### **2. Create Migration**

```bash
npx prisma migrate dev --name migration_name
```

- Create migration file baru
- Apply migration ke database
- Update Prisma Client

#### **3. Apply Migration (Production)**

```bash
npx prisma migrate deploy
```

- Apply pending migrations
- Untuk production environment
- Tidak auto-generate client

#### **4. Reset Database**

```bash
npx prisma migrate reset
```

- Drop database
- Re-run all migrations
- Run seed script
- ⚠️ **DANGER**: Deletes all data!

#### **5. Prisma Studio (GUI)**

```bash
npx prisma studio
```

- Open web GUI untuk browse/edit data
- URL: `http://localhost:5555`
- Visual database management

#### **6. Format Schema**

```bash
npx prisma format
```

- Auto-format `schema.prisma`
- Fix indentation dan spacing

#### **7. Validate Schema**

```bash
npx prisma validate
```

- Check schema for errors
- Verify relations dan syntax

---

## 🔑 Key Concepts

### **Migration Strategy**:

1. **Development**:
   - Use `prisma migrate dev`
   - Creates migration + applies + generates client
   - Safe untuk experiments

2. **Production**:
   - Use `prisma migrate deploy`
   - Never use `migrate dev` in prod
   - Always test migrations di staging first

### **Schema Best Practices**:

1. **Naming Conventions**:
   - Tables: `snake_case` (e.g., `training_menus`)
   - Fields: `snake_case` (e.g., `coach_id`)
   - Relations: `camelCase` di Prisma model (e.g., `assignedClient`)

2. **Indexes**:
   - Add index untuk foreign keys
   - Add index untuk frequently queried fields
   - Consider composite indexes untuk complex queries

3. **JSONB Usage**:
   - ✅ Good for: Flexible nested data (exercises, recap summary)
   - ❌ Avoid for: Searchable/filterable data
   - Use `Json` type di Prisma, becomes `JSONB` di PostgreSQL

4. **ID Strategy**:
   - Users: Custom strings (`C00001`, `U00001`)
   - Other tables: Auto-increment integers
   - Consider UUID untuk distributed systems

---

## 📊 Database Size Estimates

**Assuming Active Usage**:

| Table            | Rows/Month | Storage                     |
| ---------------- | ---------- | --------------------------- |
| `users`          | ~10        | < 1 KB                      |
| `training_menus` | ~50        | ~5 KB                       |
| `user_recaps`    | ~500       | ~500 KB (with per-rep data) |
| `activity_logs`  | ~10,000    | ~1 MB                       |

**Total**: ~2 MB/month dengan moderate usage

**Optimization Tips**:

- Archive old `activity_logs` after 30 days
- Compress old recaps
- Add pagination untuk large queries

---

## 🔐 Security Considerations

### **Implemented**:

- ✅ Foreign key constraints prevent orphaned data
- ✅ Indexes prevent slow queries (avoid DOS)
- ✅ ON DELETE SET NULL untuk soft deletes

### **TODO / Recommendations**:

- [ ] Add `email` field dengan `@unique` constraint
- [ ] Add `password_hash` field (currently not in schema!)
- [ ] Add `role` as enum type instead of string
- [ ] Add `soft_delete` timestamp instead of hard delete
- [ ] Add row-level security (RLS) di PostgreSQL

---

## 🚀 Future Enhancements

### **Planned Schema Changes**:

1. **Add Authentication Fields**:

```prisma
model users {
  email         String   @unique
  password_hash String
  email_verified Boolean @default(false)
}
```

2. **Add Workout Sessions** (untuk track progress over time):

```prisma
model workout_sessions {
  id          Int      @id @default(autoincrement())
  user_id     String
  menu_id     Int
  started_at  DateTime
  ended_at    DateTime?
  status      String   // "IN_PROGRESS" | "COMPLETED" | "ABANDONED"
}
```

3. **Add Exercise Library** (normalize exercises):

```prisma
model exercises {
  id          Int      @id @default(autoincrement())
  name        String   @unique
  category    String   // "UPPER" | "LOWER" | "CORE"
  instructions Json?
}
```

4. **Add Personal Records**:

```prisma
model personal_records {
  id          Int      @id @default(autoincrement())
  user_id     String
  exercise    String
  weight_kg   Float
  reps        Int
  achieved_at DateTime
}
```

---

## 💡 Troubleshooting

### **Common Issues**:

#### **1. Migration Failed**

```bash
Error: Migration failed to apply
```

**Solution**:

```bash
# Reset database
npx prisma migrate reset

# Or fix manually
npx prisma db push --skip-generate
npx prisma generate
```

#### **2. Client Out of Sync**

```bash
Error: Prisma Client is out of sync with schema
```

**Solution**:

```bash
npx prisma generate
```

#### **3. Connection Error**

```bash
Error: Can't reach database server
```

**Check**:

1. PostgreSQL running? (`sudo systemctl status postgresql`)
2. `DATABASE_URL` correct di `.env`?
3. Network/firewall issues?

#### **4. Seed Script Fails**

```bash
Error: Unique constraint violation
```

**Solution**: Data already exists

```bash
# Clear database first
npx prisma migrate reset
```

---

## 📚 Resources

**Official Docs**:

- [Prisma Schema Reference](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference)
- [Prisma Migrate](https://www.prisma.io/docs/concepts/components/prisma-migrate)
- [Prisma Client API](https://www.prisma.io/docs/reference/api-reference/prisma-client-reference)

**Tutorials**:

- [Prisma Quickstart](https://www.prisma.io/docs/getting-started/quickstart)
- [PostgreSQL Best Practices](https://wiki.postgresql.org/wiki/Best_practices)

---

## ✅ Checklist Maintenance

- [x] Schema documented
- [x] Migrations tracked in Git
- [x] Seed data available
- [ ] Backup strategy defined
- [ ] Migration rollback tested
- [ ] Production deployment guide
- [ ] Performance benchmarks
