Repository navigation
feat(core): MVP feature flags that hide non-MVP areas - #44
Merged
Merged
Conversation
Introduce a single source of truth for hiding non-MVP areas: a `features` map in both environment files (all off), typed by the `FeatureKey` union and checked with `satisfies FeatureFlagMap`, read through the `FeatureFlags.isEnabled()` service. Tests override flags with `provideFeatureFlags()`. `featureGuard(key, next?)` is a functional canMatch guard: while the flag is off the route does not match, so the URL falls through to the wildcard fallback like an unknown path (no blank page, no lazy chunk). An existing canMatch guard is chained through `next` because Angular runs every guard of a canMatch array eagerly.
Gate every non-MVP route with featureGuard so a disabled feature's URLs fall through to the `**` -> /projects fallback like unknown paths: billing (settings page + checkout success/cancel), usage, integrations (org + project pages and the Jira OAuth callback), members (org + project pages and the invitation landing), customRoles (roles list/new/edit) and the notifications/tokens account placeholders. Routes that already had a permission canMatch chain it through featureGuard so a hidden page never fetches permissions or toasts a denial. The invitation landing follows `members`: with it off nobody can invite from the UI and an owner has no screen to see or remove whoever joins, so a stale link must not add people to an org. The project settings landing skips members/roles while their feature is off. A spec drives the real route table to pin both directions.
Move the nav segment lists and their visibility rule into shell-nav.ts so they can be unit-tested, and add an optional `feature` to NavSeg that visibleNavSegs checks alongside role/permission. Flagged entries: org members/billing/integrations/usage, project roles/members/integrations and the account notifications/tokens placeholders. A "Settings" root entry with no reachable sub-page is now dropped, and the org one opens the first reachable sub-page instead of the owner-only General, so an admin never lands on a "no access" toast. The Jira job banner only mounts while integrations are on.
…menu The palette's "Members" quick action and backend MEMBER hits (both open /settings/members) only appear while `members` is on; the user menu's "Upgrade" CTA only while `billing` is on.
Wrap the backlog's Import from Jira / Push all / Push selected buttons and the story detail's Push to Jira in the `integrations` flag, skip the backlog's Jira-target lookup, and only let INTEGRATION_SYNC reveal the row-selection column while bulk push exists (bulk delete still needs STORY_DELETE).
The project overview drops its Members card (and no longer counts members/roles toward the Settings card) while `members` / `customRoles` are off. Org General hides the Transfer ownership card, and skips the member fetch that only feeds it, while `members` is off: without members there is nobody to pick and its empty state asks to invite someone.
Usage and billing are separate flags; keep the usage page free of a dead link to /settings/billing when only `usage` is turned on.
Add docs/FEATURE-FLAGS.md (each flag, what it hides, how to turn it on or add one, the invitation/ownership decisions and the backend FREE-plan limits) and link it from the README environments section.
jhosepmyr
requested review from
Eric396,
VarBus and
salimramirez
as code owners
October 7, 2026 08:13
14 of 18 tasks
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds typed build-time feature flags so the deployed product shows only the MVP. Non-MVP areas stay in the code and the backend but disappear from the UI and their URLs stop matching. Turning a flag back on in both environment files restores the area with no other change.
featuresmap inenvironment.tsandenvironment.prod.ts(FeatureKeyunion,FeatureFlags.isEnabled()); a missing key is a compile error.featureGuard()canMatch: a disabled route behaves like an unknown URL (falls through to/projects, no blank page or "no access" toast).All seven flags are off:
billing(pages, checkout returns, Upgrade CTA),usage,integrations(Jira pages, OAuth callback, job banner, import/push actions),members(org and project members, invitation landing, palette action, ownership transfer),customRoles,notifications,tokens. With them off the app sends no requests to those endpoints. Seedocs/FEATURE-FLAGS.md.Feature module / area: core / layout / shared / workspace / discovery / billing
Related issue / US: MVP scope ("prune the tree"): Jira export, billing, custom roles and members move to a later increment
Type of Change
feat— new feature or UI componentfix— bug fixrefactor— code change without behavior changetest— tests onlydocs— documentation onlybuild/ci— build, dependencies, or CI/CDchore— maintenanceChecklist
develop(notmain)feature/*,bugfix/*, orhotfix/*bun run lintpasses locally (ESLint + angular-eslint)bun run testpasses locally (Vitest) — 339 passedbun run buildpasses locally (no type errors, no budget exceeded)ChangeDetectionStrategy.OnPushand Angular signalslocalStorage/sessionStorageaccess for JWT tokens (use the auth store)bypassSecurityTrust*calls without explicit review.envcontent committedCHANGELOG.mdupdated under[Unreleased]How to Test
/settings/billingor/projects/<id>/settings/roles→ lands on/projects.truein both environment files → everything comes back.Notes (optional)
billingoff, a user who hits a limit sees the message but has no upgrade path.membersoff there is no screen to invite or remove members, and invitation links land on/projects.