-
Notifications
You must be signed in to change notification settings - Fork 0
Samples
The repository ships two consumer-facing samples: a complete application (SupportTickets) and an external capability module (Inbox). Together they demonstrate the whole consumption surface this wiki documents.
samples/Groundwork.SupportTickets
demonstrates a small support-ticket domain as an ASP.NET Core API with a React/Vite client. The
same manifest runs against SQLite, PostgreSQL, SQL Server, or MongoDB.
The sample:
- declares
supportTicketandsupportTicketCommentstorage units inSupportTicketManifest.cs— logical indexes with declared 128-unit key lengths, bounded query declarations, and explicit physical-entity-table definitions with bounded projected columns; - opens the selected provider through its
OpenPhysicalAsyncfactory with safe startup auto-apply, resolving each unit's executable route from the store'sRoutes(seeSupportTicketSampleHost.cs); - creates and loads tickets and comments through
IDocumentStore, and executes every read as a declaredDocumentQuerythroughIBoundedDocumentStore— one bounded-query identity per repository operation, nothing queries outside them; - updates tickets with optimistic concurrency, including version-gated comment writes;
- wires the external Inbox module (below) alongside the ticket store and reports its capability fit;
- serves the built React workspace from
wwwroot.
Groundwork__Provider=Sqlite \
Groundwork__ConnectionString="Data Source=support-tickets.db" \
dotnet run --project samples/Groundwork.SupportTickets/Groundwork.SupportTickets.csprojthen browse to the reported address (http://localhost:5000 by default). The sample also accepts
PostgreSql, SqlServer, and MongoDb as Groundwork__Provider values when the matching
connection string is supplied; for MongoDB, set Groundwork__DatabaseName to override the default
groundwork_support_tickets database name.
For client development, run the API and the Vite dev server separately:
GROUNDWORK_SUPPORT_TICKETS_API_URL=http://localhost:5000 \
npm --prefix samples/Groundwork.SupportTickets/Client run dev- A realistic manifest with explicit
PhysicalStoragePolicy.Explicitentity tables that match what the default policy would synthesize — useful when you need to see both styles (Declaring-Storage). - A configuration-driven provider switch over all four factories, including SQLite's connection-taking overload for in-memory databases and MongoDB's open handle (Opening-Stores).
- The 128-unit keyword key-length sizing that keeps SQL Server's widest index key inside its 1700-byte budget (Provider-SQL-Server).
samples/Groundwork.Modules.Inbox
shows Groundwork's open/closed capability system from the consumer side: it contributes a
brand-new persistence semantic — an idempotent inbox / exactly-once consumer — entirely from
outside Groundwork.Core.
| Layer | Project | Contents |
|---|---|---|
| Capability + contract | Groundwork.Modules.Inbox |
InboxCapabilities.IdempotentConsumer (community.inbox.idempotent-consumer), InboxModule : IGroundworkModule, IInboxStore, schema DDL. References only Groundwork.Core. |
| Provider impl | Groundwork.Modules.Inbox.Sqlite |
SqliteInboxStore on the reusable Groundwork.Provider.Relational toolkit; advertises the capability. |
| Proof | Groundwork.Modules.Inbox.Tests |
Dedup behaviour + capability-fit derivation. |
The contract:
public interface IInboxStore
{
Task<InboxAdmission> TryAdmitAsync(string consumer, string messageKey, CancellationToken ct = default);
Task MarkProcessedAsync(string consumer, string messageKey, CancellationToken ct = default);
Task<bool> IsProcessedAsync(string consumer, string messageKey, CancellationToken ct = default);
}
// InboxAdmission = Admitted | DuplicateTryAdmitAsync returns Admitted the first time a (consumer, messageKey) pair is seen and
Duplicate on every redelivery — implemented with INSERT ... ON CONFLICT DO NOTHING.
Wiring the module:
var (registry, evidencePolicy) = new GroundworkModuleCatalog()
.Add(new InboxModule())
.Build();
var validator = new ProviderCapabilityValidator(registry);
ProviderFit fit = validator.Evaluate(manifest, providerReport, evidencePolicy);A provider advertises support with
report.WithCapabilities(InboxCapabilities.IdempotentConsumer); a manifest unit declares the need
with StorageIntent.Operational(rationale, descriptor, InboxCapabilities.IdempotentConsumer).
A core-only validator (default registry) rejects the unknown capability with GW-CAP-014 — the
registry, not a hardcoded enum, is the source of truth.
This is the intended pattern whenever your application needs a persistence semantic Groundwork's document contract cannot honestly serve: contribute the capability and contract in your own module, implement it per provider on the reusable toolkit, and let the standard validator derive fit. See the module README and Providers.
Both samples have test projects
(samples/Groundwork.SupportTickets.Tests,
samples/Groundwork.Modules.Inbox.Tests)
that double as executable documentation for the patterns above.
This wiki is generated from
docs/wiki/ in the main
repository and republished on every push to main — do not edit pages here; changes made
directly in the wiki will be overwritten. To propose a change, open a pull request against
docs/wiki/.
Using Groundwork
- Getting-Started
- Declaring-Storage
- Opening-Stores
- Querying
- Transactions-and-Unit-of-Work
- Storage-Scopes
- Schema-Evolution
- Identity-Generators
Providers
Beyond documents
Reference