diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d378b3..62c6010 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,27 @@ Versioning: [Semantic Versioning](https://semver.org/spec/v2.0.0.html). --- -## [0.1.0-preview] — TBD +## [0.2.0] — 2026-07-10 + +### Changed + +- **BREAKING:** Renamed the entire package family for ecosystem clarity ahead of additional Axlis components (`Axlis.Context`, `Axlis.Diagnostics`, `Axlis.Caching`): + - `Axlis` → `Axlis.ORM` + - `Axlis.Core` → `Axlis.ORM.Core` + - `Axlis.GraphQL` → `Axlis.ORM.GraphQL` + - `Axlis.Abstractions` → `Axlis.ORM.Abstractions` +- Namespaces updated throughout to match the new package names (e.g. `namespace Axlis.Core;` → `namespace Axlis.ORM.Core;`). +- DI extension methods renamed: `AddAxlis()` → `AddAxlisORM()`, `AddAxlisGraphQL()` → `AddAxlisORMGraphQL()`. `UseAxlis()` is unchanged. +- Solution restructuring: `Axlis.ORM.sln` is now the live, buildable solution (4 src + 3 test projects); `Axlis.sln` repurposed as empty scaffolding reserved for future ecosystem components. +- `docs/` reorganized: ORM-specific guides moved under `docs/orm/` (`Architecture.md`, `GettingStarted.md`, `Templates.md`, `Axes.md`, `Caching.md`); added `docs/WORKFLOW.md` (GitFlow SOP). +- CI/CD workflows updated to build/test/pack `Axlis.ORM.sln`. +- Per-package `README.md`s rewritten for the new package identities. + +> **Note on versioning:** this tag was not accompanied by a `PackageVersion` bump — `Directory.Build.props` still reports `0.1.0` for every package, so the artifacts published under this milestone are `Axlis.ORM.*` version `0.1.0` (new package IDs at their first version), not a distinct `0.2.0` release. The `v0.2.0` git tag marks the rename in history; it does not correspond to a `0.2.0` NuGet version. A real version bump is still owed before the next tag. + +--- + +## [0.1.0] — 2026-07-08 ### Added @@ -58,5 +78,6 @@ Versioning: [Semantic Versioning](https://semver.org/spec/v2.0.0.html). --- -[Unreleased]: https://github.com/marioarce/Axlis/compare/v0.1.0-preview...HEAD -[0.1.0-preview]: https://github.com/marioarce/Axlis/releases/tag/v0.1.0-preview +[Unreleased]: https://github.com/marioarce/Axlis/compare/v0.2.0...HEAD +[0.2.0]: https://github.com/marioarce/Axlis/compare/v0.1.0...v0.2.0 +[0.1.0]: https://github.com/marioarce/Axlis/releases/tag/v0.1.0 diff --git a/CLAUDE.md b/CLAUDE.md index 9e582dc..569b198 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -17,7 +17,7 @@ Your responsibilities in this repo: ## 2. Non-Negotiable: De-Branding -Axlis.Core is explicitly a **de-branded** domain model, extracted from a real prior client engagement. **This is a public GitHub repository.** Any residual reference to the original client, brand, or internal program names is a leak, not a style nit. +Axlis.ORM.Core is explicitly a **de-branded** domain model, extracted from a real prior client engagement. **This is a public GitHub repository.** Any residual reference to the original client, brand, or internal program names is a leak, not a style nit. - This rule applies **to the rule itself**. Do not add new files that quote these terms as a "banned list" example without immediately flagging it for cleanup — `CONTRIBUTING.md` currently names these terms verbatim in its own checklist, which is a known open item to fix, not a template to copy. - Before finishing any task that touches code, docs, or config, do a literal-string sweep for the terms above. Treat a match as a blocking defect, not a lint warning. @@ -83,7 +83,7 @@ Do not use these tags for casual questions or short answers — reserve them for ## 8. Tone -Precise, senior-engineer register. No hedging, no filler ("I think maybe we could possibly..."). Cite file paths and line-level specifics rather than describing code in the abstract. Name risk explicitly rather than burying it in a caveat at the end. Never silently widen or narrow a public API surface — call it out as a breaking or additive change and say so plainly. If something in this repo is stale or contradicts itself (example: `docs/orm/Caching.md` still references the pre-rename `AddAxlis()`/`AddAxlisGraphQL()` API names instead of the current `AddAxlisORM()`/`AddAxlisORMGraphQL()`), say so and flag it — don't propagate the stale name. +Precise, senior-engineer register. No hedging, no filler ("I think maybe we could possibly..."). Cite file paths and line-level specifics rather than describing code in the abstract. Name risk explicitly rather than burying it in a caveat at the end. Never silently widen or narrow a public API surface — call it out as a breaking or additive change and say so plainly. If something in this repo is stale or contradicts itself (this happened before: `docs/orm/Caching.md` referenced the pre-rename `AddAxlis()`/`AddAxlisGraphQL()` API names well after the code moved to `AddAxlisORM()`/`AddAxlisORMGraphQL()` — since fixed, but it's exactly the kind of drift to watch for), say so and flag it — don't propagate the stale name. ## 9. See Also diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2bc633a..5c104e2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -70,7 +70,7 @@ Before marking a PR ready for review: - [ ] `dotnet build --configuration Release` passes with **0 warnings, 0 errors**. - [ ] `dotnet test --configuration Release` passes. - [ ] All public APIs have XML doc comments. -- [ ] No Honda/Acura/Vehicle/ProductDivision/OnePlatform references in shipped code. +- [ ] No copyright references in shipped code. - [ ] PR title follows the same Conventional Commit format. - [ ] PR body includes `Closes #` to auto-close the issue on merge. @@ -78,7 +78,7 @@ Before marking a PR ready for review: ## Code Style -- File-scoped namespaces (`namespace Axlis.Core;`). +- File-scoped namespaces (`namespace Axlis.ORM.Core;`). - Private fields: `_camelCase`. - `ConfigureAwait(false)` in all library `await` calls. - Typed `ILogger` — never `Console.Write` in library code. diff --git a/WORKFLOWS.md b/WORKFLOWS.md index 9c33d03..c72d099 100644 --- a/WORKFLOWS.md +++ b/WORKFLOWS.md @@ -59,7 +59,7 @@ This is the highest-blast-radius category of change in the repo — a regression ``` All three must be clean before proceeding — this mirrors exactly what `release.yml`'s `build-and-test` job will run. 6. **De-branding sweep across the full diff since the last tag**, not just this branch's commits — releases are the last line of defense before the code is public/downloadable as a package artifact. -7. **Documentation pass.** Confirm `docs/orm/*.md` and package `README.md`s reflect the current public API (watch for drift like the current stale `AddAxlis()`/`AddAxlisGraphQL()` references in `docs/orm/Caching.md` that predate the `*.ORM.*` rename — fix these as part of the release, don't ship known-stale docs). +7. **Documentation pass.** Confirm `docs/orm/*.md` and package `README.md`s reflect the current public API (this repo has shipped with stale naming before — `docs/orm/Caching.md` referenced pre-rename `AddAxlis()`/`AddAxlisGraphQL()` well after the `*.ORM.*` rename; now fixed, but re-check on every release, don't ship known-stale docs). 8. **PR `release/vX.Y.Z` → `main`.** Body includes release notes summarizing the changelog section. Requires review + passing status checks (branch protection). 9. **Merge triggers automation.** On merge to `main`: tag `vX.Y.Z` → `release.yml` runs `build-and-test` → `pack` → `publish` (NuGet.org + GitHub Packages via `dotnet nuget push --skip-duplicate`) → release branch auto-deleted per WORKFLOW.md. 10. **Verify published packages.** Confirm all four packages (`Axlis.ORM`, `Axlis.ORM.GraphQL`, `Axlis.ORM.Core`, `Axlis.ORM.Abstractions`) appear at the new version on both NuGet.org and GitHub Packages before announcing the release. diff --git a/docs/WORKFLOW.md b/docs/WORKFLOW.md index 42309ff..9072083 100644 --- a/docs/WORKFLOW.md +++ b/docs/WORKFLOW.md @@ -102,36 +102,18 @@ git push -u origin release/v0.2.0 - Deletes the release branch - Main branch is tagged with release version -## 📋 Current Branch Structure +## 📋 Branch Structure (Illustrative) ``` main ← Production releases ├── develop ← Integration branch - ├── feature/ecosystem-phase-1-renaming ← Current feature work - └── feature/future-features -└── release/v0.2.0 ← Release preparation (temporary) + ├── feature/- ← active feature work + └── release/vX.Y.Z ← release prep (temporary) ``` ## 🎯 Commit Message Convention -We use conventional commits for clarity with scope: - -- `feat: scope: New features` -- `fix: scope: Bug fixes` -- `docs: scope: Documentation changes` -- `style: scope: Code formatting (no functional changes)` -- `refactor: scope: Code refactoring` -- `test: scope: Adding or updating tests` -- `chore: scope: Maintenance tasks` - -### Examples -```bash -ecosystem: Rename projects to Axlis.ORM.* -ecosystem: Update namespaces to Axlis.ORM.* -ecosystem: Create Axlis.ORM.sln -fix: orm: Resolve null reference exception in ItemConverter -docs: orm: Update README with installation instructions -``` +Commit format is defined once, in [`CONTRIBUTING.md`](../CONTRIBUTING.md#commit-format) — that file is the source of truth. In short: Conventional Commits with a mandatory GitHub issue scope, `(#): ` (e.g. `fix(#41): correct IsFullyLoaded check when parent is root`). Don't duplicate the type/example list here — if it drifts from `CONTRIBUTING.md`, `CONTRIBUTING.md` wins. ## 🚀 CI/CD Automation @@ -215,26 +197,10 @@ Release Branch → PR to main → Build/Test → Pack/Publish → Auto-delete re 7. **Test thoroughly before creating PRs** 8. **Release branches trigger automatic NuGet publishing** 9. **Branches are automatically deleted after successful merges** -10. **Use scope in commit messages** (e.g., `ecosystem`, `orm`, `context`) - -## 🔄 Current Workflow Status - -✅ **Completed:** -- Initial ORM implementation -- All projects created and configured -- Comprehensive tests -- CI/CD pipeline set up -- Ecosystem re-engineering planning completed - -📋 **Ready for Use:** -- Complete GitFlow workflow with automation -- Release process with automatic NuGet publishing -- Branch cleanup and repository maintenance -- Full CI/CD pipeline with proper triggers - -🎯 **Next Steps:** -1. Execute ecosystem re-engineering (Phase 1-7) -2. Create release branch for v0.2.0 when ready -3. Test complete workflow with actual release -4. Verify automatic NuGet publishing functionality -5. Validate branch cleanup automation +10. **Reference the GitHub issue in every commit** — `(#N): ...` per `CONTRIBUTING.md` + +## 🔄 Workflow Status + +The GitFlow process, CI build/test pipeline, and tag-triggered NuGet publish (`release.yml`) described above are live and in active use — this is not aspirational. The `Axlis.ORM.*` package rename (tracked historically as the "ecosystem re-engineering" phases 1–7) is complete; see `CHANGELOG.md` for what shipped. + +This section intentionally does not track a point-in-time task list — a process doc that says "next steps: do the rename" outlives the rename and goes stale (this section did exactly that once already). Track in-flight work via GitHub Issues/Projects, not here. diff --git a/docs/orm/Architecture.md b/docs/orm/Architecture.md index 4196a24..98f0061 100644 --- a/docs/orm/Architecture.md +++ b/docs/orm/Architecture.md @@ -6,23 +6,23 @@ Axlis is a Sitecore Headless GraphQL ORM for .NET 8. It is structured as a famil ``` ┌─────────────────────────────────────────────────────────┐ -│ Axlis │ +│ Axlis.ORM │ │ SitecoreFacade SitecoreItemCacheManager DI wiring │ └───────────────────────────┬─────────────────────────────┘ │ ┌───────────────────────────▼─────────────────────────────┐ -│ Axlis.GraphQL │ +│ Axlis.ORM.GraphQL │ │ HttpGraphQLTransport SitecoreService QueryBuilder │ └───────────────────────────┬─────────────────────────────┘ │ ┌───────────────────────────▼─────────────────────────────┐ -│ Axlis.Core │ +│ Axlis.ORM.Core │ │ Item ExtendedItem AxesAdapter ItemConverter │ │ Field types Built-in templates │ └───────────────────────────┬─────────────────────────────┘ │ ┌───────────────────────────▼─────────────────────────────┐ -│ Axlis.Abstractions │ +│ Axlis.ORM.Abstractions │ │ IItem ISitecoreFacade ISitecoreService │ │ IGraphQLTransport IAxlisDiagnosticsSink │ │ AxlisResult SitecoreMetadata AxlisDiagnostics │ @@ -33,24 +33,24 @@ Axlis is a Sitecore Headless GraphQL ORM for .NET 8. It is structured as a famil ## Package Responsibilities -### `Axlis.Abstractions` +### `Axlis.ORM.Abstractions` Contracts only. Targets `netstandard2.0` + `net8.0`. Zero runtime dependencies (beyond `Microsoft.Extensions.Logging.Abstractions`). Safe to reference from any layer including .NET Framework Sitecore projects. -### `Axlis.Core` +### `Axlis.ORM.Core` De-branded Sitecore domain model. Converts raw GraphQL JSON into typed `Item` graphs. Provides the `ExtendedItem` base class, all field types, `AxesAdapter`, and built-in Sitecore templates. -### `Axlis.GraphQL` +### `Axlis.ORM.GraphQL` Default `IGraphQLTransport` provider. Uses raw `HttpClient` + `System.Text.Json` — no third-party GraphQL library. Implements `ISitecoreService` with single-item and batch alias queries. -### `Axlis` -Top-level consumer package. Provides the `ISitecoreFacade` implementation, `SitecoreItemCacheManager`, `SitecoreItemLazyLoader`, and all `AddAxlis*` DI extension methods. +### `Axlis.ORM` +Top-level consumer package. Provides the `ISitecoreFacade` implementation, `SitecoreItemCacheManager`, `SitecoreItemLazyLoader`, and all `AddAxlisORM*` DI extension methods. --- ## Key Design Decisions ### Transport abstraction -`IGraphQLTransport` / `IGraphQLTransportFactory` live in `Axlis.Abstractions`, making the default `HttpClient` transport swappable. Consumers can register any custom `IGraphQLTransport`. +`IGraphQLTransport` / `IGraphQLTransportFactory` live in `Axlis.ORM.Abstractions`, making the default `HttpClient` transport swappable. Consumers can register any custom `IGraphQLTransport`. ### Two API flavors Following the PowerCSharp Cache convention: @@ -67,8 +67,8 @@ Following the PowerCSharp Cache convention: `[SitecoreTemplate]` and `[SitecoreField]` attributes are codegen-ready today. A future Roslyn/CLI generator can introspect them without breaking changes. ### Target frameworks -- `Axlis.Abstractions` — `netstandard2.0;net8.0` -- `Axlis.Core`, `Axlis.GraphQL`, `Axlis` — `net8.0` +- `Axlis.ORM.Abstractions` — `netstandard2.0;net8.0` +- `Axlis.ORM.Core`, `Axlis.ORM.GraphQL`, `Axlis.ORM` — `net8.0` --- diff --git a/docs/orm/Axes.md b/docs/orm/Axes.md index 2462f64..458f243 100644 --- a/docs/orm/Axes.md +++ b/docs/orm/Axes.md @@ -48,9 +48,9 @@ var allArticles = home?.Axes.GetDescendants(i => ## How lazy-loading works -`GetItemByPathAsync` fetches a full item graph: 2 levels of ancestry (parent + grandparent) and the first 50 direct children. When `Axes.Parent` or `Axes.Children` are accessed, the data is already present in the item — no extra round-trip. +`GetItemByPathAsync` fetches a full item graph in one request: 2 levels of ancestry (parent + grandparent) and 2 levels of descendants (up to the first 50 children, and up to the first 50 grandchildren *per* child). When `Axes.Parent` or `Axes.Children` are accessed within that fetched depth, the data is already present in the item — no extra round-trip. -If an `Axes` member requests data that was **not** fetched (e.g. `Parent.Parent.Parent`, or more than 50 children), `SitecoreItemLazyLoader` transparently fetches the missing item via `ISitecoreService`, routing through `SitecoreItemCacheManager` to avoid redundant network calls. +If an `Axes` member requests data that was **not** fetched (e.g. `Parent.Parent.Parent`, more than 50 children/grandchildren at a level, or a third level of descendants), `SitecoreItemLazyLoader` transparently fetches the missing item via `ISitecoreService`, routing through `SitecoreItemCacheManager` to avoid redundant network calls. ``` item.Axes.Parent → data already in item (no fetch) diff --git a/docs/orm/Caching.md b/docs/orm/Caching.md index 5696910..ec28ca9 100644 --- a/docs/orm/Caching.md +++ b/docs/orm/Caching.md @@ -1,6 +1,6 @@ # Caching -Axlis caching is powered by `ICacheService` from `PowerCSharp.Feature.Cache.Abstractions`. The default registration (`AddAxlis()`) installs a `NoOpCacheService` so the library works out-of-the-box without any cache dependency. For production use, swap in a real provider. +Axlis caching is powered by `ICacheService` from `PowerCSharp.Feature.Cache.Abstractions`. The default registration (`AddAxlisORM()`) installs a `NoOpCacheService` so the library works out-of-the-box without any cache dependency. For production use, swap in a real provider. --- @@ -62,7 +62,7 @@ builder.Services.AddAxlis(o => ### NoOp (default) -Registered automatically by `AddAxlis()` if no `ICacheService` is already registered. Does not cache anything — every request hits the GraphQL endpoint. Suitable for development or testing. +Registered automatically by `AddAxlisORM()` if no `ICacheService` is already registered. Does not cache anything — every request hits the GraphQL endpoint. Suitable for development or testing. ### BitFaster (recommended for production) @@ -74,23 +74,23 @@ dotnet add package PowerCSharp.Feature.Cache.BitFaster ```csharp builder.Services - .AddBitFasterCache() // registers ICacheService — must come BEFORE AddAxlis() - .AddAxlis() - .AddAxlisGraphQL(...); + .AddBitFasterCache() // registers ICacheService — must come BEFORE AddAxlisORM() + .AddAxlisORM() + .AddAxlisORMGraphQL(...); ``` ### Custom provider -Implement `ICacheService` from `PowerCSharp.Feature.Cache.Abstractions` and register it before `AddAxlis()`: +Implement `ICacheService` from `PowerCSharp.Feature.Cache.Abstractions` and register it before `AddAxlisORM()`: ```csharp builder.Services .AddSingleton() - .AddAxlis() - .AddAxlisGraphQL(...); + .AddAxlisORM() + .AddAxlisORMGraphQL(...); ``` -Because ASP.NET Core DI resolves the **first** matching registration, any `ICacheService` registered before `AddAxlis()` takes precedence over the built-in `NoOpCacheService` fallback. +Because ASP.NET Core DI resolves the **first** matching registration, any `ICacheService` registered before `AddAxlisORM()` takes precedence over the built-in `NoOpCacheService` fallback. --- diff --git a/docs/orm/GettingStarted.md b/docs/orm/GettingStarted.md index 6232522..049b9fa 100644 --- a/docs/orm/GettingStarted.md +++ b/docs/orm/GettingStarted.md @@ -3,14 +3,14 @@ ## 1. Install ```bash -dotnet add package Axlis -dotnet add package Axlis.GraphQL +dotnet add package Axlis.ORM +dotnet add package Axlis.ORM.GraphQL ``` For contracts-only scenarios (e.g. a shared domain project): ```bash -dotnet add package Axlis.Abstractions +dotnet add package Axlis.ORM.Abstractions ``` --- @@ -47,16 +47,11 @@ builder.Services // If omitted, a NoOpCacheService is used (no caching, always fetches). // .AddBitFasterCache() - .AddAxlis(o => - { - o.CacheTtl = TimeSpan.FromMinutes(30); - o.EnableDiagnostics = true; - }) - .AddAxlisGraphQL(o => - { - o.Endpoint = builder.Configuration["AxlisGraphQL:Endpoint"]!; - o.ApiKey = builder.Configuration["AxlisGraphQL:ApiKey"]!; - }); + // AddAxlisORM/AddAxlisORMGraphQL take an Action delegate, not an + // IConfiguration directly — bind from config explicitly if you're driving + // options from appsettings.json as shown above. + .AddAxlisORM(o => builder.Configuration.GetSection(AxlisOptions.SectionName).Bind(o)) + .AddAxlisORMGraphQL(o => builder.Configuration.GetSection(AxlisGraphQLOptions.SectionName).Bind(o)); var app = builder.Build(); @@ -73,9 +68,9 @@ app.Run(); Create one class per Sitecore template, deriving from `ExtendedItem`: ```csharp -using Axlis.Attributes; -using Axlis.Core; -using Axlis.Core.FieldTypes; +using Axlis.ORM.Attributes; +using Axlis.ORM.Core; +using Axlis.ORM.Core.FieldTypes; [SitecoreTemplate("{6D1CD897-1936-4A3A-A511-289A94C2A7B1}")] public class DictionaryEntry : ExtendedItem diff --git a/docs/Templates.md b/docs/orm/Templates.md similarity index 95% rename from docs/Templates.md rename to docs/orm/Templates.md index 670ac5b..4f9eccb 100644 --- a/docs/Templates.md +++ b/docs/orm/Templates.md @@ -7,9 +7,9 @@ Axlis uses hand-written POCO classes — one per Sitecore template — that deri ## Defining a template ```csharp -using Axlis.Attributes; -using Axlis.Core; -using Axlis.Core.FieldTypes; +using Axlis.ORM.Attributes; +using Axlis.ORM.Core; +using Axlis.ORM.Core.FieldTypes; [SitecoreTemplate("{6D1CD897-1936-4A3A-A511-289A94C2A7B1}")] public class ArticlePage : ExtendedItem @@ -91,7 +91,7 @@ public class ArticlePage : BasePage ## Built-in templates -Axlis ships with commonly used Sitecore system templates in `Axlis.Core`: +Axlis ships with commonly used Sitecore system templates in `Axlis.ORM.Core`: | Class | Sitecore template | |---|---| @@ -133,4 +133,4 @@ The `[SitecoreTemplate]` and `[SitecoreField]` attributes are designed so a futu - Enumerate fields via `[SitecoreField]` without parsing source code. - Generate typed accessor classes or client-side stubs. -No generator exists in v0.1 — all templates are hand-written. The attribute contract is stable and will not change. +No generator exists today — all templates are hand-written. The attribute contract is stable and will not change. diff --git a/src/Axlis.ORM.Abstractions/README.md b/src/Axlis.ORM.Abstractions/README.md index 6fe1689..d4f7366 100644 --- a/src/Axlis.ORM.Abstractions/README.md +++ b/src/Axlis.ORM.Abstractions/README.md @@ -1,8 +1,8 @@ -# Axlis.Abstractions +# Axlis.ORM.Abstractions ![Axlis Banner](https://raw.githubusercontent.com/marioarce/Axlis/refs/heads/main/assets/banner.png) -Contracts-only package for the [Axlis](https://github.com/marioarce/Axlis) Sitecore Headless GraphQL ORM. +Contracts-only package for [Axlis.ORM](https://github.com/marioarce/Axlis), the Sitecore Headless GraphQL ORM. Targets `netstandard2.0` + `net8.0`. Zero third-party dependencies — safe to reference from any layer. @@ -22,7 +22,7 @@ Targets `netstandard2.0` + `net8.0`. Zero third-party dependencies — safe to r ## Install ``` -dotnet add package Axlis.Abstractions +dotnet add package Axlis.ORM.Abstractions ``` See the [Axlis repository](https://github.com/marioarce/Axlis) for full documentation. diff --git a/src/Axlis.ORM.Abstractions/Services/ISitecoreFacade.cs b/src/Axlis.ORM.Abstractions/Services/ISitecoreFacade.cs index 21a5276..a0772f4 100644 --- a/src/Axlis.ORM.Abstractions/Services/ISitecoreFacade.cs +++ b/src/Axlis.ORM.Abstractions/Services/ISitecoreFacade.cs @@ -9,7 +9,7 @@ namespace Axlis.ORM.Services; /// Clean — returns T? directly, logs internally. /// WithResult — returns with item, metadata, and diagnostics. /// -/// Implemented by SitecoreFacade in the Axlis package. +/// Implemented by SitecoreFacade in the Axlis.ORM package. /// public interface ISitecoreFacade { diff --git a/src/Axlis.ORM.Abstractions/Services/ISitecoreService.cs b/src/Axlis.ORM.Abstractions/Services/ISitecoreService.cs index 22a4f77..1c7638b 100644 --- a/src/Axlis.ORM.Abstractions/Services/ISitecoreService.cs +++ b/src/Axlis.ORM.Abstractions/Services/ISitecoreService.cs @@ -3,7 +3,7 @@ namespace Axlis.ORM.Services; /// /// Low-level Sitecore data-access contract. Returns raw domain objects. /// Consumers should typically use for strongly-typed access. -/// Implemented by SitecoreService in Axlis.GraphQL. +/// Implemented by SitecoreService in Axlis.ORM.GraphQL. /// public interface ISitecoreService { diff --git a/src/Axlis.ORM.Abstractions/Site/ISiteContext.cs b/src/Axlis.ORM.Abstractions/Site/ISiteContext.cs index 8e0384f..ee58540 100644 --- a/src/Axlis.ORM.Abstractions/Site/ISiteContext.cs +++ b/src/Axlis.ORM.Abstractions/Site/ISiteContext.cs @@ -7,6 +7,6 @@ namespace Axlis.ORM.Site; /// public interface ISiteContext { - /// Gets the key that identifies the current site (e.g. "honda", "acura", "my-brand"). + /// Gets the key that identifies the current site (e.g. "my-site", "my-brand"). string SiteKey { get; } } diff --git a/src/Axlis.ORM.Abstractions/Transport/IGraphQLTransport.cs b/src/Axlis.ORM.Abstractions/Transport/IGraphQLTransport.cs index 2fb2624..4bfbc76 100644 --- a/src/Axlis.ORM.Abstractions/Transport/IGraphQLTransport.cs +++ b/src/Axlis.ORM.Abstractions/Transport/IGraphQLTransport.cs @@ -2,7 +2,7 @@ namespace Axlis.ORM.Transport; /// /// Abstraction for sending GraphQL requests to a Sitecore Headless endpoint. -/// The default implementation in Axlis.GraphQL uses raw HttpClient + System.Text.Json. +/// The default implementation in Axlis.ORM.GraphQL uses raw HttpClient + System.Text.Json. /// Replace this with your own implementation via DI if needed. /// public interface IGraphQLTransport diff --git a/src/Axlis.ORM.Core/ItemConverter.cs b/src/Axlis.ORM.Core/ItemConverter.cs index be5deaf..a8e000d 100644 --- a/src/Axlis.ORM.Core/ItemConverter.cs +++ b/src/Axlis.ORM.Core/ItemConverter.cs @@ -6,7 +6,7 @@ namespace Axlis.ORM.Core; /// Converts trees into domain objects. /// Handles circular-reference protection via a processedIds hash set /// that is threaded through recursive calls. -/// Cache integration is handled externally (by SitecoreService in Axlis.GraphQL). +/// Cache integration is handled externally (by SitecoreService in Axlis.ORM.GraphQL). /// public static class ItemConverter { diff --git a/src/Axlis.ORM.Core/Model/ExtendedItem.cs b/src/Axlis.ORM.Core/Model/ExtendedItem.cs index ca39905..460212b 100644 --- a/src/Axlis.ORM.Core/Model/ExtendedItem.cs +++ b/src/Axlis.ORM.Core/Model/ExtendedItem.cs @@ -19,7 +19,9 @@ public class ExtendedItem : BaseItem, IExtendedItem private static IItemLazyLoader? _lazyLoader; /// Initializes the ambient lazy-loader used by and . - /// Call this once at application startup, typically inside AddAxlis(). + /// Call this once at application startup — the Axlis.ORM package's + /// UseAxlis(IServiceProvider) extension method calls this for you; you should not + /// need to call it directly unless you are wiring a custom host without that extension. public static void Initialize(IItemLazyLoader loader) => _lazyLoader = loader; /// Clears the ambient lazy-loader (for testing). diff --git a/src/Axlis.ORM.Core/Model/IItemLazyLoader.cs b/src/Axlis.ORM.Core/Model/IItemLazyLoader.cs index fe2248d..30ed7a1 100644 --- a/src/Axlis.ORM.Core/Model/IItemLazyLoader.cs +++ b/src/Axlis.ORM.Core/Model/IItemLazyLoader.cs @@ -5,8 +5,9 @@ namespace Axlis.ORM.Core; /// and to lazy-load missing parent/children data. /// Replaces the ambient static SitecoreFactory from the original implementation, /// making the lazy-fetch seam testable via DI. -/// Register an implementation in DI (provided by the Axlis package) and -/// call on application startup. +/// Register an implementation in DI (provided by the Axlis.ORM package) and +/// call on application startup — in practice via +/// the UseAxlis(IServiceProvider) extension method, which wires this for you. /// public interface IItemLazyLoader { diff --git a/src/Axlis.ORM.Core/README.md b/src/Axlis.ORM.Core/README.md index 0f7c360..62009e2 100644 --- a/src/Axlis.ORM.Core/README.md +++ b/src/Axlis.ORM.Core/README.md @@ -1,13 +1,13 @@ -# Axlis.Core +# Axlis.ORM.Core ![Axlis Banner](https://raw.githubusercontent.com/marioarce/Axlis/refs/heads/main/assets/banner.png) -Domain model and ORM core for the [Axlis](https://github.com/marioarce/Axlis) Sitecore Headless GraphQL ORM. Targets `net8.0`. +Domain model and ORM core for [Axlis.ORM](https://github.com/marioarce/Axlis), the Sitecore Headless GraphQL ORM. Targets `net8.0`. ## Install ``` -dotnet add package Axlis.Core +dotnet add package Axlis.ORM.Core ``` ## What's included @@ -51,4 +51,4 @@ public class ArticlePage : ExtendedItem } ``` -See the [Templates Guide](https://github.com/marioarce/Axlis/blob/main/docs/Templates.md) and the [Axlis repository](https://github.com/marioarce/Axlis) for full documentation. +See the [Templates Guide](https://github.com/marioarce/Axlis/blob/main/docs/orm/Templates.md) and the [Axlis repository](https://github.com/marioarce/Axlis) for full documentation. diff --git a/src/Axlis.ORM.GraphQL/README.md b/src/Axlis.ORM.GraphQL/README.md index d5b6fd3..7285e65 100644 --- a/src/Axlis.ORM.GraphQL/README.md +++ b/src/Axlis.ORM.GraphQL/README.md @@ -1,15 +1,15 @@ -# Axlis.GraphQL +# Axlis.ORM.GraphQL ![Axlis Banner](https://raw.githubusercontent.com/marioarce/Axlis/refs/heads/main/assets/banner.png) -Default Sitecore Headless GraphQL transport for the [Axlis](https://github.com/marioarce/Axlis) ORM. Targets `net8.0`. +Default Sitecore Headless GraphQL transport for [Axlis.ORM](https://github.com/marioarce/Axlis). Targets `net8.0`. Uses raw `HttpClient` + `System.Text.Json` — no third-party GraphQL library required. ## Install ``` -dotnet add package Axlis.GraphQL +dotnet add package Axlis.ORM.GraphQL ``` ## What's included @@ -33,12 +33,12 @@ dotnet add package Axlis.GraphQL } ``` -## Register via `AddAxlisGraphQL` +## Register via `AddAxlisORMGraphQL` ```csharp builder.Services - .AddAxlis() - .AddAxlisGraphQL(o => + .AddAxlisORM() + .AddAxlisORMGraphQL(o => { o.Endpoint = builder.Configuration["AxlisGraphQL:Endpoint"]!; o.ApiKey = builder.Configuration["AxlisGraphQL:ApiKey"]!; diff --git a/src/Axlis.ORM.GraphQL/SitecoreService.cs b/src/Axlis.ORM.GraphQL/SitecoreService.cs index 37668fa..9d57c69 100644 --- a/src/Axlis.ORM.GraphQL/SitecoreService.cs +++ b/src/Axlis.ORM.GraphQL/SitecoreService.cs @@ -15,7 +15,7 @@ namespace Axlis.ORM.GraphQL; /// /// Default implementation that fetches Sitecore items via the /// Axlis GraphQL transport layer. Performs no caching; caching is handled by -/// SitecoreItemCacheManager in the Axlis facade package. +/// SitecoreItemCacheManager in the Axlis.ORM facade package. /// public sealed class SitecoreService : ISitecoreService { diff --git a/src/Axlis.ORM.GraphQL/Transport/AxlisGraphQLOptions.cs b/src/Axlis.ORM.GraphQL/Transport/AxlisGraphQLOptions.cs index 87e1d7c..8e9b084 100644 --- a/src/Axlis.ORM.GraphQL/Transport/AxlisGraphQLOptions.cs +++ b/src/Axlis.ORM.GraphQL/Transport/AxlisGraphQLOptions.cs @@ -2,7 +2,7 @@ namespace Axlis.ORM.GraphQL.Transport; /// /// Configuration options for the Axlis GraphQL HTTP transport. -/// Bind to the "AxlisGraphQL" configuration section via AddAxlisGraphQL(). +/// Bind to the "AxlisGraphQL" configuration section via AddAxlisORMGraphQL(). /// public sealed class AxlisGraphQLOptions { diff --git a/src/Axlis.ORM/AxlisOptions.cs b/src/Axlis.ORM/AxlisOptions.cs index b9a47a4..01cf59f 100644 --- a/src/Axlis.ORM/AxlisOptions.cs +++ b/src/Axlis.ORM/AxlisOptions.cs @@ -1,8 +1,8 @@ namespace Axlis.ORM; /// -/// Top-level configuration options for the Axlis package. -/// Bind to the "Axlis" configuration section via AddAxlis(). +/// Top-level configuration options for the Axlis.ORM package. +/// Bind to the "Axlis" configuration section via AddAxlisORM(). /// public sealed class AxlisOptions { diff --git a/src/Axlis.ORM/CLAUDE.md b/src/Axlis.ORM/CLAUDE.md index 1b3e0fd..40f520c 100644 --- a/src/Axlis.ORM/CLAUDE.md +++ b/src/Axlis.ORM/CLAUDE.md @@ -22,7 +22,7 @@ Scoped guidance for this project. Inherits everything in the repo-root [`CLAUDE. ## Naming Note (Known Doc Drift) -The DI extension methods are `AddAxlisORM()` / `AddAxlisORMGraphQL()` / `UseAxlis()` in current code (post ecosystem-rename). Some docs (`docs/orm/Caching.md`) still reference the pre-rename `AddAxlis()` / `AddAxlisGraphQL()`. When writing new docs or examples, use the current names; when you notice stale references in existing docs, fix them as part of the change rather than propagating them. +The DI extension methods are `AddAxlisORM()` / `AddAxlisORMGraphQL()` / `UseAxlis()` in current code (post ecosystem-rename). All docs and XML doc comments were swept and corrected as of the 2026-07-22 documentation audit — `docs/orm/Caching.md` and several source XML doc comments previously referenced the pre-rename `AddAxlis()` / `AddAxlisGraphQL()`. When writing new docs or examples, use the current names; when you notice stale references creep back in, fix them as part of the change rather than propagating them. ## See Also diff --git a/src/Axlis.ORM/Caching/CacheManager.md b/src/Axlis.ORM/Caching/CacheManager.md index 83f1fa1..17e156f 100644 --- a/src/Axlis.ORM/Caching/CacheManager.md +++ b/src/Axlis.ORM/Caching/CacheManager.md @@ -3,7 +3,7 @@ **File:** `src/Axlis.ORM/Caching/SitecoreItemCacheManager.cs` **Consumed by:** `SitecoreFacade` (every cacheable fetch method), `SitecoreItemLazyLoader` (`src/Axlis.ORM/LazyLoader/SitecoreItemLazyLoader.cs`) **Wraps:** `ICacheService` from `PowerCSharp.Feature.Cache.Abstractions` (external dependency, treated as a black box — see this project's `CLAUDE.md`) -**Status:** Fragile zone — referenced from root [`CLAUDE.md`](../../CLAUDE.md) §4 and this project's `CLAUDE.md`. +**Status:** Fragile zone — referenced from root [`CLAUDE.md`](../../../CLAUDE.md) §4 and this project's `CLAUDE.md`. ## Purpose @@ -24,7 +24,7 @@ Stampede-safe(*) in-memory cache for `IItem` results, sitting between `SitecoreF 1. Any change to the dual-indexing write logic requires updated tests in `tests/Axlis.ORM.Tests/SitecoreItemCacheManagerTests.cs` covering: write-then-read-by-ID, write-then-read-by-path, and the null-miss non-caching behavior. 2. Do not add caching of `null`/not-found results without an explicit, separate opt-in mechanism and a call-out in `CHANGELOG.md` — this is a behavioral change every consumer depends on implicitly. 3. If you touch `SitecoreItemLazyLoader` (which routes lazy `Axes` fetches through this same cache manager), re-read [`../../Axlis.ORM.Core/AxesLazyLoading.md`](../../Axlis.ORM.Core/AxesLazyLoading.md) — the sync-over-async wrapper there depends on this class's async methods completing promptly (a cache implementation that blocks or is slow directly affects that hazard). -4. Keep `docs/orm/Caching.md` in sync if you change the public shape of `GetOrCreateAsync`/`InvalidateAsync` — and fix the stale `AddAxlis()`/`AddAxlisGraphQL()` naming in that doc if you're already editing it (see this project's `CLAUDE.md` "Naming Note"). +4. Keep `docs/orm/Caching.md` in sync if you change the public shape of `GetOrCreateAsync`/`InvalidateAsync` — this doc previously drifted to stale `AddAxlis()`/`AddAxlisGraphQL()` naming after a rename (since fixed); don't let it happen again (see this project's `CLAUDE.md` "Naming Note"). ## Verification Checklist for Any Change Here diff --git a/src/Axlis.ORM/README.md b/src/Axlis.ORM/README.md index f800e49..2169cbc 100644 --- a/src/Axlis.ORM/README.md +++ b/src/Axlis.ORM/README.md @@ -34,14 +34,24 @@ Or à la carte — reference only what you need. ```csharp // Program.cs -builder.Services.AddAxlisORM(builder.Configuration); +// AddAxlisORM/AddAxlisORMGraphQL take an Action delegate — bind from +// IConfiguration explicitly, or set values inline. +builder.Services + .AddAxlisORM(o => builder.Configuration.GetSection("Axlis").Bind(o)) + .AddAxlisORMGraphQL(o => builder.Configuration.GetSection("AxlisGraphQL").Bind(o)); + +var app = builder.Build(); +app.Services.UseAxlis(); // wires the ambient lazy-loader for Axes traversal // appsettings.json { "Axlis": { - "GraphQL": { - "BaseAddress": "https://your-sitecore-instance/sitecore/api/graph/edge" - } + "CacheTtl": "01:00:00", + "EnableDiagnostics": true + }, + "AxlisGraphQL": { + "Endpoint": "https://your-sitecore-instance/sitecore/api/graph/edge", + "ApiKey": "your-sc_apikey-here" } } ``` @@ -67,7 +77,7 @@ var children = item?.Axes.Children; var parent = item?.Axes.Parent; var siblings = item?.Axes.Siblings; -var pages = item?.Axes.GetChildren(i => i.InnerItem?.Template?.Equals(MyPage.TemplateId) ?? false); +var pages = item?.Axes.GetChildren(i => i.InnerItem?.Template?.Id == MyPage.TemplateId); // Rich result with metadata and diagnostics var result = await facade.GetItemByPathWithResultAsync("/sitecore/content/dictionary/my-key"); diff --git a/src/Axlis.ORM/WORKFLOWS.md b/src/Axlis.ORM/WORKFLOWS.md index 137236a..9f3b058 100644 --- a/src/Axlis.ORM/WORKFLOWS.md +++ b/src/Axlis.ORM/WORKFLOWS.md @@ -20,7 +20,7 @@ This is a high-caution SOP — every consumer's `Program.cs` depends on the curr 3. If adding a new required service, provide it a sensible default registration so `AddAxlisORM()` remains a one-call "it just works" experience — don't force new mandatory configuration on existing consumers. 4. `UseAxlis()` must remain idempotent-safe to call once and must continue to be the single wiring point for `ExtendedItem`'s static loader — do not introduce a second code path that also calls `ExtendedItem.Initialize`. 5. Add/update a test in `tests/Axlis.ORM.Tests/` (or a new DI-focused test file) that builds a minimal `ServiceCollection`, calls `AddAxlisORM()` + `AddAxlisORMGraphQL()`, builds the provider, and resolves `ISitecoreFacade` successfully — this is the cheapest regression guard against a broken registration graph. -6. Update `docs/orm/GettingStarted.md` and `docs/orm/Caching.md` if the public registration API surface changes at all — and fix any stale `AddAxlis()`/`AddAxlisGraphQL()` references you encounter while you're in there (see this project's `CLAUDE.md` "Naming Note"). +6. Update `docs/orm/GettingStarted.md` and `docs/orm/Caching.md` if the public registration API surface changes at all — this repo has previously shipped with stale `AddAxlis()`/`AddAxlisGraphQL()` references in those exact docs after a rename, so treat any registration-API change as a doc-sync trigger, not an afterthought (see this project's `CLAUDE.md` "Naming Note"). ## SOP F3 — Touching `SitecoreItemCacheManager` or `SitecoreItemLazyLoader`