Skip to content

MILAB-6817: make project templates first-class entities - #1797

Open
AStaroverov wants to merge 2 commits into
mainfrom
feat/MILAB-6817_project-templates-first-class
Open

MILAB-6817: make project templates first-class entities#1797
AStaroverov wants to merge 2 commits into
mainfrom
feat/MILAB-6817_project-templates-first-class

Conversation

@AStaroverov

@AStaroverov AStaroverov commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

Makes project templates first-class entities in the middle layer: stored in the user's root, listed like projects, and shareable.

What a template is now

  • The immutable template-v1 document lives in an ephemeral resource's data blob; the mutable label and timestamps live in KV. Nothing that can change is inside the document, so the document is never rewritten.
  • The shelf is a Templates resource under the user's root, listed and watched the same way the project list is (template_list.ts: pruning function, field filter, computable).
  • New middle-layer surface: saveProjectAsTemplate, renameTemplate, deleteTemplate, getTemplateData, resolveTemplate, createProjectFromTemplate, applyTemplateToProject, shareTemplate.

applyTemplateToProject is split into prepareTemplateEntries + applyPreparedEntries: every entry is resolved before anything is created, so a template that cannot resolve produces no project rather than a partial one.

Sharing

  • EnvelopePayload becomes a discriminated union — { kind: "projects" } | { kind: "template" } — and EnvelopeData.schemaVersion goes 1 → 2.
  • A template share is read-only (lockInputs, no writable grant) and writes no acceptance/{login} receipt: the recipient gets the document on their own shelf and decides when to apply it, so there is no acceptance to report back. OutgoingShare.responsesAvailable says so.
  • createPendingSharesComputable recognises-or-hides: a payload kind the client does not know is hidden rather than mis-rendered.

Tests

  • templates.test.ts — the shelf: create, rename, delete, list.
  • template_share.test.ts, sharing_model.test.ts — envelope building and the payload discriminant.
  • template-round-trip.test.ts (drivers-ml-blocks-integration) — save a project as a template, share it, accept it, build a project from it.

Notes for the reviewer

  • Old clients are not protected by the schemaVersion bump alone: the shipped v1 client has no version or kind check, so it will see a template share as a project share. The recognise-or-hide logic protects clients from this PR onward only.
  • If an apply throws after the project resource is created, the empty project stays. Worth a follow-up.
  • changeShare cannot re-point a template share yet — the templateId is not part of the change path.

Desktop side: milaboratory/platforma-desktop-app#535

Greptile Summary

The PR promotes project templates to persistent, listable, applicable, and shareable middle-layer entities while extending sharing envelopes with discriminated payloads and backward-compatible version-1 decoding.

  • Adds a user-root template shelf, immutable stored template documents, mutable metadata, CRUD operations, and reactive listing.
  • Adds resolution-first template application and project creation to avoid creating projects for templates that cannot be prepared.
  • Adds read-only template sharing, acceptance onto the recipient’s shelf, payload-aware pending/outgoing share views, and version-2 envelopes.
  • Important touched terms:
    • TemplateId — branded identifier for a stored UserTemplate; newly introduced as the template-operation key.
    • StoredTemplateData — immutable template document and provenance stored in resource data; newly introduced with schema version 1.
    • TemplateListEntry — reactive shelf representation containing label, creation time, block count, and provenance; newly introduced.
    • Templates / UserTemplate — resource types representing the user’s template shelf and each stored template; newly introduced under the client root.
    • EnvelopePayload — contents carried by a share; changed to a discriminated union of project packs and template documents.
    • EnvelopeData — immutable shared-envelope metadata; changed from schema version 1 with top-level projects to version 2 with payload, while version 1 is upcast on read.
    • PendingShare / OutgoingShare — recipient- and donor-facing share views; changed to expose payload kind and template-specific metadata, with outgoing shares indicating whether responses are available.
    • TemplateShareProblem — entry-specific reason a template cannot be shared, particularly local or unresolvable block locations; newly introduced.
    • CreateProjectFromTemplateOutcome — result of preparing and applying a stored template to a new project; newly introduced with success and problem variants.

Confidence Score: 5/5

The PR appears safe to merge; no unacknowledged blocking or independently actionable non-blocking defect was established.

The template shelf, payload-aware sharing paths, compatibility normalization, and resolution-first application are internally coordinated and covered by focused and integration tests; the remaining empty-project exceptional path is already explicitly documented for follow-up.

Important Files Changed

