Skip to content

feat(common): add site-features API backed by AppSettings - #149

Draft
geourjoa wants to merge 4 commits into
feat-1/app-settings-modelfrom
feat-2/feature-flags-app-settings
Draft

feat(common): add site-features API backed by AppSettings#149
geourjoa wants to merge 4 commits into
feat-1/app-settings-modelfrom
feat-2/feature-flags-app-settings

Conversation

@geourjoa

@geourjoa geourjoa commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Stacked on #148 (feat-1) — merge/rebase after that lands.

Superseded an earlier version of this PR (commit 7b0cbd6) that shipped a generic feature-flag KV helper after only searching this repo for a JSON config to migrate. The user has since confirmed the real site-features.json lives in the frontend repo (archetype3-frontend/config/site-features.json) — a structured blob (section visibility/order + per-search-category column/facet config), not flat booleans. Commits 6018c42/f8cdc0b remove that placeholder and replace it with the real feature:

  • New SiteFeaturesView in apps/common/views.py, modeled directly on the existing SiteLabelsView/SiteLabel pattern: GET /api/v1/site-features/ (public), PUT /api/v1/site-features/ (superuser-only via IsSuperuserOrReadOnly), backed by one AppSettings row (key="site_features") holding the whole JSON blob.
  • Data migration seeds that row from the real, current content of the frontend's config/site-features.json.
  • Corresponding frontend PR: fix(site-features): wire site features to the backend AppSettings API frontend#106 wires lib/site-features-server.ts to this endpoint instead of local file I/O.

Test plan

  • ruff check / ruff format / mypy clean
  • pytest apps/common — 51 passed (30 for site-features + site-labels together)
  • makemigrations --check --dry-run — no missing migrations

No new dependencies.

Adds is_feature_enabled/set_feature_enabled in apps.common.services so
callers read boolean flags via a small helper instead of comparing
AppSettings.value strings directly (error-prone: "True"/"1"/typos).

No site-features.json or existing ad-hoc feature-flag code was found in
this repo to migrate, and no boolean env var currently gates behaviour
in a way that would clearly benefit from becoming a runtime-toggleable
flag (SEARCH_AUTO_REINDEX is unused dead config, and the one related
reindex-on-save path is explicitly documented as an unconditional
invariant). Ships the read/write mechanism plus a data migration
seeding two clearly-labelled illustrative example flags instead of
inventing a fake product feature.
apps/common/services.py and its seed migration guessed at a feature-flag
mechanism in the absence of any known JSON source, and seeded two
illustrative, unwired example flags. The real source (the frontend's
config/site-features.json) has since been confirmed, so this generic
KV-flag layer is being replaced by a dedicated site-features endpoint
rather than kept alongside it.
…ettings

Adds SiteFeaturesView, an AppSettings-backed replacement for the
frontend's config/site-features.json file: the whole config blob
(section visibility, section order, per-search-category column/facet
visibility) is stored as one AppSettings row (key="site_features"),
JSON-encoded, mirroring the SiteLabel/SiteLabelsView pattern.

GET /api/v1/site-features/ is public and returns the raw config object
at the top level, falling back to the seeded defaults if the row is
missing, inactive, or fails to parse. PUT is superuser-only and
validates only the top-level shape (sections + searchCategories keys),
leaving deeper validation to the frontend. The seed migration populates
the row with the real content of config/site-features.json as of this
writing.
@geourjoa geourjoa changed the title feat(common): add AppSettings-backed feature-flag helper feat(common): add site-features API backed by AppSettings Aug 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant