# plcbundle-rs Coding Rules

## Core Design Principles

1. **Single Entry Point**: All operations go through `BundleManager`
2. **Options Pattern**: Complex operations use dedicated option structs  
3. **Result Types**: Operations return structured result types, not raw tuples
4. **Streaming by Default**: Use iterators for large datasets
5. **NO DIRECT FILE ACCESS**: CLI commands and server code NEVER open bundle files directly

## Critical Rules

### File Access
- ❌ **NEVER** use `std::fs::File::open` for bundle files in CLI commands or server code
- ❌ **NEVER** use `std::fs::read` for bundle data in CLI commands or server code
- ❌ **NEVER** use `std::fs::remove_file` for bundles in CLI commands or server code
- ❌ **NEVER** access core components (Index, bundle_format, etc.) directly from CLI or server
- ✅ **ALWAYS** use `BundleManager` methods for bundle operations
- ✅ **ALWAYS** add new operations to `BundleManager` API if needed

### API-First Development
- All CLI commands in `src/bin/commands/` must use **ONLY** public `BundleManager` APIs
- All server code must use **ONLY** public `BundleManager` APIs
- If CLI or server code needs file access, add the method to `BundleManager` first
- The `BundleManager` is the single source of truth for all bundle operations

### Examples

**❌ WRONG - Direct file access:**
```rust
let bundle_path = dir.join(format!("{:06}.jsonl.zst", bundle_num));
std::fs::remove_file(&bundle_path)?;
```

**✅ CORRECT - Via BundleManager API:**
```rust
manager.delete_bundle_files(&[bundle_num])?;
```

## Architecture

```
CLI Commands / Server → BundleManager API → Internal Implementation
     ↓                        ↓                       ↓
   Uses                   Provides               Opens files
   Only                   Public API             Directly
```

## When Adding New Features

1. Design the API method in `BundleManager` first
2. Document it in `docs/API.md`
3. Implement the method in `src/manager.rs`
4. Export types in `src/lib.rs` if needed
5. Use the API from CLI command or server

## Reference Documentation

- Full API design: `docs/API.md`
- Bundle format: `docs/BUNDLE_FORMAT.md`
- All public APIs are listed in `docs/API.md` Quick Reference

## Common Patterns

### Loading Bundles
```rust
// ❌ Don't open files directly
let file = File::open(bundle_path)?;

// ✅ Use the API
let result = manager.load_bundle(bundle_num, LoadOptions::default())?;
```

### Getting Operations
```rust
// ❌ Don't parse files directly
let json = std::fs::read_to_string(bundle_path)?;

// ✅ Use the API
let json = manager.get_operation_raw(bundle_num, position)?;
```

### Deleting Bundles
```rust
// ❌ Don't remove files directly
std::fs::remove_file(bundle_path)?;

// ✅ Use the API
manager.delete_bundle_files(&[bundle_num])?;
```

## Testing

**IMPORTANT**: Always test compilation with all features enabled.

When implementing features:
- **Always run**: `cargo check --all-features` or `cargo build --all-features` before considering work complete
- This ensures code compiles with both `cli` and `server` features enabled
- It's very common that code compiles with default features but fails with all features
- Fix any compilation errors that appear with all features enabled

If writing actual tests:
- Test through the public API
- Don't test internal implementation details
- CLI tests should use actual `BundleManager` instances

## Questions?

If you're implementing a feature and need file access:
1. Check if `BundleManager` already has the method
2. If not, add it to `BundleManager` first
3. Update `docs/API.md` with the new method
4. Then use it from the CLI or server

**Remember: The CLI and server are just thin wrappers around `BundleManager`!**

