Org Web Adapter

hungryroot/jira/be_7895_add_cookbook_sharing_via_sqid_based_url.org

ID
a3370188-045f-427f-a305-0b5c32bb53ce

BE-7895 Exp 242 - Add cookbook sharing via Sqid-based URL

- source :: https://hungryroot.atlassian.net/browse/BE-7895

- tags :: Hungryroot API Project

- epic :: EP-650 Exp 242: Favorites + User Cookbooks

- sprint :: [[id:b9ee0cab-ac1a-47ee-b813-9efc4f1a778f][HR BE Sprint 112]]

- status :: Status - In Progress

- priority :: Priority - Medium

Summary

Replace the Base62 slug sharing introduced in BE-7819 with Sqid-based sharing. Add a ~visibility~ field to ~Cookbook~ controlling access. Remove Base62 slug infrastructure entirely.

Sqids are URL-safe, reversible, and designed to avoid offensive words. Derived deterministically from the cookbook's integer PK — no storage needed on the model.

Sqid generation

Use the ~sqids~ Python package. Encode the cookbook's integer PK:

#+begin_src python

from sqids import Sqids

sqids = Sqids()

def encode_cookbook_id(pk: int) -> str:

return sqids.encode([pk])

def decode_cookbook_sqid(sqid: str) -> int | None:

numbers = sqids.decode(sqid)

return numbers[0] if numbers else None

#+end_src

Sqid is deterministic and reversible — no need to store it on the model.

Visibility field

Add ~visibility~ to ~Cookbook~ using ~TextChoices~:

| Value | Description |

|-----------+--------------------------------------|

| ~shared~ | Accessible via Sqid-based share URL |

| ~private~ | Visible only to owner |

Default: ~private~. Share URL returns 404 if ~visibility=private~.

Scope

- ~cookbooks/models.py~ — add ~Visibility(TextChoices)~ and ~visibility~ field (default ~private~); migration required.

- ~cookbooks/services.py~ — add Sqid encode/decode helpers; update share logic to use Sqid and set ~visibility=shared~.

- ~cookbooks/views.py~ — accept Sqid as cookbook identifier; return 404 if ~visibility=private~.

- ~cookbooks/views.py~ — update list view default filter to exclude ~private~ cookbooks; remove Favorites filter.

- Remove all Base62 slug code introduced in BE-7819.

Out of scope

- Favorites GET endpoint and FavoritesService core logic.

- Any frontend URL changes beyond the API contract.

Acceptance criteria

- [ ] ~Cookbook~ has ~visibility~ field (~shared~ / ~private~, default ~private~); migration included.

- [ ] Sqid encodes/decodes cookbook PK (round-trip); not stored on model.

- [ ] ~/cookbooks/<sqid>/~ returns 200 for ~shared~ cookbook; 404 for ~private~.

- [ ] Cookbooks list view defaults to excluding ~private~ cookbooks.

- [ ] Favorites filter removed from list view.

- [ ] All Base62 slug code removed.

- [ ] Unit tests: encode/decode round-trip, lookup by Sqid, visibility access rules (shared=200, private=404).

- [ ] ~prek run ruff~ and ~prek run ruff-format~ clean on touched files.