Filename Overview
lib/node/pl-middle-layer/src/middle_layer/middle_layer.ts Adds template lifecycle, preparation/application, sharing, acceptance, initialization, and reactive shelf integration; the documented post-creation exceptional cleanup gap remains.
lib/node/pl-middle-layer/src/middle_layer/template_list.ts Defines template resource contracts, public types, shelf initialization, and the reactive template-list projection.
lib/node/pl-middle-layer/src/model/sharing_model.ts Introduces discriminated envelope payloads, schema version 2, version-1 normalization, and template-sharing option types.
lib/node/pl-middle-layer/src/middle_layer/sharing_list.ts Makes pending and outgoing share projections payload-aware and hides unsupported envelope versions or payload kinds.
lib/node/pl-middle-layer/src/mutator/sharing.ts Writes version-2 project envelopes and new immutable read-only template envelopes.
lib/node/pl-middle-layer/src/mutator/template.ts Implements atomic creation, metadata-only rename, and list-detachment deletion for stored templates.
lib/node/pl-middle-layer/src/model/template_share.ts Rejects template sharing for local-file and syntactically unresolvable block locations.
lib/node/pl-middle-layer/src/middle_layer/templates.test.ts Exercises template storage, listing, rename, failed preparation, shareability, acceptance, and share replacement.
tests/drivers-ml-blocks-integration/src/template-round-trip.test.ts Adds an end-to-end stored-template round trip preserving block order, parameters, and relocated references.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Project[Project] -->|saveProjectAsTemplate| Template[Stored UserTemplate]
  Template --> Shelf[Templates shelf]
  Template -->|resolve and prepare| Prepared[Prepared entries]
  Prepared -->|create and apply| NewProject[New project]
  Template -->|shareTemplate| Envelope[Read-only template envelope]
  Envelope -->|grant| Recipient[Recipient]
  Recipient -->|acceptShare| RecipientShelf[Recipient template shelf]
  RecipientShelf -->|createProjectFromTemplate| RecipientProject[Recipient project]
Loading

Reviews (1): Last reviewed commit: "MILAB-6817: add changeset for the templa..." | Re-trigger Greptile

Context used:

  • Context used - Terms is a types in codebase. Provide the list of ... (source)

A template stops being a file you export and becomes an object stored on the
server next to projects.

- UserTemplate resource: the template-v1 document in the immutable data blob,
  the mutable label and timestamps in KV, listed through a Templates resource
  the same way projects are.
- saveProjectAsTemplate, renameTemplate, deleteTemplate, resolveTemplate and
  createProjectFromTemplate on MiddleLayer. Applying resolves and prepares
  every entry before it creates the project, so a template that cannot be
  built in full leaves nothing behind.
- Template sharing: EnvelopeData carries a discriminated payload and moves to
  schemaVersion 2, a v1 envelope still decodes as a project share, and an
  envelope whose payload kind is unknown is hidden rather than offered. A
  template share is granted read-only and is refused outright while any entry
  is installed from a folder on the author's machine.
- Accepting a template share puts a template on the recipient's shelf and
  creates no project.
@changeset-bot

changeset-bot Bot commented Aug 26, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4ea0a55

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@milaboratories/pl-middle-layer Minor
@milaboratories/pl-mcp-server Major
@platforma-sdk/pl-cli Patch
@platforma-sdk/test Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@notion-workspace

Copy link
Copy Markdown

@codecov

codecov Bot commented Aug 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 57.84753% with 94 lines in your changes missing coverage. Please review.
✅ Project coverage is 54.34%. Comparing base (2e59d0a) to head (4ea0a55).
⚠️ Report is 14 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...e/pl-middle-layer/src/middle_layer/middle_layer.ts 44.85% 56 Missing and 19 partials ⚠️
.../pl-middle-layer/src/middle_layer/template_list.ts 78.37% 4 Missing and 4 partials ⚠️
lib/node/pl-middle-layer/src/mutator/template.ts 46.66% 8 Missing ⚠️
...e/pl-middle-layer/src/middle_layer/sharing_list.ts 66.66% 0 Missing and 2 partials ⚠️
...b/node/pl-middle-layer/src/model/template_share.ts 90.90% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1797      +/-   ##
==========================================
+ Coverage   53.07%   54.34%   +1.26%     
==========================================
  Files         412      418       +6     
  Lines       21248    21895     +647     
  Branches     4744     4889     +145     
==========================================
+ Hits        11277    11898     +621     
+ Misses       8616     8559      -57     
- Partials     1355     1438      +83     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant