[ArtStudio P1] Backend foundation — ArtAsset domain, stage workflow docs, CQRS slice + endpoints #347

Closed
opened 2026-07-04 05:10:18 +00:00 by spikerj · 1 comment
Owner

Sub-ticket of epic #346. No dependencies — this is the starting point.

What: the CQRS domain foundation for multi-stage art assets, generalizing the existing single-stage ThreeDModel vertical (SpikerSoft.Data/Mongos/ThreeDModel.cs, SpikerSoft.Business/Domain/ThreeDModel/) into a stage-graph model matching art_pipe's ASSET_TYPE_STAGES (concept → modeling → texturing → rigging → animation → export → enrichment).

Scope:

  • Mongo docs: ArtAsset (owner, asset type, prompt/source refs, current stage, status, GridFS artifact refs per stage) + ArtAssetStage workflow doc per stage run (mirror BlogMediaWorkflowState: state machine, timestamps, error, retry count, model used, timings) + indexes
  • Decide slice placement: new SpikerSoft.Business.ArtStudio project (model: SpikerSoft.Business.CodeExecution) vs folder in SpikerSoft.Business; absorb/deprecate the existing Domain/ThreeDModel slice either way
  • Commands: SubmitArtAssetCommand (creates asset, stages plan, publishes first stage job — IRemoteCommand so RemoteDispatchBehavior routes it), CancelArtAssetCommand, RestartFromStageCommand (mirrors art_pipe's restart_from/<stage>), DeleteArtAssetCommand
  • Queries: GetArtAssetById, GetArtAssetStages, ListMyArtAssets (paged, student-scoped), DownloadArtifact (GridFS stream: GLB / textures / previews)
  • ArtStudioController in SpikerSoft.Api/Domain/ArtStudio/ — thin MediatR passthrough, [Authorize], ownership enforced in handlers (student sees only own assets; staff sees all)
  • Event contracts in SpikerSoft.Contracts.Workers: art.asset.lifecycle exchange, art.asset.stage.requested / .completed / .failed routing keys, W3C trace-context propagated (telemetry-correlation rule)
  • GridFS artifact service (pattern: IGridFsVaultFileService) — per-stage artifacts keyed by assetId + stage
  • Unit tests for handlers (pattern: SpikerSoft.Tests.Unit/Domain/ThreeDModel)

Note: stage plan should be data-driven per asset type (prop vs character vs texture-only), mirroring art_pipe/src/artpipe/config.py::ASSET_TYPE_STAGES — characters get rigging/animation, props skip them.

Acceptance: a submitted asset appears with a planned stage list and a stage.requested message on the exchange; list/get/download/cancel/restart endpoints work against seeded data; a student cannot read or download another student's asset.

Sub-ticket of epic #346. No dependencies — this is the starting point. **What:** the CQRS domain foundation for multi-stage art assets, generalizing the existing single-stage `ThreeDModel` vertical (`SpikerSoft.Data/Mongos/ThreeDModel.cs`, `SpikerSoft.Business/Domain/ThreeDModel/`) into a stage-graph model matching art_pipe's `ASSET_TYPE_STAGES` (concept → modeling → texturing → rigging → animation → export → enrichment). **Scope:** - [ ] Mongo docs: `ArtAsset` (owner, asset type, prompt/source refs, current stage, status, GridFS artifact refs per stage) + `ArtAssetStage` workflow doc per stage run (mirror `BlogMediaWorkflowState`: state machine, timestamps, error, retry count, model used, timings) + indexes - [ ] Decide slice placement: new `SpikerSoft.Business.ArtStudio` project (model: `SpikerSoft.Business.CodeExecution`) vs folder in `SpikerSoft.Business`; absorb/deprecate the existing `Domain/ThreeDModel` slice either way - [ ] Commands: `SubmitArtAssetCommand` (creates asset, stages plan, publishes first stage job — `IRemoteCommand` so `RemoteDispatchBehavior` routes it), `CancelArtAssetCommand`, `RestartFromStageCommand` (mirrors art_pipe's `restart_from/<stage>`), `DeleteArtAssetCommand` - [ ] Queries: `GetArtAssetById`, `GetArtAssetStages`, `ListMyArtAssets` (paged, student-scoped), `DownloadArtifact` (GridFS stream: GLB / textures / previews) - [ ] `ArtStudioController` in `SpikerSoft.Api/Domain/ArtStudio/` — thin MediatR passthrough, `[Authorize]`, ownership enforced in handlers (student sees only own assets; staff sees all) - [ ] Event contracts in `SpikerSoft.Contracts.Workers`: `art.asset.lifecycle` exchange, `art.asset.stage.requested` / `.completed` / `.failed` routing keys, W3C trace-context propagated (telemetry-correlation rule) - [ ] GridFS artifact service (pattern: `IGridFsVaultFileService`) — per-stage artifacts keyed by assetId + stage - [ ] Unit tests for handlers (pattern: `SpikerSoft.Tests.Unit/Domain/ThreeDModel`) **Note:** stage plan should be data-driven per asset type (prop vs character vs texture-only), mirroring `art_pipe/src/artpipe/config.py::ASSET_TYPE_STAGES` — characters get rigging/animation, props skip them. **Acceptance:** a submitted asset appears with a planned stage list and a `stage.requested` message on the exchange; list/get/download/cancel/restart endpoints work against seeded data; a student cannot read or download another student's asset.
spikerj added the enhancement label 2026-07-04 05:10:18 +00:00
Author
Owner

Implementation up: spikersoft-backend PR #61 (branch feature/artstudio-p1-347, 39 files). Build clean, 104/104 unit tests green (86 new + 18 ThreeDModel regression), independently re-verified.

Scope notes vs the ticket:

  • Slice placement: folder in SpikerSoft.Business (extraction to a slice project deferred, as allowed)
  • Submit is a local command that dispatches the IRemoteCommand (RequestArtAssetStageCommand) — RemoteDispatchBehavior short-circuits IRemoteCommands before local handlers, so one command can't do both; JobId returned as correlation id
  • Cancel is DB-state only in P1 — #348's worker must check ArtAssetStageRun.State before/while running (noted there)

Awaiting CI + review on the PR.

Implementation up: spikersoft-backend PR [#61](https://git.spikersoft.com/spikerj/spikersoft-backend/pulls/61) (branch `feature/artstudio-p1-347`, 39 files). Build clean, 104/104 unit tests green (86 new + 18 ThreeDModel regression), independently re-verified. Scope notes vs the ticket: - Slice placement: folder in `SpikerSoft.Business` (extraction to a slice project deferred, as allowed) - Submit is a local command that dispatches the `IRemoteCommand` (`RequestArtAssetStageCommand`) — RemoteDispatchBehavior short-circuits IRemoteCommands before local handlers, so one command can't do both; JobId returned as correlation id - Cancel is DB-state only in P1 — #348's worker must check `ArtAssetStageRun.State` before/while running (noted there) Awaiting CI + review on the PR.
Sign in to join this conversation.