NestJS-YALC
Table of Contents:
  1. FEAT β€” Task app CrudGen-first refactor map
    1. Purpose
    2. Key observation
    3. Resource-by-resource map
    4. 1) Projects
      1. Desired public meaning
      2. Omni mapping
      3. CrudGen-first target
      4. Custom logic should live in
      5. Avoid
    5. 2) Tasks
      1. Desired public meaning
      2. Omni mapping
      3. CrudGen-first target
      4. Custom logic should live in
      5. Likely custom query need
      6. Avoid
    6. 3) Events
      1. Desired public meaning
      2. Omni mapping
      3. CrudGen-first target
      4. Custom logic should live in
      5. Avoid
    7. 4) External refs
      1. Desired public meaning
      2. Omni mapping
      3. CrudGen-first target
      4. Custom logic should live in
      5. Avoid
    8. 5) Sync states
      1. Desired public meaning
      2. Omni mapping
      3. CrudGen-first target
      4. Custom logic should live in
      5. Open design question
    9. Cross-cutting refactor rules
    10. Rule 1 β€” Keep existing task-system DTO intent where it is already good
    11. Rule 2 β€” Move custom behavior downward
    12. Rule 3 β€” Separate standard CRUD from semantic operations
    13. Rule 4 β€” Preserve Omni-only persistence
    14. Likely implementation sequence for task-app
      1. Phase 1 β€” DTO/contract alignment
      2. Phase 2 β€” Service/repository alignment
      3. Phase 3 β€” Restore generated surfaces
      4. Phase 4 β€” Custom semantic operations only where needed
      5. Phase 5 β€” Tests and docs
    15. Current status

FEAT β€” Task app CrudGen-first refactor map

Status: draft / in progress
Related plan: docs/todo/FEAT-crudgen-first-omnikernel-task-app-plan.md

Purpose

This document breaks the task-app refactor down resource by resource so the migration back to a CrudGen-first architecture stays reviewable.

The idea is to avoid a vague β€œrewrite task-app with CrudGen” effort and instead define, for each resource:

  • what the current legacy/task-system surface already models well
  • what can stay generated by CrudGen
  • what should move into Omni-backed service/repository overrides
  • what should remain custom only if strictly necessary

Key observation

The old task-system-module is actually very useful as a surface model reference.

Its DTOs already express most of the app-facing contract we want to preserve:

  • TaskProjectType
  • TaskItemType
  • TaskEventType
  • TaskExternalRefType
  • TaskSyncStateType

And several of those DTOs already use CrudGen relation metadata correctly, for example:

  • TaskProjectType.tasks
  • TaskProjectType.events
  • TaskItemType.project
  • TaskEventType.project

This means the future task-app should probably reuse the DTO modeling patterns much more aggressively, instead of rebuilding the whole surface manually.


Resource-by-resource map

1) Projects

Desired public meaning

Project/container resource.

Omni mapping

  • storage target: OmniCollectionEntity
  • semantic kind: collection/container
  • membership relation to tasks/events: contains

CrudGen-first target

Prefer:

  • generated GraphQL CRUD via resolverFactory
  • generated REST CRUD via crudRestControllerFactory
  • DTO keeps relation metadata for:
    • tasks
    • events

Custom logic should live in

  • service override:
    • normalize/create/update as collection semantics
    • enforce kind / collectionKind
    • event-manager logging/hooks
  • repository override only if relation/grid behavior cannot be expressed with existing repo path

Avoid

  • handwritten CRUD controller for basic project CRUD
  • handwritten get/update/delete GraphQL surface

2) Tasks

Desired public meaning

Task resource inside a project/container.

Omni mapping

  • storage target: OmniRecordEntity
  • semantic kind: task
  • project membership: contains
  • optional semantic cross-links:
    • references
    • related_to

CrudGen-first target

Prefer:

  • generated GraphQL CRUD/grid
  • generated REST CRUD
  • DTO keeps relation metadata for:
    • project
    • potentially future derived/semantic fields

Custom logic should live in

  • service override:
    • map task DTO/input -> Omni record payload
    • synchronize contains
    • synchronize references / related_to
    • event-manager logs/errors/events
    • optional API strategy calls for downstream sync/orchestration
  • repository override only when generic grid/filter/join support needs semantic adaptation

Likely custom query need

Potentially a semantic query for relation-heavy views if generic grid is not expressive enough yet.

Avoid

  • handwritten CRUD mutation/query surface unless relation semantics truly require it

3) Events

Desired public meaning

Calendar-like event resource associated to a project.

Omni mapping

  • storage target: OmniRecordEntity
  • semantic kind: event
  • project membership: contains

CrudGen-first target

Prefer:

  • generated GraphQL CRUD/grid
  • generated REST CRUD
  • DTO keeps relation metadata for project

