mirror of
https://github.com/cloud-shuttle/leptos-shadcn-ui.git
synced 2025-12-22 22:00:00 +00:00
- Complete documentation reorganization into professional structure - Achieved 90%+ test coverage across all components - Created sophisticated WASM demo matching shadcn/ui quality - Fixed all compilation warnings and missing binary files - Optimized dependencies across all packages - Professional code standards and performance optimizations - Cross-browser compatibility with Playwright testing - New York variants implementation - Advanced signal management for Leptos 0.8.8+ - Enhanced testing infrastructure with TDD approach
509 lines
17 KiB
Markdown
509 lines
17 KiB
Markdown
# ADR-009: Leptos Ecosystem Maintainership and "Drink Our Own Champagne" Philosophy
|
|
|
|
## Status
|
|
**ACCEPTED** - 2024-09-08
|
|
|
|
## Context
|
|
As a data engineering consultancy specializing in Rust and Leptos, we have the unique advantage of being maintainers of critical Leptos ecosystem crates. This positions us as not just users of the technology, but as core contributors to its development and evolution. We must leverage this advantage while maintaining the highest standards of quality and innovation.
|
|
|
|
## Decision
|
|
We establish a **"Drink Our Own Champagne" philosophy** where we actively maintain and contribute to the Leptos ecosystem crates we own, ensuring they meet the highest standards and serve as examples of best practices for the entire community.
|
|
|
|
### Maintained Crates Portfolio
|
|
|
|
#### Core Leptos Ecosystem Crates
|
|
- **leptos-flow**: Data flow and state management
|
|
- **leptos-forms-rs**: Form handling and validation
|
|
- **leptos-helios**: UI components and design system
|
|
- **leptos-motion**: Animations and transitions
|
|
- **leptos-query-rs**: Data fetching and caching
|
|
- **leptos-shadcn-ui**: Modern UI component library
|
|
- **leptos-state**: State management and reactivity
|
|
- **leptos-sync**: Real-time synchronization
|
|
- **leptos-ws-pro**: WebSocket professional features
|
|
- **leptos-next-metadata**: SEO and metadata management
|
|
- **radix-leptos**: Accessibility-first component primitives
|
|
|
|
### Maintainership Philosophy
|
|
|
|
#### "Drink Our Own Champagne" Principles
|
|
- **First Users**: We are the first users of our own crates
|
|
- **Real-World Testing**: Our crates are battle-tested in production
|
|
- **Community Leadership**: We lead by example in the Leptos community
|
|
- **Quality Standards**: Our crates set the standard for quality
|
|
- **Innovation**: We drive innovation in the Leptos ecosystem
|
|
|
|
## Implementation
|
|
|
|
### Crate Maintenance Strategy
|
|
```rust
|
|
// Example: Crate maintenance framework
|
|
use serde::{Deserialize, Serialize};
|
|
use chrono::{DateTime, Utc};
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
pub struct MaintainedCrate {
|
|
pub name: String,
|
|
pub category: CrateCategory,
|
|
pub version: String,
|
|
pub last_updated: DateTime<Utc>,
|
|
pub maintenance_status: MaintenanceStatus,
|
|
pub usage_in_projects: Vec<String>,
|
|
pub community_metrics: CommunityMetrics,
|
|
pub quality_metrics: QualityMetrics,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
pub enum CrateCategory {
|
|
StateManagement,
|
|
UIComponents,
|
|
DataFetching,
|
|
Animations,
|
|
Forms,
|
|
RealTime,
|
|
Accessibility,
|
|
SEO,
|
|
DesignSystem,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
pub enum MaintenanceStatus {
|
|
Active,
|
|
Stable,
|
|
Deprecated,
|
|
Experimental,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
pub struct CommunityMetrics {
|
|
pub downloads: u64,
|
|
pub stars: u64,
|
|
pub forks: u64,
|
|
pub issues: u64,
|
|
pub pull_requests: u64,
|
|
pub community_health: f64, // 0-100 score
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
pub struct QualityMetrics {
|
|
pub test_coverage: f64,
|
|
pub documentation_coverage: f64,
|
|
pub performance_score: f64,
|
|
pub security_score: f64,
|
|
pub maintainability_score: f64,
|
|
}
|
|
|
|
// Crate maintenance service
|
|
pub struct CrateMaintenanceService {
|
|
maintained_crates: Vec<MaintainedCrate>,
|
|
maintenance_schedule: MaintenanceSchedule,
|
|
}
|
|
|
|
impl CrateMaintenanceService {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
maintained_crates: Self::load_maintained_crates(),
|
|
maintenance_schedule: MaintenanceSchedule::new(),
|
|
}
|
|
}
|
|
|
|
pub fn get_maintenance_plan(&self, crate_name: &str) -> Option<MaintenancePlan> {
|
|
let crate_info = self.maintained_crates.iter()
|
|
.find(|c| c.name == crate_name)?;
|
|
|
|
Some(MaintenancePlan {
|
|
crate_name: crate_name.to_string(),
|
|
current_version: crate_info.version.clone(),
|
|
next_version: self.calculate_next_version(crate_info),
|
|
planned_features: self.get_planned_features(crate_info),
|
|
maintenance_tasks: self.get_maintenance_tasks(crate_info),
|
|
community_engagement: self.get_community_engagement_plan(crate_info),
|
|
})
|
|
}
|
|
|
|
pub fn update_crate(&mut self, crate_name: &str, update: CrateUpdate) -> Result<(), MaintenanceError> {
|
|
let crate_info = self.maintained_crates.iter_mut()
|
|
.find(|c| c.name == crate_name)
|
|
.ok_or(MaintenanceError::CrateNotFound)?;
|
|
|
|
// Update crate information
|
|
crate_info.version = update.new_version;
|
|
crate_info.last_updated = Utc::now();
|
|
|
|
// Update quality metrics
|
|
crate_info.quality_metrics = self.calculate_quality_metrics(crate_info);
|
|
|
|
// Update community metrics
|
|
crate_info.community_metrics = self.fetch_community_metrics(crate_info);
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
```
|
|
|
|
### "Drink Our Own Champagne" Implementation
|
|
```rust
|
|
// Example: Using our own crates in our projects
|
|
use leptos_flow::*;
|
|
use leptos_forms_rs::*;
|
|
use leptos_helios::*;
|
|
use leptos_motion::*;
|
|
use leptos_query_rs::*;
|
|
use leptos_shadcn_ui::*;
|
|
use leptos_state::*;
|
|
use leptos_sync::*;
|
|
use leptos_ws_pro::*;
|
|
use leptos_next_metadata::*;
|
|
use radix_leptos::*;
|
|
|
|
// Our consultancy website using our own crates
|
|
#[component]
|
|
pub fn ConsultancyWebsite() -> impl IntoView {
|
|
// Use our own state management
|
|
let (app_state, set_app_state) = create_signal(AppState::new());
|
|
|
|
// Use our own form handling
|
|
let contact_form = ContactForm::new();
|
|
|
|
// Use our own UI components
|
|
let header = Header::new()
|
|
.with_logo(Logo::new())
|
|
.with_navigation(Navigation::new());
|
|
|
|
// Use our own animations
|
|
let hero_section = HeroSection::new()
|
|
.with_animation(FadeIn::new().duration(1000));
|
|
|
|
// Use our own data fetching
|
|
let services_query = use_query(|| fetch_services());
|
|
|
|
// Use our own real-time features
|
|
let real_time_updates = use_websocket("wss://api.dataengineeringpro.com/updates");
|
|
|
|
view! {
|
|
<html>
|
|
<head>
|
|
// Use our own metadata management
|
|
<MetaTags>
|
|
<Title>"Data Engineering Pro - Rust-Powered Solutions"</Title>
|
|
<Meta name="description" content="High-performance data engineering consultancy"/>
|
|
<Meta name="keywords" content="rust, leptos, data engineering, wasm"/>
|
|
</MetaTags>
|
|
</head>
|
|
<body>
|
|
// Use our own design system
|
|
<ThemeProvider theme=Theme::Professional>
|
|
<header>
|
|
{header}
|
|
</header>
|
|
|
|
<main>
|
|
// Use our own motion components
|
|
<MotionDiv initial={{ opacity: 0.0 }} animate={{ opacity: 1.0 }}>
|
|
{hero_section}
|
|
</MotionDiv>
|
|
|
|
// Use our own state management
|
|
<Show when=move || app_state.get().is_loaded>
|
|
<ServicesSection services=services_query.data/>
|
|
</Show>
|
|
|
|
// Use our own form components
|
|
<ContactSection form=contact_form/>
|
|
</main>
|
|
|
|
<footer>
|
|
// Use our own accessibility components
|
|
<Footer>
|
|
<AccessibleLink href="/privacy">"Privacy Policy"</AccessibleLink>
|
|
<AccessibleLink href="/terms">"Terms of Service"</AccessibleLink>
|
|
</Footer>
|
|
</footer>
|
|
</ThemeProvider>
|
|
</body>
|
|
</html>
|
|
}
|
|
}
|
|
```
|
|
|
|
### Crate Development and Testing
|
|
```rust
|
|
// Example: Comprehensive testing of our own crates
|
|
#[cfg(test)]
|
|
mod crate_tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_leptos_flow_integration() {
|
|
// Test our state management crate
|
|
let flow = LeptosFlow::new();
|
|
let state = flow.create_state("test_state", "initial_value");
|
|
|
|
assert_eq!(state.get(), "initial_value");
|
|
|
|
state.set("updated_value");
|
|
assert_eq!(state.get(), "updated_value");
|
|
}
|
|
|
|
#[test]
|
|
fn test_leptos_forms_validation() {
|
|
// Test our forms crate
|
|
let form = ContactForm::new();
|
|
let validation_result = form.validate();
|
|
|
|
assert!(validation_result.is_valid());
|
|
}
|
|
|
|
#[test]
|
|
fn test_leptos_motion_performance() {
|
|
// Test our motion crate performance
|
|
let motion = FadeIn::new().duration(1000);
|
|
let start_time = std::time::Instant::now();
|
|
|
|
motion.animate();
|
|
|
|
let duration = start_time.elapsed();
|
|
assert!(duration.as_millis() < 1100); // Allow 100ms tolerance
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_leptos_query_data_fetching() {
|
|
// Test our query crate
|
|
let query = use_query(|| async {
|
|
// Simulate API call
|
|
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
|
"test_data".to_string()
|
|
});
|
|
|
|
// Wait for query to complete
|
|
query.await;
|
|
|
|
assert_eq!(query.data(), Some("test_data".to_string()));
|
|
}
|
|
}
|
|
```
|
|
|
|
### Playwright Testing for Our Crates
|
|
```typescript
|
|
// Example: Playwright testing for our maintained crates
|
|
import { test, expect } from '@playwright/test';
|
|
|
|
test.describe('Our Maintained Crates Integration', () => {
|
|
test('should demonstrate leptos-flow state management', async ({ page }) => {
|
|
await page.goto('/demo/leptos-flow');
|
|
|
|
// Test state management functionality
|
|
await page.click('[data-testid="increment-button"]');
|
|
await expect(page.locator('[data-testid="counter"]')).toContainText('1');
|
|
|
|
await page.click('[data-testid="increment-button"]');
|
|
await expect(page.locator('[data-testid="counter"]')).toContainText('2');
|
|
});
|
|
|
|
test('should demonstrate leptos-forms validation', async ({ page }) => {
|
|
await page.goto('/demo/leptos-forms');
|
|
|
|
// Test form validation
|
|
await page.fill('[data-testid="email-input"]', 'invalid-email');
|
|
await page.click('[data-testid="submit-button"]');
|
|
|
|
await expect(page.locator('[data-testid="error-message"]'))
|
|
.toContainText('Invalid email format');
|
|
|
|
// Test valid form submission
|
|
await page.fill('[data-testid="email-input"]', 'valid@example.com');
|
|
await page.fill('[data-testid="name-input"]', 'John Doe');
|
|
await page.click('[data-testid="submit-button"]');
|
|
|
|
await expect(page.locator('[data-testid="success-message"]'))
|
|
.toContainText('Form submitted successfully');
|
|
});
|
|
|
|
test('should demonstrate leptos-motion animations', async ({ page }) => {
|
|
await page.goto('/demo/leptos-motion');
|
|
|
|
// Test animation performance
|
|
const startTime = Date.now();
|
|
await page.click('[data-testid="animate-button"]');
|
|
|
|
await expect(page.locator('[data-testid="animated-element"]'))
|
|
.toHaveClass(/animated/, { timeout: 2000 });
|
|
|
|
const animationTime = Date.now() - startTime;
|
|
expect(animationTime).toBeLessThan(2000);
|
|
});
|
|
|
|
test('should demonstrate leptos-query data fetching', async ({ page }) => {
|
|
await page.goto('/demo/leptos-query');
|
|
|
|
// Test data fetching
|
|
await page.click('[data-testid="fetch-data-button"]');
|
|
|
|
await expect(page.locator('[data-testid="loading-indicator"]'))
|
|
.toBeVisible();
|
|
|
|
await expect(page.locator('[data-testid="data-display"]'))
|
|
.toBeVisible({ timeout: 5000 });
|
|
|
|
await expect(page.locator('[data-testid="data-display"]'))
|
|
.toContainText('Data loaded successfully');
|
|
});
|
|
|
|
test('should demonstrate leptos-helios design system', async ({ page }) => {
|
|
await page.goto('/demo/leptos-helios');
|
|
|
|
// Test design system components
|
|
await expect(page.locator('[data-testid="button-primary"]'))
|
|
.toHaveClass(/btn-primary/);
|
|
|
|
await expect(page.locator('[data-testid="card-component"]'))
|
|
.toHaveClass(/card/);
|
|
|
|
await expect(page.locator('[data-testid="modal-component"]'))
|
|
.toHaveClass(/modal/);
|
|
});
|
|
|
|
test('should demonstrate radix-leptos accessibility', async ({ page }) => {
|
|
await page.goto('/demo/radix-leptos');
|
|
|
|
// Test accessibility features
|
|
await page.keyboard.press('Tab');
|
|
await expect(page.locator(':focus')).toBeVisible();
|
|
|
|
// Test screen reader compatibility
|
|
const ariaLabels = await page.locator('[aria-label]').count();
|
|
expect(ariaLabels).toBeGreaterThan(0);
|
|
|
|
// Test keyboard navigation
|
|
await page.keyboard.press('Enter');
|
|
await expect(page.locator('[data-testid="accessible-button"]'))
|
|
.toHaveClass(/focused/);
|
|
});
|
|
});
|
|
```
|
|
|
|
### Community Engagement Strategy
|
|
```rust
|
|
// Example: Community engagement framework
|
|
pub struct CommunityEngagement {
|
|
crate_name: String,
|
|
engagement_metrics: EngagementMetrics,
|
|
community_activities: Vec<CommunityActivity>,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct EngagementMetrics {
|
|
pub github_issues_resolved: u64,
|
|
pub pull_requests_merged: u64,
|
|
pub community_questions_answered: u64,
|
|
pub documentation_updates: u64,
|
|
pub release_frequency: f64, // releases per month
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum CommunityActivity {
|
|
IssueResolution { issue_id: u64, resolution_time: u64 },
|
|
PullRequestReview { pr_id: u64, review_time: u64 },
|
|
DocumentationUpdate { section: String, update_time: u64 },
|
|
Release { version: String, release_time: u64 },
|
|
CommunitySupport { question_id: u64, response_time: u64 },
|
|
}
|
|
|
|
impl CommunityEngagement {
|
|
pub fn track_issue_resolution(&mut self, issue_id: u64, resolution_time: u64) {
|
|
self.engagement_metrics.github_issues_resolved += 1;
|
|
self.community_activities.push(
|
|
CommunityActivity::IssueResolution { issue_id, resolution_time }
|
|
);
|
|
}
|
|
|
|
pub fn track_pull_request_review(&mut self, pr_id: u64, review_time: u64) {
|
|
self.engagement_metrics.pull_requests_merged += 1;
|
|
self.community_activities.push(
|
|
CommunityActivity::PullRequestReview { pr_id, review_time }
|
|
);
|
|
}
|
|
|
|
pub fn generate_community_report(&self) -> CommunityReport {
|
|
CommunityReport {
|
|
crate_name: self.crate_name.clone(),
|
|
total_activities: self.community_activities.len(),
|
|
average_response_time: self.calculate_average_response_time(),
|
|
community_health_score: self.calculate_community_health(),
|
|
recommendations: self.generate_recommendations(),
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Quality Standards
|
|
|
|
### Crate Maintenance Requirements
|
|
- **Regular Updates**: Monthly updates and improvements
|
|
- **Community Engagement**: Active issue resolution and PR reviews
|
|
- **Documentation**: Comprehensive documentation and examples
|
|
- **Testing**: 100% test coverage for all maintained crates
|
|
- **Performance**: Continuous performance monitoring and optimization
|
|
|
|
### "Drink Our Own Champagne" Requirements
|
|
- **First Users**: We must be the first users of our own crates
|
|
- **Production Testing**: All crates must be used in production
|
|
- **Real-World Validation**: Crates must solve real-world problems
|
|
- **Community Leadership**: We must lead by example in the community
|
|
|
|
## Tools and Technologies
|
|
|
|
### Crate Development
|
|
- **Cargo**: Rust package management
|
|
- **GitHub**: Version control and issue tracking
|
|
- **Crates.io**: Package distribution
|
|
- **Documentation**: Comprehensive documentation generation
|
|
|
|
### Community Engagement
|
|
- **GitHub Issues**: Issue tracking and resolution
|
|
- **Pull Requests**: Code review and collaboration
|
|
- **Discord/Slack**: Community communication
|
|
- **Blog Posts**: Technical articles and tutorials
|
|
|
|
### Quality Assurance
|
|
- **CI/CD**: Automated testing and deployment
|
|
- **Code Coverage**: Comprehensive test coverage
|
|
- **Performance Testing**: Continuous performance monitoring
|
|
- **Security Audits**: Regular security vulnerability scanning
|
|
|
|
## Metrics and Monitoring
|
|
|
|
### Crate Quality Metrics
|
|
- **Download Count**: Monthly download statistics
|
|
- **Community Health**: GitHub stars, forks, and activity
|
|
- **Issue Resolution**: Average time to resolve issues
|
|
- **Release Frequency**: Regular release schedule maintenance
|
|
|
|
### Community Engagement Metrics
|
|
- **Response Time**: Average time to respond to community
|
|
- **Issue Resolution Rate**: Percentage of issues resolved
|
|
- **Community Satisfaction**: Community feedback and ratings
|
|
- **Contribution Rate**: Community contributions and PRs
|
|
|
|
## Review and Updates
|
|
|
|
### Regular Reviews
|
|
- **Weekly**: Crate maintenance and issue resolution
|
|
- **Monthly**: Community engagement and metrics review
|
|
- **Quarterly**: Strategic planning for crate development
|
|
- **Annually**: Long-term roadmap and vision planning
|
|
|
|
### Update Triggers
|
|
- **New Leptos Release**: Update crates for compatibility
|
|
- **Community Feedback**: Respond to community needs
|
|
- **Performance Issues**: Address performance concerns
|
|
- **Security Vulnerabilities**: Immediate security updates
|
|
|
|
## Related ADRs
|
|
- ADR-001: Test-Driven Development (TDD) First Approach
|
|
- ADR-002: Testing Pyramid Strategy
|
|
- ADR-003: Playwright Testing for Demos
|
|
- ADR-006: Leptos Versioning and Latest Support Strategy
|
|
- ADR-007: Rust Coding Standards and Latest Practices
|
|
- ADR-008: Competitive Analysis and Capability Matching Strategy
|