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.
Summary
Functions
Creates realistic document seed data for a single site.
Stress seed: large volumes of document data for a site.
Functions
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: 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.