Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions .agents/skills/bottlenote-admin-api/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
---
name: bottlenote-admin-api
description: >
Check Bottlenote admin API documentation and apply frontend API contract
updates for this dashboard. Use when Codex needs to inspect admin API specs,
compare docs with code, add or update endpoints, fix request/response type
mismatches, or support feature spec/plan work with API field analysis.
Trigger on requests mentioning Bottlenote API, admin API docs, endpoint
updates, response shape changes, or code/API inconsistencies.
---

# Bottlenote Admin API Contract

Use this skill to inspect Bottlenote admin API documentation and keep frontend
API contracts aligned with the dashboard code.

## Workflow

1. Confirm the target domain and operation.
- If the user names a feature or bug, identify the relevant domain files in
`src/types/api`, `src/services`, and `src/hooks`.
- If the user asks for a broad API audit, scan all API domains and report
changes by domain before editing.

2. Check the API source.
- Treat the published admin API documentation as the source of truth when the
user says the API was deployed, the spec changed, or a backend response
shape is available.
- Prefer the latest published API documentation:
`https://bottle-note.github.io/bottle-note-api-server/bottle-note/admin-api/admin-api.html`
- If the request specifically mentions dev, development, or behavior that is
missing from the published docs, check the dev API server from
`.env.local` (`VITE_API_BASE_URL`) before falling back to the local
snapshot.
- If dev documentation paths return 403/404 but API endpoints respond, use
non-destructive endpoint probing to confirm the contract:
- Authenticate with available local dev credentials when present.
- Use `OPTIONS` to discover allowed methods.
- Use safe `GET` requests for list/detail shapes.
- Use malformed or empty-body mutation requests to discover validation,
required fields, duplicate errors, and route existence.
- For delete/update checks, prefer impossible IDs or invalid payloads. Do
not create, update, or delete real records just to inspect a contract
unless the user explicitly approves it.
- Clearly label findings as "dev API behavior" when they come from probing
instead of a published document.
- If published docs and dev API behavior differ, report the difference and
prefer the source the user asked for. For feature docs targeting imminent
dev work, record dev API behavior and note that published docs may be
stale.
- If neither live docs nor dev API behavior can be checked, use
`references/api-spec.md` as the local snapshot and explicitly say it may be
stale.
- When live docs differ from `references/api-spec.md`, update the snapshot
only when the user explicitly wants the repo to record the new API
contract snapshot.

3. Compare documentation with code.
- `src/types/api/*.api.ts`: endpoint constants and request/response types.
- `src/services/*.service.ts`: service functions, endpoint interpolation,
query keys, response normalization.
- `src/hooks/use*.ts`: TanStack Query hooks, mutation variables, cache
invalidation, Korean toast messages.

4. Produce a concise diff report when the scope is not already obvious.
- Missing endpoint: method and path exist in docs but not code.
- Missing field: request/response field exists in docs but not types.
- Changed field: type, requiredness, or name differs.
- Removed endpoint: code has an endpoint that no longer exists in docs.
- UI implication: list/detail/form/filter behavior needed by the frontend.

5. Apply changes in the project order.
- Update `src/types/api/{domain}.api.ts`.
- Update `src/types/api/index.ts` only when an existing export pattern
requires it.
- Update `src/services/{domain}.service.ts`.
- Update `src/hooks/use{Domain}.ts`.
- Add or update focused tests when behavior or contracts changed.

6. Record API findings in the feature docs when this supports feature work.
- Put user-facing requirements and field meanings in
`docs/features/<feature-slug>/spec.md`.
- Put concrete frontend type/service/hook mapping in
`docs/features/<feature-slug>/plan.md`.
- Do not create a standalone API report unless the user explicitly asks for a
broad API audit.

7. Verify with the narrowest useful commands.
- Prefer targeted `pnpm test:run ...` when supported.
- Run `pnpm lint` or `pnpm test:run` when changes touch shared contracts or
multiple domains.

## Output Contract

For API contract work, leave the user with:

- API source used: published docs, dev API behavior, or local snapshot.
- Contract changes found: endpoint and field-level summary.
- Code changes applied: types, services, hooks, tests.
- Feature docs updated, when applicable.
- Verification result: exact commands run and pass/fail status.
- Follow-up needed: missing backend docs, ambiguous fields, or manual UI checks.

## References

- `references/api-spec.md`: Local snapshot of the admin API documentation. Use
only as fallback or for quick orientation when live docs are not needed.
- `references/code-patterns.md`: Dashboard API layer examples and conventions.

