Refactor codebase for Phase 3
This commit is contained in:
@@ -0,0 +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.
|
||||
Reference in New Issue
Block a user