@@ -6,12 +6,20 @@ NuGet packages & CLI for Power Platform: plugin attributes, Dataverse connectivi
66
77| Rule | Why |
88| ------| -----|
9- | Commit directly to main | Protected branch; always create branch + PR |
10- | Regenerate ` PPDS.Plugins.snk ` | Breaks strong naming |
11- | Create new ServiceClient per request | 42,000x slower than pool |
12- | Hold single pooled client for multiple queries | Defeats pool parallelism |
13- | Use magic strings for generated entities | Use ` EntityLogicalName ` and ` Fields.* ` |
14- | Write CLI status messages to stdout | stdout = data, stderr = status |
9+ | Commit directly to ` main ` | Branch is protected; all changes require PR |
10+ | Regenerate ` PPDS.Plugins.snk ` | Breaks strong naming; existing assemblies won't load |
11+ | Skip XML documentation on public APIs | Consumers need IntelliSense documentation |
12+ | Commit with failing tests | All tests must pass before merge |
13+ | Create new ServiceClient per request | 42,000x slower than Clone/pool pattern |
14+ | Guess parallelism values | Use ` RecommendedDegreesOfParallelism ` from server |
15+ | Hold single pooled client for multiple queries | Defeats pool parallelism; see ` .claude/rules/DATAVERSE_PATTERNS.md ` |
16+ | Use magic strings for generated entities | Use ` EntityLogicalName ` and ` Fields.* ` constants |
17+ | Use late-bound ` Entity ` for generated entity types | Use early-bound classes; compile-time safety |
18+ | Write CLI status messages to stdout | Use ` Console.Error.WriteLine ` for status; stdout is for data |
19+ | Access ` ~/.ppds/ ` files directly from UI code | Use Application Services; they handle caching, locking (ADR-0024) |
20+ | Implement data/business logic in UI layer | UIs are dumb views; logic belongs in Application Services |
21+ | Write progress directly to console from services | Accept ` IProgressReporter ` ; let UI render (ADR-0025) |
22+ | Throw raw exceptions from Application Services | Wrap in ` PpdsException ` with ErrorCode/UserMessage (ADR-0026) |
1523
1624## ALWAYS
1725
@@ -20,20 +28,97 @@ NuGet packages & CLI for Power Platform: plugin attributes, Dataverse connectivi
2028| Use connection pool for multi-request scenarios | See ` .claude/rules/DATAVERSE_PATTERNS.md ` |
2129| Use bulk APIs (` CreateMultiple ` , ` UpdateMultiple ` ) | 5x faster than ` ExecuteMultiple ` |
2230| Add new services to ` RegisterDataverseServices() ` | Keeps CLI and library DI in sync |
31+ | Use Application Services for all persistent state | Single code path for CLI/TUI/RPC (ADR-0024) |
32+ | Accept ` IProgressReporter ` for operations >1 second | All UIs need feedback for long operations (ADR-0025) |
33+ | Include ErrorCode in ` PpdsException ` | Enables programmatic handling (retry, re-auth) (ADR-0026) |
34+ | Make new user data accessible via ` ppds serve ` | VS Code extension needs same data as CLI/TUI |
2335
24- ## Structure
36+ ---
2537
38+ ## 💻 Tech Stack
39+
40+ | Technology | Version | Purpose |
41+ | ------------| ---------| ---------|
42+ | .NET | 4.6.2, 8.0, 9.0, 10.0 | Plugins: 4.6.2 only; libraries/CLI: 8.0+ |
43+ | C# | Latest (LangVersion) | Primary language |
44+ | Strong Naming | .snk file | Required for Dataverse plugin assemblies |
45+ | Terminal.Gui | 1.19+ | TUI application framework |
46+ | Spectre.Console | 0.54+ | CLI command output |
47+
48+ ---
49+
50+ ## 📁 Project Structure
51+
52+ ```
53+ ppds-sdk/
54+ ├── src/
55+ │ ├── PPDS.Plugins/ # Plugin attributes (PluginStep, PluginImage)
56+ │ ├── PPDS.Dataverse/ # Connection pool, bulk operations, metadata
57+ │ │ └── Generated/ # Early-bound entity classes (DO NOT edit)
58+ │ ├── PPDS.Migration/ # Migration engine library
59+ │ ├── PPDS.Auth/ # Authentication profiles
60+ │ └── PPDS.Cli/ # CLI tool (ppds command)
61+ │ ├── Commands/ # CLI command handlers
62+ │ ├── Services/ # Application Services (ADR-0015)
63+ │ └── Tui/ # Terminal.Gui application
64+ ├── tests/ # Unit, integration, and live tests
65+ ├── docs/adr/ # Architecture Decision Records
66+ └── CHANGELOG.md
67+ ```
68+
69+ ## 🏛️ Platform Architecture
70+
71+ PPDS is a ** multi-interface platform** , not just a CLI tool. The TUI is the primary development interface, with VS Code extension and other frontends consuming the same services.
72+
73+ ```
74+ ┌─────────────────────────────────────────────────────────────┐
75+ │ User Interfaces │
76+ ├───────────────┬───────────────┬───────────────┬─────────────┤
77+ │ CLI Commands │ TUI App │ VS Code Ext │ Future │
78+ │ (ppds data) │ (ppds -i) │ (RPC client) │ (Web, etc) │
79+ │ │ │ │ │
80+ │ Spectre.Console│ Terminal.Gui │ JSON-RPC │ │
81+ ├───────────────┴───────────────┴───────────────┴─────────────┤
82+ │ ppds serve (RPC Server) │
83+ │ Long-running service for extensions │
84+ ├─────────────────────────────────────────────────────────────┤
85+ │ Application Services Layer (ADR-0015) │
86+ │ ISqlQueryService, IDataMigrationService, IPluginService │
87+ │ • Accepts IProgressReporter (ADR-0025) │
88+ │ • Throws PpdsException (ADR-0026) │
89+ │ • Reads/writes ~/.ppds/ (ADR-0024) │
90+ ├─────────────────────────────────────────────────────────────┤
91+ │ PPDS.Dataverse / PPDS.Migration / PPDS.Auth │
92+ └─────────────────────────────────────────────────────────────┘
2693```
27- src/
28- ├── PPDS.Plugins/ # Plugin attributes (PluginStep, PluginImage)
29- ├── PPDS.Dataverse/ # Connection pool, bulk operations
30- │ └── Generated/ # Early-bound entities (DO NOT edit)
31- ├── PPDS.Migration/ # Migration engine
32- ├── PPDS.Auth/ # Auth profiles
33- └── PPDS.Cli/ # CLI (ppds command)
94+
95+ ### Design Principles
96+
97+ | Principle | Implication |
98+ | -----------| -------------|
99+ | ** TUI-first** | Build features in TUI first, then expose via RPC for extensions |
100+ | ** Service layer** | All business logic in Application Services, never in UI code |
101+ | ** Shared local state** | All UIs access same ` ~/.ppds/ ` data via services (ADR-0024) |
102+ | ** Framework choice** | CLI: Spectre.Console, TUI: Terminal.Gui, Extension: RPC client |
103+
104+ ### Shared Local State
105+
106+ All user data lives in ` ~/.ppds/ ` and is accessed via Application Services:
107+
34108```
109+ ~/.ppds/
110+ ├── profiles.json # Auth profiles (IProfileService)
111+ ├── history/ # Query history per-environment (IQueryHistoryService)
112+ ├── settings.json # User preferences (ISettingsService)
113+ ├── msal_token_cache.bin # MSAL token cache
114+ └── ppds.credentials.dat # Encrypted credentials
115+ ```
116+
117+ ** Access pattern:** ` CLI/TUI/VSCode → Application Service → ~/.ppds/ `
118+
119+ ---
35120
36- ## Generated Entities
121+ ## 🏗️ Generated Entities
37122
38123Early-bound in ` src/PPDS.Dataverse/Generated/ ` . Use ` EntityLogicalName ` and ` Fields.* ` constants.
39124
@@ -51,7 +136,204 @@ Key: Get client INSIDE parallel loops. Use `pool.GetTotalRecommendedParallelism(
51136
52137MinVer tags: ` {Package}-v{version} ` (e.g., ` Cli-v1.0.0-beta.11 ` )
53138
54- ## Commands
139+ ## 🛠️ Common Commands
140+
141+ ``` powershell
142+ dotnet build # Debug build
143+ dotnet build -c Release # Release build
144+ dotnet test # Run all tests
145+ dotnet pack -c Release -o ./nupkgs
146+ ```
147+
148+ ---
149+
150+ ## 🔄 Development Workflow
151+
152+ 1 . Create feature branch from ` main `
153+ 2 . Make changes + ** add tests for new classes**
154+ 3 . Update ` CHANGELOG.md ` (same commit)
155+ 4 . Run ` /pre-pr ` before committing
156+ 5 . Create PR to ` main `
157+ 6 . Run ` /review-bot-comments ` after bots comment
158+
159+ ### Plan Mode Checklist
160+
161+ - [ ] ** Shared utilities identified** - Will logic be needed in multiple files?
162+ - [ ] ** Constants centralized** - Magic numbers/strings that should be shared?
163+ - [ ] ** Existing patterns checked** - Similar functionality to extend?
164+
165+ ** Anti-pattern:** Planning WHAT without WHERE. Always consider where shared logic should live to avoid expensive refactoring.
166+
167+ ### Code Conventions
168+
169+ - Use nullable reference types (` string? ` not ` string ` )
170+ - XML documentation on public APIs
171+ - Comments explain WHY, not WHAT
172+ - Namespaces: ` PPDS.{Package}.{Area} ` (e.g., ` PPDS.Auth.Credentials ` )
173+
174+ ---
175+
176+ ## 📦 Version Management
177+
178+ Each package has independent versioning using MinVer:
179+
180+ | Package | Tag Format |
181+ | ---------| ------------|
182+ | PPDS.Plugins | ` Plugins-v{version} ` |
183+ | PPDS.Dataverse | ` Dataverse-v{version} ` |
184+ | PPDS.Migration | ` Migration-v{version} ` |
185+ | PPDS.Auth | ` Auth-v{version} ` |
186+ | PPDS.Cli | ` Cli-v{version} ` |
187+
188+ Pre-release: ` -alpha.N ` , ` -beta.N ` , ` -rc.N ` suffix
189+
190+ ---
191+
192+ ## 🔀 Git Strategy
193+
194+ | Branch | Purpose |
195+ | --------| ---------|
196+ | ` main ` | Protected, always releasable |
197+ | ` feature/* ` | New features |
198+ | ` fix/* ` | Bug fixes |
199+
200+ ** Merge:** Squash merge to main. Pre-release = fix pattern issues now, don't defer.
201+
202+ ---
203+
204+ ## 🚀 Release Process
205+
206+ 1 . Update per-package ` CHANGELOG.md ` (in ` src/{package}/ ` )
207+ 2 . Merge to ` main `
208+ 3 . Create GitHub Release with package-specific tag
209+ 4 . ` publish-nuget.yml ` workflow publishes to NuGet.org
210+
211+ ---
212+
213+ ## ⚡ Dataverse Performance
214+
215+ ** See ` .claude/rules/DATAVERSE_PATTERNS.md ` for pool usage patterns, DOP parallelism, and code examples.**
216+
217+ Key points:
218+ - Get client INSIDE parallel loops (not outside)
219+ - Use ` pool.GetTotalRecommendedParallelism() ` as DOP ceiling
220+ - Reference impl: ` BulkOperationExecutor.cs `
221+
222+ ### Architecture Decision Records
223+
224+ | ADR | Summary |
225+ | -----| ---------|
226+ | [ 0001] ( docs/adr/0001_DISABLE_AFFINITY_COOKIE.md ) | Disable affinity cookie for 10x throughput |
227+ | [ 0002] ( docs/adr/0002_MULTI_CONNECTION_POOLING.md ) | Multiple Application Users multiply API quota |
228+ | [ 0003] ( docs/adr/0003_THROTTLE_AWARE_SELECTION.md ) | Route away from throttled connections |
229+ | [ 0004] ( docs/adr/0004_THROTTLE_RECOVERY_STRATEGY.md ) | Transparent throttle waiting |
230+ | [ 0005] ( docs/adr/0005_DOP_BASED_PARALLELISM.md ) | DOP-based parallelism |
231+ | [ 0006] ( docs/adr/0006_CONNECTION_SOURCE_ABSTRACTION.md ) | IConnectionSource for custom auth |
232+ | [ 0007] ( docs/adr/0007_UNIFIED_CLI_AND_AUTH.md ) | Unified CLI and auth profiles |
233+ | [ 0008] ( docs/adr/0008_CLI_OUTPUT_ARCHITECTURE.md ) | CLI stdout/stderr separation |
234+ | [ 0009] ( docs/adr/0009_CLI_COMMAND_TAXONOMY.md ) | CLI command taxonomy |
235+ | [ 0010] ( docs/adr/0010_PUBLISHED_UNPUBLISHED_DEFAULT.md ) | Default to published content |
236+ | [ 0011] ( docs/adr/0011_DEPLOYMENT_SETTINGS_FORMAT.md ) | Deployment settings format |
237+ | [ 0012] ( docs/adr/0012_HYBRID_FILTER_DESIGN.md ) | Hybrid filter design |
238+ | [ 0013] ( docs/adr/0013_CLI_DRY_RUN_CONVENTION.md ) | CLI --dry-run convention |
239+ | [ 0014] ( docs/adr/0014_CSV_MAPPING_SCHEMA.md ) | CSV mapping schema |
240+ | [ 0015] ( docs/adr/0015_APPLICATION_SERVICE_LAYER.md ) | Application service layer for CLI/TUI/Daemon |
241+ | [ 0019] ( docs/adr/0019_POOL_MANAGED_CONCURRENCY.md ) | Pool-managed concurrency |
242+ | [ 0020] ( docs/adr/0020_IMPORT_ERROR_REPORTING.md ) | Import error reporting |
243+ | [ 0021] ( docs/adr/0021_TRUNCATE_COMMAND.md ) | Truncate command |
244+ | [ 0022] ( docs/adr/0022_IMPORT_DIAGNOSTICS_ARCHITECTURE.md ) | Import diagnostics architecture |
245+ | [ 0023] ( docs/adr/0023_CLI_BINARY_RELEASE_PROCESS.md ) | CLI binary release process |
246+ | [ 0024] ( docs/adr/0024_SHARED_LOCAL_STATE.md ) | Shared local state for multi-UI |
247+ | [ 0025] ( docs/adr/0025_UI_AGNOSTIC_PROGRESS.md ) | UI-agnostic progress reporting |
248+ | [ 0026] ( docs/adr/0026_STRUCTURED_ERROR_MODEL.md ) | Structured error model |
249+
250+ ---
251+
252+ ## 🖥️ CLI (PPDS.Cli)
253+
254+ See [ CLI README] ( src/PPDS.Cli/README.md ) for full documentation.
255+
256+ Quick start:
257+ ``` bash
258+ ppds auth create --name dev # Create profile
259+ ppds env select # Select environment
260+ ppds data export --schema schema.xml --output data.zip
261+ ` ` `
262+
263+ ** Output conventions:** stdout = data, stderr = status messages.
264+
265+ ---
266+
267+ # # 🔌 DI Registration
268+
269+ Two DI paths must stay synchronized:
270+ - ** Library:** ` AddDataverseConnectionPool(config)`
271+ - ** CLI:** ` ProfileServiceFactory.CreateFromProfileAsync()`
272+
273+ Both call ` RegisterDataverseServices()` to register shared services. When adding a service, add it there (not to individual paths).
274+
275+ ---
276+
277+ # # 🧪 Testing
278+
279+ ** See ` .claude/rules/TESTING.md` for test categories, CI behavior, and local setup.**
280+
281+ Key rules:
282+ - New public class → must have test class
283+ - Run ` /run-integration-local` for live tests
284+ - CI: Unit tests on commits, full tests on PRs
285+
286+ ---
287+
288+ # # 🤖 Bot Review Handling
289+
290+ PRs reviewed by Copilot, Gemini, CodeQL. Not all findings are valid.
291+
292+ | Finding Type | Action |
293+ | --------------| --------|
294+ | Unused code, resource leaks | Usually valid - fix |
295+ | Style suggestions | Often preference - dismiss with reason |
296+ | Logic errors | Verify manually |
297+
298+ Run ` /review-bot-comments [PR#]` to triage.
299+
300+ ---
301+
302+ # # 🗺️ Issue Triage
303+
304+ Issues are tracked in the [PPDS Roadmap](https://github.com/users/joshsmithxrm/projects/3) project.
305+
306+ # ## Triage Command
307+
308+ ` /triage` - Systematically categorize GitHub issues with project fields and labels
309+
310+ # ## Project Fields
311+
312+ | Field | Values | Purpose |
313+ | -------| --------| ---------|
314+ | ** Type** | feature, bug, chore, docs, refactor | Work category |
315+ | ** Priority** | P0-Critical, P1-High, P2-Medium, P3-Low | Urgency/importance |
316+ | ** Size** | XS, S, M, L, XL | Effort estimate |
317+ | ** Status** | Todo, In Progress, Done | Current state |
318+ | ** Target** | This Week, Next, Q1 2026, CLI v1.0.0, Blocked | Sequencing |
319+ | ** Parent Issue** | Link to epic/parent | Issue hierarchy |
320+
321+ # ## Label Strategy
322+
323+ ** Use labels for:**
324+ - ** Epics** : epic:cli-daemon, epic:testing, epic:data-migration
325+ - ** Phases** : phase:1-core, phase:2-connections, phase:3-traces, phase:4-webresources, phase:5-migration
326+ - ** Areas** : area:plugins, area:data, area:auth, area:cli, area:tui, area:pooling, area:daemon
327+ - ** Special** : foundation, blocked, performance
328+ - ** Type hints** (optional): bug, enhancement, documentation
329+
330+ ** Don' t use labels for:** Priority, Size, Status, Target (use project fields instead)
331+
332+ See [docs/ROADMAP.md](docs/ROADMAP.md) for detailed guidelines.
333+
334+ ---
335+
336+ ## 🛠️ Claude Commands
55337
56338| Command | Purpose |
57339|---------|---------|
0 commit comments