chore: Remove redundancies and update AGENTS
This commit is contained in:
3 files changed
+239
-405
No files matched your search
@@ -2,335 +2,288 @@
|
|||||||
|
|
||||||
## 📋 Project Overview
|
## 📋 Project Overview
|
||||||
|
|
||||||
**www.ermnvldmr.com** is Vladimir Eremin's personal website built with modern web technologies. The project serves as a platform for sharing thoughts, creations, and personal content through a carefully crafted design system.
|
**ermnvldmr.com** is Vladimir Eremin's personal ecosystem of services delivered through a modern monorepo architecture. The project encompasses personal websites, documentation sites, and shared infrastructure for web-based content and services.
|
||||||
|
|
||||||
### Core Architecture
|
### Monorepo Architecture
|
||||||
- **Framework**: Astro.js v5+ (Static Site Generator)
|
- **Repository Structure**: pnpm workspace monorepo
|
||||||
- **UI Library**: React 19+ (Islands Architecture)
|
- **Package Manager**: pnpm v9.12.3+
|
||||||
- **Styling**: Tailwind CSS v4+ with custom design system
|
- **Core Technology**: TypeScript (Strict mode)
|
||||||
- **Language**: TypeScript (Strict mode)
|
- **Services**: Independent web services with shared dependencies
|
||||||
- **Build Tool**: Vite 7+
|
- **Packages**: Reusable configurations and component libraries
|
||||||
- **Package Manager**: pnpm
|
- **Build System**: Distributed builds with dependency management
|
||||||
- **Deployment**: GitHub Pages with automated CI/CD
|
- **CI/CD**: GitHub Actions with path-based triggers
|
||||||
|
|
||||||
### Design Philosophy
|
### Design Philosophy
|
||||||
- **Component-First**: All UI elements are developed as isolated, reusable components
|
- **Component-First**: All UI elements developed as isolated, reusable components
|
||||||
- **Design System**: Custom "rainby" color palette with consistent theming
|
- **Configuration Sharing**: Centralized tooling configurations across services
|
||||||
- **Performance-First**: Static generation with minimal JavaScript islands
|
|
||||||
- **TypeScript-First**: Strict typing for all public APIs and components
|
- **TypeScript-First**: Strict typing for all public APIs and components
|
||||||
- **Documentation-Driven**: TSDoc required for all exported elements
|
- **Documentation-Driven**: TSDoc required for all exported elements
|
||||||
|
- **Dependency Isolation**: Clear separation between packages and services
|
||||||
|
- **Build Optimization**: Efficient dependency building and caching
|
||||||
|
|
||||||
## 🏗️ Directory Structure
|
## 🏗️ Repository Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
├── src/
|
├── packages/ # Shared packages and configurations
|
||||||
│ ├── components/ # React component library
|
│ ├── eslint-config/ # Shared ESLint configurations
|
||||||
│ │ ├── shared/ # Common reusable components
|
│ ├── jest-config/ # Shared Jest configurations
|
||||||
│ │ └── {theme_name}/ # Theme-specific components
|
│ ├── storybook-config/ # Shared Storybook configurations
|
||||||
│ ├── www/ # Astro application (custom srcDir)
|
│ ├── vite-config/ # Shared Vite configurations
|
||||||
│ │ ├── layouts/ # Page layout templates (.astro)
|
│ ├── stl/ # Standard Type Library (utilities)
|
||||||
│ │ ├── pages/ # File-based routing (.astro)
|
│ └── ui/ # Shared React component library
|
||||||
│ │ ├── shared/ # Utilities and constants
|
├── services/ # Independent web services
|
||||||
│ │ └── widgets/ # Feature-specific components
|
│ ├── www/ # Main website (Astro + React)
|
||||||
│ └── global.css # Design system + Tailwind configuration
|
│ └── docs/ # Documentation site (Hugo)
|
||||||
├── content/ # Astro Content Collections
|
├── .github/workflows/ # CI/CD automation
|
||||||
│ └── {collections}/ # Blog posts, articles, etc.
|
├── pnpm-workspace.yaml # Workspace configuration
|
||||||
├── .storybook/ # Component development environment
|
└── [root config files] # Global configurations
|
||||||
├── .github/workflows/ # CI/CD automation
|
|
||||||
├── public/ # Static assets
|
|
||||||
└── [config files] # Various configuration files
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Package Organization
|
||||||
|
|
||||||
|
#### Configuration Packages (`packages/`)
|
||||||
|
- **eslint-config**: Shared ESLint rules for TypeScript, React, and Astro
|
||||||
|
- **jest-config**: Shared Jest configurations for different project types
|
||||||
|
- **storybook-config**: Shared Storybook setup and configurations
|
||||||
|
- **vite-config**: Shared Vite configurations for library builds
|
||||||
|
|
||||||
|
#### Library Packages (`packages/`)
|
||||||
|
- **stl** (Standard Type Library): Common utilities, types, and helper functions
|
||||||
|
- **ui**: React component library with design system and Storybook stories
|
||||||
|
|
||||||
|
#### Service Packages (`services/`)
|
||||||
|
- **www**: Main website built with Astro.js, React, and Tailwind CSS
|
||||||
|
- **docs**: Documentation site built with Hugo and Hextra theme
|
||||||
|
|
||||||
### Key Directory Rules
|
### Key Directory Rules
|
||||||
|
|
||||||
#### `/src/components/`
|
#### `/packages/`
|
||||||
- **Purpose**: Reusable React components developed in isolation
|
- **Purpose**: Shared configurations and reusable libraries
|
||||||
- **Structure**: Organized by usage scope (`shared/` for common, `{theme}/` for themed)
|
- **Dependencies**: Can depend on each other following build order (configs → stl → ui)
|
||||||
- **Requirements**: All components must have Storybook stories
|
- **Exports**: Must provide proper TypeScript declarations
|
||||||
- **Exports**: Only manually developed components, no external UI library dependencies
|
- **Building**: Required before dependent services can build
|
||||||
|
- **Testing**: Individual test suites for each package
|
||||||
|
|
||||||
#### `/src/www/`
|
#### `/services/`
|
||||||
- **Purpose**: Astro application code (set as custom srcDir in config)
|
- **Purpose**: Independent web applications and sites
|
||||||
- **Constraint**: Only use manually developed components from `/src/components/`
|
- **Dependencies**: Can consume packages but not other services
|
||||||
- **Organization**: Standard Astro structure with layouts, pages, and utilities
|
- **Deployment**: Independent deployment pipelines
|
||||||
|
- **Development**: Can be developed and tested in isolation
|
||||||
#### `/src/www/widgets/`
|
- **Configuration**: Inherit from shared packages but can override
|
||||||
- **Purpose**: Feature-specific components tied to particular functionality
|
|
||||||
- **Usage**: Components that don't fit in shared or themed categories
|
|
||||||
|
|
||||||
#### `/content/`
|
|
||||||
- **Purpose**: Content management using Astro Content Collections
|
|
||||||
- **Structure**: Organized by content type (blog, projects, etc.)
|
|
||||||
- **Format**: Markdown/MDX files with frontmatter validation
|
|
||||||
|
|
||||||
## 🛠️ Development Workflow
|
## 🛠️ Development Workflow
|
||||||
|
|
||||||
### Component Development
|
### Monorepo Development Principles
|
||||||
1. **Storybook-First**: All components must be developed and tested in Storybook
|
- **Root-Level Scripts**: Check `package.json` at repository root for monorepo-wide operations
|
||||||
2. **Isolation**: Components should work independently without page context
|
- **Service-Specific Scripts**: Each service in `services/` has its own development commands
|
||||||
3. **Documentation**: Each component requires comprehensive Storybook stories
|
- **Package Filtering**: Use pnpm workspace filtering to target specific packages/services
|
||||||
4. **Manual Development**: No external UI library components in `/src/www/`
|
- **Dependency-Aware Building**: UI components must be built before dependent services
|
||||||
|
|
||||||
|
### Package Development Workflow
|
||||||
|
The monorepo follows a strict dependency hierarchy that must be respected:
|
||||||
|
|
||||||
|
#### 1. Configuration Packages First
|
||||||
|
Configuration packages provide shared tooling setups and must be built before anything else. Look for packages ending in `-config` in the `packages/` directory.
|
||||||
|
|
||||||
|
#### 2. Library Packages
|
||||||
|
Library packages (`stl`, `ui`) provide reusable code and components. They depend on configuration packages and must be built in dependency order (check their `package.json` dependencies).
|
||||||
|
|
||||||
|
#### 3. Services
|
||||||
|
Services consume packages but are independent of each other. They can be developed and deployed separately. Check `services/` directory for available services and their individual `package.json` files for available scripts.
|
||||||
|
|
||||||
### Code Organization Principles
|
### Code Organization Principles
|
||||||
- **Single Responsibility**: Each component serves one clear purpose
|
- **Dependency Order**: configs → stl → ui → services
|
||||||
- **Composition Over Inheritance**: Build complex UIs by composing simple components
|
- **Single Responsibility**: Each package serves one clear purpose
|
||||||
- **TypeScript-First**: All public APIs must be properly typed
|
- **Explicit Dependencies**: All inter-package dependencies declared in package.json
|
||||||
- **Documentation-Required**: TSDoc for all exported elements
|
- **Build Isolation**: Each package can be built independently
|
||||||
|
- **Configuration Inheritance**: Services inherit from shared configurations
|
||||||
|
|
||||||
## 📝 Coding Conventions
|
## 📝 Coding Conventions
|
||||||
|
|
||||||
|
### Package Naming Convention
|
||||||
|
All packages use the `@ermnvldmr/` namespace:
|
||||||
|
- `@ermnvldmr/eslint-config` - Shared ESLint configurations
|
||||||
|
- `@ermnvldmr/jest-config` - Shared Jest configurations
|
||||||
|
- `@ermnvldmr/storybook-config` - Shared Storybook configurations
|
||||||
|
- `@ermnvldmr/vite-config` - Shared Vite configurations
|
||||||
|
- `@ermnvldmr/stl` - Standard Type Library
|
||||||
|
- `@ermnvldmr/ui` - Component library
|
||||||
|
- `@ermnvldmr/www` - Main website service
|
||||||
|
- `@ermnvldmr/docs` - Documentation service
|
||||||
|
|
||||||
### TypeScript Guidelines
|
### TypeScript Guidelines
|
||||||
- **Strict Mode**: All TypeScript strict checks must pass
|
- **Strict Mode**: All TypeScript strict checks must pass
|
||||||
- **Explicit Types**: Avoid `any` and prefer explicit type definitions
|
- **Explicit Types**: Avoid `any` and prefer explicit type definitions
|
||||||
- **Interface First**: Use interfaces for component props and public APIs
|
- **Interface First**: Use interfaces for component props and public APIs
|
||||||
- **Generic Constraints**: Properly constrain generic types
|
- **Cross-Package Types**: Export types from packages for service consumption
|
||||||
|
|
||||||
### TSDoc Documentation Requirements
|
### TSDoc Documentation Requirements
|
||||||
**MANDATORY for all exported elements**: types, functions, constants, components
|
**MANDATORY for all exported elements**: types, functions, constants, components
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
/**
|
/**
|
||||||
* Formats a date string or timestamp into human-readable format.
|
* Combines class names using clsx and tailwind-merge for consistent styling.
|
||||||
*
|
*
|
||||||
* @param input - The date to format (string or number timestamp)
|
* @param inputs - Class name inputs to combine
|
||||||
* @returns Formatted date string in "Month Day, Year" format
|
* @returns Combined and deduplicated class string
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* \`\`\`typescript
|
* \`\`\`typescript
|
||||||
* formatDate('2024-01-15') // "January 15, 2024"
|
* cn('px-4 py-2', 'bg-blue-500', 'px-6') // 'py-2 bg-blue-500 px-6'
|
||||||
* formatDate(1705276800000) // "January 15, 2024"
|
* cn('text-lg', condition && 'font-bold') // 'text-lg font-bold'
|
||||||
* \`\`\`
|
* \`\`\`
|
||||||
*/
|
*/
|
||||||
export function formatDate(input: string | number): string {
|
export function cn(...inputs: ClassValue[]): string {
|
||||||
// implementation
|
return twMerge(clsx(inputs));
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Props for the PageHead component.
|
|
||||||
*/
|
|
||||||
export interface PageHeadProps {
|
|
||||||
/** The main title displayed in the header */
|
|
||||||
title: string;
|
|
||||||
/** Array of breadcrumbs, displayed above the title */
|
|
||||||
breadcrumbs?: Breadcrumb[];
|
|
||||||
/** Navigation items displayed on the right */
|
|
||||||
navItems?: NavItem[];
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### React Component Patterns
|
### Component Development Patterns
|
||||||
- **Functional Components**: Use function declarations with explicit typing
|
#### UI Package Components
|
||||||
- **Props Interfaces**: Define props as separate interfaces with TSDoc
|
|
||||||
- **Memo Usage**: Wrap components with `memo()` for performance when appropriate
|
|
||||||
- **Event Handlers**: Type event handlers explicitly
|
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
/**
|
/**
|
||||||
* A reusable button component with consistent styling and behavior.
|
* Props for the Button component.
|
||||||
*/
|
*/
|
||||||
export interface ButtonProps {
|
export interface ButtonProps {
|
||||||
/** The button text content */
|
/** The button content */
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
/** Click event handler */
|
|
||||||
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
|
|
||||||
/** Visual style variant */
|
/** Visual style variant */
|
||||||
variant?: 'primary' | 'secondary' | 'outline';
|
variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link';
|
||||||
|
/** Button size */
|
||||||
|
size?: 'default' | 'sm' | 'lg' | 'icon';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Button component following the design system patterns.
|
* Versatile button component with multiple variants and sizes.
|
||||||
*/
|
*/
|
||||||
export const Button = memo(function Button({
|
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||||
children,
|
({ className, variant = 'default', size = 'default', ...props }, ref) => {
|
||||||
onClick,
|
return (
|
||||||
variant = 'primary'
|
<button
|
||||||
}: ButtonProps) {
|
className={cn(buttonVariants({ variant, size, className }))}
|
||||||
// implementation
|
ref={ref}
|
||||||
});
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
### File Naming Conventions
|
### File Naming Conventions
|
||||||
- **Components**: PascalCase (e.g., `PageHead.tsx`, `NavigationMenu.tsx`)
|
- **Components**: PascalCase (e.g., `Button.tsx`, `NavigationMenu.tsx`)
|
||||||
- **Utilities**: camelCase (e.g., `formatDate.ts`, `apiHelpers.ts`)
|
- **Utilities**: camelCase (e.g., `cn.ts`, `formatters.ts`)
|
||||||
- **Constants**: UPPER_SNAKE_CASE for exports (e.g., `SITE_TITLE`)
|
- **Constants**: UPPER_SNAKE_CASE for exports (e.g., `API_ENDPOINTS`)
|
||||||
- **Types**: PascalCase with descriptive suffixes (e.g., `ButtonProps`, `ApiResponse`)
|
- **Types**: PascalCase with descriptive suffixes (e.g., `ButtonProps`, `ApiResponse`)
|
||||||
|
- **Config Files**: kebab-case (e.g., `jest-config`, `eslint-config`)
|
||||||
|
|
||||||
### Module Structure Patterns
|
### Module Structure Patterns
|
||||||
|
|
||||||
Each module in the project follows a consistent internal structure to maintain organization and scalability.
|
#### Package Structure
|
||||||
|
|
||||||
#### Component Modules
|
|
||||||
For widgets and shared components:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
src/widgets/SomeComponent/
|
packages/ui/
|
||||||
├── hooks/
|
├── src/
|
||||||
│ └── someHook/
|
│ ├── components/ # Component categories
|
||||||
│ └── someHook.tsx
|
│ │ ├── generic/ # Layout and generic components
|
||||||
├── helpers/
|
│ │ └── paper/ # Themed component variants
|
||||||
│ └── someHelper/
|
│ ├── styles/ # Global styles and CSS
|
||||||
│ └── someHelper.ts
|
│ ├── test-utils.tsx # Testing utilities
|
||||||
├── components/
|
│ └── index.ts # Main package exports
|
||||||
│ └── SomeSubComponent/
|
├── package.json
|
||||||
│ └── SomeSubComponent.tsx
|
├── vite.config.ts
|
||||||
├── SomeComponent.tsx
|
├── tsconfig.json
|
||||||
├── SomeComponent.test.tsx (if needed)
|
└── .storybook/ # Storybook configuration
|
||||||
└── SomeComponent.stories.tsx
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Shared Helper Modules
|
#### Service Structure (www example)
|
||||||
For standalone utility functions:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
src/shared/helpers/someHelper/
|
services/www/
|
||||||
├── helpers/
|
├── src/
|
||||||
│ └── someSubHelper/
|
│ ├── layouts/ # Astro layout components
|
||||||
│ └── someSubHelper.ts
|
│ ├── pages/ # Astro pages (file-based routing)
|
||||||
├── someHelper.ts
|
│ ├── shared/ # Shared utilities and constants
|
||||||
└── someHelper.test.ts
|
│ └── global.css # Service-specific styles
|
||||||
|
├── public/ # Static assets
|
||||||
|
├── astro.config.mjs # Astro configuration
|
||||||
|
├── package.json
|
||||||
|
└── tailwind.config.mjs # Tailwind configuration
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Shared Hook Modules
|
## 🎨 Design System (UI Package)
|
||||||
For reusable React hooks:
|
|
||||||
|
|
||||||
```
|
### Component Organization
|
||||||
src/shared/hooks/someHook/
|
- **Generic Components**: Layout utilities (Stack, VStack, HStack)
|
||||||
├── hooks/
|
- **Themed Components**: Paper-themed variants with consistent styling
|
||||||
│ └── someSubHook/
|
- **Radix Integration**: Accessibility-first components using Radix UI
|
||||||
│ └── someSubHook.ts
|
- **Storybook Stories**: Every component has comprehensive documentation
|
||||||
├── someHook.ts
|
|
||||||
└── someHook.test.ts
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Module Organization Rules
|
### Styling Approach
|
||||||
|
- **Tailwind CSS v4+**: Utility-first CSS framework
|
||||||
1. **Single Entry Point**: Each module exports its main functionality from the root file
|
- **Class Variance Authority**: Type-safe variant generation
|
||||||
2. **Internal Dependencies**: Sub-modules (helpers/, hooks/, components/) are implementation details
|
- **Custom Design Tokens**: Consistent spacing, colors, typography
|
||||||
3. **Testing Strategy**: Test only the final exported component/function, not internal dependencies
|
- **Responsive Design**: Mobile-first responsive patterns
|
||||||
4. **Story Strategy**: Create Storybook stories only for the main exported component
|
|
||||||
5. **Naming Consistency**: Directory names match the main export name
|
|
||||||
6. **Isolation**: Each module should be self-contained and independently testable
|
|
||||||
|
|
||||||
#### Testing Guidelines
|
|
||||||
|
|
||||||
- **Focus on Public API**: Test the main exported functionality, not internal helpers
|
|
||||||
- **Integration Over Unit**: Test how the complete module works, not individual pieces
|
|
||||||
- **Story-Driven Testing**: Use Storybook stories as living documentation and manual testing
|
|
||||||
- **Avoid Over-Testing**: Don't create separate tests for internal sub-modules
|
|
||||||
|
|
||||||
#### Import/Export Patterns
|
|
||||||
|
|
||||||
|
### Component Categories
|
||||||
```typescript
|
```typescript
|
||||||
// Main module file (SomeComponent.tsx)
|
// Generic Layout Components
|
||||||
import { someHelper } from './helpers/someHelper/someHelper';
|
export { Stack } from './components/generic/Stack/Stack';
|
||||||
import { useSomeHook } from './hooks/someHook/someHook';
|
export { VStack } from './components/generic/VStack/VStack';
|
||||||
import SomeSubComponent from './components/SomeSubComponent/SomeSubComponent';
|
export { HStack } from './components/generic/HStack/HStack';
|
||||||
|
|
||||||
// Export only the main component
|
// Themed Components (Paper)
|
||||||
export default SomeComponent;
|
export { Button } from './components/paper/PaperButton/Button';
|
||||||
export type { SomeComponentProps };
|
export { Separator } from './components/paper/PaperSeparator/Separator';
|
||||||
```
|
```
|
||||||
|
|
||||||
## 🎨 Design System
|
## ⚙️ Configuration Management
|
||||||
|
|
||||||
### Color Palette
|
### Shared Configurations
|
||||||
The project uses a custom "rainby" color palette with semantic color mapping:
|
Each configuration package provides standardized setups:
|
||||||
- **Core Colors**: Red, Orange, Yellow, Green, Cyan, Blue, Violet, Neutral
|
|
||||||
- **Each Color**: 50-950 scale following Tailwind conventions
|
|
||||||
- **Semantic Mapping**: Primary (cyan), Secondary (green), Accent (violet), etc.
|
|
||||||
|
|
||||||
### Theme Structure
|
#### ESLint Configuration
|
||||||
```css
|
```javascript
|
||||||
:root {
|
// Provides: base, react, astro configurations
|
||||||
/* Light mode variables */
|
import { base } from '@ermnvldmr/eslint-config';
|
||||||
--color-background: var(--color-rainby-neutral-50);
|
import { react } from '@ermnvldmr/eslint-config/react';
|
||||||
--color-foreground: var(--color-rainby-neutral-950);
|
import { astro } from '@ermnvldmr/eslint-config/astro';
|
||||||
/* ... */
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark {
|
|
||||||
/* Dark mode overrides */
|
|
||||||
--color-background: var(--color-rainby-neutral-950);
|
|
||||||
--color-foreground: var(--color-rainby-neutral-50);
|
|
||||||
/* ... */
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Custom Utilities
|
#### Jest Configuration
|
||||||
- **`frosted-glass`**: Backdrop blur effect for overlays
|
```typescript
|
||||||
- **`vstack`**: Vertical flex layout utility
|
// Provides: base, react configurations
|
||||||
- **`hstack`**: Horizontal flex layout utility
|
import { base } from '@ermnvldmr/jest-config/base';
|
||||||
|
import { react } from '@ermnvldmr/jest-config/react';
|
||||||
### Typography
|
|
||||||
- **Sans**: Lato (headings, UI text)
|
|
||||||
- **Serif**: EB Garamond (body text, content)
|
|
||||||
- **Responsive**: Tailwind responsive typography classes
|
|
||||||
|
|
||||||
## ⚙️ Configuration Files
|
|
||||||
|
|
||||||
### Path Mapping (tsconfig.json)
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"baseUrl": ".",
|
|
||||||
"paths": {
|
|
||||||
"@*": ["./src/*"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Astro Configuration
|
#### Vite Configuration
|
||||||
- **Custom srcDir**: `./src/www` (Astro application code)
|
```typescript
|
||||||
- **Integrations**: MDX, Sitemap, React
|
// Provides: library build configurations
|
||||||
- **Vite Plugins**: Tailwind CSS integration
|
import { defineLibConfig } from '@ermnvldmr/vite-config/lib';
|
||||||
|
```
|
||||||
|
|
||||||
### Development Tools
|
### Service Configuration Inheritance
|
||||||
- **ESLint**: Astro + React + TypeScript configurations
|
Services inherit from shared configs but can override:
|
||||||
- **Prettier**: Astro + React + Tailwind plugins
|
```typescript
|
||||||
- **Storybook**: React-Vite with Tailwind integration
|
// In service package.json devDependencies
|
||||||
|
"@ermnvldmr/eslint-config": "workspace:*"
|
||||||
|
"@ermnvldmr/jest-config": "workspace:*"
|
||||||
|
```
|
||||||
|
|
||||||
## 🚀 Build & Deployment
|
## 🚀 Build & Deployment
|
||||||
|
|
||||||
### Scripts
|
### Build Dependencies
|
||||||
```json
|
The monorepo must respect a strict build order due to package dependencies:
|
||||||
{
|
|
||||||
"dev": "astro dev", // Development server
|
|
||||||
"build": "astro build", // Production build
|
|
||||||
"preview": "astro preview", // Preview built site
|
|
||||||
"storybook": "storybook dev", // Component development
|
|
||||||
"check": "lint + typecheck" // Code quality checks
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### CI/CD Pipeline
|
1. **Configuration packages** (eslint-config, jest-config, etc.) - Foundation tooling
|
||||||
1. **Semantic Release**: Automated versioning and changelog generation
|
2. **STL package** - Shared utilities and types
|
||||||
2. **GitHub Actions**: Automated build and deployment to GitHub Pages
|
3. **UI package** - Component library (depends on STL)
|
||||||
3. **Quality Gates**: ESLint, TypeScript checking, build verification
|
4. **Services** - Applications that consume packages (www, docs)
|
||||||
|
|
||||||
### Release Process
|
### CI/CD Pipeline Structure
|
||||||
- **Branches**: `next` (prerelease), `release/*` (stable releases)
|
The repository uses path-based CI/CD triggers - each package and service has dedicated workflows in `.github/workflows/`. Examine the workflow files to understand:
|
||||||
- **Triggers**: Release creation automatically deploys to production
|
- **Trigger Patterns**: Which file changes activate each pipeline
|
||||||
- **Versioning**: Semantic versioning with conventional commits
|
- **Build Dependencies**: How packages are built in sequence
|
||||||
|
- **Quality Gates**: Linting, type-checking, and testing requirements
|
||||||
## 📚 Content Management
|
- **Deployment Targets**: Where each service is deployed
|
||||||
|
|
||||||
### Astro Content Collections
|
|
||||||
Content is managed through Astro's Content Collections system in the `/content/` directory:
|
|
||||||
- **Type Safety**: Schema validation for frontmatter
|
|
||||||
- **Organization**: Content organized by collection type
|
|
||||||
- **Processing**: Automatic type generation and content APIs
|
|
||||||
|
|
||||||
### Content Structure Example
|
|
||||||
```
|
|
||||||
content/
|
|
||||||
├── blog/ # Blog posts
|
|
||||||
│ ├── post-1.md
|
|
||||||
│ └── post-2.mdx
|
|
||||||
└── projects/ # Project showcases
|
|
||||||
├── project-1.md
|
|
||||||
└── project-2.md
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔧 Development Environment
|
## 🔧 Development Environment
|
||||||
|
|
||||||
@@ -338,104 +291,57 @@ content/
|
|||||||
- **Node.js**: v20+
|
- **Node.js**: v20+
|
||||||
- **pnpm**: v9.12.3+
|
- **pnpm**: v9.12.3+
|
||||||
- **TypeScript**: v5.8+
|
- **TypeScript**: v5.8+
|
||||||
|
- **Hugo**: v0.110.0+ (for docs service)
|
||||||
|
|
||||||
### Setup Commands
|
### Initial Setup
|
||||||
```bash
|
To start development, follow the dependency hierarchy:
|
||||||
pnpm install # Install dependencies
|
|
||||||
pnpm dev # Start development server
|
|
||||||
pnpm storybook # Start component development
|
|
||||||
pnpm check # Run all quality checks
|
|
||||||
```
|
|
||||||
|
|
||||||
### Development Guidelines
|
1. **Install dependencies** using the root `package.json` scripts
|
||||||
1. **Component-First**: Develop components in Storybook before integration
|
2. **Build configuration packages** first (check packages ending in `-config`)
|
||||||
2. **Type Safety**: All public APIs must be properly typed with TSDoc
|
3. **Build library packages** in dependency order (STL before UI)
|
||||||
3. **Manual Components**: Only use manually developed components in www
|
4. **Start services** after dependencies are built
|
||||||
4. **Design System**: Follow the established color palette and utilities
|
|
||||||
5. **Performance**: Leverage Astro's static generation with minimal client-side JavaScript
|
### Development Commands
|
||||||
6. **Testing**: Write tests for utilities, hooks, and interactive components
|
The monorepo provides scripts at multiple levels:
|
||||||
|
|
||||||
|
- **Root Level**: Check root `package.json` for monorepo-wide operations
|
||||||
|
- **Package Level**: Each package has its own build, test, and development scripts
|
||||||
|
- **Service Level**: Services have development servers, build commands, and testing
|
||||||
|
|
||||||
|
Use pnpm workspace filtering (`--filter`) to target specific packages or services. Examine individual `package.json` files to discover available scripts for each component.
|
||||||
|
|
||||||
## 🧪 Testing Strategy
|
## 🧪 Testing Strategy
|
||||||
|
|
||||||
### Testing Framework
|
### Testing Framework Distribution
|
||||||
- **Test Runner**: Jest with TypeScript support
|
- **Shared Configuration**: Jest configs in `@ermnvldmr/jest-config`
|
||||||
- **Component Testing**: React Testing Library for component interactions
|
- **Package Testing**: Each package has its own test suite
|
||||||
- **Utilities**: Jest for unit testing of pure functions and hooks
|
- **Service Testing**: Services test their specific functionality
|
||||||
- **Coverage**: HTML and LCOV reports for coverage tracking
|
- **Component Testing**: UI package uses React Testing Library
|
||||||
|
- **Storybook Testing**: Visual regression and interaction testing
|
||||||
|
|
||||||
### Testing Patterns
|
### Test Organization
|
||||||
|
|
||||||
#### Component Testing
|
|
||||||
```typescript
|
```typescript
|
||||||
import { render, screen } from '@/test/test-utils';
|
// Package-level testing (packages/stl/src/functions/cn/cn.test.ts)
|
||||||
import { SomeComponent } from './SomeComponent';
|
describe('cn function', () => {
|
||||||
|
it('combines class names correctly', () => {
|
||||||
|
expect(cn('px-4', 'py-2')).toBe('px-4 py-2');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
// Component testing (packages/ui/src/components/paper/Button/Button.test.tsx)
|
||||||
* Test suite for SomeComponent
|
describe('components/paper/Button/Button', () => {
|
||||||
*/
|
it('renders with correct variant', () => {
|
||||||
describe('SomeComponent', () => {
|
render(<Button variant="destructive">Test</Button>);
|
||||||
const defaultProps = {
|
expect(screen.getByRole('button')).toHaveClass('destructive');
|
||||||
title: 'Test Title',
|
|
||||||
};
|
|
||||||
|
|
||||||
it('renders correctly', () => {
|
|
||||||
render(<SomeComponent {...defaultProps} />);
|
|
||||||
expect(screen.getByText('Test Title')).toBeInTheDocument();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Utility Testing
|
### Coverage Strategy
|
||||||
```typescript
|
- **Package Coverage**: Individual coverage reports per package
|
||||||
import { someUtility } from './someUtility';
|
- **Service Coverage**: Service-specific coverage including Storybook tests
|
||||||
|
- **Aggregated Coverage**: Combined reporting for the entire monorepo
|
||||||
/**
|
|
||||||
* Test suite for utility functions
|
|
||||||
*/
|
|
||||||
describe('someUtility', () => {
|
|
||||||
it('handles expected inputs correctly', () => {
|
|
||||||
expect(someUtility('input')).toBe('expected');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('handles edge cases', () => {
|
|
||||||
expect(someUtility('')).toBe('');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### Testing Commands
|
|
||||||
```bash
|
|
||||||
pnpm test # Run all tests
|
|
||||||
pnpm test:watch # Run tests in watch mode
|
|
||||||
pnpm test:coverage # Run tests with coverage report
|
|
||||||
```
|
|
||||||
|
|
||||||
### Testing Guidelines
|
|
||||||
- **Focus on Public API**: Test exported functionality, not implementation details
|
|
||||||
- **Module-Level Testing**: Test the main export of each module, not sub-dependencies
|
|
||||||
- **Integration Over Unit**: Test how complete modules work together
|
|
||||||
- **Accessibility Testing**: Use screen reader queries and accessibility matchers
|
|
||||||
- **User-Centric**: Test from the user's perspective (what they see and interact with)
|
|
||||||
|
|
||||||
### Naming Conventions for Tests and Stories
|
|
||||||
- **Test describe blocks**: Use full component path format: `components/paper-kit/ComponentName/ComponentName`
|
|
||||||
- **Storybook titles**: Use full component path format: `components/paper-kit/ComponentName`
|
|
||||||
- **Consistency**: Both tests and stories should use the same path-based naming for organization
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```typescript
|
|
||||||
// In Component.test.tsx
|
|
||||||
describe('components/paper-kit/Button/Button', () => {
|
|
||||||
// tests
|
|
||||||
});
|
|
||||||
|
|
||||||
// In Component.stories.tsx
|
|
||||||
const meta: Meta<typeof Component> = {
|
|
||||||
title: 'components/paper-kit/Button',
|
|
||||||
component: Component,
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*This guide serves as the architectural foundation for the project. Focus on these stable patterns and structures rather than specific implementation details that may change over time.*
|
*This guide serves as the architectural foundation for the monorepo. Focus on these stable patterns and structures rather than specific implementation details that may change over time.*
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
# Docker Compose for local development and testing
|
|
||||||
# Use: docker-compose up to start services locally
|
|
||||||
|
|
||||||
version: '3.8'
|
|
||||||
|
|
||||||
services:
|
|
||||||
# WWW service (Astro static site)
|
|
||||||
www:
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: docker/astro/Dockerfile
|
|
||||||
target: production
|
|
||||||
ports:
|
|
||||||
- "3000:8080"
|
|
||||||
container_name: ermnvldmr-www
|
|
||||||
environment:
|
|
||||||
- NODE_ENV=production
|
|
||||||
restart: unless-stopped
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/"]
|
|
||||||
interval: 30s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 3
|
|
||||||
start_period: 40s
|
|
||||||
|
|
||||||
# WWW Storybook
|
|
||||||
www-storybook:
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: docker/storybook/Dockerfile
|
|
||||||
target: production
|
|
||||||
ports:
|
|
||||||
- "6006:8080"
|
|
||||||
container_name: ermnvldmr-www-storybook
|
|
||||||
environment:
|
|
||||||
- NODE_ENV=production
|
|
||||||
restart: unless-stopped
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/"]
|
|
||||||
interval: 30s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 3
|
|
||||||
start_period: 40s
|
|
||||||
|
|
||||||
# Docs service (Hugo static site) - Future implementation
|
|
||||||
# docs:
|
|
||||||
# build:
|
|
||||||
# context: .
|
|
||||||
# dockerfile: docker/hugo/Dockerfile
|
|
||||||
# target: production
|
|
||||||
# ports:
|
|
||||||
# - "3001:8080"
|
|
||||||
# container_name: ermnvldmr-docs
|
|
||||||
# environment:
|
|
||||||
# - NODE_ENV=production
|
|
||||||
# restart: unless-stopped
|
|
||||||
|
|
||||||
# Optional: Add a reverse proxy for unified access
|
|
||||||
# nginx-proxy:
|
|
||||||
# image: nginx:alpine
|
|
||||||
# ports:
|
|
||||||
# - "80:80"
|
|
||||||
# volumes:
|
|
||||||
# - ./docker/nginx/proxy.conf:/etc/nginx/conf.d/default.conf:ro
|
|
||||||
# depends_on:
|
|
||||||
# - www
|
|
||||||
# - www-storybook
|
|
||||||
# container_name: ermnvldmr-proxy
|
|
||||||
|
|
||||||
networks:
|
|
||||||
default:
|
|
||||||
name: ermnvldmr-infrastructure
|
|
||||||
Reference in new issue
Block a user