The MOOD MNKY ecosystem uses a mono repository architecture to organize all codebase components and ensure consistency across our digital products. This approach allows us to share code, maintain unified standards, and streamline development workflows.
Our mono repo is managed with Turborepo, providing parallel execution, incremental builds, and a structured development experience.
We use a combination of tools to manage dependencies in our mono repo:
1
Package Manager
pnpm is our primary package manager, chosen for its efficient handling of dependencies in a mono repo structure.
Copy
# Installing a dependency in a specific package or apppnpm --filter @mood-mnky/web add react-query# Installing a dependency for all packages and appspnpm add -w typescript# Installing a workspace package as a dependencypnpm --filter @mood-mnky/dojo add @mood-mnky/ui
2
Workspace Configuration
Our workspaces are configured in pnpm-workspace.yaml:
The Supabase integration follows our structured organization:
Database Schema
Database schemas are defined in SQL files within the data/schemas directory:
Copy
-- data/schemas/users.sqlCREATE TABLE public.users ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, email TEXT UNIQUE NOT NULL, full_name TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT now(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT now(), scent_profile JSONB, preferences JSONB);-- Add indexes for common query patternsCREATE INDEX users_email_idx ON public.users (email);-- Add RLS policiesALTER TABLE public.users ENABLE ROW LEVEL SECURITY;CREATE POLICY "Users can view their own data" ON public.users FOR SELECT USING (auth.uid() = id);CREATE POLICY "Users can update their own data" ON public.users FOR UPDATE USING (auth.uid() = id);
These schema files are the source of truth for table definitions and are used to generate migrations.
Data Models
TypeScript data models provide type safety for database interactions:
Migrations in the infra/supabase/migrations directory reflect changes to the database schema:
Copy
-- infra/supabase/migrations/20240401000000_create_users_table.sqlCREATE TABLE public.users ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, email TEXT UNIQUE NOT NULL, full_name TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT now(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT now());-- infra/supabase/migrations/20240402000000_add_scent_profile.sqlALTER TABLE public.users ADD COLUMN scent_profile JSONB;ALTER TABLE public.users ADD COLUMN preferences JSONB;
Each migration is a timestamped file that can be applied in sequence to build the database structure.
Supabase Client
The packages/supabase-client package provides a consistent way to interact with Supabase:
Copy
// packages/supabase-client/src/index.tsimport { createClient } from '@supabase/supabase-js';import type { Database } from '@repo/types';let supabaseInstance: ReturnType<typeof createClient> | null = null;export function getSupabaseClient() { if (!supabaseInstance) { const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL; const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY; if (!supabaseUrl || !supabaseKey) { throw new Error('Missing Supabase environment variables'); } supabaseInstance = createClient<Database>(supabaseUrl, supabaseKey); } return supabaseInstance;}export function getSupabaseServerClient() { const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL; const supabaseServiceKey = process.env.SUPABASE_SERVICE_ROLE_KEY; if (!supabaseUrl || !supabaseServiceKey) { throw new Error('Missing Supabase environment variables for server client'); } return createClient<Database>(supabaseUrl, supabaseServiceKey);}
This client is used across all applications to ensure consistent API access.
# Start development server for a specific apppnpm --filter @mood-mnky/web dev# Start development servers for multiple appspnpm --filter "@mood-mnky/web..." dev# Build a specific package and its dependenciespnpm --filter "@mood-mnky/ui..." build# Run tests for all packages and appspnpm test# Create a new migrationcd infra/supabasesupabase migration new add_new_feature