> ## Documentation Index
> Fetch the complete documentation index at: https://docs.scriptonia.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Github integration

# GitHub Integration

GitHub OAuth, project export, repository creation, and practices.

***

## GitHub OAuth Setup

### 1. OAuth App

1. Open [GitHub Developer Settings](https://github.com/settings/developers) → **OAuth Apps** → **New OAuth App**.
2. **Homepage URL:** `https://your-domain` or `http://localhost:3000` for local.
3. **Authorization callback URL:**
   * Production: `https://your-domain/api/github/callback`
   * Local: `http://localhost:3000/api/github/callback`

***

### 2. Environment variables

```
GITHUB_CLIENT_ID=your_client_id
GITHUB_CLIENT_SECRET=your_client_secret
GITHUB_CALLBACK_URL=https://your-domain/api/github/callback
```

For local dev: `GITHUB_CALLBACK_URL=http://localhost:3000/api/github/callback`.

If `GITHUB_CALLBACK_URL` is unset, the code uses\
`${NEXT_PUBLIC_SITE_URL || 'http://localhost:3000'}/api/github/callback`.

***

## OAuth Flow

### 1. Start authorization

**GET** `/api/github/authorize?sessionId=...`

* Requires `sessionId` (workflow session).
* Builds `state` from `{ sessionId }` (base64), stores it in cookie `github_oauth_state` (HttpOnly, 10 min).
* Redirects to:

  ```
  https://github.com/login/oauth/authorize?client_id=...&redirect_uri=...&scope=repo&state=...

  ```
* `scope=repo` — full control of private repos (create, push, etc.).

***

### 2. Callback

**GET** `/api/github/callback?code=...&state=...`

* Verifies `state` against `github_oauth_state` cookie.
* Decodes `state` to get `sessionId`.
* Exchanges `code` for `access_token` via `https://github.com/login/oauth/access_token`.
* Fetches user with `https://api.github.com/user`.
* Sets cookies:
  * `github_access_token` — HttpOnly, 30 days
  * `github_user` — username
  * Clears `github_oauth_state`
* Redirects to: `/execution?sessionId=...&githubConnected=true` (or `&githubError=...` on failure).

***

### 3. Connection status

**GET** `/api/github/status`

* Reads `github_access_token` and `github_user` from cookies.
* If token present, calls `https://api.github.com/user` to check it. On 4xx, clears the auth cookies and returns `connected: false`.
* Response: `{ connected: true, username }` or `{ connected: false, error? }`.

***

## Project Export and Upload

### Download (ZIP)

**GET** `/api/projects/download?sessionId=...`

* Prefer: read ZIP from `ZipFile` (DB) for `sessionId`. If found, stream `fileData` as `application/zip` with `Content-Disposition: attachment; filename="..."`.
* Fallback: build ZIP from `projects/{sessionId}` on disk (or `PROJECTS_DIR/projects/{sessionId}` if `PROJECTS_DIR` is set). Project name for the filename comes from `refinedRequirements.title` or `sessionId`.

The **generate** step (`POST /api/projects/generate`) writes files under `{PROJECTS_DIR||os.tmpdir()}/projects/{sessionId}` and can also store the ZIP in `ZipFile`. For download to use the filesystem fallback, that path must exist and match what the server can read.

***

### Upload to GitHub

**POST** `/api/github/upload`

**Body:** `{ sessionId, repoName?, repoDescription?, isPrivate? }`

* **Auth:** `github_access_token` cookie (from OAuth). If missing → 401.
* **Repository:**
  * `repoName` default: `scriptonia-project-{first 8 chars of sessionId}`.
  * `repoDescription` default: `Project generated by Scriptonia`.
  * `private`: `isPrivate === true`.
* **Source of files:** `join(process.cwd(), 'projects', sessionId)`. The handler reads from that directory recursively (skips `node_modules`, `.git`, `.next`, `.`, etc.). Text files use `utf-8`, others `base64`.
* **GitHub flow:**
  1. `POST /user/repos` — create repo, `auto_init: false`.
  2. For each file: `POST /repos/{full_name}/git/blobs` (content + encoding).
  3. `POST /repos/{full_name}/git/trees` with the blob SHAs.
  4. `POST /repos/{full_name}/git/commits` with the tree and message `Initial commit: Project generated by Scriptonia`.
  5. `PATCH /repos/{full_name}/git/refs/heads/main` (or `POST /refs` if the ref does not exist) to point at the commit.
* **Response:** `{ status: 'success', message, repositoryUrl }` or `{ status: 'error', error }`.

For upload to find files, the project must exist at `projects/{sessionId}` under the app’s `process.cwd()`. Ensure the generate/execution pipeline writes there, or that you configure `PROJECTS_DIR` and any file-writing logic so the same directory is used.

***

## Repository Creation

* Repos are created via GitHub’s **Create a repository** API with:
  * `name`, `description`, `private`, `auto_init: false`
* First commit uses the Git Data API: blobs → tree → commit → update `main` (or create the ref). No `.git` on disk is required.

***

## Best Practices

### 1. Callback URL

* Must exactly match the OAuth App’s **Authorization callback URL** (including `/api/github/callback`).
* Use HTTPS in production. For localhost, `http://localhost:3000` is fine.

***

### 2. State and cookies

* `state` is bound to `sessionId` and checked in the callback. Keep `sessionId` in `state` so the redirect can return the user to the right workflow.
* `github_oauth_state` is short-lived (10 min) and cleared after use. `github_access_token` is 30 days; `/api/github/status` invalidates it when GitHub returns 4xx.

***

### 3. Scope

* `repo` is broad (private repos, delete, etc.). If you only need to create and push to new repos, consider whether a more limited GitHub App or a different scope is better; the current implementation uses `repo`.

***

### 4. Where files come from

* **Upload** reads from `process.cwd()/projects/{sessionId}`.
* **Generate** writes to `{PROJECTS_DIR||os.tmpdir()}/projects/{sessionId}` and can also store a ZIP in `ZipFile`.
* Align these (e.g. set `PROJECTS_DIR` to `process.cwd()` and ensure generate writes there) so upload finds the project. If you only persist in `ZipFile`, you’d need to extract to `projects/{sessionId}` (or change upload) before calling upload.

***

### 5. Token storage

* Tokens are in HttpOnly cookies. For stronger security, move to a server-side session or DB keyed by user/session, and limit cookie scope/path.

***

### 6. Errors

* Upload can fail with “Project files not found” if `projects/{sessionId}` is missing or empty.
* “GitHub not connected” means the auth cookies are missing or cleared.
* GitHub API errors (e.g. repo name taken, 403) are returned in `error`.
