Skip to content
bitzorcas
中EN

Guide

Documents Testing, Observability, and Production Gates

Existing test assets, missing contract and concurrency coverage, telemetry, reconciliation, capacity, runbooks, and GA blockers for Documents.

Last updated

Documents cannot be accepted for production merely because CRUD returns 200. Version history expands the aggregate, access data is not enforced, trees can contain invalid references, search stops at 200 candidates, and collaboration is process memory. Tests and operations must target those risks.

1. Existing test baseline

Test fileCurrent FactsFocus
DocumentTests21Creation, versions, lifecycle, tags, rules, view count
KnowledgeBaseTests13Members, counts, restore
DocumentCategoryTests10Names, parents, counts
WhiteboardTests14Data versions, archive, members
CollaborationSessionTests11Join, leave, end, restore
DocumentSearchServiceTests13Scoring, filters, paging, suggestions
JSON/QueryShape/filters/recycle bin18Persistence shape and tenant reads
Application read handlers4Trusted tenant and read-store delegation
Infrastructure architecture8Dependency and persistence rules

This is useful local semantic coverage. It does not establish HTTP authorization, ORM parity, concurrency, CAP publishing, cache correctness, database indexes, or multi-instance collaboration.

2. Risk-driven pyramid

Focused E2E
auth + HTTP + DB + CAP/Redis

Contract/integration
routes / permissions / tenant / ORM / concurrency

Broad unit
aggregate state / JSON / scoring / trees / diff

Aggregate coverage

  • every Document state crossed with every mutation;
  • SHA-256, UTF-8 byte count, and Patch progression;
  • forward-only rollback and unpublish/version-marker semantics;
  • fail-closed restoration of embedded JSON;
  • orphan and cycle behavior in trees;
  • the intentionally simplified diff limits.

Application and authorization contracts

  • method, route, authentication, rate limit, and timeout for every generated endpoint;
  • every write message derives a permission present in its catalog;
  • every read message explicitly chooses authorization behavior;
  • User.TenantId versus EffectiveTenantId;
  • member, ACL, public, creator, and administrator decision tables;
  • KB/category/parent integrity on create and authoritative references on delete.

Persistence and concurrency

  • SqlSugar/EF Core parity for fields, JSON, soft delete, and tenant behavior;
  • category unique-index races;
  • two content updates cannot lose a version;
  • two whiteboard updates with one expected version cannot both commit;
  • large VersionsJson/Canvas Data performance and migration;
  • knowledge-base/category count reconciliation.

3. Authorization contract example

Protect document detail
[Theory]
[InlineData("tenant-a", "tenant-b", false)]
[InlineData("tenant-a", "tenant-a", true)]
public async Task Detail_Must_Enforce_Tenant_And_Resource_Access(
string callerTenant,
string documentTenant,
bool sameTenant)
{
// Arrange a private document without an allowed member.
await fixture.SeedDocumentAsync(
documentTenant,
"doc-secret",
isPublic: false,
members: []);
using var client = fixture.CreateAuthenticatedClient(
callerTenant,
userId: "outsider");
// Act as either a cross-tenant caller or a same-tenant outsider.
using var response = await client.GetAsync("/api/v1/documents/doc-secret");
// Cross-tenant access hides existence; same-tenant outsider is forbidden by target ACL.
response.StatusCode.ShouldBe(
sameTenant ? HttpStatusCode.Forbidden : HttpStatusCode.NotFound);
}

This is the target security contract. The same-tenant case fails against the current implementation and should drive the policy integration red-to-green.

4. Event and cache testing

Define the producer before claiming index synchronization:

Search index/cacheIndex subscriberCAP deliveryTransaction + outboxDocument commandSearch index/cacheIndex subscriberCAP deliveryTransaction + outboxDocument commandaggregate + eventcommitevent, possibly repeatedidempotent upsert/deleteacknowledge after durable change

The current subscriber suppresses failures and Index/Delete are no-ops. A consumed message is not evidence of index consistency. Test duplicate EventId, out-of-order update/delete, unavailable index, rebuild behavior, ACL revocation, cache invalidation, and poison messages.

5. Observability

Never log full Content, Canvas Data, members, access rules, search terms, or cloud-drive download URLs. Use stable low-cardinality dimensions such as module/use_case, result category, hashed tenant, content type/status, lifecycle transition, and dependency.

Recommended metrics:

  • documents_command_duration_seconds{use_case,result};
  • documents_version_snapshot_bytes and versions per document;
  • documents_authorization_denied_total{resource,operation};
  • search candidates and truncation totals;
  • index lag;
  • invalid tree references by kind;
  • active collaboration sessions and rejected/replayed operations;
  • count-reconciliation deltas.

