338 lines
7.3 KiB
Markdown
338 lines
7.3 KiB
Markdown
# 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.
|