feat(cards): stamp active conflicts on collections, series, and preview JSON

The last behavior gap in the H2 batch: has_conflict was part of the
frozen card shape but stamped false-forever on these three JSON
surfaces (only dashboard sections, search, and the SSR pages had it),
so every conflict-driven card action — the resolve-conflict CTA in
BookCard — never fired there. MarkActiveConflicts now runs after the
builder on GET /api/collections/:id, series books, and smart-collection
preview (all user-scoped; the endpoint already authenticates).

Key set is unchanged — has_conflict was always emitted, this only
makes its value truthful. All 15 contract pins + H1 tests green; the
pin's bookInfoKeys freeze unaffected.
This commit is contained in:
John O'Keefe committed 2026-10-17 14:08:45 -04:00
1 parent a13b268adc
commit b2b89ba789
2 files changed
+10

No files matched your search

+7
View File
@@ -309,6 +309,10 @@ func (h *CollectionHandler) GetCollection(c *echo.Context) error {
bookList = BookCardsFromCollectionItemRows(books, libTypes) bookList = BookCardsFromCollectionItemRows(books, libTypes)
} }
if u, ok := c.Get("user").(database.Users); ok {
bookList = MarkActiveConflicts(c.Request().Context(), h.db, u.ID, bookList)
}
var viewSettings map[string]interface{} var viewSettings map[string]interface{}
if len(collection.ViewSettings) > 0 { if len(collection.ViewSettings) > 0 {
err := json.Unmarshal(collection.ViewSettings, &viewSettings) err := json.Unmarshal(collection.ViewSettings, &viewSettings)
@@ -1252,6 +1256,9 @@ func (h *CollectionHandler) PreviewCollection(c *echo.Context) error {
} }
bookCards := BookCardsFromMediaItems(matchedItems, LibraryTypeMap(c.Request().Context(), h.db)) bookCards := BookCardsFromMediaItems(matchedItems, LibraryTypeMap(c.Request().Context(), h.db))
if u, ok := c.Get("user").(database.Users); ok {
bookCards = MarkActiveConflicts(c.Request().Context(), h.db, u.ID, bookCards)
}
return c.JSON(http.StatusOK, map[string]interface{}{"items": bookCards}) return c.JSON(http.StatusOK, map[string]interface{}{"items": bookCards})
} }
+3
View File
@@ -153,6 +153,9 @@ func (h *SeriesHandler) GetSeriesBooks(c *echo.Context) error {
} }
bookCards := BookCardsFromMediaItems(books, LibraryTypeMap(c.Request().Context(), h.db)) bookCards := BookCardsFromMediaItems(books, LibraryTypeMap(c.Request().Context(), h.db))
if u, ok := c.Get("user").(database.Users); ok {
bookCards = MarkActiveConflicts(c.Request().Context(), h.db, u.ID, bookCards)
}
return c.JSON(http.StatusOK, map[string]interface{}{ return c.JSON(http.StatusOK, map[string]interface{}{
"name": seriesName, "name": seriesName,