# SaC Authoring

`univer sac migration create <slug> <univerfile>` writes a draft `pack.ts` and editable
`migration.ts` entrypoint under the resolved hidden sidecar `migrations/` directory. Keep `pack.ts`
as metadata and execution order; author workbook-visible changes in migration entrypoint files
listed by `pack.files`.

Template selection starts from public CLI discovery. Use `univer help sac migration create` to see
whether templates are supported, and use `univer sac migration templates --json` when an agent or
script needs machine-readable template metadata. If no template's `useWhen` matches the
workbook-visible task evidence, create the ordinary draft and author the generated `migration.ts`
entrypoint by hand.

`univer sac migration create <slug> <univerfile> --template sheet-keyed-write` writes ordinary TODO
TypeScript source for keyed spreadsheet updates such as "find rows by task id and write a status
into column K". Inspect the key column and target column first, then edit the generated
`*.unit.ts` placeholders for `localUnitId`, `sheetName`, `keyColumn`, `targetColumn`, row scope, and
`valuesByKey`. The template writes target cells through A1 addresses built from explicit column
letters and one-based row numbers. It is not a DSL and does not interpret `--params` as workbook
mutation data.

Current hand-authored examples focus on spreadsheet units. Remote doc import can generate doc-owned source under `migrations/<pack>/units/<local-unit-id>/`; use `docs/sac/doc.md` and local sidecar `types/` to see which doc source structures are generated today.

The `<univerfile>` path is the local target container. Unit-specific source should use a discovered
sheet unit `localUnitId`; sheet names and A1 ranges are coordinates inside that selected unit, not
top-level unit identities.

## Migration Module Shape

`pack.ts` owns pack metadata and workbook unit execution order:

```typescript
import { defineFacadeMigrationPack } from "univer:sac/facade-migration-pack";
import type { FacadeMigrationModule } from "univer:sac/facade-migration-pack";
import revenue from "./revenue.unit";

const pack = defineFacadeMigrationPack({
  id: "20260523090000-add-revenue-model",
  description: "Add Revenue Model",
  appliesAfter: "20260522000000-materialized-baseline",
  files: ["revenue.unit.ts"]
});

export default {
  pack,
  unitMigrations: [revenue]
} satisfies FacadeMigrationModule;
```

The `files` list is authoritative. Every unit migration source file in the pack directory must be listed, and files execute in that order.
Do not put workbook mutation implementation directly in `pack.ts`; put it in listed migration
entrypoint files such as `migration.ts` or `*.unit.ts`.
Do not list assertion files in `pack.files`; keep workbook-level verification source under
`assertions/**/*.assertions.ts`. `univer sac verify` discovers global assertion entrypoints separately
from migration apply source.

## Spreadsheet Migration Shape

Each unit migration runs inside the runtime session already bound to the target univerfile. The wrapper stays thin: `apply` receives a context object whose first field is the initialized `univerAPI`. Use Facade APIs inside `apply` to get, create, delete, or edit units and sheets when those APIs are present in the local generated types.

```typescript
import { defineUnitMigration } from "univer:sac/facade-migration-pack";
import rowsText from "./revenue.tsv";

const rows = rowsText
  .trim()
  .split("\n")
  .map((line) => line.split("\t"));

export default defineUnitMigration({
  apply({ univerAPI }) {
    const localUnitId = "replace-with-discovered-sheet-localUnitId";
    const workbook = univerAPI.getWorkbook(localUnitId);
    const sheet = workbook.getSheetByName("Revenue") ?? workbook.create("Revenue", 1000, 26);
    sheet.getRange("A1:C4").setValues(rows);
  }
});
```

Put tabular seed data in CSV or TSV files when that keeps the migration easier to review. Referenced data assets are part of the source hash.

When seeding a workbook with `univerAPI.createWorkbook({ sheetOrder, sheets })`, `sheetOrder`
entries enumerate the `sheets` map keys, and each `sheets` map key is the canonical sheet id.
Each `sheets[sheetId].id` must match the enclosing `sheetId`; use
`workbook.create("Sheet Name", rows, columns, { sheet: { id } })` when authoring through Facade APIs
is simpler.

For ranges with intentional blanks, clear the target range first and skip per-cell writes for blank
cells, or write nonblank cells individually. Do not pass `null` inside `setValues()` matrices; use
only Facade `CellValue` values such as strings, numbers, and booleans. When writing totals or other
formulas in amount columns, set the formula/value and the expected number format in the same
migration so workbook display values match the contract. Prefer A1 range strings for simple table
writes, and check local `types/*.d.ts` before using less familiar range APIs such as `offset()`.

## Document Import Source Shape

Generated doc import source uses the official document model and builder path. Body text and rich text metadata stay in `body.ts`, document metadata stays in `document.ts` / `styles.ts` / `resources.ts`, and the executable migration creates the unit through docs Facade:

```typescript
const body = univerAPI
  .newRichText({
    id: documentId,
    documentStyle: {},
    body: documentBodySource
  })
  .getData().body;

univerAPI.createDocument({
  id: documentId,
  title: "Remote Doc",
  body,
  documentStyle
});
```

Generated doc source preserves `IDocumentData` / `IDocumentBody` fidelity. User-authored follow-up changes are ordinary SaC migrations; the generator does not yet provide a doc-specific draft template or local doc checkpoint generation.

## Authoring Rules

- Keep one durable workbook intent per migration.
- Use Facade APIs against the initialized target runtime; do not invent cloud unit ids, remote unit
  ids, default workbook ids, or external artifact paths.
- Prefer one clear unit or sheet intent per migration source file.
- Use `univer:sac/facade-migration-pack` for helper types and definitions.
- Check `univer help sac facade-api` before using unfamiliar Facade APIs.
