Initial: project plan

This commit is contained in:
lyn
2026-04-14 09:10:55 +00:00
commit 8ddb7c2846

169
PROJECT_PLAN.md Normal file
View 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)