Skip to content

Instantly share code, notes, and snippets.

@vqc1909a
Last active February 26, 2026 06:30
Show Gist options
  • Select an option

  • Save vqc1909a/b1e98223053677639470fa6e2392464c to your computer and use it in GitHub Desktop.

Select an option

Save vqc1909a/b1e98223053677639470fa6e2392464c to your computer and use it in GitHub Desktop.
LEGACY_TEAM_ACCOUNTS_DISADVANTAGES.md

Legacy Team Accounts Architecture - Disadvantages Analysis

Overview

The current team accounts implementation uses a dual-authentication architecture built by a previous developer. This document outlines the technical disadvantages of continuing with this approach versus migrating to a unified system.


1. Dual Authentication Systems

The legacy approach maintains two separate auth systems:

  • team_users table: Custom auth outside Supabase Auth with manually hashed passwords and session management via team_user_sessions.
  • team_sub_accounts table: Real Supabase Auth users tied as "children" of a parent user.

This means every security concern (token refresh, password reset, session expiry, brute-force protection) must be handled in two places. Supabase Auth provides these out of the box, but the custom team_users system reimplements them manually.

Risk: Any security vulnerability in the custom auth layer (e.g., weak hashing, session fixation, missing rate limiting) is a liability that Supabase Auth already solves.


2. Separate Login Flows

Two login pages exist:

  • /get-started β€” Regular users (Supabase Auth)
  • /team-login (TeamLogin.tsx) β€” Team users (custom auth)

Users must know which login to use. This doubles the login surface area for bugs, UX confusion, and support requests. A single login page that works for everyone is simpler for users and developers.


3. Over-Engineered Permission Model

Four separate permission tables exist for per-user-per-resource granularity:

Table Scope
team_user_platform_access Per platform: can_create_campaigns, can_manage_creatives, can_view_insights
team_user_mapping_access Per account_mapping: read / write / admin
team_sub_account_platform_access Same as above, but for sub-accounts
team_sub_account_mapping_access Same as above, but for sub-accounts

The product brief only requires 4 predefined roles (Admin, Manager, Contributor, Read-Only). The legacy system solves a much more complex problem than what is actually needed, adding maintenance burden without product value.

Impact: Every permission check requires querying multiple tables with joins. A single team_members.role field checked against a permission matrix achieves the same result with one query.


4. No Single Source of Truth for Team Membership

Team members can exist in three different tables:

Table User Type
team_members Supabase Auth users
team_users Custom auth users (password-hashed, session-based)
team_sub_accounts Child Supabase Auth users (parent-child relationship)

Querying "who is on this team" requires checking all three tables. Member counts, display lists, permission checks, and team management operations all need UNION queries across multiple tables. This creates inconsistency and makes bugs harder to trace.


5. JSONB Array for Account Mapping Sharing

The teams table stores shared account mapping IDs as a JSONB array (account_mapping_ids):

-- Current approach
teams.account_mapping_ids = '["a49b50ad-...", "b12c34de-..."]'::jsonb

Problems with this approach:

Issue Impact
No referential integrity Array can reference deleted account_mappings with no error
No index support Full table scan with unnest() on every query
Manual sync required Adding/removing mappings requires updating the array manually
Cannot write RLS policies PostgreSQL RLS cannot efficiently filter based on JSONB array contents
No cascade behavior Deleting an account_mapping does not remove it from the array

The alternative (a team_id FK column on account_mappings) provides proper foreign keys, B-tree index support, standard JOIN performance, and clean RLS policies.


6. Wide-Open RLS Policies (Security Risk)

The team_users and team_invitations tables have permissive "allow all" RLS policies left from development:

-- Current state: any authenticated user can read/modify ANY team's data
CREATE POLICY "allow_all" ON team_users FOR ALL USING (true);
CREATE POLICY "allow_all" ON team_invitations FOR ALL USING (true);

This means any authenticated user in the system can:

  • Read all team invitations across all teams
  • Modify team membership records they do not belong to
  • View sensitive team configuration data

Shipping with these policies is a data isolation failure. Proper RLS requires team membership and role checks.


7. Prototype-Quality Code in Production Path

The TeamLogin.tsx page shows signs of incomplete implementation:

  • Fallback chains: Try edge function, fall back to RPC, fall back to direct query β€” indicates unstable API contracts
  • Debug logging left in: Console statements with emoji markers (πŸ”, βœ…, ❌) in production code
  • Type bypassing: (supabase as any).rpc(...) casting to avoid TypeScript errors rather than fixing the type definitions
  • No error recovery: If the invitation acceptance fails after login succeeds, the user is in a broken state (logged in but not on the team)

These patterns suggest the implementation was still in prototype/exploration phase, not production-ready.


8. 3x Feature Development Cost

Every new feature must work for three user types:

User Type Auth Method Session Management Token Storage
Regular users Supabase Auth Supabase managed Supabase JWT
Team users Custom password hash team_user_sessions table Custom session token
Sub-account users Supabase Auth (child) Supabase managed Supabase JWT

This triples testing, edge cases, and maintenance for every feature shipped. Each new page, edge function, or query must account for all three user types and their different authentication patterns.


9. No Clear Upgrade Path

The legacy architecture does not have a migration path to the product brief's requirements:

  • Custom auth users (team_users) cannot use Supabase Auth features: password reset, email verification, OAuth providers, session management β€” all unavailable.
  • Sub-accounts create real Supabase Auth users but with no team awareness: The parent-child relationship is tracked in a separate table, not in the auth system itself.
  • Role mapping is impossible: The granular per-resource permissions (4 tables) do not map cleanly to the 4 predefined roles (Admin, Manager, Contributor, Read-Only) from the product brief.

Comparison Summary

Aspect Legacy Approach New Approach
Auth systems 2 (Supabase + custom) 1 (Supabase only)
Login pages 2 (/get-started + /team-login) 1 (/get-started)
Permission tables 4 (per-user-per-resource) 1 (team_members.role)
Membership tables 3 (team_members + team_users + team_sub_accounts) 1 (team_members)
Account mapping linking JSONB array (no FK, no index, no RLS) team_id FK (proper constraints, indexed, RLS-compatible)
RLS policies Allow all (insecure) Role-based policies per table
New feature cost 3x (three user types) 1x (one user type)
Total team-related tables 10+ 3 (teams, team_members, team_invitations)
Permission query complexity Multi-table JOINs across 4 permission tables Single lookup: team_members.role
Security posture Custom auth + open RLS Supabase Auth + proper RLS

Legacy Tables to Deprecate

Table Reason for Deprecation
team_users Custom auth replaced by Supabase Auth via team_members
team_user_sessions Session management goes with team_users
team_sub_accounts Parent-child model replaced by flat team_members
team_sub_account_mapping_access Per-resource permissions replaced by role-based RLS
team_sub_account_platform_access Per-platform permissions replaced by role-permission matrix
team_user_platform_access Goes with team_users
team_user_mapping_access Goes with team_users
organizations Table exists but was never used in the codebase
org_members Table exists but was never used in the codebase

Legacy Frontend to Deprecate

File / Route Reason
src/pages/TeamLogin.tsx Separate team login no longer needed β€” single login at /get-started
/team-login route Remove from App.tsx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment