diff --git a/packages/features/feature-opt-in/FEATURE_OPT_IN_BANNER_PLAN.md b/packages/features/feature-opt-in/FEATURE_OPT_IN_BANNER_PLAN.md
deleted file mode 100644
index d8a6eceab4..0000000000
--- a/packages/features/feature-opt-in/FEATURE_OPT_IN_BANNER_PLAN.md
+++ /dev/null
@@ -1,201 +0,0 @@
-# Feature Opt-In Banner System Plan
-
-This document outlines the high-level plan for implementing a feature opt-in banner/popup system that allows users to opt into experimental features directly from the pages where those features apply.
-
-## Overview
-
-When a new opt-in feature (like "bookings-v3") is available, users will see a floating banner on relevant pages. Clicking the banner opens a confirmation dialog where users can opt-in based on their role (org owner, team owner, or regular user).
-
----
-
-## 1. Backend: New TRPC Procedure
-
-**Location:** `packages/trpc/server/routers/viewer/featureOptIn/_router.ts`
-
-**New Procedure:** `checkFeatureOptInEligibility`
-
-This procedure will:
-- Accept a `featureId` parameter (e.g., "bookings-v3")
-- Use the existing `resolveFeatureStatesAcrossTeams` function from `FeatureOptInService`
-- Return one of three response types:
- 1. **Already Enabled**: User effectively has the feature enabled - no banner needed
- 2. **Can Opt-In**: User can opt-in - return user's role context (feature metadata like title/description comes from `getOptInFeatureConfig()` in `config.ts`)
- 3. **Cannot Opt-In**: User is blocked by org/team (strict policy) - return blocking reason
-
-The response should include:
-- User's role context for the confirmation dialog:
- - Is org owner/admin?
- - Which teams is user owner/admin of?
- - Organization ID (if applicable)
- - Team IDs where user has admin rights
-
----
-
-## 2. Frontend: Custom Hook
-
-**Location:** New file in `apps/web/modules/feature-opt-in/hooks/`
-
-**Hook:** `useFeatureOptInBanner(featureId: string)`
-
-This hook will:
-1. **Check localStorage first** for dismissal state in a single consolidated key `feature-opt-in-dismissed`
- - The key stores an object mapping feature IDs to dismissal status: `{ "bookings-v3": true, "insights-v2": true }`
- - If the feature is dismissed, skip the TRPC call entirely and return `{ shouldShow: false }`
- - Using a single key avoids localStorage bloat from multiple per-feature keys
-2. **Call the TRPC procedure** if not dismissed
-3. **Get feature metadata** from `getOptInFeatureConfig(featureId)` in `config.ts` for title/description i18n keys
-4. **Return state** for the banner:
- - `shouldShow: boolean`
- - `featureConfig: OptInFeatureConfig` (from config.ts, includes titleI18nKey, descriptionI18nKey)
- - `canOptIn: boolean`
- - `blockingReason: string | null`
- - `userRoleContext: { isOrgAdmin, adminTeamIds, orgId }`
- - `dismiss(): void` - updates the consolidated localStorage key
- - `openDialog(): void` - triggers confirmation dialog
-
----
-
-## 3. UI Components
-
-### 3a. Floating Banner Component
-
-**Location:** `packages/features/feature-opt-in/components/FeatureOptInBanner.tsx`
-
-A minimal floating banner positioned at bottom-right:
-- Small rectangle with feature title and brief description
-- Close button (X) - calls `dismiss()` to save to localStorage
-- Clickable area - opens confirmation dialog
-- Can be refined later for design polish
-
-### 3b. Confirmation Dialog
-
-**Location:** `packages/features/feature-opt-in/components/FeatureOptInConfirmDialog.tsx`
-
-Complex dialog with role-based options:
-
-**For Org Owners/Admins:**
-- Radio/checkbox to choose scope:
- - "Enable for entire organization"
- - "Enable just for me"
-- Auto opt-in checkbox: "Automatically opt into future features for my organization"
-
-**For Team Owners/Admins (not org admin):**
-- Radio/checkbox to choose scope:
- - "Enable for my teams" (list team names if multiple)
- - "Enable just for me"
-- Auto opt-in checkbox: "Automatically opt into future features for my teams"
-
-**For Regular Users:**
-- Simple confirmation message
-- Auto opt-in checkbox: "Automatically opt into future features"
-
-**CTA Button:** "Enable Feature" - calls appropriate mutation(s) based on selection
-
-### 3c. Success State (within Confirmation Dialog)
-
-Instead of a separate success dialog (which would cause UI flashing), the confirmation dialog handles the success state internally:
-
-**Flow:**
-1. User clicks "Enable Feature" button
-2. Button shows a loading spinner while the mutation runs
-3. On success, the dialog content transitions to show success state
-4. Success state displays:
- - "Successfully enabled!" message
- - Two buttons:
- 1. "Dismiss" - closes dialog
- 2. "View Settings" - redirects to appropriate settings page
-
-**Redirect Logic:**
-- If user opted in for org: `/settings/organizations/features`
-- If user opted in for team(s): `/settings/teams/[first-team-id]/features`
-- If user opted in for self only: `/settings/my-account/features`
-
-This approach provides a smoother UX by avoiding the jarring close-and-reopen of separate dialogs.
-
----
-
-## 4. Integration Points
-
-**Example:** `apps/web/modules/bookings/views/bookings-view.tsx`
-
-At the view level:
-1. Import and call the hook: `const optInBanner = useFeatureOptInBanner("bookings-v3")`
-2. Conditionally render the banner: `{optInBanner.shouldShow && }`
-
-This pattern can be replicated for any view where a feature opt-in banner is needed.
-
----
-
-## 5. Policy Considerations
-
-The existing `computeEffectiveStateAcrossTeams` function already handles the two policies:
-
-**Permissive Policy:**
-- User can opt-in even if org/teams haven't explicitly enabled
-- Only blocked if ALL teams have explicitly disabled
-
-**Strict Policy:**
-- User cannot opt-in alone; requires org/team to enable first
-- ANY explicit disable from org/team blocks the user
-
-The TRPC procedure should use the feature's policy (from `OPT_IN_FEATURES` config) to determine if the user can opt-in.
-
----
-
-## 6. Data Flow Summary
-
-```
-View (bookings-view.tsx)
- |
- v
-useFeatureOptInBanner("bookings-v3")
- |
- v
-[Check localStorage for dismissal]
- | (if not dismissed)
- v
-TRPC: checkFeatureOptInEligibility
- |
- v
-FeatureOptInService.resolveFeatureStatesAcrossTeams
- |
- v
-[Return eligibility + user role context]
- |
- v
-Render FeatureOptInBanner (if eligible)
- | (on click)
- v
-FeatureOptInConfirmDialog
- | (on confirm)
- v
-Existing mutations: setUserState / setTeamState / setOrganizationState
- |
- v
-[Dialog transitions to success state]
-```
-
----
-
-## 7. Key Dependencies on PR #25892
-
-This plan relies on these existing pieces from the underlying PR:
-- `FeatureOptInService` and `resolveFeatureStatesAcrossTeams`
-- `computeEffectiveStateAcrossTeams` with policy support
-- `OPT_IN_FEATURES` config with policy field
-- Existing mutations for setting user/team/org states
-- Settings pages at `/settings/*/features`
-
----
-
-## 8. Files to Create/Modify
-
-### New Files:
-- `packages/features/feature-opt-in/components/FeatureOptInBanner.tsx`
-- `packages/features/feature-opt-in/components/FeatureOptInConfirmDialog.tsx` (includes success state handling)
-- `apps/web/modules/feature-opt-in/hooks/useFeatureOptInBanner.ts`
-
-### Modified Files:
-- `packages/trpc/server/routers/viewer/featureOptIn/_router.ts` (add new procedure)
-- `apps/web/modules/bookings/views/bookings-view.tsx` (integrate banner)
-- Translation files for new i18n keys
diff --git a/packages/features/flags/DECORATOR_IMPLEMENTATION_PLAN.md b/packages/features/flags/DECORATOR_IMPLEMENTATION_PLAN.md
deleted file mode 100644
index 3d67efa1fc..0000000000
--- a/packages/features/flags/DECORATOR_IMPLEMENTATION_PLAN.md
+++ /dev/null
@@ -1,290 +0,0 @@
-# Memoize/Unmemoize Decorator Implementation Plan
-
-## Overview
-
-This plan outlines the implementation of `@Memoize` and `@Unmemoize` decorators to replace the current CachedXXRepository + PrismaXXRepository + RedisXXRepository pattern (9 classes per 3 entities) with a more declarative approach.
-
-## Current State
-
-The current implementation uses three layers per entity:
-- `PrismaUserFeatureRepository` - Database access
-- `RedisUserFeatureRepository` - Cache operations (get/set/invalidate)
-- `CachedUserFeatureRepository` - Orchestrates cache-aside pattern
-
-This results in 9 repository classes for 3 entities (Feature, TeamFeature, UserFeature), with repetitive cache-aside logic in each CachedXXRepository.
-
-## Target State
-
-A single repository class per entity with decorators handling caching:
-
-```typescript
-class UserFeatureRepository {
- @Memoize({ key: (userId, featureId) => `features:user:${userId}:${featureId}`, schema: userFeaturesSchema })
- async findByUserIdAndFeatureId(userId: number, featureId: FeatureId): Promise {
- return this.prisma.userFeatures.findUnique({ where: { userId_featureId: { userId, featureId } } });
- }
-
- @Unmemoize({ keys: (userId, featureId) => [`features:user:${userId}:${featureId}`] })
- async upsert(userId: number, featureId: FeatureId, enabled: boolean, assignedBy: string): Promise {
- return this.prisma.userFeatures.upsert({ ... });
- }
-}
-```
-
-## Implementation Steps
-
-### Step 1: Enable Decorators in tsconfig (if needed)
-
-The `packages/features/tsconfig.json` extends `@calcom/tsconfig/react-library.json`. We need to add `experimentalDecorators: true` to enable legacy decorators.
-
-**Note**: Many packages already have `experimentalDecorators: true` (apps/web, apps/api/v2, packages/trpc, etc.), so this is consistent with the codebase.
-
-### Step 2: Create Decorator Infrastructure
-
-Create new files in `packages/features/cache/`:
-
-1. **`packages/features/cache/decorators/Memoize.ts`**
- - Decorator that wraps methods with cache-aside logic
- - Accepts configuration: `key`, `ttl`, `schema` (Zod)
- - Uses `IRedisService` for cache operations
- - Validates cached data with Zod schema before returning
-
-2. **`packages/features/cache/decorators/Unmemoize.ts`**
- - Decorator that invalidates cache keys after method execution
- - Accepts configuration: `keys` (function returning array of cache keys)
- - Invalidates specified keys after the wrapped method completes
-
-3. **`packages/features/cache/decorators/index.ts`**
- - Re-exports both decorators
-
-4. **`packages/features/cache/decorators/types.ts`**
- - Shared types for decorator configuration
-
-### Step 3: Implement @Memoize Decorator
-
-```typescript
-interface MemoizeConfig {
- key: (...args: TArgs) => string;
- ttl?: number;
- schema?: ZodSchema;
-}
-
-function Memoize(config: MemoizeConfig) {
- return function (
- target: (this: T, ...args: TArgs) => Promise,
- context: ClassMethodDecoratorContext
- ) {
- return async function (this: T, ...args: TArgs) {
- const cacheKey = config.key(...args);
- const cached = await this.redis.get(cacheKey);
-
- if (cached !== null) {
- if (config.schema) {
- const parsed = config.schema.safeParse(cached);
- if (parsed.success) return parsed.data;
- } else {
- return cached;
- }
- }
-
- const result = await target.call(this, ...args);
- if (result !== null) {
- await this.redis.set(cacheKey, result, { ttl: config.ttl ?? DEFAULT_TTL });
- }
- return result;
- };
- };
-}
-```
-
-### Step 4: Implement @Unmemoize Decorator
-
-```typescript
-interface UnmemoizeConfig {
- keys: (...args: TArgs) => string[];
-}
-
-function Unmemoize(config: UnmemoizeConfig) {
- return function (
- target: (this: T, ...args: TArgs) => Promise,
- context: ClassMethodDecoratorContext
- ) {
- return async function (this: T, ...args: TArgs) {
- const result = await target.call(this, ...args);
- const keysToInvalidate = config.keys(...args);
- await Promise.all(keysToInvalidate.map((key) => this.redis.del(key)));
- return result;
- };
- };
-}
-```
-
-### Step 5: Refactor UserFeatureRepository
-
-Create a new unified `UserFeatureRepository` that uses decorators:
-
-```typescript
-export class UserFeatureRepository implements IUserFeatureRepository {
- constructor(
- private prisma: PrismaClient,
- private redis: IRedisService
- ) {}
-
- async findByUserId(userId: number): Promise {
- return this.prisma.userFeatures.findMany({ where: { userId } });
- }
-
- @Memoize({
- key: (userId: number, featureId: FeatureId) => `features:user:${userId}:${featureId}`,
- schema: userFeaturesSchema,
- })
- async findByUserIdAndFeatureId(userId: number, featureId: FeatureId): Promise {
- return this.prisma.userFeatures.findUnique({
- where: { userId_featureId: { userId, featureId } },
- });
- }
-
- @Memoize({
- key: (userId: number) => `features:user:autoOptIn:${userId}`,
- schema: booleanSchema,
- })
- async findAutoOptInByUserId(userId: number): Promise {
- const user = await this.prisma.user.findUnique({
- where: { id: userId },
- select: { autoOptInFeatures: true },
- });
- return user?.autoOptInFeatures ?? false;
- }
-
- @Unmemoize({
- keys: (userId: number, featureId: FeatureId) => [`features:user:${userId}:${featureId}`],
- })
- async upsert(userId: number, featureId: FeatureId, enabled: boolean, assignedBy: string): Promise {
- return this.prisma.userFeatures.upsert({
- where: { userId_featureId: { userId, featureId } },
- create: { userId, featureId, enabled, assignedBy },
- update: { enabled, assignedBy },
- });
- }
-
- @Unmemoize({
- keys: (userId: number, featureId: FeatureId) => [`features:user:${userId}:${featureId}`],
- })
- async delete(userId: number, featureId: FeatureId): Promise {
- await this.prisma.userFeatures.delete({
- where: { userId_featureId: { userId, featureId } },
- });
- }
-
- @Unmemoize({
- keys: (userId: number) => [`features:user:autoOptIn:${userId}`],
- })
- async updateAutoOptIn(userId: number, enabled: boolean): Promise {
- await this.prisma.user.update({
- where: { id: userId },
- data: { autoOptInFeatures: enabled },
- });
- }
-
- // Methods without caching (complex queries)
- async checkIfUserBelongsToTeamWithFeature(userId: number, slug: string): Promise {
- // ... existing implementation
- }
-
- async checkIfUserBelongsToTeamWithFeatureNonHierarchical(userId: number, slug: string): Promise {
- // ... existing implementation
- }
-}
-```
-
-### Step 6: Update DI Configuration
-
-Update the DI module to use the new unified repository:
-
-```typescript
-// packages/features/flags/di/UserFeatureRepository.module.ts
-const loadModule = bindModuleToClassOnToken({
- module: thisModule,
- moduleToken,
- token,
- classs: UserFeatureRepository,
- depsMap: {
- prisma: prismaModuleLoader,
- redis: redisModuleLoader,
- },
-});
-```
-
-### Step 7: Write Tests
-
-Create comprehensive tests for the decorators:
-
-1. **`packages/features/cache/decorators/__tests__/Memoize.test.ts`**
- - Test cache hit returns cached value
- - Test cache miss fetches from source and caches
- - Test Zod validation on cached data
- - Test null results are not cached
- - Test TTL is respected
-
-2. **`packages/features/cache/decorators/__tests__/Unmemoize.test.ts`**
- - Test cache keys are invalidated after method execution
- - Test multiple keys can be invalidated
- - Test method result is returned correctly
-
-## File Structure
-
-```
-packages/features/
- cache/
- decorators/
- __tests__/
- Memoize.test.ts
- Unmemoize.test.ts
- Memoize.ts
- Unmemoize.ts
- types.ts
- index.ts
- flags/
- repositories/
- UserFeatureRepository.ts (new unified repository)
- # Keep existing files for backward compatibility during migration
- di/
- UserFeatureRepository.module.ts (new module)
- tokens.ts (add new token)
-```
-
-## Migration Strategy
-
-1. Create the new decorator infrastructure alongside existing code
-2. Create the new unified `UserFeatureRepository` with decorators
-3. Add new DI module for the unified repository
-4. Update consumers to use the new repository
-5. Remove old CachedXXRepository, RedisXXRepository files after migration is complete
-
-## Benefits
-
-1. **Reduced boilerplate**: 1 class instead of 3 per entity
-2. **Declarative caching**: Cache behavior is visible at method level
-3. **Co-located logic**: Caching and invalidation rules are next to the methods they affect
-4. **Type-safe**: Full TypeScript support with proper typing
-5. **Testable**: Decorators can be tested independently
-6. **Consistent**: Same pattern for all repositories
-
-## Considerations
-
-1. **Decorator limitations**: Legacy decorators (experimentalDecorators) are used since TC39 decorators have different semantics
-2. **Redis dependency**: Repository classes must have `redis: IRedisService` property for decorators to work
-3. **Zod validation**: Optional but recommended for cached data integrity
-4. **TTL**: Default 5 minutes, configurable per method
-
-## Timeline
-
-1. Step 1-2: Create decorator infrastructure (~30 min)
-2. Step 3-4: Implement decorators (~30 min)
-3. Step 5: Refactor UserFeatureRepository (~30 min)
-4. Step 6: Update DI configuration (~15 min)
-5. Step 7: Write tests (~45 min)
-6. Type checks and lint (~15 min)
-7. Create PR (~10 min)
-
-Total estimated time: ~3 hours