Skip to main content
Wildo.ai Coming soon

Declaring a resource

Decide what remains when a parent is removed

Declare how owned records are deleted or retained when their parent is removed.

Partially available today — the limit is described on this page.

A project and its owned tasks grouped under a declared delete-together policy.

Decide what remains when a parent is removed

Removing a project raises another question: what should happen to the work it owns? Some child records should go with it; others need to remain with a deliberate treatment of personal information.

Wildo lets you state that behavior on the ownership relationship. The decision stays beside the connection it governs instead of being scattered across unrelated delete handlers.

You choose the records affected and whether deletion runs immediately or is deferred. Retaining and treating personal fields is a distinct lifecycle choice.

Example — Remove a recurring task and its occurrences

A recurring task owns the occurrences generated from it. Its relationship can declare that removing the parent also removes those occurrences, without making an unrelated person or referenced task part of that deletion.

For engineers

Declare the child action on its relationship

childOperations.lifecycle.onParentDelete belongs to a composition relationship. It enables the lifecycle, selects timing and can bound how deeply the cascade proceeds. The relationship still identifies the child resource and the field used to find its rows.

Wonder Todos declares this behavior for recurring occurrences in tasks-manager.relationships.ts. Standalone source comments are omitted:

createResourcesRelationship(
  TasksManager_ResourceType.TODOS, TasksManager_ResourceType.TODOS_RECURRING_OCCURRENCES,
  ResourceRelationshipCardinality.ONE, ResourceRelationshipCardinality.MANY,
  {
    nature: RelationshipNature.COMPOSITION,
    foreignKeyField: 'todoId',
    discriminator: { discriminatorField: todosRecurringTypeField, values: [Todos_RecurrenceType.RECURRING] },
    childOperations: { lifecycle: { onParentDelete: { enabled: true, mode: ChildLifecycleMode.IMMEDIATE, maxDepth: 1 } } },
    contextPolicy: {
      operationOverrides: {
        [CoreResourceOperation.LIST]: { enabled: false },
        [CoreResourceOperation.SEARCH]: { enabled: false },
      }
    }
  }
),

The discriminator restricts this edge to recurring tasks. IMMEDIATE runs the child deletion with the parent operation, and maxDepth: 1 handles direct occurrences only. It does not visit children owned by those occurrences. The context overrides below it concern loading related data for list and search; they are separate from the deletion rule.

Choose the outcome before its timing

The strategy is DELETE or IMPERSONALIZE_AND_RETAIN. Deletion removes the owned rows. The retain strategy applies the configured personal-field treatment and keeps the records. With no strategy selected, deletion is the default.

Immediate deletion uses the parent’s execution and transaction context. Lazy deletion enqueues a teardown job; the worker resolves the relationship again and runs the deletion path. Queue support must be configured for that timing. Retain-and-treat currently uses immediate mode, so select it explicitly when the children must survive.

Define the wider lifecycle deliberately

A cascade follows the configured composition graph and depth policy. It does not make every reference an owned child. Use the relationship’s static settings or supported conditional policy to express the intended treatment, and check that the child resource offers the operations needed by that lifecycle.

Choose the personal-field treatments on the retained resource and document their business purpose. Retaining a row, deleting a row and treating its personal values are distinct outcomes; the application’s retention decision determines which one to configure.

Read the depth as a concrete boundary

Consider an illustrative project → work item → work log composition chain. Assume immediate deletion and enabled lifecycle declarations on both edges. Removing the project has these outcomes:

Project-to-item policyWork itemWork log
DELETE, maxDepth: 1Deleted.Not visited by this cascade.
DELETE, maxDepth: 2; item-to-log policy is DELETEDeleted after its configured descendants are handled.Deleted.
DELETE, maxDepth: 2; item-to-log policy is immediate IMPERSONALIZE_AND_RETAINDeleted.Treated and retained under its own resource policy.
Immediate IMPERSONALIZE_AND_RETAINTreated and retained.Not visited: its parent still exists.

Depth is a maximum, not permission to traverse every edge. Each reached composition must enable its lifecycle and supplies its own strategy and timing. A depth of one does not establish that leaving grandchildren untouched is appropriate for your model: choose the budget and descendant policies together.

Connect retained children to field treatment

The relationship chooses which children to retain; the child’s resource configuration chooses retention mode, and its schema chooses the field treatment. These three illustrative excerpts belong to the same retained work-item model; they are not changes to Wonder Todos:

// On the project → work-item composition relationship:
childOperations: {
  lifecycle: {
    onParentDelete: {
      enabled: true,
      strategy: ChildLifecycleStrategy.IMPERSONALIZE_AND_RETAIN,
      mode: ChildLifecycleMode.IMMEDIATE,
    },
  },
},
// In the child schema:
contactName: z.string().impersonalizeWith(RedactionType.MASK, { maskValue: 'Removed' }),
contactEmail: z.string().nullish().impersonalizeWith(RedactionType.REMOVE),
reference: z.string(),

// In that child's resource configuration:
retentionPolicy: {
  mode: ErasureRetentionMode.RETAIN_AND_IMPERSONALIZE,
},

The retained row keeps its reference, replaces contactName with Removed, and clears contactEmail. The engine marks it retained so ordinary reads and edits exclude it. Mask values must satisfy the field schema; REMOVE needs a clearable field. The factory checks those conditions and rejects an ineffective or contradictory retention declaration.

This handles the direct child records, not an entire personal-data journey. Use subject erasure and retention when the request concerns a person’s information across dependent resources. Retention is not a claim of anonymity or an automatic expiry schedule.

Building a B2B product or an internal tool?

Wildo is not self-service yet. Tell us what you have in mind and we will say plainly whether it fits, and what happens next.