# `MishkaDocument.Dev.Seeds`
[🔗](https://github.com/mishka-group/mishka_document/blob/v0.0.1/lib/mishka_document/dev/seeds.ex#L5)

Dev seeds for MishkaDocument.

Models a realistic documentation lifecycle for five MishkaCMS products:
Mishka CMS, Mishka Gervaz, Mishka Installer, GuardedStruct and Mishka
Chelekom. Each product has an English canonical workspace — the master —
plus one translated workspace per entry in its `:translations` list,
linked to the master via `language_group_id`. Persian, French and Arabic
editions carry translated names, descriptions and section titles; note
bodies outside Persian reuse the English copy.

Every product aims at a different completion band, so the admin card grid
renders each colour: Mishka CMS 100 (blue), Mishka Gervaz 90 (green),
Mishka Installer 65 (indigo), GuardedStruct 40 (amber) and Mishka
Chelekom 15 (red).

Each English workspace progresses through six versions (0.0.1 → 0.0.6)
using the version system — not separate workspaces; translated workspaces
get three (0.0.1 → 0.0.3). Later versions clone sections from earlier ones
(`source_section_id` + shared `section_lineage_id`) and record the clone
relationship in `WorkspaceVersionLineage`. A translated section joins the
language group of the English section holding the same position in the
version of the same number, so `read :language_variants` has data at the
section level too.

Drafts live only on the latest stable English version (0.0.6), covering a
new chapter, an edit and a rewrite; a third of them reach `applied_at`, and
two note drafts hang off a sibling section draft rather than a live section.
Twenty issues are spread over sections and notes — a quarter of them on a
translated workspace — with long-tailed comment threads, the longest on the
ones that end up resolved or closed. When a master is among the users, about
one comment in five is theirs, so a tenant admin sees comments it can read but
not edit or delete.

Views, bookmarks and follows are seeded so the reader-facing counters are not
uniformly zero; those three carry their real creation time rather than a
backdated one.

## Review status

A section, note or draft carries two independent review axes, and completion
is the share of a workspace's items where *both* are approved. One stable hash
per item decides full approval at the product's target rate, so the
100/90/65/40/15 bands land exactly; a second hash gives every other item a
divergent pair — content approved while technical is still pending is the
ordinary mid-review state — and sends a fifth of them to `:rejected` or
`:needs_revision` so the Sections filters and the draft `:draft_applied`
column have rows in every branch. `:archived` is never written here: the
destroy action force-sets both fields when a section or note is soft deleted.

## Archived vs. archived

`archived_at` (AshArchival soft delete, what the admin Archived tab filters
on) and a `status` of `:archived` are separate things. The seed only ever
reaches the first one through `Ash.destroy!/2` on the archival `:destroy`
action, which force-sets `status`/`content_review_status`/
`technical_review_status` to `:archived` by itself on the resources that have
such a field. No workspace is created carrying the `:archived` label alone —
`MishkaDocumentWeb.Templates.DocumentCard.archived?/1` matches the status
before it looks at `archived_at`, so such a row would render as archived while
still sitting in the Active tab. `MishkaDocument.WorkspaceVersion` is the one
place where the label is the whole story: it has no `archived_at` at all, and
versions 0.0.1 → 0.0.3 keep `status: :archived`.

Archiving runs last, after every create, status transition and timestamp
backdate. `prevent_archived_*_updates` raises on any update of a row that is
already archived, and no resource declares `archive_related`, so children are
archived before parents and language masters are never archived while a live
translation still points at them.

# `dev_seed`

```elixir
@spec dev_seed(String.t(), [struct()], (String.t() -&gt; any())) :: :ok | :already_seeded
```

Creates realistic document seed data for a single site.

RUN AGAIN ON A SITE THAT HAS DOCUMENTS, this adds none of the products and answers
`:already_seeded`. The five products would come back under the same names — `unique_slug_per_site`
would refuse the second set outright — and everything hanging off them, versions, sections, notes,
drafts and issues, is generated with nothing to recognise it by afterwards. So the thing that is
either there or not is the documentation, and a site that has it keeps what its authors have done
to it. The permission and robots examples are asked apart from it, each by its own slug, so a site
seeded before they existed gets them on its next run.

# `stress_seed`

Stress seed: large volumes of document data for a site.

Runs the same building blocks as `dev_seed/3` at scale — language-paired tags, long-tailed note
counts, per-record authors, commented issues and a closing archival pass — so a stress run
exercises the code paths the admin pages actually render rather than a flat grid of identical
rows.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
