Add Google Calendar integration via Supabase Edge Functions
- Create new create-google-meet-event edge function - Use service account authentication (no OAuth needed) - Add google_service_account_json field to platform_settings - Add admin UI for service account JSON configuration - Include test connection button in Integrasi tab - Add comprehensive setup documentation - Keep n8n workflows as alternative option Features: - Direct Google Calendar API integration - JWT authentication with service account - Auto-create Google Meet links - No external dependencies needed - Simple configuration via admin panel 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
219
docs/google-calendar-edge-function-setup.md
Normal file
219
docs/google-calendar-edge-function-setup.md
Normal file
@@ -0,0 +1,219 @@
|
||||
# Google Calendar Integration with Supabase Edge Functions
|
||||
|
||||
This guide walks you through setting up Google Calendar integration directly in Supabase Edge Functions, without needing n8n or OAuth.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Access Hub App → Supabase Edge Function → Google Calendar API
|
||||
↓
|
||||
JWT Authentication
|
||||
↓
|
||||
Service Account JSON
|
||||
```
|
||||
|
||||
## Setup Steps
|
||||
|
||||
### 1. Create Google Service Account
|
||||
|
||||
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
|
||||
2. Create a new project or select existing one
|
||||
3. Navigate to **IAM & Admin** → **Service Accounts**
|
||||
4. Click **Create Service Account**
|
||||
5. Fill in details:
|
||||
- Name: `access-hub-calendar`
|
||||
- Description: `Service account for Access Hub calendar integration`
|
||||
6. Click **Create and Continue** (skip granting roles)
|
||||
7. Click **Done**
|
||||
|
||||
### 2. Enable Google Calendar API
|
||||
|
||||
1. In Google Cloud Console, go to **APIs & Services** → **Library**
|
||||
2. Search for "Google Calendar API"
|
||||
3. Click **Enable**
|
||||
|
||||
### 3. Create Service Account Key
|
||||
|
||||
1. Go to your service account page
|
||||
2. Click the **Keys** tab
|
||||
3. Click **Add Key** → **Create New Key**
|
||||
4. Select **JSON** format
|
||||
5. Click **Create** - download the JSON file
|
||||
|
||||
Keep this file secure! It contains your private key.
|
||||
|
||||
### 4. Share Calendar with Service Account
|
||||
|
||||
1. Go to [Google Calendar](https://calendar.google.com/)
|
||||
2. Hover over the calendar you want to use
|
||||
3. Click the **three dots (⋮)** → **Settings and sharing**
|
||||
4. Scroll to **Share with specific people**
|
||||
5. Click **+ Add people**
|
||||
6. Enter the service account email from your JSON: `xxx@xxx.iam.gserviceaccount.com`
|
||||
7. Set permissions to **Make changes to events**
|
||||
8. Click **Send**
|
||||
|
||||
### 5. Add Database Column
|
||||
|
||||
Run this SQL in your Supabase SQL Editor:
|
||||
|
||||
```sql
|
||||
ALTER TABLE platform_settings
|
||||
ADD COLUMN IF NOT EXISTS google_service_account_json TEXT;
|
||||
```
|
||||
|
||||
### 6. Deploy Edge Function
|
||||
|
||||
```bash
|
||||
# Deploy the new function
|
||||
supabase functions deploy create-google-meet-event --verify-jwt
|
||||
```
|
||||
|
||||
Or use the deployment script:
|
||||
```bash
|
||||
./deploy-edge-functions.sh
|
||||
```
|
||||
|
||||
### 7. Configure in Admin Panel
|
||||
|
||||
1. Go to **Settings** → **Integrasi**
|
||||
2. Find the **Google Calendar** section
|
||||
3. Enter your **Calendar ID** (e.g., `your-email@gmail.com`)
|
||||
4. Paste the **Service Account JSON** (entire content from the JSON file)
|
||||
5. Click **Simpan Semua Pengaturan**
|
||||
6. Click **Test Google Calendar Connection**
|
||||
|
||||
If successful, you'll see a test event created in your Google Calendar with a Google Meet link.
|
||||
|
||||
## How It Works
|
||||
|
||||
### Authentication Flow
|
||||
|
||||
1. Edge Function reads service account JSON
|
||||
2. Creates a JWT signed with the private key
|
||||
3. Exchanges JWT for an access token
|
||||
4. Uses access token to call Google Calendar API
|
||||
|
||||
### Event Creation
|
||||
|
||||
When a consultation slot is confirmed:
|
||||
|
||||
1. `create-google-meet-event` function is called
|
||||
2. Creates a Google Calendar event with Meet link
|
||||
3. Returns the Meet link to be stored in the database
|
||||
|
||||
## API Reference
|
||||
|
||||
### Request
|
||||
|
||||
```typescript
|
||||
POST /functions/v1/create-google-meet-event
|
||||
|
||||
{
|
||||
slot_id: string; // Unique slot identifier
|
||||
date: string; // YYYY-MM-DD
|
||||
start_time: string; // HH:MM:SS
|
||||
end_time: string; // HH:MM:SS
|
||||
client_name: string; // Client's full name
|
||||
client_email: string; // Client's email
|
||||
topic: string; // Consultation topic
|
||||
notes?: string; // Optional notes
|
||||
}
|
||||
```
|
||||
|
||||
### Response
|
||||
|
||||
```typescript
|
||||
{
|
||||
success: true;
|
||||
meet_link: string; // https://meet.google.com/xxx-xxx-xxx
|
||||
event_id: string; // Google Calendar event ID
|
||||
html_link: string; // Link to event in Google Calendar
|
||||
}
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
### Test via Admin Panel
|
||||
|
||||
Use the **Test Google Calendar Connection** button in the Integrasi settings.
|
||||
|
||||
### Test via Curl
|
||||
|
||||
```bash
|
||||
curl -X POST https://your-project.supabase.co/functions/v1/create-google-meet-event \
|
||||
-H "Authorization: Bearer YOUR_ANON_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"slot_id": "test-123",
|
||||
"date": "2025-12-25",
|
||||
"start_time": "14:00:00",
|
||||
"end_time": "15:00:00",
|
||||
"client_name": "Test Client",
|
||||
"client_email": "test@example.com",
|
||||
"topic": "Test Topic"
|
||||
}'
|
||||
```
|
||||
|
||||
## Security Notes
|
||||
|
||||
1. **Never commit** the service account JSON to version control
|
||||
2. **Store securely** in database (consider encryption for production)
|
||||
3. **Rotate keys** if compromised
|
||||
4. **Limit permissions** to only Calendar API
|
||||
5. **Use separate service accounts** for different environments
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Error: "Google Service Account JSON belum dikonfigurasi"
|
||||
- Make sure you've saved the JSON in the admin settings
|
||||
- Check the database column exists: `google_service_account_json`
|
||||
|
||||
### Error: 403 Forbidden
|
||||
- Verify calendar is shared with service account email
|
||||
- Check service account has "Make changes to events" permission
|
||||
|
||||
### Error: 401 Unauthorized
|
||||
- Verify service account JSON is valid
|
||||
- Check Calendar API is enabled in Google Cloud Console
|
||||
|
||||
### Error: "Failed to parse service account JSON"
|
||||
- Make sure you pasted the entire JSON content
|
||||
- Check for any truncation or formatting issues
|
||||
|
||||
### Error: "Gagal membuat event di Google Calendar"
|
||||
- Check the error message for details
|
||||
- Verify Calendar API is enabled
|
||||
- Check service account has correct permissions
|
||||
|
||||
## Comparison: n8n vs Edge Function
|
||||
|
||||
| Feature | n8n Integration | Edge Function |
|
||||
|---------|----------------|---------------|
|
||||
| Setup Complexity | Medium | Low |
|
||||
| OAuth Required | No (Service Account) | No (Service Account) |
|
||||
| External Dependencies | n8n instance | None |
|
||||
| Cost | Requires n8n hosting | Included in Supabase |
|
||||
| Maintenance | n8n updates | Supabase updates |
|
||||
| Performance | Extra hop | Direct API call |
|
||||
| **Recommended** | For complex workflows | ✅ **For simple integrations** |
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. ✅ Create service account
|
||||
2. ✅ Share calendar with service account
|
||||
3. ✅ Run database migration
|
||||
4. ✅ Deploy edge function
|
||||
5. ✅ Configure in admin panel
|
||||
6. ✅ Test connection
|
||||
7. ✅ Integrate with consultation booking flow
|
||||
|
||||
## Files Modified/Created
|
||||
|
||||
- `supabase/functions/create-google-meet-event/index.ts` - New edge function
|
||||
- `supabase/migrations/20250323_add_google_service_account.sql` - Database migration
|
||||
- `src/components/admin/settings/IntegrasiTab.tsx` - Admin UI for configuration
|
||||
|
||||
---
|
||||
|
||||
**Need Help?** Check the Supabase Edge Functions logs in your dashboard for detailed error messages.
|
||||
214
docs/google-calendar-service-account-setup.md
Normal file
214
docs/google-calendar-service-account-setup.md
Normal file
@@ -0,0 +1,214 @@
|
||||
# Google Calendar Integration with Service Account
|
||||
|
||||
## Overview
|
||||
Using a Service Account to integrate Google Calendar API without OAuth user consent.
|
||||
|
||||
## Setup Instructions
|
||||
|
||||
### 1. Create Service Account in Google Cloud Console
|
||||
|
||||
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
|
||||
2. Create a new project or select existing one
|
||||
3. Navigate to **IAM & Admin** → **Service Accounts**
|
||||
4. Click **Create Service Account**
|
||||
5. Fill in details:
|
||||
- Name: `access-hub-calendar`
|
||||
- Description: `Service account for Access Hub calendar integration`
|
||||
6. Click **Create and Continue**
|
||||
7. Skip granting roles (not needed for Calendar API)
|
||||
8. Click **Done**
|
||||
|
||||
### 2. Enable Google Calendar API
|
||||
|
||||
1. In Google Cloud Console, go to **APIs & Services** → **Library**
|
||||
2. Search for "Google Calendar API"
|
||||
3. Click on it and press **Enable**
|
||||
|
||||
### 3. Create Service Account Key
|
||||
|
||||
1. Go to your service account page
|
||||
2. Click on the **Keys** tab
|
||||
3. Click **Add Key** → **Create New Key**
|
||||
4. Select **JSON** format
|
||||
5. Click **Create** - this will download a JSON file with credentials
|
||||
6. **Keep this file secure** - it contains your private key
|
||||
|
||||
The JSON file looks like:
|
||||
```json
|
||||
{
|
||||
"type": "service_account",
|
||||
"project_id": "your-project-id",
|
||||
"private_key_id": "...",
|
||||
"private_key": "-----BEGIN PRIVATE KEY-----\n...",
|
||||
"client_email": "access-hub-calendar@your-project-id.iam.gserviceaccount.com",
|
||||
"client_id": "...",
|
||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||
"token_uri": "https://oauth2.googleapis.com/token"
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Share Calendar with Service Account
|
||||
|
||||
1. Go to [Google Calendar](https://calendar.google.com/)
|
||||
2. Find the calendar you want to use (e.g., your main calendar)
|
||||
3. Click the **three dots** next to the calendar name
|
||||
4. Select **Settings and sharing**
|
||||
5. Scroll to **Share with specific people**
|
||||
6. Click **+ Add people**
|
||||
7. Enter the service account email: `access-hub-calendar@your-project-id.iam.gserviceaccount.com`
|
||||
8. Set permissions to **Editor** (can make changes to events)
|
||||
9. Click **Send** (ignore the email notification)
|
||||
|
||||
### 5. Get Calendar ID
|
||||
|
||||
- For your primary calendar: `your-email@gmail.com`
|
||||
- For other calendars: Go to Calendar Settings → **Integrate calendar** → **Calendar ID**
|
||||
|
||||
## n8n Workflow Configuration
|
||||
|
||||
### Option A: Using Google Calendar Node
|
||||
|
||||
1. Add a **Google Calendar** node to your workflow
|
||||
2. Select **Service Account** as authentication
|
||||
3. Paste the entire Service Account JSON content
|
||||
4. Select the calendar ID
|
||||
5. Choose operation: **Create Event**
|
||||
|
||||
### Option B: Using HTTP Request Node (More Control)
|
||||
|
||||
```javascript
|
||||
// In n8n Code node or HTTP Request node
|
||||
|
||||
const { GoogleToken } = require('gtoken');
|
||||
const { google } = require('googleapis');
|
||||
|
||||
// Service account credentials
|
||||
const serviceAccount = {
|
||||
type: 'service_account',
|
||||
project_id: 'your-project-id',
|
||||
private_key_id: '...',
|
||||
private_key: '-----BEGIN PRIVATE KEY-----\n...',
|
||||
client_email: 'access-hub-calendar@your-project-id.iam.gserviceaccount.com',
|
||||
client_id: '...',
|
||||
};
|
||||
|
||||
// Create JWT client
|
||||
const jwtClient = new google.auth.JWT(
|
||||
serviceAccount.client_email,
|
||||
null,
|
||||
serviceAccount.private_key,
|
||||
['https://www.googleapis.com/auth/calendar']
|
||||
);
|
||||
|
||||
// Authorize and create event
|
||||
jwtClient.authorize(async (err, tokens) => {
|
||||
if (err) {
|
||||
console.error('JWT authorization error:', err);
|
||||
return;
|
||||
}
|
||||
|
||||
const calendar = google.calendar({ version: 'v3', auth: jwtClient });
|
||||
|
||||
const event = {
|
||||
summary: 'Konsultasi: ' + $json.topic + ' - ' + $json.client_name,
|
||||
start: {
|
||||
dateTime: new Date($json.date + 'T' + $json.start_time).toISOString(),
|
||||
timeZone: 'Asia/Jakarta',
|
||||
},
|
||||
end: {
|
||||
dateTime: new Date($json.date + 'T' + $json.end_time).toISOString(),
|
||||
timeZone: 'Asia/Jakarta',
|
||||
},
|
||||
description: 'Client: ' + $json.client_email + '\n\n' + $json.notes,
|
||||
attendees: [
|
||||
{ email: $json.client_email },
|
||||
],
|
||||
conferenceData: {
|
||||
createRequest: {
|
||||
requestId: $json.slot_id,
|
||||
conferenceSolutionKey: { type: 'hangoutsMeet' },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
const result = await calendar.events.insert({
|
||||
calendarId: $json.calendar_id,
|
||||
resource: event,
|
||||
conferenceDataVersion: 1,
|
||||
});
|
||||
|
||||
return {
|
||||
meet_link: result.data.hangoutLink,
|
||||
event_id: result.data.id,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error creating calendar event:', error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Incoming Webhook Payload
|
||||
|
||||
Your n8n webhook at `/webhook-test/create-meet` will receive:
|
||||
|
||||
```json
|
||||
{
|
||||
"slot_id": "uuid-of-slot",
|
||||
"date": "2025-12-25",
|
||||
"start_time": "14:00:00",
|
||||
"end_time": "15:00:00",
|
||||
"client_name": "John Doe",
|
||||
"client_email": "john@example.com",
|
||||
"topic": "Business Consulting",
|
||||
"notes": "Discuss project roadmap",
|
||||
"calendar_id": "your-calendar@gmail.com",
|
||||
"brand_name": "Your Brand",
|
||||
"test_mode": true
|
||||
}
|
||||
```
|
||||
|
||||
## Expected Response
|
||||
|
||||
Your n8n workflow should return:
|
||||
|
||||
```json
|
||||
{
|
||||
"meet_link": "https://meet.google.com/abc-defg-hij",
|
||||
"event_id": "event-id-from-google-calendar"
|
||||
}
|
||||
```
|
||||
|
||||
## Security Notes
|
||||
|
||||
1. **Never commit the service account JSON** to version control
|
||||
2. Store it securely in n8n credentials
|
||||
3. Rotate the key if compromised
|
||||
4. Only grant minimum necessary permissions to the service account
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Error: 403 Forbidden
|
||||
- Check if the calendar is shared with the service account email
|
||||
- Verify the service account has **Editor** permissions
|
||||
|
||||
### Error: 401 Unauthorized
|
||||
- Verify the service account JSON is correct
|
||||
- Check if Calendar API is enabled in Google Cloud Console
|
||||
|
||||
### Error: 400 Invalid
|
||||
- Check date/time format (should be ISO 8601)
|
||||
- Verify calendar ID is correct
|
||||
- Ensure the service account email format is correct
|
||||
|
||||
## Alternative: Use Google Calendar API Key (Less Secure)
|
||||
|
||||
If you don't want to use service accounts, you can create an API key:
|
||||
|
||||
1. Go to Google Cloud Console → **APIs & Services** → **Credentials**
|
||||
2. Click **Create Credentials** → **API Key**
|
||||
3. Restrict the key to Google Calendar API only
|
||||
4. Use it with HTTP requests
|
||||
|
||||
However, this is **not recommended** for production as it's less secure than service accounts.
|
||||
Reference in New Issue
Block a user