433 lines
9.2 KiB
Markdown
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
|
|
|