Initial: project plan
This commit is contained in:
169
PROJECT_PLAN.md
Normal file
169
PROJECT_PLAN.md
Normal file
@@ -0,0 +1,169 @@
|
||||
# GiteaCustomApi
|
||||
|
||||
Gitea repository metadata cache + query API for git.hangman-lab.top.
|
||||
|
||||
## Overview
|
||||
|
||||
A lightweight Go service that:
|
||||
- Caches repository metadata (id, name, owner, visibility, url) from Gitea MySQL database
|
||||
- Refreshes every 5 hours via full sync
|
||||
- Listens for Gitea webhook events (repo create/delete) for real-time cache updates
|
||||
- Exposes a `/list?username=xxx` endpoint that queries cached repos + live collaborator permissions from MySQL
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ VPS.git │
|
||||
│ ┌──────────────┐ ┌─────────────┐ ┌──────────────────┐ │
|
||||
│ │ Gitea DB │ │ go-server │ │ Nginx │ │
|
||||
│ │ (MySQL) │◄──│ (cache+api) │ │ /c-api -> :8080 │ │
|
||||
│ └──────────────┘ └─────────────┘ └──────────────────┘ │
|
||||
│ ▲ │
|
||||
│ ┌────────┴────────┐ │
|
||||
│ │ Gitea Webhook │ │
|
||||
│ │ (create/delete)│ │
|
||||
│ └─────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Tech Stack
|
||||
|
||||
- **Language**: Go
|
||||
- **Database**: SQLite (local cache)
|
||||
- **Source DB**: Gitea MySQL (read-only, same docker network)
|
||||
- **HTTP**: Standard library `net/http`
|
||||
- **Deployment**: Docker + Docker Compose on vps.git
|
||||
|
||||
## API
|
||||
|
||||
### `GET /list?username={username}`
|
||||
|
||||
Returns all repositories visible to the given Gitea user.
|
||||
|
||||
**Response** (JSON):
|
||||
```json
|
||||
[
|
||||
{
|
||||
"name": "ClawSkills",
|
||||
"owner": "lyn",
|
||||
"url": "https://git.hangman-lab.top/lyn/ClawSkills.git",
|
||||
"is_private": false,
|
||||
"can_write": true
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
`can_write` is determined at query time by checking:
|
||||
- User is the repo owner, OR
|
||||
- User has explicit access via `access` table, OR
|
||||
- User is a member of a team that has access to the repo
|
||||
|
||||
### `POST /webhook/gitea`
|
||||
|
||||
Receives Gitea webhook events (requires `X-Gitea-Event` header).
|
||||
|
||||
Supported events:
|
||||
- `repository.create` — insert new repo into cache
|
||||
- `repository.delete` — remove repo from cache
|
||||
|
||||
### `GET /health`
|
||||
|
||||
Returns `{"status": "ok"}`.
|
||||
|
||||
## Data Model
|
||||
|
||||
### SQLite cache table: `repos`
|
||||
|
||||
| Column | Type | Notes |
|
||||
|--------------|---------|------------------------------|
|
||||
| id | INTEGER | Gitea repo ID (primary key) |
|
||||
| name | TEXT | |
|
||||
| owner | TEXT | Gitea username of owner |
|
||||
| is_private | INTEGER | 0 or 1 |
|
||||
| url | TEXT | Full .git HTTPS URL |
|
||||
| updated_at | INTEGER | Unix timestamp of last sync |
|
||||
|
||||
## Configuration
|
||||
|
||||
Environment variables:
|
||||
|
||||
| Variable | Default | Description |
|
||||
|---------------|---------|------------------------------|
|
||||
| `DB_HOST` | `mysql` | MySQL container hostname |
|
||||
| `DB_USER` | `root` | MySQL username |
|
||||
| `DB_PASS` | — | MySQL password |
|
||||
| `DB_NAME` | `giteadb` | MySQL database name |
|
||||
| `SQLITE_PATH` | `cache.db` | SQLite file path |
|
||||
| `WEBHOOK_SECRET` | — | Gitea webhook secret token |
|
||||
| `PORT` | `8080` | HTTP listen port |
|
||||
|
||||
## Docker
|
||||
|
||||
### Dockerfile
|
||||
|
||||
```dockerfile
|
||||
FROM golang:1.22-alpine AS build
|
||||
WORKDIR /app
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
COPY *.go ./
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -o server .
|
||||
CMD ["./server"]
|
||||
```
|
||||
|
||||
### docker-compose.yml (fragment to merge into vps.git compose)
|
||||
|
||||
```yaml
|
||||
services:
|
||||
gitea-custom-api:
|
||||
build: ./gitea-custom-api
|
||||
container_name: gitea-custom-api
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
DB_HOST: mysql
|
||||
DB_USER: root
|
||||
DB_PASS: ${MYSQL_ROOT_PASSWORD}
|
||||
DB_NAME: giteadb
|
||||
SQLITE_PATH: /data/cache.db
|
||||
WEBHOOK_SECRET: ${GITEA_WEBHOOK_SECRET}
|
||||
PORT: 8080
|
||||
volumes:
|
||||
- ./gitea-custom-api/data:/data
|
||||
networks:
|
||||
- git-network
|
||||
|
||||
networks:
|
||||
git-network:
|
||||
external: true
|
||||
```
|
||||
|
||||
### Nginx location (merge into vps.git nginx config)
|
||||
|
||||
```nginx
|
||||
location /c-api/ {
|
||||
proxy_pass http://localhost:8080/;
|
||||
}
|
||||
```
|
||||
|
||||
## Gitea Webhook Setup
|
||||
|
||||
In Gitea admin panel → Webhooks → Add webhook:
|
||||
- **URL**: `https://git.hangman-lab.top/c-api/webhook/gitea`
|
||||
- **HTTP Method**: POST
|
||||
- **Content Type**: `application/json`
|
||||
- **Secret**: set a strong token, pass via `WEBHOOK_SECRET`
|
||||
- **Events**: Repository: Create, Repository: Delete
|
||||
|
||||
## Refresh Strategy
|
||||
|
||||
1. **Startup**: full sync of all non-archived repos from `repository` table
|
||||
2. **Every 5 hours**: full sync (upsert based on repo id)
|
||||
3. **Webhook**: incremental create/delete for real-time updates
|
||||
4. **On cache miss during query**: fall back to live MySQL query
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- Authentication on the API endpoint (internal service, only accessible via nginx on vps.git)
|
||||
- Caching collaborator permissions (queried live per request)
|
||||
- Handling repo rename/transfer (caught by 5h refresh)
|
||||
Reference in New Issue
Block a user