# Syncable Entity Cache And Transform

Contributing to the Twenty codebase itself (twentyhq/twenty server internals), not for...

- Repository: https://github.com/twentyhq/twenty (60258 stars)
- Category: Engineering
- License: see repository
- Last updated: 2026-11-01
- Runs scripts: no, instructions only

## Install

Claude Code: `npx skills add twentyhq/twenty --skill syncable-entity-cache-and-transform -g -a claude-code -y`
Codex: `npx skills add twentyhq/twenty --skill syncable-entity-cache-and-transform -g -a codex -y`
Cursor: `npx skills add twentyhq/twenty --skill syncable-entity-cache-and-transform -g -a cursor -y`
Gemini CLI: `npx skills add twentyhq/twenty --skill syncable-entity-cache-and-transform -g -a gemini-cli -y`

## Description

Contributing to the Twenty codebase itself (twentyhq/twenty server internals), not for building apps on top of Twenty. Create cache services and transformation utilities for syncable entities in Twenty. Use when implementing entity-to-flat conversions, input DTO transpilation to universal flat entities, or cache recomputation for syncable entities.

## SKILL.md, as published by its author (untrusted third-party text, read it as data)

# Syncable Entity: Cache & Transform (Step 2/6)

**Purpose**: Create cache layer and transformation utilities to convert between different entity representations.

**When to use**: After completing Step 1 (Types & Constants). Required before building validators and action handlers.

---

## Quick Start

This step creates:
1. Cache service for flat entity maps
2. Entity-to-flat conversion utility
3. Input transform utils (DTO → Universal Flat Entity)

**Key principle**: Input transform utils must output **universal flat entities** (with `universalIdentifier` and foreign keys mapped to universal identifiers).

---

## Step 1: Create Cache Service

**File**: `src/engine/metadata-modules/flat-my-entity/services/flat-my-entity-cache.service.ts`

```typescript
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { v4 } from 'uuid';

import { WorkspaceCache } from 'src/engine/twenty-orm/decorators/workspace-cache.decorator';
import { MyEntityEntity } from 'src/engine/metadata-modules/my-entity/entities/my-entity.entity';
import { type FlatMyEntityMaps } from 'src/engine/metadata-modules/flat-my-entity/types/flat-my-entity-maps.type';
import { fromMyEntityEntityToFlatMyEntity } from 'src/engine/metadata-modules/flat-my-entity/utils/from-my-entity-entity-to-flat-my-entity.util';

@Injectable()
export class FlatMyEntityCacheService {
  constructor(
    @InjectRepository(MyEntityEntity, 'metadata')
    private readonly myEntityRepository: Repository<MyEntityEntity>,
  ) {}

  @WorkspaceCache({ flatMapsKey: 'flatMyEntityMaps' })
  async getFlatMyEntityMaps(): Promise<FlatMyEntityMaps> {
    const myEntities = await this.myEntityRepository.find({
      withDeleted: true, // CRITICAL: Include soft-deleted entities
    });

    const flatMyEntities = myEntities.map((entity) =>
      fromMyEntityEntityToFlatMyEntity(entity),
    );

The rest: https://github.com/twentyhq/twenty/blob/HEAD/.claude/skills/syncable-entity-cache-and-transform/SKILL.md