6. Runbook

SignalLikely causeFirst response
Version failures increaseConcurrency, large row, database lockingInspect version count/row size; do not blindly retry
Detail P95 growsincludeVersions ignored, history growthSample VersionsJson and switch to lightweight projection
Tree timeout/stack errorParent cycle or extreme depthFreeze hierarchy writes; export and run cycle detection
Search suddenly returns zeroRead failure cached as emptyPurge search keys, check DB, fix failure caching
Search misses contentCandidate set exceeds 200Compare tenant document count; move to real index
Member/tenant data leakMissing query policyDisable route at gateway, audit access, apply policy
Whiteboard conflicts spikeFull snapshots or DTO conversionCheck client version parsing and retry behavior
Collaboration loses editsRestart or node switchThe current memory service cannot recover; stop production use

7. Reconciliation

Run periodic read-only checks for stored versus actual document counts, orphan category/parent/knowledge-base identifiers, cross-KB category references, cycles, CurrentVersion absent from VersionsJson, current content/hash mismatches, invalid publish metadata, and active children beneath soft-deleted parents.

Knowledge-base count reconciliation concept
-- Confirm generated schema and soft-delete names before running in production.
-- Compare the denormalized value with an authoritative count of live documents.
SELECT kb.Id, kb.DocumentCount, COUNT(doc.Id) AS ActualCount
FROM DocsKnowledgeBase kb
LEFT JOIN DocsDocument doc
ON doc.TenantId = kb.TenantId
AND doc.KnowledgeBaseId = kb.Id
AND doc.IsDeleted = 0
WHERE kb.IsDeleted = 0
GROUP BY kb.Id, kb.DocumentCount
HAVING kb.DocumentCount <> COUNT(doc.Id);

8. Capacity and retention

Each version stores full content, so storage is approximately content size multiplied by version count, with large JSON potentially rewritten on every edit. Measure real P50/P95/P99 document size and history length before rollout.

Evolution options include keeping current content in Document while moving snapshots to a separate table/object store, hot/cold history tiers, immutable FileAssets for large binaries, and a policy-driven retention/legal-hold model. Never prune history without audit, export, and legal-retention decisions.

9. GA blockers

  • Every public read/write path uses one resource-access policy; ACL/member data is enforced.
  • Category and whiteboard permissions exist; Publish/Manage mapping is explicit.
  • documents.manage is runtime-enforced or removed from product claims.
  • Create paths validate references and cycles.
  • Counts use authoritative queries or a reconciled consistency mechanism.
  • Document and whiteboard writes have database concurrency protection.
  • includeVersions=false uses a lightweight projection.
  • Search is complete, does not cache dependency failure as empty, and is XSS-safe.
  • Binary documents use Files; no mislabeled PDF/Word response remains.
  • Exposed collaboration replaces memory/null hubs with tenant-safe durable scale-out.
  • Collaboration-session reads include tenant predicates.
  • Event production, idempotent indexing, retries, and rebuilds have contract tests.
  • Dual-ORM, HTTP, permission, tenant, backup/restore, concurrency, and capacity suites pass.

Character-level diff, Major/Minor policies, cloud-drive synchronization, conversion, offline CRDT, and recommendation analytics can follow after these blockers.

10. Verification commands

Terminal window
# Run focused domain and service semantics first.
dotnet test tests/BitzOrcas.Unit.Tests/BitzOrcas.Unit.Tests.csproj \
--filter 'FullyQualifiedName~BitzOrcas.Unit.Tests.Docs'
dotnet test tests/BitzOrcas.Application.Tests/BitzOrcas.Application.Tests.csproj \
--filter 'FullyQualifiedName~Documents'
dotnet test tests/BitzOrcas.Architecture.Tests/BitzOrcas.Architecture.Tests.csproj \
--filter 'FullyQualifiedName~DocumentsInfrastructureArchitectureTests'
# Sweep for model methods and development defaults that still lack production paths.
# These sweeps expose methods/defaults that still lack a complete product path.
rg -n 'HasAccess\(|SetStorage\(|IncrementViewCount\(' src tests -g '*.cs'
rg -n 'default-tenant|NullRealtimeCollaborationHub|NullWhiteboardCollaborationHub' \
src/Platform/Documents -g '*.cs'

Back to Documents

100%

Scroll or use controls to zoom · drag when enlarged · double-click for 100% / 200%