Custom logic should live in

  • service override:
    • event payload mapping
    • contains membership sync
    • event-manager hooks

Avoid

  • manual CRUD surface for standard event lifecycle

4) External refs

Desired public meaning

External system identity binding.

Omni mapping

  • storage target: OmniExternalRefEntity
  • semantic uniqueness: (provider, externalId, account, container)
  • internal target type maps to collection/document/record as needed

CrudGen-first target

Prefer:

  • generated GraphQL CRUD/grid
  • generated REST CRUD

Custom logic should live in

  • service override:
    • semantic upsert/deduping
    • internal target validation
    • provider/account/container identity handling
    • event-manager errors for invalid refs

Avoid

  • hand-rolled endpoints just to support upsert semantics; start from generated CRUD and extend service behavior first

5) Sync states

Desired public meaning

Synchronization state resource tied to an external ref.

Omni mapping

  • storage target: OmniRecordEntity
  • semantic kind: sync-state
  • relation to ref currently modeled by externalRefId in payload/DTO surface

CrudGen-first target

Prefer:

  • generated GraphQL CRUD/grid
  • generated REST CRUD

Custom logic should live in

  • service override:
    • payload mapping
    • external-ref existence validation
    • event-manager logging/errors
    • optional API strategy orchestration for sync lifecycle later

Open design question

Decide whether externalRefId should stay as a direct scalar surface only, or whether OmniKernel should eventually expose a stronger relation pattern for it.


Cross-cutting refactor rules

Rule 1 β€” Keep existing task-system DTO intent where it is already good

The old DTO layer already captures important relation semantics. Reuse/adapt that before inventing a fresh manual surface.

Rule 2 β€” Move custom behavior downward

When a task-app resource needs special behavior, prefer this order:

  1. DTO metadata
  2. service override
  3. repository override
  4. custom query/mutation attached to generated surface
  5. only then a full handwritten resolver/controller method

Rule 3 β€” Separate standard CRUD from semantic operations

Examples of standard CRUD:

  • create/update/delete/get/list/grid on projects/tasks/events/external-refs/sync-states

Examples of semantic operations that may justify custom surfaces later:

  • β€œlink this task to that task as references”
  • β€œmove this task between collections with semantic event emission”
  • β€œsync this resource with provider X now”

Do not let semantic operations force the entire resource back into a handwritten CRUD stack.

Rule 4 β€” Preserve Omni-only persistence

Restoring CrudGen-first architecture must not mean restoring legacy task-system storage.

Generated surfaces should sit on top of Omni-backed services/repositories.


Likely implementation sequence for task-app

Phase 1 β€” DTO/contract alignment

  • decide which current task-system DTOs can be reused directly
  • decide which must become Omni-aware DTOs with copyFrom / metadata reuse
  • normalize relation metadata so CrudGen can do more automatically

Phase 2 β€” Service/repository alignment

  • make Omni-backed service overrides the primary semantic layer
  • decide which queries need repository specialization
  • remove behavior from handwritten controllers/resolvers that belongs in services

Phase 3 β€” Restore generated surfaces

  • projects generated via CrudGen
  • tasks generated via CrudGen
  • events generated via CrudGen
  • external refs generated via CrudGen
  • sync states generated via CrudGen

Current note:

  • tasks now uses dedicated CrudGen DTOs plus generated GraphQL/REST surfaces, while the Omni-backed service override keeps contains, references, and related_to semantics below the API layer.
  • The generated REST path now relies on a framework-level flat-query equality mapping, so collection filters such as GET /tasks?projectId=... can stay generated-first instead of forcing a handwritten list controller.
  • projects and events now use dedicated CrudGen DTOs plus generated GraphQL/REST surfaces, while Omni-specific collection/record semantics remain in the service overrides.
  • The mapper/service split is now explicit:
    • base CRUD DTOs stay scalar-first and CrudGen-compatible
    • relation fields such as project.tasks, project.events, and event.project are resolved in the GraphQL relation layer instead of being eagerly materialized in the mapper
  • external-refs now uses a generated GraphQL surface plus crudRestControllerFactory, while the Omni-specific dedupe/validation logic stays in the service override.
  • The slice also flushed out two framework composition issues that are now explicit:
    • app-local GraphQL enum names must not collide with CrudGen enum names (SortDirection, JoinTypes)
    • example-local dataloader wiring is safer with an explicit provider override than with an implicit event-emitter token that can vary across duplicated package installs

Phase 4 β€” Custom semantic operations only where needed

  • identify remaining true custom operations
  • attach them narrowly via custom queries/mutations or dedicated semantic endpoints

Phase 5 β€” Tests and docs

  • move specs into conventional separated folders
  • add tests around generated + overridden behavior
  • update task-app docs to explain composition clearly

Current status

  • initial per-resource map drafted
  • align map with exact current task-app code paths
  • turn each resource section into concrete implementation tasks