diff --git a/plans/PHASE_1_PLAN.md b/plans/PHASE_1_PLAN.md index 1c78af9..d7550f8 100644 --- a/plans/PHASE_1_PLAN.md +++ b/plans/PHASE_1_PLAN.md @@ -1,337 +1,337 @@ -# Gitocean Phase 1 Plan: MVP - -Phase 1 focuses on building the minimum viable Git hosting platform: CLI + API only, MySQL metadata, repositories stored on disk, HTTP Smart Git transport, public/private repositories, search, forks, and pull requests. - -This phase intentionally avoids a web UI, SSH Git transport, organizations, teams, CI/CD, and enterprise features. The goal is a working personal Git hosting foundation. - -## Goals - -- Build a Go-based Git repository hosting platform. -- Store bare repositories under `storage/repos/{owner}/{repo}.git`. -- Use MySQL for metadata. -- Support HTTP Smart Git clone/fetch/push. -- Provide CLI-based registration, login, repository management, search, forks, and pull requests. -- Support public and private repositories. -- Use temporary 7-day API/Git auth tokens. -- Keep permissions simple: owner-only writes and private access in MVP. - ---- - -## 1. Product decisions - -### Platform shape - -- Gitocean is a CLI + API Git hosting system. -- No Web UI in Phase 1. -- No SSH Git transport in Phase 1. -- Repositories are stored as bare Git repositories on disk. -- Metadata is stored in MySQL. - -### Registration and login - -- Registration is open. -- Users register with: - - email - - username - - password -- Users can log in with either: - - email + password - - username + password -- Login returns a temporary token that expires after 7 days. -- The CLI stores the token locally for API calls. -- The CLI can approve the token into Git's credential helper for HTTP Git operations. - -### Naming defaults - -- CLI binary name: `gitocean`. -- Default branch: `main`. -- Repository names allow lowercase letters, numbers, `.`, `_`, and `-`. -- Usernames allow lowercase letters, numbers, `_`, and `-`. -- Pull request numbers are scoped per target repository. - ---- - -## 2. Permissions - -### Repository visibility - -Public repositories: - -- Anyone can clone/fetch. -- Only the owner can push. -- Only the owner can delete or manage settings. - -Private repositories: - -- Only the owner can clone/fetch. -- Only the owner can push. -- Only the owner can delete or manage settings. - -### Writes - -- Phase 1 uses owner-only writes. -- No collaborators, organizations, teams, or fine-grained permissions yet. -- Outside collaboration happens through pull requests against public repositories. - ---- - -## 3. Storage layout - -Repositories live under: - -```text -storage/repos/{owner}/{repo}.git -``` - -Example: - -```text -storage/ - repos/ - alice/ - demo.git/ - bob/ - project.git/ -``` - -Each repository directory is a bare Git repository created with `git init --bare`. - ---- - -## 4. MySQL schema - -Core tables: - -### `users` - -- `id` -- `email` -- `username` -- `password_hash` -- `created_at` - -### `auth_tokens` - -- `id` -- `user_id` -- `token_hash` -- `expires_at` -- `revoked_at` -- `created_at` - -### `repositories` - -- `id` -- `owner_user_id` -- `name` -- `visibility`: `public` or `private` -- `forked_from_repository_id` nullable -- `created_at` -- `updated_at` - -### `pull_requests` - -- `id` -- `target_repository_id` -- `number` -- `author_user_id` -- `source_repository_id` -- `source_branch` -- `target_branch` -- `title` -- `description` -- `status`: `open`, `closed`, or `merged` -- `closed_at` nullable -- `merged_at` nullable -- `created_at` -- `updated_at` - ---- - -## 5. API routes - -### Auth - -```http -POST /api/register -POST /api/login -POST /api/logout -GET /api/me -``` - -### Repositories - -```http -POST /api/repos -GET /api/repos/search?q=demo&scope=all -GET /api/repos/search?q=demo&scope=mine -GET /api/repos/{owner}/{repo} -DELETE /api/repos/{owner}/{repo}?force=false -POST /api/repos/{owner}/{repo}/fork -``` - -### Pull requests - -```http -POST /api/repos/{owner}/{repo}/pulls -GET /api/repos/{owner}/{repo}/pulls -GET /api/repos/{owner}/{repo}/pulls/{number} -POST /api/repos/{owner}/{repo}/pulls/{number}/close -POST /api/repos/{owner}/{repo}/pulls/{number}/merge -``` - -### Git HTTP - -```http -/{owner}/{repo}.git/info/refs -/{owner}/{repo}.git/git-upload-pack -/{owner}/{repo}.git/git-receive-pack -``` - ---- - -## 6. CLI commands - -### Server - -```bash -gitocean server --addr :8080 --dsn 'user:pass@tcp(127.0.0.1:3306)/gitocean?parseTime=true' --storage storage -``` - -### Auth - -```bash -gitocean register -gitocean login -gitocean logout -gitocean whoami -``` - -### Repositories - -```bash -gitocean repo create NAME --public -gitocean repo create NAME --private -gitocean repo delete OWNER/NAME [--force] -gitocean repo search QUERY --all -gitocean repo search QUERY --mine -gitocean repo fork OWNER/NAME [--name NEW_NAME] -``` - -### Clone - -```bash -gitocean clone OWNER/NAME -``` - -### Pull requests - -```bash -gitocean pr create --from OWNER/REPO:BRANCH --to OWNER/REPO:BRANCH --title TITLE --description DESC -gitocean pr create --repo OWNER/REPO --from BRANCH --to BRANCH --title TITLE --description DESC -gitocean pr list OWNER/REPO -gitocean pr view OWNER/REPO NUMBER -gitocean pr close OWNER/REPO NUMBER -gitocean pr merge OWNER/REPO NUMBER -``` - ---- - -## 7. Git HTTP behavior - -Use Git's built-in Smart HTTP backend: - -```bash -git http-backend -``` - -Required behavior: - -- Public clone/fetch works without auth. -- Private clone/fetch requires owner auth. -- Push always requires auth. -- Push is owner-only. -- Git username is the account username. -- Git password is the 7-day token. - ---- - -## 8. Fork behavior - -- Logged-in users can fork public repositories. -- Private repositories can only be forked by the owner in Phase 1. -- Forks are copied as bare repositories under the new owner's storage path. -- Fork metadata stores `forked_from_repository_id`. - ---- - -## 9. Pull request rules - -### Same-repository PRs - -- Source and target repository are the same. -- Only the repository owner can create same-repo PRs. -- Source and target branches must both exist. - -### Cross-repository PRs - -- Source repository branch points to target repository branch. -- Source repository must be owned by the PR author. -- Target repository must be public, unless the author is also the target owner. -- Source and target branches must both exist. -- Only the target repository owner can close or merge the PR. - ---- - -## 10. Merge behavior - -Phase 1 merge mode is a normal merge commit: - -1. Clone the target repo into a temporary worktree. -2. Checkout the target branch. -3. Add/fetch the source repo branch. -4. Run `git merge --no-ff FETCH_HEAD`. -5. Push the result back to the target branch. -6. Mark the PR as merged. - -If conflicts occur: - -- Return an error. -- Keep the PR open. -- Do not modify PR status. - ---- - -## 11. Implementation milestones - -1. Project scaffold and build setup. -2. MySQL migrations. -3. User registration, login, logout, and token auth. -4. Repository create, delete, detail, and search. -5. HTTP Smart Git integration using `git http-backend`. -6. CLI auth and repository commands. -7. Fork support. -8. Pull request create/list/view/close. -9. Pull request merge. -10. Tests, hardening, and UX polish. - ---- - -## Phase 1 completion criteria - -Phase 1 is complete when: - -- The server starts with MySQL metadata storage. -- Missing MySQL databases can be created automatically. -- Users can register, login, logout, and run `whoami`. -- Login tokens expire after 7 days. -- Users can create public/private repositories. -- Public repositories can be cloned/fetched without auth. -- Private repositories require owner auth. -- Owners can push over HTTP. -- Non-owners cannot push. -- Users can search visible repositories. -- Users can fork allowed repositories. -- Users can create, list, view, close, and merge pull requests. -- `go test ./...` passes. -- `go vet ./...` passes. +# Gitocean Phase 1 Plan: MVP + +Phase 1 focuses on building the minimum viable Git hosting platform: CLI + API only, MySQL metadata, repositories stored on disk, HTTP Smart Git transport, public/private repositories, search, forks, and pull requests. + +This phase intentionally avoids a web UI, SSH Git transport, organizations, teams, CI/CD, and enterprise features. The goal is a working personal Git hosting foundation. + +## Goals + +- Build a Go-based Git repository hosting platform. +- Store bare repositories under `storage/repos/{owner}/{repo}.git`. +- Use MySQL for metadata. +- Support HTTP Smart Git clone/fetch/push. +- Provide CLI-based registration, login, repository management, search, forks, and pull requests. +- Support public and private repositories. +- Use temporary 7-day API/Git auth tokens. +- Keep permissions simple: owner-only writes and private access in MVP. + +--- + +## 1. Product decisions + +### Platform shape + +- Gitocean is a CLI + API Git hosting system. +- No Web UI in Phase 1. +- No SSH Git transport in Phase 1. +- Repositories are stored as bare Git repositories on disk. +- Metadata is stored in MySQL. + +### Registration and login + +- Registration is open. +- Users register with: + - email + - username + - password +- Users can log in with either: + - email + password + - username + password +- Login returns a temporary token that expires after 7 days. +- The CLI stores the token locally for API calls. +- The CLI can approve the token into Git's credential helper for HTTP Git operations. + +### Naming defaults + +- CLI binary name: `gitocean`. +- Default branch: `main`. +- Repository names allow lowercase letters, numbers, `.`, `_`, and `-`. +- Usernames allow lowercase letters, numbers, `_`, and `-`. +- Pull request numbers are scoped per target repository. + +--- + +## 2. Permissions + +### Repository visibility + +Public repositories: + +- Anyone can clone/fetch. +- Only the owner can push. +- Only the owner can delete or manage settings. + +Private repositories: + +- Only the owner can clone/fetch. +- Only the owner can push. +- Only the owner can delete or manage settings. + +### Writes + +- Phase 1 uses owner-only writes. +- No collaborators, organizations, teams, or fine-grained permissions yet. +- Outside collaboration happens through pull requests against public repositories. + +--- + +## 3. Storage layout + +Repositories live under: + +```text +storage/repos/{owner}/{repo}.git +``` + +Example: + +```text +storage/ + repos/ + alice/ + demo.git/ + bob/ + project.git/ +``` + +Each repository directory is a bare Git repository created with `git init --bare`. + +--- + +## 4. MySQL schema + +Core tables: + +### `users` + +- `id` +- `email` +- `username` +- `password_hash` +- `created_at` + +### `auth_tokens` + +- `id` +- `user_id` +- `token_hash` +- `expires_at` +- `revoked_at` +- `created_at` + +### `repositories` + +- `id` +- `owner_user_id` +- `name` +- `visibility`: `public` or `private` +- `forked_from_repository_id` nullable +- `created_at` +- `updated_at` + +### `pull_requests` + +- `id` +- `target_repository_id` +- `number` +- `author_user_id` +- `source_repository_id` +- `source_branch` +- `target_branch` +- `title` +- `description` +- `status`: `open`, `closed`, or `merged` +- `closed_at` nullable +- `merged_at` nullable +- `created_at` +- `updated_at` + +--- + +## 5. API routes + +### Auth + +```http +POST /api/register +POST /api/login +POST /api/logout +GET /api/me +``` + +### Repositories + +```http +POST /api/repos +GET /api/repos/search?q=demo&scope=all +GET /api/repos/search?q=demo&scope=mine +GET /api/repos/{owner}/{repo} +DELETE /api/repos/{owner}/{repo}?force=false +POST /api/repos/{owner}/{repo}/fork +``` + +### Pull requests + +```http +POST /api/repos/{owner}/{repo}/pulls +GET /api/repos/{owner}/{repo}/pulls +GET /api/repos/{owner}/{repo}/pulls/{number} +POST /api/repos/{owner}/{repo}/pulls/{number}/close +POST /api/repos/{owner}/{repo}/pulls/{number}/merge +``` + +### Git HTTP + +```http +/{owner}/{repo}.git/info/refs +/{owner}/{repo}.git/git-upload-pack +/{owner}/{repo}.git/git-receive-pack +``` + +--- + +## 6. CLI commands + +### Server + +```bash +gitocean server --addr :8080 --dsn 'user:pass@tcp(127.0.0.1:3306)/gitocean?parseTime=true' --storage storage +``` + +### Auth + +```bash +gitocean register +gitocean login +gitocean logout +gitocean whoami +``` + +### Repositories + +```bash +gitocean repo create NAME --public +gitocean repo create NAME --private +gitocean repo delete OWNER/NAME [--force] +gitocean repo search QUERY --all +gitocean repo search QUERY --mine +gitocean repo fork OWNER/NAME [--name NEW_NAME] +``` + +### Clone + +```bash +gitocean clone OWNER/NAME +``` + +### Pull requests + +```bash +gitocean pr create --from OWNER/REPO:BRANCH --to OWNER/REPO:BRANCH --title TITLE --description DESC +gitocean pr create --repo OWNER/REPO --from BRANCH --to BRANCH --title TITLE --description DESC +gitocean pr list OWNER/REPO +gitocean pr view OWNER/REPO NUMBER +gitocean pr close OWNER/REPO NUMBER +gitocean pr merge OWNER/REPO NUMBER +``` + +--- + +## 7. Git HTTP behavior + +Use Git's built-in Smart HTTP backend: + +```bash +git http-backend +``` + +Required behavior: + +- Public clone/fetch works without auth. +- Private clone/fetch requires owner auth. +- Push always requires auth. +- Push is owner-only. +- Git username is the account username. +- Git password is the 7-day token. + +--- + +## 8. Fork behavior + +- Logged-in users can fork public repositories. +- Private repositories can only be forked by the owner in Phase 1. +- Forks are copied as bare repositories under the new owner's storage path. +- Fork metadata stores `forked_from_repository_id`. + +--- + +## 9. Pull request rules + +### Same-repository PRs + +- Source and target repository are the same. +- Only the repository owner can create same-repo PRs. +- Source and target branches must both exist. + +### Cross-repository PRs + +- Source repository branch points to target repository branch. +- Source repository must be owned by the PR author. +- Target repository must be public, unless the author is also the target owner. +- Source and target branches must both exist. +- Only the target repository owner can close or merge the PR. + +--- + +## 10. Merge behavior + +Phase 1 merge mode is a normal merge commit: + +1. Clone the target repo into a temporary worktree. +2. Checkout the target branch. +3. Add/fetch the source repo branch. +4. Run `git merge --no-ff FETCH_HEAD`. +5. Push the result back to the target branch. +6. Mark the PR as merged. + +If conflicts occur: + +- Return an error. +- Keep the PR open. +- Do not modify PR status. + +--- + +## 11. Implementation milestones + +1. Project scaffold and build setup. +2. MySQL migrations. +3. User registration, login, logout, and token auth. +4. Repository create, delete, detail, and search. +5. HTTP Smart Git integration using `git http-backend`. +6. CLI auth and repository commands. +7. Fork support. +8. Pull request create/list/view/close. +9. Pull request merge. +10. Tests, hardening, and UX polish. + +--- + +## Phase 1 completion criteria + +Phase 1 is complete when: + +- The server starts with MySQL metadata storage. +- Missing MySQL databases can be created automatically. +- Users can register, login, logout, and run `whoami`. +- Login tokens expire after 7 days. +- Users can create public/private repositories. +- Public repositories can be cloned/fetched without auth. +- Private repositories require owner auth. +- Owners can push over HTTP. +- Non-owners cannot push. +- Users can search visible repositories. +- Users can fork allowed repositories. +- Users can create, list, view, close, and merge pull requests. +- `go test ./...` passes. +- `go vet ./...` passes.