# Upload API

This page describes the request format, filename rule, and responses of `POST /upload/{path}`.

## Request

| Item | Value |
|---|---|
| Method | `POST` |
| Path | `/upload/{path}`, where `{path}` is the target folder under `storage/image/upload/`; may contain `/` and is created recursively |
| Format | `multipart/form-data` |
| File field | `filepath` (single file) |
| Size limit | None in the app; `client_max_body_size 100M` through Nginx |

## Supported Types

Decided by the MIME type the client sends:

| MIME | Stored extension |
|---|---|
| `image/jpg`, `image/jpeg` | `.jpg` |
| `image/png` | `.png` |
| `image/webp` | `.webp` |
| `image/svg+xml` | `.svg` |
| `application/pdf` | `.pdf` |

## Filename

`{16 random alphanumerics}_{millisecond timestamp}.{ext}`, e.g. `ERftP1gTS7WCTeJ8_1744080848530.jpg`. The original filename is not kept.

## Responses

| Status | Type | Body |
|---|---|---|
| `201` | JSON | `{ success: 1, filename, type, size, src }` |
| `400` | Text | `請至少規劃一個資料夾位置` (empty `{path}`) |
| `400` | Text | `僅支持 jpg / png / webp / svg / pdf` |
| `400` | Text | multer error message (e.g. `"Unexpected field"` when the field is not `filepath`) |
| `500` | Text | `檔案不存在或上傳失敗` (no file in the request) |

`src` depends on `NODE_ENV`: `development` gives `http://localhost:8080/c/img/{path}/{filename}`, otherwise `https://{DOMAIN}/c/img/{path}/{filename}`.

## Example

```bash
curl -fsS -X POST \
  -F "filepath=@./photo.png" \
  http://localhost:8080/upload/products/2025 \
  || echo "upload failed"
```

