chore: copied WEB_API.md from, UpdateForge project for reference

This commit is contained in:
Andrew 2026-06-16 21:34:35 +07:00
parent f25a4bb680
commit 53e35c7263

198
WEB_API.md Normal file
View file

@ -0,0 +1,198 @@
# UpdateForge API
Base URL: `https://<your-server>`
All API routes are under `/api/v1`.
All request and response bodies are JSON.
---
## Authentication
UpdateForge uses **Bearer token** authentication. Obtain a token via the login endpoint and include it in every subsequent request:
```
Authorization: Bearer <token>
```
Tokens are long-lived JWTs signed by the server. Store them securely (e.g. Android `EncryptedSharedPreferences`). There is no built-in expiry endpoint — simply re-authenticate when you receive a `401`.
---
## Endpoints
### `POST /api/v1/auth`
Authenticate with email and password. Does not require an existing token.
**Request**
```json
{
"email": "user@example.com",
"password": "secret"
}
```
**Response `200`**
```json
{
"token": "eyJ...",
"userId": "abc123",
"email": "user@example.com"
}
```
**Error responses**
| Status | Body | Reason |
| ------ | ---------------------------------------------- | ----------------------- |
| `400` | `{"error": "email and password are required"}` | Missing fields |
| `401` | `{"error": "invalid credentials"}` | Wrong email or password |
---
### `GET /api/v1/apps`
Returns all teams the authenticated user belongs to, each with its apps. A user may belong to multiple teams. Within each app, the response includes the latest **current** and **pending** version per build type.
- **current** — the highest semver version that has an artifact file attached. Always present (may be `null` if none exists yet).
- **pending** — the highest semver version with no artifact file yet (work in progress). `null` when none exists.
Teams and apps are ordered oldest-first by creation date.
**Response `200`**
```json
{
"teams": [
{
"id": "team_id",
"name": "Acme",
"apps": [
{
"id": "app_id",
"title": "My App",
"packageName": "com.example.myapp",
"icon": "/api/files/apps/app_id/icon.png",
"release": {
"current": {
"id": "ver_id",
"version": "1.2.0",
"name": "January update",
"public": true,
"hasFile": true,
"created": "2026-01-15T10:30:00Z"
},
"pending": null
},
"debug": {
"current": {
"id": "ver_id_2",
"version": "1.3.0",
"name": "",
"public": false,
"hasFile": true,
"created": "2026-01-20T08:00:00Z"
},
"pending": {
"id": "ver_id_3",
"version": "1.4.0",
"name": "Next sprint",
"public": false,
"hasFile": false,
"created": "2026-01-21T09:00:00Z"
}
},
"profile": {
"current": null,
"pending": null
}
}
]
}
]
}
```
`teams` is an empty array if the user belongs to no teams.
**Version object fields**
| Field | Type | Description |
| --------- | ------ | ------------------------------------------------------ |
| `id` | string | Version record ID — use this for downloads |
| `version` | string | Semantic version string, e.g. `"1.2.0"` |
| `name` | string | Optional human-readable label, empty string if not set |
| `public` | bool | Whether this version is intended for all testers |
| `hasFile` | bool | Whether an artifact is available for download |
| `created` | string | ISO 8601 UTC timestamp |
**Error responses**
| Status | Body | Reason |
| ------ | --------------------------- | ------------------------ |
| `401` | `{"error": "unauthorized"}` | Missing or invalid token |
---
### `GET /api/v1/versions/{id}/download`
Download the artifact file for a version. `{id}` is the version's `id` field from the apps response.
The response is the raw file with `Content-Type: application/octet-stream` and a `Content-Disposition: attachment` header carrying the original filename. Supports HTTP range requests, so partial downloads and resume work out of the box.
**Error responses**
| Status | Body | Reason |
| ------ | -------------------------------- | ------------------------------------------ |
| `401` | `{"error": "unauthorized"}` | Missing or invalid token |
| `403` | `{"error": "forbidden"}` | User is not a member of the version's team |
| `404` | `{"error": "version not found"}` | ID does not exist |
| `404` | `{"error": "no file attached"}` | Version exists but `hasFile` is `false` |
---
## Build types
Every version belongs to exactly one build type:
| Type | Intended use |
| --------- | ------------------------------------------- |
| `release` | Production-ready builds for general testers |
| `debug` | Debug builds with logging/tooling enabled |
| `profile` | Performance-profiling builds |
---
## Icons
The `icon` field in the app object is a root-relative URL path. Prepend the server base URL to fetch it:
```
GET https://<your-server>/api/files/apps/<app_id>/<filename>
```
Icon files are served publicly and do not require authentication.
---
## Typical client flow
```
1. POST /api/v1/auth → store token
2. GET /api/v1/apps → display teams and their apps; cache version IDs
3. For each app, compare installed version string with current.version
4. If update available and current.hasFile == true:
GET /api/v1/versions/{id}/download → save & install APK
```
---
## Error format
All error responses share the same shape:
```json
{ "error": "<human-readable message>" }
```