bookmarks: account-synced saved locations API #117

Merged
admin_emi merged 9 commits from feat/location-bookmarks into dev 2026-07-26 18:40:24 +00:00
Owner

Summary

Backend half of client-side location bookmarks — lets a signed-in user save locations and have them sync across devices, with a bulk import path to absorb a visitor's pre-existing localStorage bookmarks at login.

  • New Bookmark ORM model (backend/accounts/models.py), keyed on (user_id, cell_id) like Subscription, plus alembic revision 0004_bookmarks (conditional create, matching the 0003_user_discord_only pattern).
  • Additive v2 endpoints in backend/accounts/api_accounts.py:
    • GET /bookmarks — list the user's saved locations
    • POST /bookmarks — create, or upsert-rename if one already exists for that grid cell (200, not 409)
    • PATCH /bookmarks/{id} / DELETE /bookmarks/{id} — rename / remove, 404 (never 403) on a bookmark that isn't the caller's
    • POST /bookmarks/import — bulk import of a visitor's localStorage bookmarks at login, deduped on cell_id (existing labels are never overwritten), capped at BOOKMARK_MAX_PER_USER
  • Request/response schemas and limits in backend/accounts/schemas.py.
  • Route-level tests in backend/tests/accounts/test_bookmarks.py covering CRUD, upsert-on-duplicate, ownership isolation, auth, import dedupe/counts, and the per-user cap.

The frontend half is coming on this same branch.

## Summary Backend half of client-side location bookmarks — lets a signed-in user save locations and have them sync across devices, with a bulk import path to absorb a visitor's pre-existing localStorage bookmarks at login. - New `Bookmark` ORM model (`backend/accounts/models.py`), keyed on `(user_id, cell_id)` like `Subscription`, plus alembic revision `0004_bookmarks` (conditional create, matching the `0003_user_discord_only` pattern). - Additive v2 endpoints in `backend/accounts/api_accounts.py`: - `GET /bookmarks` — list the user's saved locations - `POST /bookmarks` — create, or upsert-rename if one already exists for that grid cell (200, not 409) - `PATCH /bookmarks/{id}` / `DELETE /bookmarks/{id}` — rename / remove, 404 (never 403) on a bookmark that isn't the caller's - `POST /bookmarks/import` — bulk import of a visitor's localStorage bookmarks at login, deduped on `cell_id` (existing labels are never overwritten), capped at `BOOKMARK_MAX_PER_USER` - Request/response schemas and limits in `backend/accounts/schemas.py`. - Route-level tests in `backend/tests/accounts/test_bookmarks.py` covering CRUD, upsert-on-duplicate, ownership isolation, auth, import dedupe/counts, and the per-user cap. The frontend half is coming on this same branch.
admin_emi added 5 commits 2026-07-26 18:27:49 +00:00
bookmarks: account-synced saved locations API
All checks were successful
PR build (required check) / changes (pull_request) Successful in 6s
secrets-guard / encrypted (pull_request) Successful in 5s
shell-lint / shellcheck (pull_request) Successful in 7s
PR build (required check) / build-frontend (pull_request) Has been skipped
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / build-backend (pull_request) Successful in 1m0s
PR build (required check) / gate (pull_request) Successful in 2s
41858f3e4b
admin_emi added 1 commit 2026-07-26 18:36:38 +00:00
admin_emi added 1 commit 2026-07-26 18:36:43 +00:00
bookmarks: map + account UI for saved locations
All checks were successful
secrets-guard / encrypted (pull_request) Successful in 10s
PR build (required check) / changes (pull_request) Successful in 16s
shell-lint / shellcheck (pull_request) Successful in 12s
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Successful in 2m24s
PR build (required check) / build-backend (pull_request) Successful in 2m51s
PR build (required check) / gate (pull_request) Successful in 3s
d6ead56971
admin_emi added 1 commit 2026-07-26 18:36:47 +00:00
bookmarks: map + account UI for saved locations
All checks were successful
secrets-guard / encrypted (pull_request) Successful in 20s
PR build (required check) / changes (pull_request) Successful in 22s
shell-lint / shellcheck (pull_request) Successful in 19s
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Successful in 2m27s
PR build (required check) / build-backend (pull_request) Successful in 2m51s
PR build (required check) / gate (pull_request) Successful in 3s
17cc14b48b
admin_emi merged commit 1c6ecc2a6f into dev 2026-07-26 18:40:24 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Jinemi/thermograph#117
No description provided.