EAS-202310715274-DimasHendr.../N8N_WEBHOOK_GUIDE.md
2026-01-14 21:13:18 +07:00

433 lines
9.2 KiB
Markdown

# 🌐 N8n Webhook Integration Guide
## Endpoint Configuration
### Production Endpoint
```
URL: https://n8n.lab.ubharajaya.ac.id/webhook/23c6993d-1792-48fb-ad1c-ffc78a3e6254
Method: POST
Content-Type: application/json
```
### Testing Endpoint
```
URL: https://n8n.lab.ubharajaya.ac.id/webhook-test/23c6993d-1792-48fb-ad1c-ffc78a3e6254
Method: POST
Content-Type: application/json
```
### Switch Configuration
**File**: `config/AppConfig.kt`
```kotlin
// Production (default)
const val USE_WEBHOOK = N8N_WEBHOOK_PROD
// Switch ke testing
const val USE_WEBHOOK = N8N_WEBHOOK_TEST
```
---
## Request Format
### JSON Payload Example
```json
{
"npm": "12345678",
"nama": "John Doe",
"latitude": -6.896123,
"longitude": 107.610056,
"timestamp": 1704067200000,
"foto_base64": "iVBORw0KGgoAAAANSUhEUgAAA...ABJRU5ErkJggg=="
}
```
### Field Descriptions
| Field | Type | Example | Notes |
|-------|------|---------|-------|
| `npm` | String | "12345678" | Nomor Pokok Mahasiswa |
| `nama` | String | "John Doe" | Nama lengkap mahasiswa |
| `latitude` | Number | -6.896123 | Koordinat latitude (format: 6 desimal) |
| `longitude` | Number | 107.610056 | Koordinat longitude (format: 6 desimal) |
| `timestamp` | Number | 1704067200000 | Unix timestamp dalam milliseconds |
| `foto_base64` | String | "iVBORw0K..." | Foto compressed JPEG dalam Base64 |
---
## Response Handling
### Success Response (HTTP 200/201)
```json
{
"success": true,
"message": "Attendance recorded successfully",
"data": {
"id": "65a7b8c9d0e1f2g3h4i5j6k7",
"npm": "12345678",
"nama": "John Doe",
"timestamp": 1704067200000,
"status": "accepted"
}
}
```
**App Behavior**:
- Status badge: ✅ ACCEPTED (green)
- Message: "✓ Absensi berhasil dikirim!"
- Database: Save with status = "accepted"
### Error Response (HTTP 400+)
```json
{
"error": true,
"message": "Location outside of allowed area",
"code": "LOCATION_INVALID"
}
```
**App Behavior**:
- Status badge: ✗ REJECTED (red)
- Message: "✗ Gagal: Server returned code: 400"
- Database: Save with status = "rejected"
### Server Timeout (no response)
**App Behavior**:
- After 10 seconds: Show error
- Message: "✗ Gagal: timeout"
- Database: Save with status = "rejected"
---
## Real-World Examples
### Example 1: Valid Attendance
**Request**:
```bash
curl -X POST https://n8n.lab.ubharajaya.ac.id/webhook/23c6993d-1792-48fb-ad1c-ffc78a3e6254 \
-H "Content-Type: application/json" \
-d '{
"npm": "12345678",
"nama": "Arif Rachman Dwi",
"latitude": -6.8961,
"longitude": 107.6100,
"timestamp": 1704067200000,
"foto_base64": "[COMPRESSED_JPEG_BASE64]"
}'
```
**Response** (Success):
```json
HTTP/1.1 200 OK
{
"success": true,
"message": "Attendance recorded",
"status": "accepted"
}
```
---
### Example 2: Location Out of Area
**Request**:
```bash
curl -X POST https://n8n.lab.ubharajaya.ac.id/webhook/23c6993d-1792-48fb-ad1c-ffc78a3e6254 \
-H "Content-Type: application/json" \
-d '{
"npm": "12345678",
"nama": "Arif Rachman Dwi",
"latitude": -6.8,
"longitude": 107.5,
"timestamp": 1704067200000,
"foto_base64": "[COMPRESSED_JPEG_BASE64]"
}'
```
**Response** (Out of Radius):
```json
HTTP/1.1 400 Bad Request
{
"error": true,
"message": "Location is outside of allowed area",
"code": "LOCATION_INVALID",
"distance": 12500
}
```
---
## Image Compression Details
### Photo Processing in App
1. **Capture**: Camera Intent mengambil JPEG thumbnail
2. **Compress**: Bitmap compressed dengan quality 80%
3. **Encode**: JPEG bytes di-encode ke Base64
4. **Size**: Typical size ~50-100 KB (Base64 ~70-130 KB)
### Configuration
**File**: `config/AppConfig.kt`
```kotlin
const val PHOTO_COMPRESS_QUALITY = 80 // Range: 0-100
```
### Compression Quality Reference
| Quality | Use Case |
|---------|----------|
| 50 | Minimal quality, smallest size |
| 80 | Balanced (DEFAULT) |
| 100 | Maximum quality, largest size |
---
## N8n Workflow Integration
### Expected Workflow Steps
1. **Webhook Trigger**
- Menerima POST request dengan JSON payload
- Validasi format & required fields
2. **Data Validation**
- Check NPM format
- Validate coordinates (lat/lon ranges)
- Validate timestamp (not in future)
- Check foto_base64 format
3. **Location Validation**
- Calculate distance from campus center
- Check if within allowed radius
- Return error if out of bounds
4. **Photo Processing**
- Decode Base64 image
- Optional: Save to storage
- Optional: Run face detection
- Optional: Save metadata
5. **Database Storage**
- Insert into attendance table
- Record timestamp & location
- Update student statistics
6. **Response**
- Return HTTP 200 + success message
- Or HTTP 400 + error message
### Sample N8n Workflow JSON
See `n8n-workflow-EAS.json` in project root for complete workflow configuration.
---
## Monitoring & Testing
### Monitoring URL
```
https://ntfy.ubharajaya.ac.id/EAS
```
Monitor real-time webhook notifications:
- New attendance submissions
- Errors & rejections
- System alerts
### Spreadsheet Tracking
```
https://docs.google.com/spreadsheets/d/1jH15MfnNgpPGuGeid0hYfY7fFUHCEFbCmg8afTyyLZs/
```
Track all recorded attendance data:
- Student information
- Location & timestamp
- Photo references
- Status & notes
### Testing Endpoint
```
https://n8n.lab.ubharajaya.ac.id/webhook-test/23c6993d-1792-48fb-ad1c-ffc78a3e6254
```
Use for testing before production:
- Simulates webhook behavior
- Doesn't actually save to production database
- Useful for app development & testing
---
## Implementation Code Reference
### Sending Request (AttendanceRepository.kt)
```kotlin
fun sendToN8n(
onSuccess: () -> Unit,
onError: (String) -> Unit,
attendance: Attendance,
foto: Bitmap
) {
thread {
try {
val url = URL(AppConfig.USE_WEBHOOK)
val conn = url.openConnection() as HttpURLConnection
conn.requestMethod = "POST"
conn.setRequestProperty("Content-Type", "application/json")
conn.doOutput = true
conn.connectTimeout = 10000
conn.readTimeout = 10000
// Create JSON payload
val json = JSONObject().apply {
put("npm", attendance.npm)
put("nama", attendance.nama)
put("latitude", attendance.latitude)
put("longitude", attendance.longitude)
put("timestamp", attendance.timestamp)
put("foto_base64", bitmapToBase64(foto))
}
// Send request
conn.outputStream.use {
it.write(json.toString().toByteArray())
it.flush()
}
// Handle response
val responseCode = conn.responseCode
if (responseCode == 200 || responseCode == 201) {
onSuccess()
} else {
onError("Server returned code: $responseCode")
}
conn.disconnect()
} catch (e: Exception) {
onError(e.message ?: "Unknown error")
}
}
}
```
---
## Troubleshooting
### 1. Connection Timeout
```
Error: "✗ Gagal: timeout"
Solution:
- Check internet connection
- Verify URL is correct
- Test network connectivity
- Increase timeout if needed
```
### 2. Invalid JSON Response
```
Error: "✗ Gagal: JSON parsing error"
Solution:
- Verify payload format
- Check all required fields present
- Validate Base64 string
- Check JSON syntax
```
### 3. 400 Bad Request
```
Error: "✗ Gagal: Server returned code: 400"
Possible causes:
- Invalid NPM format
- Coordinates out of valid range
- Missing required fields
- Malformed Base64 image
```
### 4. 401 Unauthorized
```
Error: "✗ Gagal: Server returned code: 401"
Solution:
- Check webhook URL is correct
- Verify webhook is active in N8n
- Check authentication headers if required
```
### 5. 403 Forbidden
```
Error: "✗ Gagal: Server returned code: 403"
Solution:
- Verify webhook permissions
- Check if webhook is enabled
- Verify IP whitelist settings
```
### 6. 500 Server Error
```
Error: "✗ Gagal: Server returned code: 500"
Solution:
- Check N8n workflow logs
- Verify database connection
- Check N8n service status
- Contact system administrator
```
---
## Security Considerations
### Data Protection
- All data sent over HTTPS
- No sensitive data stored in logs
- Base64 photo cannot be directly viewed
- Timestamp validation prevents replay attacks
### Rate Limiting
- Consider implementing rate limiting on N8n
- Prevent duplicate submissions
- Monitor for unusual activity
### Validation
- Server should validate all inputs
- Reject invalid coordinates
- Verify photo file integrity
- Check timestamp within reasonable window
---
## API Contract
### Version Information
```
API Version: v1
Last Updated: 2025-01-14
Endpoint Status: Active
```
### Backward Compatibility
- Current version: 1.0
- No breaking changes planned
- All fields are required
- Response format is stable
### Future Enhancements
- [ ] Support for batch submissions
- [ ] Webhook signature verification
- [ ] Custom error codes
- [ ] Rate limiting headers
- [ ] API versioning in URL
---
**Document Version**: 1.0
**Last Updated**: 2025-01-14
**Status**: ✅ Complete & Current