提交0.1.0版本
- 完成了书签的基本功能和插件
This commit is contained in:
@@ -1,24 +1,24 @@
|
||||
# Design: Persistent ordering + touch-friendly DnD
|
||||
|
||||
## Database
|
||||
- Add `sort_order integer not null default 0` to `bookmarks`.
|
||||
- Add indexes to support ordered listing:
|
||||
- `(user_id, folder_id, sort_order)`
|
||||
|
||||
## API
|
||||
- Extend `Bookmark` DTO/schema with `sortOrder`.
|
||||
- Add `POST /bookmarks/reorder` similar to existing `/folders/reorder`:
|
||||
- Input: `{ folderId: uuid|null, orderedIds: uuid[] }`
|
||||
- Validates `orderedIds` is a permutation of all bookmarks for that user+folder (excluding deleted).
|
||||
- Transactionally updates `sort_order` for each id.
|
||||
|
||||
## Web UI
|
||||
- Replace native HTML5 drag/drop with a touch-capable approach.
|
||||
- Implementation choice: `sortablejs` (small, proven, touch-friendly).
|
||||
- Bind Sortable to:
|
||||
- Folder header list (per parent group) for folder ordering.
|
||||
- Each open folder’s bookmark list for bookmark ordering.
|
||||
- Root group is rendered as a first-class group and can also be reordered.
|
||||
|
||||
## Compatibility
|
||||
- If the DB schema lacks ordering columns (fresh/old DB), endpoints should return a clear 409 prompting `db:migrate`.
|
||||
# Design: Persistent ordering + touch-friendly DnD
|
||||
|
||||
## Database
|
||||
- Add `sort_order integer not null default 0` to `bookmarks`.
|
||||
- Add indexes to support ordered listing:
|
||||
- `(user_id, folder_id, sort_order)`
|
||||
|
||||
## API
|
||||
- Extend `Bookmark` DTO/schema with `sortOrder`.
|
||||
- Add `POST /bookmarks/reorder` similar to existing `/folders/reorder`:
|
||||
- Input: `{ folderId: uuid|null, orderedIds: uuid[] }`
|
||||
- Validates `orderedIds` is a permutation of all bookmarks for that user+folder (excluding deleted).
|
||||
- Transactionally updates `sort_order` for each id.
|
||||
|
||||
## Web UI
|
||||
- Replace native HTML5 drag/drop with a touch-capable approach.
|
||||
- Implementation choice: `sortablejs` (small, proven, touch-friendly).
|
||||
- Bind Sortable to:
|
||||
- Folder header list (per parent group) for folder ordering.
|
||||
- Each open folder’s bookmark list for bookmark ordering.
|
||||
- Root group is rendered as a first-class group and can also be reordered.
|
||||
|
||||
## Compatibility
|
||||
- If the DB schema lacks ordering columns (fresh/old DB), endpoints should return a clear 409 prompting `db:migrate`.
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
# Change: Add persistent drag-and-drop sorting (folders + bookmarks)
|
||||
|
||||
## Why
|
||||
Users need to reorder folders and bookmarks via drag-and-drop (including mobile/touch) and have that order persist across reloads. Current HTML5 drag/drop is unreliable on mobile and ordering is not stored for bookmarks.
|
||||
|
||||
## What Changes
|
||||
- Add persistent ordering for bookmarks (new DB column and API endpoint to reorder within a folder).
|
||||
- Use a touch-friendly drag-and-drop implementation in the web UI for:
|
||||
- Reordering folders within the same parent.
|
||||
- Reordering bookmarks within the same folder.
|
||||
- Keep the root group (no folder) as a first-class group in the UI.
|
||||
|
||||
## Impact
|
||||
- Affected specs: API (OpenAPI-backed)
|
||||
- Affected code:
|
||||
- Server: migrations, bookmarks routes, admin routes, row DTO mapping
|
||||
- Web: MyPage and AdminPage UI ordering and drag/drop
|
||||
- OpenAPI: Bookmark schema and reorder endpoint
|
||||
# Change: Add persistent drag-and-drop sorting (folders + bookmarks)
|
||||
|
||||
## Why
|
||||
Users need to reorder folders and bookmarks via drag-and-drop (including mobile/touch) and have that order persist across reloads. Current HTML5 drag/drop is unreliable on mobile and ordering is not stored for bookmarks.
|
||||
|
||||
## What Changes
|
||||
- Add persistent ordering for bookmarks (new DB column and API endpoint to reorder within a folder).
|
||||
- Use a touch-friendly drag-and-drop implementation in the web UI for:
|
||||
- Reordering folders within the same parent.
|
||||
- Reordering bookmarks within the same folder.
|
||||
- Keep the root group (no folder) as a first-class group in the UI.
|
||||
|
||||
## Impact
|
||||
- Affected specs: API (OpenAPI-backed)
|
||||
- Affected code:
|
||||
- Server: migrations, bookmarks routes, admin routes, row DTO mapping
|
||||
- Web: MyPage and AdminPage UI ordering and drag/drop
|
||||
- OpenAPI: Bookmark schema and reorder endpoint
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Folder ordering persistence
|
||||
The system SHALL persist folder ordering per user per parent folder.
|
||||
|
||||
#### Scenario: List folders returns stable ordered result
|
||||
- **GIVEN** an authenticated user
|
||||
- **WHEN** the user calls `GET /folders`
|
||||
- **THEN** the server returns folders ordered by `(parentId, sortOrder, name)`
|
||||
|
||||
#### Scenario: Reorder folders within the same parent
|
||||
- **GIVEN** an authenticated user
|
||||
- **WHEN** the user calls `POST /folders/reorder` with `parentId` and `orderedIds`
|
||||
- **THEN** the server persists the new order and returns `{ ok: true }`
|
||||
|
||||
### Requirement: Bookmark ordering persistence
|
||||
The system SHALL persist bookmark ordering per user per folder.
|
||||
|
||||
#### Scenario: List my bookmarks returns stable ordered result
|
||||
- **GIVEN** an authenticated user
|
||||
- **WHEN** the user calls `GET /bookmarks`
|
||||
- **THEN** the server returns bookmarks ordered by `(folderId, sortOrder, updatedAt desc)`
|
||||
|
||||
#### Scenario: Reorder bookmarks within the same folder
|
||||
- **GIVEN** an authenticated user
|
||||
- **WHEN** the user calls `POST /bookmarks/reorder` with `folderId` and `orderedIds`
|
||||
- **THEN** the server persists the new order and returns `{ ok: true }`
|
||||
|
||||
### Requirement: Root group treated consistently
|
||||
The system SHALL treat `folderId=null` bookmarks as belonging to the root group.
|
||||
|
||||
#### Scenario: Reorder root-group bookmarks
|
||||
- **GIVEN** an authenticated user
|
||||
- **WHEN** the user calls `POST /bookmarks/reorder` with `folderId=null`
|
||||
- **THEN** the server reorders root-group bookmarks and returns `{ ok: true }`
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Folder ordering persistence
|
||||
The system SHALL persist folder ordering per user per parent folder.
|
||||
|
||||
#### Scenario: List folders returns stable ordered result
|
||||
- **GIVEN** an authenticated user
|
||||
- **WHEN** the user calls `GET /folders`
|
||||
- **THEN** the server returns folders ordered by `(parentId, sortOrder, name)`
|
||||
|
||||
#### Scenario: Reorder folders within the same parent
|
||||
- **GIVEN** an authenticated user
|
||||
- **WHEN** the user calls `POST /folders/reorder` with `parentId` and `orderedIds`
|
||||
- **THEN** the server persists the new order and returns `{ ok: true }`
|
||||
|
||||
### Requirement: Bookmark ordering persistence
|
||||
The system SHALL persist bookmark ordering per user per folder.
|
||||
|
||||
#### Scenario: List my bookmarks returns stable ordered result
|
||||
- **GIVEN** an authenticated user
|
||||
- **WHEN** the user calls `GET /bookmarks`
|
||||
- **THEN** the server returns bookmarks ordered by `(folderId, sortOrder, updatedAt desc)`
|
||||
|
||||
#### Scenario: Reorder bookmarks within the same folder
|
||||
- **GIVEN** an authenticated user
|
||||
- **WHEN** the user calls `POST /bookmarks/reorder` with `folderId` and `orderedIds`
|
||||
- **THEN** the server persists the new order and returns `{ ok: true }`
|
||||
|
||||
### Requirement: Root group treated consistently
|
||||
The system SHALL treat `folderId=null` bookmarks as belonging to the root group.
|
||||
|
||||
#### Scenario: Reorder root-group bookmarks
|
||||
- **GIVEN** an authenticated user
|
||||
- **WHEN** the user calls `POST /bookmarks/reorder` with `folderId=null`
|
||||
- **THEN** the server reorders root-group bookmarks and returns `{ ok: true }`
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
## 1. Implementation
|
||||
- [ ] Add DB support for bookmark ordering (migration + init schema)
|
||||
- [ ] Expose bookmark ordering in DTOs and OpenAPI schema
|
||||
- [ ] Add API endpoint to reorder bookmarks within the same folder
|
||||
- [ ] Ensure list endpoints return folders/bookmarks in stable order (parent+sortOrder, etc.)
|
||||
- [ ] Implement touch-friendly drag sorting in Web UI for folders and bookmarks
|
||||
- [ ] Treat root group (folderId null) as a first-class group for display and bookmark reorder
|
||||
- [ ] Add basic verification steps (build + manual smoke checklist)
|
||||
|
||||
## 2. Spec Updates
|
||||
- [ ] Update OpenAPI contract for bookmark sortOrder and reorder endpoint
|
||||
- [ ] Update OpenSpec API capability delta requirements
|
||||
## 1. Implementation
|
||||
- [ ] Add DB support for bookmark ordering (migration + init schema)
|
||||
- [ ] Expose bookmark ordering in DTOs and OpenAPI schema
|
||||
- [ ] Add API endpoint to reorder bookmarks within the same folder
|
||||
- [ ] Ensure list endpoints return folders/bookmarks in stable order (parent+sortOrder, etc.)
|
||||
- [ ] Implement touch-friendly drag sorting in Web UI for folders and bookmarks
|
||||
- [ ] Treat root group (folderId null) as a first-class group for display and bookmark reorder
|
||||
- [ ] Add basic verification steps (build + manual smoke checklist)
|
||||
|
||||
## 2. Spec Updates
|
||||
- [ ] Update OpenAPI contract for bookmark sortOrder and reorder endpoint
|
||||
- [ ] Update OpenSpec API capability delta requirements
|
||||
|
||||
@@ -1,65 +1,65 @@
|
||||
# Capability: API (OpenAPI-backed)
|
||||
|
||||
## Purpose
|
||||
Describe the core HTTP API behavior and constraints. The OpenAPI 3.1 contract lives in `spec/openapi.yaml`.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: Health check
|
||||
The system SHALL expose a health endpoint for availability checks.
|
||||
|
||||
#### Scenario: Health endpoint returns OK
|
||||
- **WHEN** a client calls `GET /health`
|
||||
- **THEN** the server returns `200`
|
||||
|
||||
### Requirement: Authentication
|
||||
The system SHALL support email+password registration and login.
|
||||
|
||||
#### Scenario: Register then login
|
||||
- **WHEN** a user registers with a valid email and password
|
||||
- **THEN** the server returns a JWT token
|
||||
- **WHEN** the user logs in with the same credentials
|
||||
- **THEN** the server returns a JWT token
|
||||
|
||||
### Requirement: Public bookmarks visibility
|
||||
The system SHALL allow anonymous users to view public bookmarks.
|
||||
|
||||
#### Scenario: List public bookmarks without auth
|
||||
- **WHEN** a client calls `GET /bookmarks/public` without a token
|
||||
- **THEN** the server returns `200` and a list of bookmarks
|
||||
|
||||
### Requirement: Private bookmarks visibility
|
||||
The system SHALL restrict private bookmark data to authenticated users.
|
||||
|
||||
#### Scenario: List my bookmarks requires auth
|
||||
- **WHEN** a client calls `GET /bookmarks` without a token
|
||||
- **THEN** the server returns an auth error
|
||||
- **WHEN** a client calls `GET /bookmarks` with a valid token
|
||||
- **THEN** the server returns `200` and the user's bookmarks
|
||||
|
||||
### Requirement: Sync (LWW)
|
||||
The system SHALL support last-write-wins (LWW) synchronization for folders and bookmarks.
|
||||
|
||||
#### Scenario: Push local changes then pull
|
||||
- **WHEN** an authenticated client calls `POST /sync/push` with folders/bookmarks
|
||||
- **THEN** the server stores the items using LWW semantics
|
||||
- **WHEN** the client calls `GET /sync/pull`
|
||||
- **THEN** the server returns folders/bookmarks and `serverTime`
|
||||
|
||||
### Requirement: Admin user management (email-based)
|
||||
The system SHALL treat exactly one configured email as an administrator and allow that user to manage/view users.
|
||||
|
||||
#### Scenario: Non-admin cannot access admin APIs
|
||||
- **GIVEN** an authenticated user whose email is not equal to `ADMIN_EMAIL`
|
||||
- **WHEN** the user calls `GET /admin/users`
|
||||
- **THEN** the server returns a 403 error
|
||||
|
||||
#### Scenario: Admin can list users
|
||||
- **GIVEN** an authenticated user whose email equals `ADMIN_EMAIL`
|
||||
- **WHEN** the user calls `GET /admin/users`
|
||||
- **THEN** the server returns `200` and a list of users
|
||||
|
||||
#### Scenario: Admin can view a user's bookmarks
|
||||
- **GIVEN** an authenticated admin user
|
||||
- **WHEN** the admin calls `GET /admin/users/{id}/bookmarks`
|
||||
- **THEN** the server returns `200` and that user's bookmarks
|
||||
# Capability: API (OpenAPI-backed)
|
||||
|
||||
## Purpose
|
||||
Describe the core HTTP API behavior and constraints. The OpenAPI 3.1 contract lives in `spec/openapi.yaml`.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: Health check
|
||||
The system SHALL expose a health endpoint for availability checks.
|
||||
|
||||
#### Scenario: Health endpoint returns OK
|
||||
- **WHEN** a client calls `GET /health`
|
||||
- **THEN** the server returns `200`
|
||||
|
||||
### Requirement: Authentication
|
||||
The system SHALL support email+password registration and login.
|
||||
|
||||
#### Scenario: Register then login
|
||||
- **WHEN** a user registers with a valid email and password
|
||||
- **THEN** the server returns a JWT token
|
||||
- **WHEN** the user logs in with the same credentials
|
||||
- **THEN** the server returns a JWT token
|
||||
|
||||
### Requirement: Public bookmarks visibility
|
||||
The system SHALL allow anonymous users to view public bookmarks.
|
||||
|
||||
#### Scenario: List public bookmarks without auth
|
||||
- **WHEN** a client calls `GET /bookmarks/public` without a token
|
||||
- **THEN** the server returns `200` and a list of bookmarks
|
||||
|
||||
### Requirement: Private bookmarks visibility
|
||||
The system SHALL restrict private bookmark data to authenticated users.
|
||||
|
||||
#### Scenario: List my bookmarks requires auth
|
||||
- **WHEN** a client calls `GET /bookmarks` without a token
|
||||
- **THEN** the server returns an auth error
|
||||
- **WHEN** a client calls `GET /bookmarks` with a valid token
|
||||
- **THEN** the server returns `200` and the user's bookmarks
|
||||
|
||||
### Requirement: Sync (LWW)
|
||||
The system SHALL support last-write-wins (LWW) synchronization for folders and bookmarks.
|
||||
|
||||
#### Scenario: Push local changes then pull
|
||||
- **WHEN** an authenticated client calls `POST /sync/push` with folders/bookmarks
|
||||
- **THEN** the server stores the items using LWW semantics
|
||||
- **WHEN** the client calls `GET /sync/pull`
|
||||
- **THEN** the server returns folders/bookmarks and `serverTime`
|
||||
|
||||
### Requirement: Admin user management (email-based)
|
||||
The system SHALL treat exactly one configured email as an administrator and allow that user to manage/view users.
|
||||
|
||||
#### Scenario: Non-admin cannot access admin APIs
|
||||
- **GIVEN** an authenticated user whose email is not equal to `ADMIN_EMAIL`
|
||||
- **WHEN** the user calls `GET /admin/users`
|
||||
- **THEN** the server returns a 403 error
|
||||
|
||||
#### Scenario: Admin can list users
|
||||
- **GIVEN** an authenticated user whose email equals `ADMIN_EMAIL`
|
||||
- **WHEN** the user calls `GET /admin/users`
|
||||
- **THEN** the server returns `200` and a list of users
|
||||
|
||||
#### Scenario: Admin can view a user's bookmarks
|
||||
- **GIVEN** an authenticated admin user
|
||||
- **WHEN** the admin calls `GET /admin/users/{id}/bookmarks`
|
||||
- **THEN** the server returns `200` and that user's bookmarks
|
||||
|
||||
Reference in New Issue
Block a user