.claude/skills/ridendine-modular-architecture/SKILL.md
Master RidenDine's modular monorepo architecture with three independent apps. Use when: (1) understanding project structure, (2) adding new apps to monorepo, (3) configuring shared packages, (4) deploying apps independently, (5) debugging cross-app dependencies. Key insight: Admin, Web, and Mobile are separate apps with independent deployments but share packages via pnpm workspace (packages/shared, packages/data).
npx skillsauth add Ritenoob/ridedine ridendine-modular-architectureInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
RidenDine is built as a modular monorepo where three separate applications (Admin, Web, Mobile) share common code but deploy independently. Each app serves a different user persona and has its own deployment pipeline.
Use this skill when:
ridendine-demo-main/
├── apps/
│ ├── admin/ # Admin Dashboard (Next.js 15)
│ ├── web/ # Customer Web App (Next.js 15)
│ └── mobile/ # Driver Mobile App (Expo/React Native)
├── packages/
│ ├── shared/ # Types, enums, utilities
│ └── data/ # Supabase repositories, data access layer
├── backend/
│ └── supabase/ # Database migrations, Edge Functions
└── pnpm-workspace.yaml # Workspace configuration
| App | Tech Stack | Users | URL | Deployment | |-----|-----------|-------|-----|------------| | Admin | Next.js 15 | Admins, Chefs | https://ridedine-admin.vercel.app | Vercel (apps/admin root) | | Web | Next.js 15 | Customers | https://ridedine-web.vercel.app | Vercel (apps/web root) | | Mobile | Expo SDK 50 | Drivers | APK/IPA via EAS | EAS Build |
Key Principle: Each app is independently deployable - you can deploy Admin without touching Web or Mobile.
Location: pnpm-workspace.yaml (project root)
packages:
- 'apps/*'
- 'packages/*'
Why pnpm workspaces?
Common commands:
# Install all dependencies (run from root)
pnpm install
# Run command in specific app
pnpm --filter admin dev
pnpm --filter web build
pnpm --filter mobile start
# Run command in all apps
pnpm -r dev # Recursive, all workspaces
pnpm -r --parallel dev # Parallel execution
# Add dependency to specific app
pnpm --filter admin add @supabase/supabase-js
pnpm --filter web add stripe
# Add shared package dependency to app
pnpm --filter admin add @home-chef/shared --workspace
pnpm --filter mobile add @home-chef/data --workspace
@home-chef/sharedLocation: packages/shared/
Contains:
Chef, Order, Delivery, MenuItem)OrderStatus, DeliveryStatus, PaymentStatus, UserRole)Usage across apps:
// In apps/admin/src/components/ChefApproval.tsx
import { Chef, ChefStatus } from '@home-chef/shared';
// In apps/web/app/checkout/page.tsx
import { Order, OrderStatus } from '@home-chef/shared';
// In apps/mobile/app/(driver)/jobs.tsx
import { DeliveryStatus, calculateDistance } from '@home-chef/shared';
Why shared? Ensures type consistency across all apps - when you update Order type, all apps get the change.
@home-chef/dataLocation: packages/data/
Contains:
OrdersRepository, DeliveriesRepository, ChefsRepository)Usage:
// In apps/admin/src/lib/orders.ts
import { OrdersRepository } from '@home-chef/data';
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(/* ... */);
const ordersRepo = new OrdersRepository(supabase);
const orders = await ordersRepo.getPendingOrders();
// In apps/mobile/app/(driver)/jobs.tsx
import { DeliveriesRepository } from '@home-chef/data';
const repo = new DeliveriesRepository(supabase);
const availableDeliveries = await repo.getAvailableDeliveries(50);
Why shared? Prevents duplicate data access logic - all apps use the same database queries.
Each app has distinct features that do not overlap:
apps/admin)Purpose: Chef/driver approval, order monitoring, platform management
Key Features:
Tech Stack:
Entry Point: apps/admin/app/page.tsx
Deployment:
cd apps/admin
npm run build
# Deploy to Vercel with Root Directory: apps/admin
apps/web)Purpose: Customer-facing marketplace for ordering food
Key Features:
Tech Stack:
Entry Point: apps/web/app/page.tsx
Deployment:
cd apps/web
npm run build
# Deploy to Vercel with Root Directory: apps/web
apps/mobile)Purpose: Driver app for accepting and completing deliveries
Key Features:
Tech Stack:
Entry Point: apps/mobile/app/_layout.tsx
Deployment:
cd apps/mobile
eas build --profile production --platform android
eas submit --platform android --latest
Key Principle: Each app deploys independently without affecting others.
Configuration per app:
// apps/admin/vercel.json
{
"framework": "nextjs"
}
// apps/web/vercel.json
{
"framework": "nextjs"
}
Vercel Project Settings:
apps/adminapps/webEnvironment Variables (per project):
NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...
SUPABASE_SERVICE_ROLE_KEY=eyJ... # Admin only
Deploy triggers:
main branch → Auto-deploys both appsapps/admin/ → Only Admin rebuildsapps/web/ → Only Web rebuildspackages/ → Both Admin and Web rebuildConfiguration: apps/mobile/eas.json
{
"build": {
"development": { "developmentClient": true, "distribution": "internal" },
"preview": { "distribution": "internal" },
"production": { "channel": "production" }
}
}
Deployment:
cd apps/mobile
eas build --profile production --platform all
eas submit --platform ios --latest
eas submit --platform android --latest
Environment Variables (in eas.json):
"env": {
"EXPO_PUBLIC_SUPABASE_URL": "https://xxx.supabase.co",
"EXPO_PUBLIC_SUPABASE_ANON_KEY": "eyJ..."
}
All three apps connect to the same Supabase backend:
backend/supabase/
├── migrations/ # Database schema
│ ├── 20240101_init.sql
│ ├── 20240102_add_chefs.sql
│ └── 20240103_add_deliveries.sql
├── functions/ # Edge Functions (serverless)
│ ├── create_checkout_session/
│ ├── create_connect_account/
│ ├── webhook_stripe/
│ ├── geocode_address/
│ └── get_route/
└── seed/ # Test data
Row Level Security (RLS) enforces app boundaries:
-- Admin can view all orders
CREATE POLICY "admin_can_view_all_orders"
ON orders FOR SELECT TO authenticated
USING (
(SELECT role FROM profiles WHERE id = auth.uid()) = 'admin'
);
-- Customers can only view their own orders
CREATE POLICY "customers_can_view_own_orders"
ON orders FOR SELECT TO authenticated
USING (customer_id = auth.uid());
-- Drivers can only view orders assigned to them
CREATE POLICY "drivers_can_view_assigned_orders"
ON orders FOR SELECT TO authenticated
USING (
EXISTS (
SELECT 1 FROM deliveries d
JOIN drivers dr ON d.driver_id = dr.id
WHERE d.order_id = orders.id AND dr.profile_id = auth.uid()
)
);
Example: Adding a "Chef Portal" app
Step 1: Create app directory
mkdir -p apps/chef-portal
cd apps/chef-portal
npx create-next-app@latest . --typescript --tailwind --app
Step 2: Update package.json
{
"name": "@home-chef/chef-portal",
"version": "0.1.0",
"dependencies": {
"@home-chef/shared": "workspace:*",
"@home-chef/data": "workspace:*",
"next": "15.0.0",
"react": "18.2.0"
}
}
Step 3: Verify workspace
# From project root
pnpm install
pnpm --filter chef-portal dev
Step 4: Configure deployment
apps/chef-portalCause: Shared package not installed or wrong import path
Fix:
# From project root
pnpm install
# Verify workspace structure
pnpm list --depth 0 --filter admin
# Should show @home-chef/shared in dependencies
# If missing, add it
pnpm --filter admin add @home-chef/shared --workspace
Cause: Root Directory not configured
Fix:
apps/admin or apps/webCause: TypeScript not recompiling shared package
Fix:
# From packages/shared
pnpm build
# Or use watch mode during development
pnpm dev # (if configured in packages/shared/package.json)
Cause: Expo Metro bundler doesn't follow symlinks by default
Fix: Add to apps/mobile/metro.config.js:
const { getDefaultConfig } = require('expo/metro-config');
const path = require('path');
const projectRoot = __dirname;
const workspaceRoot = path.resolve(projectRoot, '../..');
const config = getDefaultConfig(projectRoot);
// Watch for changes in shared packages
config.watchFolders = [workspaceRoot];
// Resolve shared packages
config.resolver.nodeModulesPaths = [
path.resolve(projectRoot, 'node_modules'),
path.resolve(workspaceRoot, 'node_modules'),
];
module.exports = config;
After setting up or modifying the monorepo structure:
Verify workspace:
# From root
pnpm -r list --depth 0
# Should show all apps and packages
# Verify shared package resolution
pnpm --filter admin why @home-chef/shared
pnpm --filter web why @home-chef/shared
pnpm --filter mobile why @home-chef/shared
Test builds:
# Build each app independently
pnpm --filter admin build
pnpm --filter web build
cd apps/mobile && npx expo export # Check bundling works
Test shared package changes:
packages/shared/src/types.ts (add a new field)apps/admin and apps/webFrom separate repos to monorepo:
If Admin, Web, and Mobile were separate repos and you're consolidating:
packages/sharedpackages/data// Before
import { Chef } from '../types/chef';
// After
import { Chef } from '@home-chef/shared';
.claude/skills/vercel-deployment/SKILL.mdpackages/shared/README.md, packages/data/README.mddevelopment
Integrate Coinbase crypto payments into payment systems. Use when: (1) adding crypto payment support, (2) building onchain features, (3) implementing wallet functionality. Covers Coinbase Commerce (payment processor) vs CDP (developer platform), Server Wallets, Embedded Wallets, and multi-network support.
development
Add Apple Pay and Google Pay to Stripe checkout. Use when: (1) adding mobile wallet payments, (2) improving mobile conversion, (3) implementing one-tap checkout. Stripe Payment Request Button automatically detects device capabilities and shows Apple Pay (Safari/iOS) or Google Pay (Chrome/Android).
development
Master Vercel deployment for RidenDine web and admin Next.js apps. Use when: (1) deploying to production, (2) configuring environment variables, (3) setting up preview deployments, (4) debugging build failures, (5) configuring domains, (6) seeing "No Next.js version detected" error in Vercel builds, (7) setting up monorepo with separate projects on free tier. Key insight: Vercel monorepos require Root Directory configuration via dashboard (not vercel.json), GitHub integration auto-detects monorepo structure, free tier allows multiple projects.
development
Master Supabase Row Level Security (RLS) for RidenDine. Use when: (1) adding new tables, (2) modifying RLS policies, (3) debugging access control issues, (4) role-based data access. Key insight: All tables use RLS with role-based policies from profiles.role column.