## Rules

- Keep API types in `src/types/api`; do not duplicate them in components.
- Follow the three-layer order: types -> service -> hook.
- Do not edit `src/components/ui`.
- Do not create new barrel files unless the repo already requires one at that
boundary.
- Treat pagination as 0-based.
- Preserve TanStack Query ownership of server data.
- Use Korean toast and validation messages for admin-facing UI.
4 changes: 4 additions & 0 deletions .agents/skills/bottlenote-admin-api/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Bottlenote Admin API"
short_description: "Sync Bottlenote API contracts"
default_prompt: "Use $bottlenote-admin-api to compare the admin API docs with this dashboard code."
181 changes: 181 additions & 0 deletions .agents/skills/bottlenote-admin-api/references/api-spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
# Bottlenote Admin API Specification

Source: https://bottle-note.github.io/bottle-note-api-server/bottle-note/admin-api/admin-api.html

## Common Response Wrapper

All responses follow this structure:
```json
{ "success": boolean, "code": string, "data": T, "errors": [], "meta": {} }
```

Paginated responses include `meta`:
```json
{ "page": number, "size": number, "totalElements": number, "totalPages": number, "hasNext": boolean }
```

Mutation responses (create/update/delete) return:
```json
{ "code": string, "message": string, "targetId": number, "responseAt": string }
```

All endpoints except login require `Authorization: Bearer <token>`.

---

## 1. Auth API

| Method | Path | Request | Response |
|--------|------|---------|----------|
| POST | `/admin/api/v1/auth/login` | `{ email, password }` | `{ accessToken, refreshToken }` |
| POST | `/admin/api/v1/auth/refresh` | `{ refreshToken }` | `{ accessToken, refreshToken }` |
| POST | `/admin/api/v1/auth/signup` | `{ email, password, name, roles[] }` | `{ adminId, email, name, roles[] }` |
| DELETE | `/admin/api/v1/auth/withdraw` | - | `{ message }` |

## 2. Alcohol API

| Method | Path | Request | Response |
|--------|------|---------|----------|
| GET | `/admin/api/v1/alcohols` | Query: `keyword`, `category`, `regionId`, `sortType`, `sortOrder`, `page`, `size`, `includeDeleted` | Paginated `AlcoholListItem[]` |
| GET | `/admin/api/v1/alcohols/{alcoholId}` | - | `AlcoholDetail` (includes `tastingTags[]`) |
| POST | `/admin/api/v1/alcohols` | See create request below | Mutation response |
| PUT | `/admin/api/v1/alcohols/{alcoholId}` | Same as create | Mutation response |
| DELETE | `/admin/api/v1/alcohols/{alcoholId}` | - | Mutation response |
| GET | `/admin/api/v1/alcohols/categories/reference` | - | `CategoryReference[]` |

### Alcohol Create/Update Request
```typescript
{
korName: string;
engName: string;
abv: string; // e.g. "40%"
type: AlcoholType; // WHISKY | RUM | VODKA | GIN | TEQUILA | BRANDY | BEER | WINE | ETC
korCategory: string;
engCategory: string;
categoryGroup: AlcoholCategory; // SINGLE_MALT | BLEND | BLENDED_MALT | BOURBON | RYE | OTHER
regionId: number;
distilleryId: number;
age: string;
cask: string;
imageUrl: string;
description: string;
volume: string;
tastingTagIds: number[]; // IMPORTANT: tasting tag IDs to connect
}
```

### Alcohol Detail Response
```typescript
{
alcoholId: number;
korName: string;
engName: string;
imageUrl: string | null;
type: string;
korCategory: string;
engCategory: string;
categoryGroup: AlcoholCategory;
abv: string | null;
age: string | null;
cask: string | null;
volume: string | null;
description: string | null;
regionId: number | null;
korRegion: string | null;
engRegion: string | null;
distilleryId: number | null;
korDistillery: string | null;
engDistillery: string | null;
tastingTags: { id: number; korName: string; engName: string; }[];
avgRating: number;
totalRatingsCount: number;
reviewCount: number;
pickCount: number;
createdAt: string;
modifiedAt: string;
deletedAt: string | null;
}
```

## 3. Tasting Tag API

| Method | Path | Request | Response |
|--------|------|---------|----------|
| GET | `/admin/api/v1/tasting-tags` | Query: `keyword`, `page`, `size`, `sortOrder` | Paginated `TastingTagListItem[]` |
| GET | `/admin/api/v1/tasting-tags/{tagId}` | - | `{ tag: TastingTag, alcohols: TastingTagAlcohol[] }` |
| POST | `/admin/api/v1/tasting-tags` | `{ korName, engName, icon?, description?, parentId? }` | Mutation response |
| PUT | `/admin/api/v1/tasting-tags/{tagId}` | Same as create | Mutation response |
| DELETE | `/admin/api/v1/tasting-tags/{tagId}` | - | Mutation response |
| POST | `/admin/api/v1/tasting-tags/{tagId}/alcohols` | `{ alcoholIds: number[] }` | Mutation response |
| DELETE | `/admin/api/v1/tasting-tags/{tagId}/alcohols` | `{ alcoholIds: number[] }` | Mutation response |

## 4. Help (Inquiry) API

| Method | Path | Request | Response |
|--------|------|---------|----------|
| GET | `/admin/api/v1/helps` | Query: `status`, `type`, `cursor`, `pageSize` | Cursor-paginated help list |
| GET | `/admin/api/v1/helps/{helpId}` | - | Help detail with images |
| POST | `/admin/api/v1/helps/{helpId}/answer` | `{ responseContent, status }` | `{ helpId, status, message }` |

## 5. File (S3) API

| Method | Path | Request | Response |
|--------|------|---------|----------|
| GET | `/admin/api/v1/s3/presign-url` | Query: `rootPath`, `uploadSize` | `{ bucketName, expiryTime, imageUploadInfo[] }` |

## 6. Region API

| Method | Path | Request | Response |
|--------|------|---------|----------|
| GET | `/admin/api/v1/regions` | Query: `keyword`, `page`, `size`, `sortOrder` | Paginated region array |

## 7. Distillery API

| Method | Path | Request | Response |
|--------|------|---------|----------|
| GET | `/admin/api/v1/distilleries` | Query: `keyword`, `page`, `size`, `sortOrder` | Paginated distillery array |

## 8. Curation API

| Method | Path | Request | Response |
|--------|------|---------|----------|
| GET | `/admin/api/v1/curations` | Query: `keyword`, `isActive`, `page`, `size` | Paginated curation array |
| GET | `/admin/api/v1/curations/{curationId}` | - | Curation with alcohols |
| POST | `/admin/api/v1/curations` | `{ name, description, coverImageUrl, displayOrder, alcoholIds[] }` | Mutation response |
| PUT | `/admin/api/v1/curations/{curationId}` | `{ name, description, coverImageUrl, displayOrder, isActive, alcoholIds[] }` | Mutation response |
| DELETE | `/admin/api/v1/curations/{curationId}` | - | Mutation response |
| PATCH | `/admin/api/v1/curations/{curationId}/status` | `{ isActive }` | Mutation response |
| PATCH | `/admin/api/v1/curations/{curationId}/display-order` | `{ displayOrder }` | Mutation response |
| POST | `/admin/api/v1/curations/{curationId}/alcohols` | `{ alcoholIds[] }` | Mutation response |
| DELETE | `/admin/api/v1/curations/{curationId}/alcohols/{alcoholId}` | - | Mutation response |

## 9. Banner API

| Method | Path | Request | Response |
|--------|------|---------|----------|
| GET | `/admin/api/v1/banners` | Query: `keyword`, `isActive`, `bannerType`, `page`, `size` | Paginated banner array |
| GET | `/admin/api/v1/banners/{bannerId}` | - | Banner detail |
| POST | `/admin/api/v1/banners` | See banner create request below | Mutation response |
| PUT | `/admin/api/v1/banners/{bannerId}` | Same as create + `isActive` | Mutation response |
| DELETE | `/admin/api/v1/banners/{bannerId}` | - | Mutation response |
| PATCH | `/admin/api/v1/banners/{bannerId}/status` | `{ isActive }` | Mutation response |
| PATCH | `/admin/api/v1/banners/{bannerId}/sort-order` | `{ sortOrder }` | Mutation response |

### Banner Create Request
```typescript
{
name: string;
nameFontColor: string;
descriptionA: string;
descriptionB: string;
descriptionFontColor: string;
imageUrl: string;
textPosition: string;
isExternalUrl: boolean;
targetUrl: string;
bannerType: string;
sortOrder: number;
startDate: string;
endDate: string;
}
```
Loading
Loading