Action

Type

Resolved On

Externalize Project Hierarchy refactoring - - -

Externalize Project Hierarchy

Overview

The project hierarchy mapping is hardcoded in monthly.ts, making it difficult to modify without code changes and violating the principle of configuration over code.

Problem

The projectHierarchy object is hardcoded in src/lib/monthly.ts:436-450:

const projectHierarchy: { [key: string]: string[] } = {
  benben: ["benben", "listening", "reading", "speaking", "watching"],
  hygge: [
    "hygge",
    "drawing",
    "growing",
    "selling",
    "sharing",
    "showing",
    "thinking",
    "writing",
  ],
  bearlabs: ["bearlabs"],
  walkingweekend: ["walkingweekend"],
};

Issues

  1. Code Changes Required: Adding a new project requires modifying source code
  2. Re-deployment Needed: Changes require rebuilding and redeploying
  3. Single Source: Only used in one place but could be needed elsewhere
  4. No Runtime Flexibility: Can’t be adjusted without code push

Solution

Move the project hierarchy to a configuration file or database table.

Option 1: Configuration File

src/config/projects.ts:

export interface ProjectHierarchy {
  [parent: string]: string[];
}

export const projectHierarchy: ProjectHierarchy = {
  benben: ["benben", "listening", "reading", "speaking", "watching"],
  hygge: [
    "hygge",
    "drawing",
    "growing",
    "selling",
    "sharing",
    "showing",
    "thinking",
    "writing",
  ],
  bearlabs: ["bearlabs"],
  walkingweekend: ["walkingweekend"],
};

export function getSubProjects(parent: string): string[] {
  return projectHierarchy[parent] || [parent];
}

export function isValidProject(project: string): boolean {
  return Object.values(projectHierarchy)
    .flat()
    .includes(project);
}

Option 2: Database Table

Create a project_hierarchy table in Supabase:

CREATE TABLE project_hierarchy (
  parent_project text NOT NULL,
  sub_project text NOT NULL,
  display_order int DEFAULT 0,
  PRIMARY KEY (parent_project, sub_project)
);

-- Insert current data
INSERT INTO project_hierarchy VALUES
  ('benben', 'benben', 0),
  ('benben', 'listening', 1),
  ('benben', 'reading', 2),
  ('benben', 'speaking', 3),
  ('benben', 'watching', 4),
  ('hygge', 'hygge', 0),
  ('hygge', 'drawing', 1),
  -- ... etc

Then query it:

export async function getSubProjects(parent: string): Promise<string[]> {
  const { data } = await supabase
    .from('project_hierarchy')
    .select('sub_project')
    .eq('parent_project', parent)
    .order('display_order');

  return data?.map(row => row.sub_project) || [parent];
}

Benefits

  • Configuration Over Code: Changes don’t require code modifications
  • Runtime Updates: Database option allows dynamic changes
  • Reusability: Other parts of the app can import the configuration
  • Validation: Can validate project names against known projects
  • Extensibility: Easy to add metadata (display names, colors, etc.)

Implementation Notes

  • Configuration file approach is simpler and requires no database changes
  • Database approach enables admin UI for project management
  • Consider combining both: config file as fallback, database as override
  • src/lib/monthly.ts (current location of hardcoded hierarchy)
  • src/lib/innovation.ts (if created, would also need this data)