569 lines
12 KiB
Markdown
569 lines
12 KiB
Markdown
# Dokumentasi Folder `public/`
|
||
|
||
## Gambaran Umum
|
||
|
||
Folder `public/` berisi semua static assets yang dapat diakses langsung dari browser tanpa processing. File-file di folder ini di-serve oleh Next.js dari root path `/`.
|
||
|
||
---
|
||
|
||
## 📁 Struktur Direktori
|
||
|
||
```
|
||
public/
|
||
├── models/ # Machine Learning Models
|
||
│ └── xgb_activity_model.json # XGBoost activity classifier (2.1 MB)
|
||
├── favicon.svg # App icon (browser tab)
|
||
├── file.svg # File icon asset
|
||
├── globe.svg # Globe icon asset
|
||
├── next.svg # Next.js logo
|
||
├── vercel.svg # Vercel logo
|
||
└── window.svg # Window icon asset
|
||
```
|
||
|
||
---
|
||
|
||
## 📄 File-File Utama
|
||
|
||
### **1. `models/xgb_activity_model.json`** 🤖
|
||
|
||
**Path**: `/public/models/xgb_activity_model.json`
|
||
|
||
**Fungsi**: XGBoost Machine Learning Model untuk Human Activity Recognition
|
||
|
||
**Purpose**:
|
||
|
||
- Classify pose menjadi 3 kategori:
|
||
1. **Standing** (Berdiri)
|
||
2. **Sitting** (Duduk)
|
||
3. **Fall Detected** (Jatuh terdeteksi)
|
||
|
||
**Size**: **2.1 MB** (Very Large!)
|
||
|
||
**Format**: JSON serialization dari XGBoost model
|
||
|
||
- Berisi tree structures, weights, dan thresholds
|
||
- trained model dari Python exported ke JavaScript-compatible format
|
||
|
||
**How It's Used**:
|
||
|
||
```typescript
|
||
// lib/pose/XGBoostPredictor.ts
|
||
import modelData from "../public/models/xgb_activity_model.json";
|
||
|
||
class XGBoostPredictor {
|
||
predict(features: number[]): number[] {
|
||
// Load model from JSON
|
||
// Execute XGBoost inference
|
||
// Return [standingProb, sittingProb, fallProb]
|
||
}
|
||
}
|
||
```
|
||
|
||
**Access URL**: `http://localhost:3000/models/xgb_activity_model.json`
|
||
|
||
**Tech Details**:
|
||
|
||
- Input: 141 features (33 landmarks × 4 + 9 derived)
|
||
- Output: 3-class probability distribution
|
||
- Algorithm: Gradient Boosted Decision Trees
|
||
|
||
**Performance**:
|
||
|
||
- Inference: ~5-10ms per frame
|
||
- Memory: ~2 MB loaded in browser
|
||
- Accuracy: Depends on training data quality
|
||
|
||
---
|
||
|
||
### **2. `favicon.svg`** 🎨
|
||
|
||
**Path**: `/public/favicon.svg`
|
||
|
||
**Fungsi**: App icon yang muncul di browser tab
|
||
|
||
**Size**: ~1.1 KB
|
||
|
||
**Design**:
|
||
|
||
- SVG icon dengan gambar dumbbells (barbel)
|
||
- Color: Blue (`#1E40AF` - blue-700)
|
||
- Viewbox: 24×24
|
||
- Rendered size: 48×48 pixels
|
||
|
||
**SVG Structure**:
|
||
|
||
```svg
|
||
<svg viewBox="0 0 24 24" width="48" height="48">
|
||
<!-- Left dumbbell weight -->
|
||
<path d="M7.4 7H4.6..." stroke="#1E40AF"/>
|
||
|
||
<!-- Right dumbbell weight -->
|
||
<path d="M19.4 7H16.6..." stroke="#1E40AF"/>
|
||
|
||
<!-- Center bar -->
|
||
<path d="M8 12H16" stroke="#1E40AF"/>
|
||
</svg>
|
||
```
|
||
|
||
**Visual**: Representing fitness/strength training
|
||
|
||
**Browser Display**:
|
||
|
||
- Favicon di tab browser
|
||
- Bookmark icon
|
||
- Desktop shortcut icon (PWA)
|
||
|
||
**Access**: Automatically loaded oleh Next.js dari `<link rel="icon">`
|
||
|
||
---
|
||
|
||
### **3. Icon Assets** (SVG Icons)
|
||
|
||
#### **`file.svg`**
|
||
|
||
**Size**: ~391 bytes
|
||
|
||
**Fungsi**: Generic file icon
|
||
|
||
- Bisa digunakan untuk file upload UI
|
||
- Document representation
|
||
- Attachment icons
|
||
|
||
**Use Case**: UI components yang butuh file icon
|
||
|
||
---
|
||
|
||
#### **`globe.svg`**
|
||
|
||
**Size**: ~1 KB
|
||
|
||
**Fungsi**: Globe/world icon
|
||
|
||
- Public/internet representation
|
||
- Language selection
|
||
- Global settings
|
||
|
||
**Possible Uses**:
|
||
|
||
- Language switcher (future feature)
|
||
- Public profile indicators
|
||
- Network status
|
||
|
||
---
|
||
|
||
#### **`window.svg`**
|
||
|
||
**Size**: ~385 bytes
|
||
|
||
**Fungsi**: Window/application icon
|
||
|
||
- UI element representation
|
||
- Modal/dialog indicators
|
||
- Application layout icons
|
||
|
||
**Use Case**:
|
||
|
||
- Dashboard widgets
|
||
- Window management UI
|
||
- Layout switching
|
||
|
||
---
|
||
|
||
### **4. Brand Logos**
|
||
|
||
#### **`next.svg`**
|
||
|
||
**Size**: ~1.4 KB
|
||
|
||
**Fungsi**: Next.js official logo
|
||
|
||
- Used in default Next.js templates
|
||
- Brand attribution
|
||
- Developer credits
|
||
|
||
**Current Usage**: Likely not displayed in production
|
||
|
||
- Default Next.js boilerplate file
|
||
- Can be removed if not used
|
||
|
||
---
|
||
|
||
#### **`vercel.svg`**
|
||
|
||
**Size**: ~128 bytes
|
||
|
||
**Fungsi**: Vercel deployment platform logo
|
||
|
||
- Hosting provider logo
|
||
- Deployment attribution
|
||
|
||
**Current Usage**: Likely not displayed
|
||
|
||
- Boilerplate file
|
||
- Can be removed if deploying elsewhere
|
||
|
||
---
|
||
|
||
## 🔗 How Public Files Are Accessed
|
||
|
||
### **In Code**:
|
||
|
||
```typescript
|
||
// Direct path from root
|
||
<img src="/favicon.svg" alt="Logo" />
|
||
|
||
// Model import (if using import)
|
||
import model from '@/public/models/xgb_activity_model.json';
|
||
|
||
// Or fetch at runtime
|
||
const response = await fetch('/models/xgb_activity_model.json');
|
||
const model = await response.json();
|
||
```
|
||
|
||
### **In Browser**:
|
||
|
||
- `http://localhost:3000/favicon.svg`
|
||
- `http://localhost:3000/models/xgb_activity_model.json`
|
||
- `http://localhost:3000/next.svg`
|
||
|
||
**Important**:
|
||
|
||
- ✅ NO `/public` prefix in URL
|
||
- ✅ Files served from root `/`
|
||
- ❌ Don't use `/public/favicon.svg` (404!)
|
||
|
||
---
|
||
|
||
## 📊 File Analysis
|
||
|
||
| File | Size | Type | Purpose | Status |
|
||
| ------------------------- | ------ | -------- | ----------------------- | ---------------- |
|
||
| `xgb_activity_model.json` | 2.1 MB | ML Model | Activity classification | ✅ **Critical** |
|
||
| `favicon.svg` | 1.1 KB | Icon | App branding | ✅ **Active** |
|
||
| `file.svg` | 391 B | Icon | UI asset | ⚠️ Likely unused |
|
||
| `globe.svg` | 1 KB | Icon | UI asset | ⚠️ Likely unused |
|
||
| `window.svg` | 385 B | Icon | UI asset | ⚠️ Likely unused |
|
||
| `next.svg` | 1.4 KB | Logo | Boilerplate | ⚠️ Can remove |
|
||
| `vercel.svg` | 128 B | Logo | Boilerplate | ⚠️ Can remove |
|
||
|
||
**Total Size**: ~2.1 MB
|
||
|
||
**Largest File**: `xgb_activity_model.json` (99% of total)
|
||
|
||
---
|
||
|
||
## 🎯 Optimization Recommendations
|
||
|
||
### **1. Model Optimization** ⚡
|
||
|
||
**Current**: 2.1 MB JSON file
|
||
|
||
**Options**:
|
||
|
||
- ✅ **Lazy Load**: Only load saat dibutuhkan
|
||
- ✅ **Compression**: Gzip/Brotli (automatic by Next.js)
|
||
- ✅ **CDN**: Host di CDN untuk faster global access
|
||
- ⚠️ **Quantization**: Reduce precision (may affect accuracy)
|
||
- ⚠️ **ONNX Format**: Convert ke binary format (smaller)
|
||
|
||
**Lazy Load Example**:
|
||
|
||
```typescript
|
||
// Load only when needed
|
||
const loadModel = async () => {
|
||
const model = await import("@/public/models/xgb_activity_model.json");
|
||
return model;
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
### **2. Icon Cleanup** 🧹
|
||
|
||
**Unused Icons**: Remove jika tidak digunakan
|
||
|
||
```bash
|
||
# Check usage across codebase
|
||
grep -r "file.svg" app/
|
||
grep -r "globe.svg" app/
|
||
grep -r "window.svg" app/
|
||
|
||
# If no results, safe to delete
|
||
rm public/file.svg public/globe.svg public/window.svg
|
||
rm public/next.svg public/vercel.svg
|
||
```
|
||
|
||
**Benefit**: Reduce deployment size, faster builds
|
||
|
||
---
|
||
|
||
### **3. Add More Assets** 📁
|
||
|
||
**Recommended Additions**:
|
||
|
||
#### **`robots.txt`**
|
||
|
||
```txt
|
||
# public/robots.txt
|
||
User-agent: *
|
||
Allow: /
|
||
Sitemap: https://yourapp.com/sitemap.xml
|
||
```
|
||
|
||
#### **`manifest.json`** (PWA)
|
||
|
||
```json
|
||
{
|
||
"name": "Straps Fitness",
|
||
"short_name": "Straps",
|
||
"icons": [
|
||
{
|
||
"src": "/favicon.svg",
|
||
"sizes": "48x48",
|
||
"type": "image/svg+xml"
|
||
}
|
||
],
|
||
"theme_color": "#1E40AF",
|
||
"background_color": "#000000",
|
||
"display": "standalone"
|
||
}
|
||
```
|
||
|
||
#### **`sitemap.xml`** (SEO)
|
||
|
||
```xml
|
||
<?xml version="1.0" encoding="UTF-8"?>
|
||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||
<url>
|
||
<loc>https://yourapp.com/</loc>
|
||
<priority>1.0</priority>
|
||
</url>
|
||
</urlset>
|
||
```
|
||
|
||
---
|
||
|
||
## 🔒 Security Considerations
|
||
|
||
### **Current Status**: ✅ Safe
|
||
|
||
**Why**:
|
||
|
||
- ✅ No sensitive data in public files
|
||
- ✅ Model file is read-only data (not executable)
|
||
- ✅ SVG files are static images
|
||
|
||
### **Best Practices**:
|
||
|
||
1. **Never Put Secrets Here** ❌
|
||
- No API keys
|
||
- No passwords
|
||
- No private data
|
||
2. **Validate SVG Files** ✅
|
||
- Check for XSS vectors
|
||
- Sanitize uploaded SVGs
|
||
|
||
3. **Model Integrity** 🔐
|
||
- Verify model hash before use
|
||
- Detect tampering
|
||
```typescript
|
||
const expectedHash = "sha256-abc123...";
|
||
const actualHash = await hashFile("/models/xgb_activity_model.json");
|
||
if (actualHash !== expectedHash) {
|
||
throw new Error("Model tampered!");
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🚀 Advanced Usage
|
||
|
||
### **1. Dynamic Model Loading**
|
||
|
||
```typescript
|
||
// Lazy load untuk reduce initial bundle
|
||
const HARCore = dynamic(() => import('@/lib/pose/HARCore'), {
|
||
ssr: false,
|
||
loading: () => <p>Loading AI Model...</p>
|
||
});
|
||
```
|
||
|
||
### **2. Service Worker Caching** (PWA)
|
||
|
||
```javascript
|
||
// Cache model untuk offline use
|
||
self.addEventListener("install", (event) => {
|
||
event.waitUntil(
|
||
caches.open("models-v1").then((cache) => {
|
||
return cache.add("/models/xgb_activity_model.json");
|
||
}),
|
||
);
|
||
});
|
||
```
|
||
|
||
### **3. Progressive Enhancement**
|
||
|
||
```typescript
|
||
// Fallback jika model load gagal
|
||
let classifier;
|
||
try {
|
||
classifier = await loadXGBoostModel();
|
||
} catch (err) {
|
||
console.warn("Model failed to load, using heuristics");
|
||
classifier = new FallbackHeuristicClassifier();
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 📈 Performance Metrics
|
||
|
||
### **Model Loading**:
|
||
|
||
- **Cold Start**: ~200-500ms (first load, no cache)
|
||
- **Warm Start**: ~50-100ms (cached)
|
||
- **Memory**: ~2-3 MB in-memory after parsing
|
||
|
||
### **Optimization Impact**:
|
||
|
||
```typescript
|
||
// Before: Load synchronously (blocks rendering)
|
||
import model from "@/public/models/xgb_activity_model.json";
|
||
|
||
// After: Load async (non-blocking)
|
||
const model = await fetch("/models/xgb_activity_model.json").then((r) =>
|
||
r.json(),
|
||
);
|
||
```
|
||
|
||
**Result**:
|
||
|
||
- ⚡ Faster initial page load
|
||
- ⚡ Better Lighthouse scores
|
||
- ⚡ Improved user experience
|
||
|
||
---
|
||
|
||
## 💡 Maintenance Tips
|
||
|
||
### **When Adding New Files**:
|
||
|
||
1. **Images**:
|
||
- Use WebP format (smaller than PNG/JPG)
|
||
- Optimize dengan tooling (ImageOptim, Squoosh)
|
||
- Consider `next/image` untuk auto-optimization
|
||
|
||
2. **Icons**:
|
||
- Prefer SVG (scalable, small)
|
||
- Consider icon libraries (react-icons, lucide-react)
|
||
- Avoid duplicates
|
||
|
||
3. **Data Files**:
|
||
- Compress large JSON/CSV
|
||
- Consider API route instead of static file
|
||
- Use CDN untuk large files
|
||
|
||
### **Regular Cleanup**:
|
||
|
||
```bash
|
||
# Find unused public files
|
||
du -sh public/*
|
||
|
||
# Check git history untuk unused files
|
||
git log --all --full-history -- public/
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 Troubleshooting
|
||
|
||
### **Issue**: Model not loading
|
||
|
||
```
|
||
Error: Failed to fetch /models/xgb_activity_model.json
|
||
```
|
||
|
||
**Solutions**:
|
||
|
||
1. Verify file exists: `ls public/models/`
|
||
2. Check Next.js server running
|
||
3. Clear browser cache
|
||
4. Check CORS headers (if loading from external domain)
|
||
|
||
---
|
||
|
||
### **Issue**: Icons not showing
|
||
|
||
```
|
||
404: /public/favicon.svg not found
|
||
```
|
||
|
||
**Solution**: ❌ Remove `/public` prefix
|
||
|
||
```html
|
||
<!-- Wrong -->
|
||
<img src="/public/favicon.svg" />
|
||
|
||
<!-- Correct -->
|
||
<img src="/favicon.svg" />
|
||
```
|
||
|
||
---
|
||
|
||
### **Issue**: Large bundle size
|
||
|
||
```
|
||
Warning: Page size exceeds 300 KB
|
||
```
|
||
|
||
**Solution**: Lazy load model
|
||
|
||
```typescript
|
||
// Lazy load
|
||
const model = await import("@/public/models/xgb_activity_model.json");
|
||
```
|
||
|
||
---
|
||
|
||
## 📚 Next.js Static File Best Practices
|
||
|
||
### **✅ DO**:
|
||
|
||
- Keep files small (< 1 MB ideally)
|
||
- Use modern formats (WebP, AVIF, SVG)
|
||
- Compress large files
|
||
- Use meaningful filenames
|
||
- Organize in subdirectories
|
||
|
||
### **❌ DON'T**:
|
||
|
||
- Put sensitive data
|
||
- Store frequently changing data
|
||
- Use as database replacement
|
||
- Include source files (.psd, .ai)
|
||
- Exceed 10 MB total size
|
||
|
||
---
|
||
|
||
## 🎓 Summary
|
||
|
||
**Current Status**: ✅ Well-organized, but can be optimized
|
||
|
||
**Key Files**:
|
||
|
||
1. **xgb_activity_model.json** - Critical ML model (2.1 MB)
|
||
2. **favicon.svg** - App branding
|
||
3. **Other SVGs** - Likely unused (cleanup recommended)
|
||
|
||
**Recommendations**:
|
||
|
||
1. ⚡ Lazy load ML model
|
||
2. 🧹 Remove unused icons
|
||
3. 📁 Add PWA manifest
|
||
4. 🔐 Add model integrity check
|
||
5. 📊 Monitor bundle size
|
||
|
||
**Total Size**: ~2.1 MB (99% from model file)
|
||
|
||
**Performance**: Good, but can be improved with lazy loading
|