453 lines
No EOL
12 KiB
Markdown
453 lines
No EOL
12 KiB
Markdown
# Contributing to Ziya-Slint
|
|
|
|
Thank you for your interest in contributing to Ziya-Slint! This guide outlines our development approach, coding standards, and best practices for the desktop trading application.
|
|
|
|
## Project Overview
|
|
|
|
Ziya-Slint is a desktop trading application built with Rust and Slint UI framework, designed for cryptocurrency trading with real-time market data and portfolio management.
|
|
|
|
## Development Philosophy
|
|
|
|
We follow these core principles:
|
|
|
|
1. **KISS Principle** - Keep code simple and straightforward
|
|
2. **Explicit Error Handling** - Never use dummy types or unfinished code
|
|
3. **Real-world Ready** - All code should be production-ready
|
|
4. **Async-first** - Prefer tokio over std for async operations
|
|
5. **Type Safety** - Leverage Rust's type system for correctness
|
|
6. **Desktop UX** - Native desktop app behavior and performance
|
|
|
|
## Getting Started
|
|
|
|
### Prerequisites
|
|
|
|
- Rust 2024 Edition (see `rust-toolchain.toml`)
|
|
- Just command runner (for development tasks)
|
|
- Redis (for data caching)
|
|
- Git and Git-cliff (for development workflow)
|
|
|
|
### Initial Setup
|
|
|
|
1. Clone the repository
|
|
2. Copy configuration files:
|
|
```bash
|
|
cp Config.example.toml Config.toml
|
|
```
|
|
3. Install development dependencies:
|
|
```bash
|
|
just install-deps
|
|
```
|
|
4. Verify setup:
|
|
```bash
|
|
just test
|
|
just clippy
|
|
```
|
|
|
|
### Development Workflow
|
|
|
|
We use `just` for common development tasks:
|
|
|
|
```bash
|
|
# List all available commands
|
|
just
|
|
|
|
# Development with hot reloading
|
|
just dev
|
|
|
|
# Building
|
|
just build # Build with dev features
|
|
just build-prod # Build with prod features
|
|
|
|
# Quality assurance
|
|
just test # Run tests
|
|
just clippy # Run linter
|
|
just fmt # Format code
|
|
just check # Check code for errors
|
|
just clean # Clean build artifacts
|
|
```
|
|
|
|
## Coding Standards
|
|
|
|
### Error Handling
|
|
|
|
We use strict error handling patterns. **Never** use:
|
|
- Dummy types or results
|
|
- Placeholder implementations
|
|
- TODO comments in production code
|
|
|
|
**Always** use our error handling pattern:
|
|
|
|
```rust
|
|
use crate::err_with_loc;
|
|
use crate::error::Result;
|
|
|
|
// Import the Result type
|
|
use crate::error::Result;
|
|
|
|
// Use map_err before ? operator
|
|
let result = some_operation()
|
|
.map_err(|e| {
|
|
error!("operation_failed: {}", e);
|
|
err_with_loc!(AppError::OperationFailed(format!("operation_failed: {}", e)))
|
|
})?;
|
|
```
|
|
|
|
### Async Programming
|
|
|
|
- **Use tokio** instead of std for async operations
|
|
- Follow the actors pattern from [this guide](https://ryhl.io/blog/actors-with-tokio/)
|
|
- **Never** use `tokio::spawn` with UI components directly
|
|
- **Always** use `slint::invoke_from_event_loop` for UI updates from background tasks
|
|
|
|
### Code Formatting
|
|
|
|
We use `rustfmt` with specific configuration (see `rustfmt.toml`):
|
|
|
|
- Max width: 120 characters
|
|
- Use field init shorthand
|
|
- Reorder imports and impl items
|
|
- Group imports by StdExternalCrate
|
|
- Prefer same line braces
|
|
|
|
Run formatting:
|
|
```bash
|
|
just fmt
|
|
```
|
|
|
|
## Architecture: Feature-Sliced Design (FSD)
|
|
|
|
We follow **Feature-Sliced Design (FSD)** methodology for frontend architecture:
|
|
|
|
### FSD Layer Structure
|
|
```
|
|
ui/
|
|
├── app/ # Application layer - root, global setup
|
|
├── pages/ # Page layer - complete screens
|
|
├── widgets/ # Widget layer - composite UI blocks
|
|
├── entities/ # Entity layer - business entities
|
|
├── features/ # Feature layer - user interactions
|
|
└── shared/ # Shared layer - reusable resources
|
|
├── ui/ # UI components
|
|
├── types/ # Type definitions
|
|
└── design-system/ # Theme, tokens, etc.
|
|
```
|
|
|
|
### FSD Rules & Guidelines
|
|
|
|
1. **Import Rule**: Higher layers can only import from lower layers
|
|
- ✅ `app/` → `pages/` → `widgets/` → `entities/` → `features/` → `shared/`
|
|
- ❌ Never import from higher layers
|
|
|
|
2. **Layer Responsibilities**:
|
|
- **App**: Global providers, routing, application setup
|
|
- **Pages**: Complete screens, page-level logic
|
|
- **Widgets**: Composite UI blocks (navigation, forms, cards)
|
|
- **Entities**: Business entities (token, user, market data)
|
|
- **Features**: User interactions (login, trading, portfolio management)
|
|
- **Shared**: Reusable resources (UI kit, utilities, constants)
|
|
|
|
3. **Slicing by Features**: Each feature should be self-contained
|
|
```
|
|
features/
|
|
├── authentication/
|
|
│ ├── ui/ # Login components
|
|
│ ├── model/ # Auth state
|
|
│ └── api/ # Auth API calls
|
|
└── trading/
|
|
├── ui/ # Trading components
|
|
├── model/ # Trading state
|
|
└── api/ # Trading API calls
|
|
```
|
|
|
|
4. **Component Composition**: Build from bottom-up
|
|
```slint
|
|
// shared/ui/button/
|
|
export component Button { /* base button */ }
|
|
|
|
// widgets/navigation/
|
|
import { Button } from "../../shared/ui/button/";
|
|
export component NavigationWidget {
|
|
Button { /* composed navigation */ }
|
|
}
|
|
|
|
// pages/dashboard/
|
|
import { NavigationWidget } from "../../widgets/navigation/";
|
|
export component Dashboard {
|
|
NavigationWidget { /* page composition */ }
|
|
}
|
|
```
|
|
|
|
5. **State Management**: Follow unidirectional data flow
|
|
- Global state in `app/` layer
|
|
- Feature state in respective `features/` slices
|
|
- Pass data down, emit events up
|
|
|
|
6. **Design System**: Centralized in `shared/design-system/`
|
|
- Theme tokens and variables
|
|
- Consistent spacing, colors, typography
|
|
- Reusable UI components
|
|
|
|
## Slint UI Development
|
|
|
|
### Threading & State Management
|
|
|
|
**Critical Pattern for Slint + Tokio:**
|
|
```rust
|
|
// Background work in Rust
|
|
tokio::spawn(async move {
|
|
let result = do_background_work().await;
|
|
|
|
// Update UI from main thread following FSD data flow
|
|
let _ = slint::invoke_from_event_loop(move || {
|
|
if let Some(ui) = ui_weak.upgrade() {
|
|
// Update flows from app → pages → widgets → shared
|
|
ui.update_global_state(result);
|
|
}
|
|
});
|
|
});
|
|
```
|
|
|
|
### Component Development Guidelines
|
|
|
|
1. **Start with Shared Layer**: Build reusable components first
|
|
```slint
|
|
// shared/ui/loading/loading.slint
|
|
export component LoadingSpinner {
|
|
// Base loading component
|
|
}
|
|
```
|
|
|
|
2. **Compose in Widgets**: Create business-specific blocks
|
|
```slint
|
|
// widgets/token-card/index.slint
|
|
import { LoadingSpinner } from "../../shared/ui/loading/";
|
|
export component TokenCard {
|
|
LoadingSpinner { /* token-specific loading */ }
|
|
}
|
|
```
|
|
|
|
3. **Integrate in Pages**: Assemble complete screens
|
|
```slint
|
|
// pages/dashboard/index.slint
|
|
import { TokenCard } from "../../widgets/token-card/";
|
|
export component Dashboard {
|
|
TokenCard { /* dashboard context */ }
|
|
}
|
|
```
|
|
|
|
4. **Wire in App**: Handle global state and routing
|
|
```slint
|
|
// app/index.slint
|
|
import { Dashboard } from "../pages/dashboard/";
|
|
export component App {
|
|
if current-page == "dashboard": Dashboard { }
|
|
}
|
|
```
|
|
|
|
### File Naming Conventions
|
|
|
|
- Use `index.slint` for main component exports
|
|
- Use kebab-case for file names: `token-card.slint`
|
|
- Use PascalCase for component names: `TokenCard`
|
|
|
|
### Property & Callback Flow
|
|
|
|
- Properties flow down: `app → pages → widgets → shared`
|
|
- Callbacks flow up: `shared → widgets → pages → app`
|
|
- Keep callback interfaces simple and focused
|
|
|
|
## FSD Best Practices
|
|
|
|
### ✅ Do:
|
|
- Keep components focused on single responsibility
|
|
- Use semantic component names that reflect business domain
|
|
- Extract common patterns to `shared/` layer
|
|
- Implement loading and error states consistently
|
|
- Use TypeScript-like typing through Slint properties
|
|
- Follow consistent import paths relative to FSD structure
|
|
|
|
### ❌ Don't:
|
|
- Import from higher layers (breaks FSD hierarchy)
|
|
- Put business logic directly in UI components
|
|
- Create circular dependencies between features
|
|
- Hardcode values that should be in design system
|
|
- Mix concerns (UI logic with business logic)
|
|
- Create deep nesting beyond FSD layers
|
|
|
|
### Common Anti-patterns to Avoid:
|
|
```slint
|
|
// ❌ BAD: Widget importing from pages
|
|
// widgets/header/index.slint
|
|
import { Dashboard } from "../../pages/dashboard/"; // Wrong!
|
|
|
|
// ❌ BAD: Shared component with business logic
|
|
// shared/ui/button/index.slint
|
|
export component Button {
|
|
// Don't put trading logic here!
|
|
clicked => { execute_trade(); }
|
|
}
|
|
|
|
// ✅ GOOD: Proper callback delegation
|
|
// shared/ui/button/index.slint
|
|
export component Button {
|
|
callback clicked();
|
|
}
|
|
|
|
// ✅ GOOD: Business logic in appropriate layer
|
|
// features/trading/ui/trade-button.slint
|
|
import { Button } from "../../../shared/ui/button/";
|
|
export component TradeButton {
|
|
Button {
|
|
clicked => { handle_trade_click(); }
|
|
}
|
|
}
|
|
```
|
|
|
|
## Testing
|
|
|
|
### Unit Tests
|
|
|
|
```bash
|
|
just test
|
|
```
|
|
|
|
### Integration Tests
|
|
|
|
- Test UI components with mock data
|
|
- Test service layer integration
|
|
- Use feature flags for test environments
|
|
|
|
### Feature Testing
|
|
|
|
```bash
|
|
# Run with specific features
|
|
cargo test --features dev
|
|
cargo test --features prod
|
|
```
|
|
|
|
## UI/UX Principles
|
|
|
|
We follow comprehensive usability guidelines:
|
|
|
|
1. **10 Usability Heuristics** - Nielsen's principles
|
|
2. **Gestalt Principles** - Visual hierarchy and grouping
|
|
3. **Accessibility** - Support for different user needs
|
|
4. **Simplicity** - Minimize cognitive load
|
|
5. **Desktop Patterns** - Native desktop app behavior
|
|
|
|
### Key Requirements:
|
|
- Responsive design within window constraints (1080x800 - 1920x1080)
|
|
- Proper error messaging in plain language
|
|
- Loading states with progress indication
|
|
- Keyboard navigation support
|
|
- Native desktop interactions
|
|
|
|
## Submission Guidelines
|
|
|
|
### Branch Naming
|
|
|
|
Use descriptive names:
|
|
- `feat/shared/button-component` - New shared component
|
|
- `feat/pages/dashboard-redesign` - Page-level changes
|
|
- `feat/features/trading-flow` - Feature implementation
|
|
- `fix/widgets/token-card-loading` - Bug fixes
|
|
- `refactor/shared/design-system` - Code improvements
|
|
|
|
### Commit Messages
|
|
|
|
Be descriptive:
|
|
```
|
|
feat(shared): add loading spinner component
|
|
|
|
- Implement reusable loading spinner in shared/ui
|
|
- Add animation and theme support
|
|
- Export from shared layer for use in widgets
|
|
|
|
fix(pages): resolve dashboard layout overflow
|
|
|
|
- Fix token card grid overflow in dashboard
|
|
- Improve responsive behavior for small windows
|
|
- Add proper scrolling for token list
|
|
```
|
|
|
|
### Code Review Checklist
|
|
|
|
**General:**
|
|
- [ ] Follows error handling patterns
|
|
- [ ] Uses tokio for async operations
|
|
- [ ] Includes proper logging
|
|
- [ ] Formatted with rustfmt
|
|
- [ ] Passes all tests
|
|
- [ ] Updates documentation if needed
|
|
|
|
**FSD-Specific:**
|
|
- [ ] Components placed in correct FSD layer
|
|
- [ ] Import dependencies only from lower layers
|
|
- [ ] Properties flow down, callbacks flow up
|
|
- [ ] No direct business logic in UI components
|
|
- [ ] Reusable components in `shared/` layer
|
|
- [ ] Feature-specific logic in `features/` layer
|
|
|
|
**UI/UX:**
|
|
- [ ] Follows design system patterns
|
|
- [ ] Implements proper loading states
|
|
- [ ] Handles error states gracefully
|
|
- [ ] Supports keyboard navigation
|
|
- [ ] Responsive within window constraints
|
|
|
|
## Development Environment
|
|
|
|
### Recommended Tools
|
|
|
|
- **IDE**: VS Code with rust-analyzer and Slint extension
|
|
- **Debugging**: Use tracing for structured logging
|
|
- **File Watching**: `watchexec` for auto-reload during development
|
|
- **Hot Reloading**: `just dev` for development workflow
|
|
|
|
### Common Issues
|
|
|
|
#### Slint Compilation Errors
|
|
|
|
If you encounter field offset errors with watchexec:
|
|
```bash
|
|
cargo clean
|
|
# Then rebuild
|
|
```
|
|
|
|
#### Threading Issues
|
|
|
|
Remember: Slint UI components are not `Send`. Always use `slint::invoke_from_event_loop` for UI updates from background tasks.
|
|
|
|
#### Hot Reloading
|
|
|
|
For the best development experience:
|
|
```bash
|
|
just dev
|
|
```
|
|
|
|
This watches both `src/` and `ui/` directories and automatically rebuilds.
|
|
|
|
## Documentation
|
|
|
|
- **Component APIs**: Document with clear examples
|
|
- **Architecture**: Update this guide when patterns change
|
|
- **Configuration**: Document all config options
|
|
- **UI Components**: Maintain design system documentation
|
|
|
|
## Getting Help
|
|
|
|
1. Check existing documentation
|
|
2. Search closed issues on GitHub
|
|
3. Ask in project discussions
|
|
4. Check Slint documentation for UI issues
|
|
|
|
## Code of Conduct
|
|
|
|
- Be respectful and inclusive
|
|
- Focus on constructive feedback
|
|
- Help others learn and grow
|
|
- Maintain professional communication
|
|
|
|
---
|
|
|
|
By following these guidelines, you help maintain code quality and ensure smooth collaboration on the Ziya-Slint desktop application. Thank you for contributing! 🚀 |