330 lines
8.9 KiB
Markdown
330 lines
8.9 KiB
Markdown
# Git Integration Service - Complete Flow Documentation
|
|
|
|
## Overview
|
|
This document describes the complete flow of the git-integration service for attaching GitHub repositories.
|
|
|
|
## Configuration
|
|
|
|
### Environment Variables
|
|
- `GITHUB_CLIENT_ID`: OAuth App Client ID
|
|
- `GITHUB_CLIENT_SECRET`: OAuth App Client Secret
|
|
- `GITHUB_REDIRECT_URI`: OAuth callback URL (http://localhost:8000/api/github/auth/github/callback)
|
|
- `GITHUB_WEBHOOK_SECRET`: mywebhooksecret2025
|
|
- `PUBLIC_BASE_URL`: https://98fa7f21e2e9.ngrok-free.app (your ngrok URL)
|
|
- `ATTACHED_REPOS_DIR`: /app/git-repos
|
|
- `DIFF_STORAGE_DIR`: /app/git-repos/diffs
|
|
- `FRONTEND_URL`: http://localhost:3001
|
|
|
|
### Storage Location
|
|
- **Container Path**: `/app/git-repos`
|
|
- **Host Path**: `/home/tech4biz/Desktop/today work/git-repo`
|
|
- **Repository Format**: `owner__REPONAME__branch/`
|
|
|
|
## Complete User Flow
|
|
|
|
### 1. User Attaches Repository
|
|
|
|
**Endpoint**: `POST /api/github/attach-repository`
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"repository_url": "https://github.com/owner/repo",
|
|
"branch_name": "main"
|
|
}
|
|
```
|
|
|
|
**Headers**:
|
|
- `x-user-id`: User's unique ID
|
|
|
|
### 2. Public/Private Detection
|
|
|
|
The service automatically detects if the repository is public or private:
|
|
|
|
#### For Public Repositories:
|
|
1. ✅ Attempts unauthenticated access via GitHub API
|
|
2. ✅ If successful, proceeds to clone without OAuth
|
|
3. ✅ Clones repository using `git clone` (full clone with .git directory)
|
|
4. ✅ Stores all files including .git folder
|
|
5. ✅ Creates webhook automatically (if PUBLIC_BASE_URL is set)
|
|
|
|
#### For Private Repositories:
|
|
1. ❌ Unauthenticated access fails (404 error)
|
|
2. 🔐 Checks if user has GitHub OAuth token
|
|
3. **If NOT authenticated**:
|
|
- Returns 401 with OAuth URL
|
|
- User is redirected to GitHub for authentication
|
|
4. **If authenticated**:
|
|
- Uses OAuth token to access repository
|
|
- Proceeds to clone with authentication
|
|
|
|
### 3. GitHub OAuth Flow (Private Repos Only)
|
|
|
|
**Step 1: Initiate OAuth**
|
|
- Frontend receives auth_url from backend
|
|
- User clicks "Connect GitHub" button
|
|
- Redirects to: `http://localhost:8000/api/github/auth/github?redirect=1&user_id={userId}&state={state}`
|
|
|
|
**Step 2: GitHub Authorization**
|
|
- User authorizes the app on GitHub
|
|
- GitHub redirects to callback URL with authorization code
|
|
|
|
**Step 3: OAuth Callback**
|
|
- Endpoint: `GET /api/github/auth/github/callback`
|
|
- Exchanges code for access token
|
|
- Stores token in database (table: `github_user_tokens`)
|
|
- **Auto-attaches repository** if state contains repo context
|
|
- Redirects back to frontend: `{FRONTEND_URL}/project-builder?github_connected=1&repo_attached=1`
|
|
|
|
### 4. Repository Cloning
|
|
|
|
**Clone Method**: Full git clone (includes .git directory)
|
|
|
|
**For Public Repos**:
|
|
```bash
|
|
git clone -b {branch} https://github.com/{owner}/{repo}.git
|
|
```
|
|
|
|
**For Private Repos**:
|
|
```bash
|
|
git clone -b {branch} https://oauth2:{token}@github.com/{owner}/{repo}.git
|
|
```
|
|
|
|
**Storage Structure**:
|
|
```
|
|
/home/tech4biz/Desktop/today work/git-repo/
|
|
├── owner__REPONAME__branch/
|
|
│ ├── .git/ # ✅ Full git history included
|
|
│ ├── src/
|
|
│ ├── package.json
|
|
│ └── ... (all files)
|
|
└── diffs/ # Diff storage for webhooks
|
|
```
|
|
|
|
### 5. File Storage in Database
|
|
|
|
Files are stored using the **optimized JSON schema** (migration 003):
|
|
|
|
**Table: `repository_files`**
|
|
- One row per directory
|
|
- All files in a directory stored as JSON array
|
|
- Unique constraint on `directory_id`
|
|
|
|
**Example**:
|
|
```json
|
|
{
|
|
"directory_id": "uuid-123",
|
|
"relative_path": "src/components",
|
|
"files": [
|
|
{
|
|
"filename": "Header.tsx",
|
|
"file_extension": ".tsx",
|
|
"file_size_bytes": 1024,
|
|
"is_binary": false,
|
|
"mime_type": "text/plain"
|
|
},
|
|
{
|
|
"filename": "Footer.tsx",
|
|
"file_extension": ".tsx",
|
|
"file_size_bytes": 512,
|
|
"is_binary": false,
|
|
"mime_type": "text/plain"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### 6. Automatic Webhook Creation
|
|
|
|
After successful repository attachment, the service automatically creates a webhook:
|
|
|
|
**Webhook Configuration**:
|
|
- **URL**: `https://98fa7f21e2e9.ngrok-free.app/api/github/webhook`
|
|
- **Secret**: `mywebhooksecret2025`
|
|
- **Events**: `push`
|
|
- **Content Type**: `application/json`
|
|
|
|
**Webhook Endpoint**: `POST /api/github/webhook`
|
|
|
|
**What happens on push**:
|
|
1. GitHub sends webhook payload
|
|
2. Service verifies signature using webhook secret
|
|
3. Processes commit changes
|
|
4. Updates repository files in database
|
|
5. Stores diff information
|
|
|
|
### 7. Response to Frontend
|
|
|
|
**Success Response** (201):
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Repository attached and synced successfully",
|
|
"data": {
|
|
"repository_id": "uuid-456",
|
|
"repository_name": "repo",
|
|
"owner_name": "owner",
|
|
"branch_name": "main",
|
|
"is_public": true,
|
|
"sync_status": "synced",
|
|
"webhook_result": {
|
|
"created": true,
|
|
"hook_id": 12345
|
|
},
|
|
"storage_info": {
|
|
"total_files": 150,
|
|
"total_directories": 25,
|
|
"total_size_bytes": 1048576
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Auth Required Response** (401):
|
|
```json
|
|
{
|
|
"success": false,
|
|
"message": "GitHub authentication required for private repository",
|
|
"requires_auth": true,
|
|
"auth_url": "http://localhost:8000/api/github/auth/github?redirect=1&state=...",
|
|
"repository_info": {
|
|
"owner": "owner",
|
|
"repo": "repo",
|
|
"repository_url": "https://github.com/owner/repo",
|
|
"branch_name": "main"
|
|
}
|
|
}
|
|
```
|
|
|
|
## Frontend Integration Guide
|
|
|
|
### Step 1: Attach Repository Request
|
|
|
|
```typescript
|
|
const attachRepository = async (repoUrl: string, branch: string, userId: string) => {
|
|
const response = await fetch('http://localhost:8000/api/github/attach-repository', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'x-user-id': userId
|
|
},
|
|
body: JSON.stringify({
|
|
repository_url: repoUrl,
|
|
branch_name: branch
|
|
})
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (response.status === 401 && data.requires_auth) {
|
|
// Redirect to OAuth
|
|
window.location.href = data.auth_url;
|
|
} else if (response.status === 201) {
|
|
// Success - repository attached
|
|
console.log('Repository attached:', data.data);
|
|
}
|
|
};
|
|
```
|
|
|
|
### Step 2: Handle OAuth Redirect
|
|
|
|
```typescript
|
|
// In your /project-builder page
|
|
useEffect(() => {
|
|
const params = new URLSearchParams(window.location.search);
|
|
|
|
if (params.get('github_connected') === '1') {
|
|
// GitHub connected successfully
|
|
const repoAttached = params.get('repo_attached') === '1';
|
|
const repositoryId = params.get('repository_id');
|
|
const syncStatus = params.get('sync_status');
|
|
|
|
if (repoAttached) {
|
|
// Repository was auto-attached after OAuth
|
|
console.log('Repository attached:', repositoryId, syncStatus);
|
|
}
|
|
}
|
|
}, []);
|
|
```
|
|
|
|
### Step 3: Display Repository Data
|
|
|
|
```typescript
|
|
const getRepositoryFiles = async (repositoryId: string) => {
|
|
const response = await fetch(
|
|
`http://localhost:8000/api/github/repository/${repositoryId}/files`
|
|
);
|
|
|
|
const data = await response.json();
|
|
return data.data; // File structure
|
|
};
|
|
```
|
|
|
|
## Database Schema
|
|
|
|
### Main Tables
|
|
|
|
1. **all_repositories**: Repository metadata
|
|
2. **repository_storage**: Storage tracking
|
|
3. **repository_directories**: Directory structure
|
|
4. **repository_files**: Files as JSON arrays (one row per directory)
|
|
5. **github_user_tokens**: OAuth tokens
|
|
6. **github_webhooks**: Webhook event logs
|
|
|
|
## Key Features
|
|
|
|
✅ **Public/Private Detection**: Automatic detection and handling
|
|
✅ **OAuth Flow**: Seamless GitHub authentication
|
|
✅ **Full Git Clone**: Includes .git directory and complete history
|
|
✅ **Automatic Webhooks**: Auto-creates webhooks with ngrok URL
|
|
✅ **JSON Storage**: Optimized file storage in database
|
|
✅ **Auto-Attach**: Repository automatically attached after OAuth
|
|
✅ **Frontend Redirect**: Redirects back to your app after OAuth
|
|
|
|
## Testing the Flow
|
|
|
|
1. Start the services:
|
|
```bash
|
|
docker compose up -d --build git-integration
|
|
```
|
|
|
|
2. Try attaching a public repository:
|
|
```bash
|
|
curl -X POST http://localhost:8000/api/github/attach-repository \
|
|
-H "Content-Type: application/json" \
|
|
-H "x-user-id: your-user-id" \
|
|
-d '{"repository_url": "https://github.com/octocat/Hello-World", "branch_name": "master"}'
|
|
```
|
|
|
|
3. Try attaching a private repository:
|
|
- Will return auth_url
|
|
- Visit the auth_url in browser
|
|
- Authorize on GitHub
|
|
- Will redirect back and auto-attach
|
|
|
|
4. Check stored files:
|
|
```bash
|
|
ls -la "/home/tech4biz/Desktop/today work/git-repo/"
|
|
```
|
|
|
|
5. Verify webhook was created:
|
|
- Go to GitHub repository → Settings → Webhooks
|
|
- Should see webhook with your ngrok URL
|
|
|
|
## Troubleshooting
|
|
|
|
### Repository not cloning
|
|
- Check ATTACHED_REPOS_DIR permissions
|
|
- Verify OAuth token is valid
|
|
- Check git-integration service logs
|
|
|
|
### Webhook not created
|
|
- Verify PUBLIC_BASE_URL is set correctly
|
|
- Check OAuth token has admin:repo_hook scope
|
|
- Verify ngrok is running and accessible
|
|
|
|
### OAuth redirect not working
|
|
- Check FRONTEND_URL environment variable
|
|
- Verify GITHUB_REDIRECT_URI matches GitHub App settings
|
|
- Check browser console for errors
|