Agent skill
monorepo-structure
Use when determining where to place files, understanding project organization, or working across multiple packages. Provides comprehensive knowledge of the Hounii monorepo structure and workspace configuration.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/development/monorepo-structure
SKILL.md
Monorepo Structure Skill
Use this skill when you need to understand where files should go, how packages are organized, or how the monorepo workspace is configured.
Overview
Hounii is a pnpm + Turborepo monorepo with three apps and multiple shared packages.
hounii-monorepo/
├── apps/ # Application layer
│ ├── mobile/ # React Native + Expo (SDK 53)
│ ├── web/ # Next.js 15 (App Router)
│ └── admin/ # Next.js 15 (Admin portal)
├── packages/ # Shared packages
│ ├── ui/ # Tamagui design system
│ ├── lib/ # Shared utilities & business logic
│ ├── i18n/ # Internationalization
│ ├── api/ # Supabase client & types
│ └── config/ # Shared configurations
├── supabase/ # Database & backend
│ ├── migrations/ # SQL migrations
│ └── functions/ # Edge functions
└── [root configs] # Turborepo, pnpm, ESLint, TypeScript
Where Things Go
🎯 Quick Reference
| What | Where | Why |
|---|---|---|
| Mobile screens/features | apps/mobile/features/ |
Feature-driven structure |
| Web pages | apps/web/app/ |
Next.js App Router |
| Admin pages | apps/admin/app/ |
Next.js App Router |
| UI components (atoms) | packages/ui/src/ |
Shared Tamagui primitives |
| Business logic | packages/lib/src/ |
Reusable across apps |
| Translations | packages/i18n/translations/ |
Multi-language support |
| Database schema | supabase/migrations/ |
Version-controlled migrations |
| API types | packages/api/src/types/ |
Generated from Supabase |
| Config files | packages/config/ |
Shared ESLint, TS configs |
Apps Directory (apps/)
Mobile App (apps/mobile/)
Tech: React Native + Expo SDK 53 + Expo Router
apps/mobile/
├── app/ # Expo Router routes
│ ├── (auth)/ # Auth-protected routes
│ ├── (tabs)/ # Tab navigation
│ └── _layout.tsx # Root layout
├── features/ # Feature-driven modules
│ ├── auth/
│ │ ├── screens/ # Auth screens
│ │ ├── components/ # Auth-specific components
│ │ ├── hooks/ # Auth hooks
│ │ └── index.ts # Public exports
│ ├── profile/
│ ├── pets/
│ └── map/
├── components/ # Shared mobile components
├── hooks/ # Shared hooks
├── utils/ # Mobile-specific utilities
├── assets/ # Images, fonts, etc.
└── package.json # Mobile dependencies
When to use:
- React Native screens and navigation
- Mobile-specific features (camera, location, notifications)
- Native module integrations
- Platform-specific code (iOS/Android)
Dependencies:
{
"dependencies": {
"@hounii/ui": "workspace:*",
"@hounii/lib": "workspace:*",
"@hounii/i18n": "workspace:*",
"@hounii/api": "workspace:*"
}
}
Web App (apps/web/)
Tech: Next.js 15 + App Router + Server Components
apps/web/
├── app/ # Next.js App Router
│ ├── layout.tsx # Root layout
│ ├── page.tsx # Home page
│ ├── (auth)/ # Auth routes
│ ├── profile/ # Profile pages
│ └── api/ # API routes
├── components/ # Web-specific components
├── lib/ # Web utilities
├── public/ # Static assets
└── package.json # Web dependencies
When to use:
- Public-facing web pages
- SEO-optimized content
- Server-side rendering
- Web-specific features (PWA, web push)
Admin App (apps/admin/)
Tech: Next.js 15 + App Router
apps/admin/
├── app/
│ ├── dashboard/ # Admin dashboard
│ ├── users/ # User management
│ ├── pets/ # Pet moderation
│ └── analytics/ # Analytics views
├── components/ # Admin-specific components
└── package.json # Admin dependencies
When to use:
- Internal admin tools
- Moderation interfaces
- Analytics dashboards
- User management
Packages Directory (packages/)
UI Package (packages/ui/)
Purpose: Tamagui design system - atoms and primitives ONLY
packages/ui/
├── src/
│ ├── components/ # Tamagui primitives
│ │ ├── Button.tsx
│ │ ├── Input.tsx
│ │ ├── Card.tsx
│ │ └── index.ts
│ ├── theme/ # Design tokens
│ │ ├── tokens.ts # Colors, spacing, typography
│ │ └── themes.ts # Light/dark themes
│ └── index.ts # Public exports
└── package.json
What belongs here:
- ✅ Reusable UI primitives (Button, Input, Card)
- ✅ Design tokens (colors, spacing, typography)
- ✅ Theme configuration (light/dark modes)
- ✅ Icon components
What does NOT belong:
- ❌ Business logic
- ❌ API calls
- ❌ Feature-specific components
- ❌ State management
Example:
// ✅ BELONGS in packages/ui/
export function Button({ children, onPress, variant = 'primary' }: ButtonProps) {
return (
<Tamagui.Button
backgroundColor={variant === 'primary' ? '$primary' : '$secondary'}
onPress={onPress}
>
{children}
</Tamagui.Button>
);
}
// ❌ DOES NOT BELONG in packages/ui/
export function LoginButton() {
const { signIn } = useAuth(); // ❌ Business logic
return <Button onPress={signIn}>Login</Button>;
}
Lib Package (packages/lib/)
Purpose: Shared utilities and business logic
packages/lib/
├── src/
│ ├── stores/ # Zustand stores
│ │ ├── userStore.ts
│ │ └── authStore.ts
│ ├── hooks/ # Shared hooks
│ │ ├── useAuth.ts
│ │ └── useLocation.ts
│ ├── utils/ # Utilities
│ │ ├── date.ts
│ │ ├── validation.ts
│ │ └── format.ts
│ ├── types/ # Shared types
│ └── constants/ # App constants
└── package.json
What belongs here:
- ✅ Zustand stores
- ✅ Shared hooks (auth, data fetching)
- ✅ Utility functions (date formatting, validation)
- ✅ Shared types and interfaces
- ✅ Constants and enums
Example:
// ✅ BELONGS in packages/lib/
export const useAuth = () => {
const user = useUserStore((state) => state.user);
const signIn = async (email: string, password: string) => {
// Auth logic
};
return { user, signIn };
};
i18n Package (packages/i18n/)
Purpose: Internationalization for all apps
packages/i18n/
├── translations/
│ ├── en/
│ │ ├── common.json
│ │ ├── mobile.json
│ │ └── web.json
│ ├── fr/
│ ├── de/
│ └── ar/
├── src/
│ ├── config.ts # i18next configuration
│ └── index.ts
└── package.json
Supported languages:
en- Englishfr- Frenchde- Germanar- Arabic (RTL)
Structure:
// translations/en/mobile.json
{
"auth": {
"login": "Log In",
"signup": "Sign Up"
},
"profile": {
"title": "Profile",
"edit": "Edit Profile"
}
}
Usage:
import { useTranslation } from '@hounii/i18n';
const { t } = useTranslation('mobile');
console.log(t('auth.login')); // "Log In"
API Package (packages/api/)
Purpose: Supabase client and generated types
packages/api/
├── src/
│ ├── client.ts # Supabase client factory
│ ├── types/
│ │ └── database.ts # Generated from Supabase
│ └── index.ts
└── package.json
What belongs here:
- ✅ Supabase client configuration
- ✅ Database types (auto-generated)
- ✅ API helpers
Example:
// ✅ BELONGS in packages/api/
export const createSupabaseClient = (anonKey: string) => {
return createClient<Database>(SUPABASE_URL, anonKey);
};
Config Package (packages/config/)
Purpose: Shared ESLint, TypeScript, and other configs
packages/config/
├── eslint-preset.js
├── typescript/
│ ├── base.json
│ ├── react.json
│ └── nextjs.json
└── package.json
Usage:
// apps/mobile/tsconfig.json
{
"extends": "@hounii/config/typescript/react.json"
}
Supabase Directory (supabase/)
Migrations (supabase/migrations/)
supabase/migrations/
├── 20240101000000_initial_schema.sql
├── 20240102000000_add_profiles.sql
└── 20240103000000_enable_rls.sql
Naming: YYYYMMDDHHMMSS_description.sql
Edge Functions (supabase/functions/)
supabase/functions/
├── user-profile-update/
│ └── index.ts
└── send-notification/
└── index.ts
Workspace Configuration
pnpm Workspace (pnpm-workspace.yaml)
packages:
- 'apps/*'
- 'packages/*'
All packages use workspace:* protocol:
{
"dependencies": {
"@hounii/ui": "workspace:*",
"@hounii/lib": "workspace:*"
}
}
Turborepo (turbo.json)
Defines task dependencies and caching:
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**"]
},
"lint": {},
"type-check": {}
}
}
Run from root:
pnpm build # Builds all packages in dependency order
pnpm lint # Lints entire workspace
pnpm type-check # Type checks all packages
Run specific package:
pnpm --filter @hounii/mobile build
pnpm --filter @hounii/web dev
Decision Tree: Where Should This Go?
Is it a UI primitive?
- ✅ →
packages/ui/src/components/
Is it business logic or a utility?
- ✅ →
packages/lib/src/
Is it a translation string?
- ✅ →
packages/i18n/translations/
Is it a mobile screen or feature?
- ✅ →
apps/mobile/features/[feature-name]/
Is it a web page?
- ✅ →
apps/web/app/[route]/
Is it an admin feature?
- ✅ →
apps/admin/app/[section]/
Is it a database change?
- ✅ →
supabase/migrations/[timestamp]_[name].sql
Is it a backend function?
- ✅ →
supabase/functions/[function-name]/
Is it a shared config?
- ✅ →
packages/config/
Common Scenarios
Adding a New Mobile Screen
- Create feature directory:
apps/mobile/features/[feature-name]/ - Add screen:
apps/mobile/features/[feature-name]/screens/MainScreen.tsx - Create route:
apps/mobile/app/[route].tsx - Add translations:
packages/i18n/translations/en/mobile.json - Use UI components: Import from
@hounii/ui
Adding Shared Business Logic
- Create utility:
packages/lib/src/utils/myUtil.ts - Export from index:
packages/lib/src/index.ts - Import in apps:
import { myUtil } from '@hounii/lib'
Adding a New UI Component
- Create component:
packages/ui/src/components/MyComponent.tsx - Export from index:
packages/ui/src/index.ts - Use in apps:
import { MyComponent } from '@hounii/ui'
Adding Database Table
- Create migration:
supabase/migrations/[timestamp]_add_my_table.sql - Apply migration: Use
mcp__supabase__apply_migration - Generate types:
mcp__supabase__generate_typescript_types - Update API package: Types auto-update in
packages/api/src/types/
Package Dependencies
Dependency Flow
apps/mobile
↓ depends on
packages/ui, packages/lib, packages/i18n, packages/api
↓ depends on
External packages (react, tamagui, zustand, etc.)
Rules:
- Apps can depend on packages
- Packages can depend on other packages (carefully)
- Packages cannot depend on apps
- Use
workspace:*for internal dependencies
Circular Dependencies
❌ AVOID:
packages/ui → packages/lib → packages/ui (CIRCULAR!)
✅ PREFER:
packages/ui → standalone
packages/lib → packages/ui (one direction only)
File Naming Conventions
- Components: PascalCase (
Button.tsx,UserProfile.tsx) - Utilities: camelCase (
formatDate.ts,validation.ts) - Hooks: camelCase with
useprefix (useAuth.ts,useLocation.ts) - Stores: camelCase with
Storesuffix (userStore.ts,authStore.ts) - Pages (Next.js): lowercase (
page.tsx,layout.tsx,[id],(group)) - Screens (RN): PascalCase with
Screensuffix (HomeScreen.tsx)
Import Aliases
Configured in each app's tsconfig.json:
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"], // apps/mobile: relative imports
"@/components/*": ["./components/*"],
"@/features/*": ["./features/*"]
}
}
}
Usage:
// ✅ Package imports
import { Button } from '@hounii/ui';
import { useAuth } from '@hounii/lib';
// ✅ Local imports with alias
import { HomeScreen } from '@/features/home';
// ✅ Relative imports (when close)
import { UserCard } from './components/UserCard';
References
- Main config: CLAUDE.md
- Workspace config: pnpm-workspace.yaml
- Build pipeline: turbo.json
- Package manager: pnpm v10.18.2
- Build system: Turborepo v2.5.8
Didn't find tool you were looking for?