diff --git a/templates/ItemTemplates/ContentApp/.template.config/template.json b/templates/ItemTemplates/ContentApp/.template.config/template.json
new file mode 100644
index 000000000000..f3a56c9b5a7a
--- /dev/null
+++ b/templates/ItemTemplates/ContentApp/.template.config/template.json
@@ -0,0 +1,22 @@
+{
+ "$schema": "http://json.schemastore.org/template",
+ "author": "UmbracoPackageTeam",
+ "classifications": [
+ "Web",
+ "Umbraco",
+ "ContentApp"
+ ],
+ "tags": {
+ "language": "JavaScript",
+ "type": "item"
+ },
+
+ "identity": "Umbraco.Templates.Items.ContentApp",
+ "groupIdentity": "Umbraco.Templates.Items.ContentApp",
+
+ "name": "Umbraco Content App",
+ "shortName": "umbraco-contentapp",
+ "description": "Files to add a content app to an Umbraco v10 project",
+
+ "sourceName": "UmbracoPackage.1"
+}
\ No newline at end of file
diff --git a/templates/ItemTemplates/ContentApp/App_Plugins/UmbracoPackage.1/ContentApp/Lang/en.xml b/templates/ItemTemplates/ContentApp/App_Plugins/UmbracoPackage.1/ContentApp/Lang/en.xml
new file mode 100644
index 000000000000..833031c78864
--- /dev/null
+++ b/templates/ItemTemplates/ContentApp/App_Plugins/UmbracoPackage.1/ContentApp/Lang/en.xml
@@ -0,0 +1,7 @@
+
+
+
+ UmbracoPackage.1 super content app
+ My super awesome content app
+
+
\ No newline at end of file
diff --git a/templates/ItemTemplates/ContentApp/App_Plugins/UmbracoPackage.1/ContentApp/contentapp.controller.js b/templates/ItemTemplates/ContentApp/App_Plugins/UmbracoPackage.1/ContentApp/contentapp.controller.js
new file mode 100644
index 000000000000..10c542810fe7
--- /dev/null
+++ b/templates/ItemTemplates/ContentApp/App_Plugins/UmbracoPackage.1/ContentApp/contentapp.controller.js
@@ -0,0 +1,32 @@
+/**
+ * @ngdoc
+ *
+ * @name: contentAppController
+ * @description: code for a content app in the umbraco back office
+ *
+ */
+(function () {
+ 'use strict';
+
+ function contentAppController() {
+
+ var vm = this;
+ vm.loading = true;
+ vm.message = "";
+
+ function init() {
+ getInfo();
+ }
+
+ function getInfo() {
+ vm.message = "Content App init() has run";
+ vm.loading = false;
+ }
+
+ // call init, when controller is loaded
+ init();
+ }
+
+ angular.module('umbraco')
+ .controller('umbracopackage__1ContentAppController', contentAppController);
+})();
\ No newline at end of file
diff --git a/templates/ItemTemplates/ContentApp/App_Plugins/UmbracoPackage.1/ContentApp/contentapp.html b/templates/ItemTemplates/ContentApp/App_Plugins/UmbracoPackage.1/ContentApp/contentapp.html
new file mode 100644
index 000000000000..ce0ef300ac0a
--- /dev/null
+++ b/templates/ItemTemplates/ContentApp/App_Plugins/UmbracoPackage.1/ContentApp/contentapp.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+ {{vm.message}}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/ItemTemplates/ContentApp/App_Plugins/UmbracoPackage.1/ContentApp/package.manifest b/templates/ItemTemplates/ContentApp/App_Plugins/UmbracoPackage.1/ContentApp/package.manifest
new file mode 100644
index 000000000000..a352cb57251e
--- /dev/null
+++ b/templates/ItemTemplates/ContentApp/App_Plugins/UmbracoPackage.1/ContentApp/package.manifest
@@ -0,0 +1,17 @@
+{
+ "javascript": [
+ "~/App_Plugins/UmbracoPackage.1/ContentApp/contentapp.controller.js"
+ ],
+ "contentApps": [
+ {
+ "name": "My App", // required - the name that appears under the icon
+ "alias": "umbracopackage._1-contentapp", // required - unique alias for your app
+ "weight": 0, // optional, default is 0, use values between -99 and +99 to appear between the existing Content (-100) and Info (100) apps
+ "icon": "icon-cupcake", // required - the icon to use
+ "view": "~/App_Plugins/UmbracoPackage.1/ContentApp/contentapp.html", // required - the location of the view file
+ "show": [
+ "+content/*" // show app for all content types
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/templates/ItemTemplates/Dashboard/.template.config/template.json b/templates/ItemTemplates/Dashboard/.template.config/template.json
new file mode 100644
index 000000000000..cd15bc346e79
--- /dev/null
+++ b/templates/ItemTemplates/Dashboard/.template.config/template.json
@@ -0,0 +1,22 @@
+{
+ "$schema": "http://json.schemastore.org/template",
+ "author": "UmbracoPackageTeam",
+ "classifications": [
+ "Web",
+ "Umbraco",
+ "Dashboard"
+ ],
+ "tags": {
+ "language": "C#",
+ "type": "item"
+ },
+
+ "identity": "Umbraco.Templates.Items.Dashboard",
+ "groupIdentity": "Umbraco.Templates.Items.Dashboard",
+
+ "name": "Umbraco Dashboard Item",
+ "shortName": "umbraco-dashboard",
+ "description": "Umbraco dashboard files",
+
+ "sourceName": "UmbracoPackage.1"
+}
\ No newline at end of file
diff --git a/templates/ItemTemplates/Dashboard/App_Plugins/UmbracoPackage.1/dashboard/Lang/en.xml b/templates/ItemTemplates/Dashboard/App_Plugins/UmbracoPackage.1/dashboard/Lang/en.xml
new file mode 100644
index 000000000000..7cd338bb67f2
--- /dev/null
+++ b/templates/ItemTemplates/Dashboard/App_Plugins/UmbracoPackage.1/dashboard/Lang/en.xml
@@ -0,0 +1,11 @@
+
+
+
+ UmbracoPackage.1 super dashboard
+ My super awesome dashboard
+
+
+ UmbracoPackage.1
+
+
+
\ No newline at end of file
diff --git a/templates/ItemTemplates/Dashboard/App_Plugins/UmbracoPackage.1/dashboard/dashboard.controller.js b/templates/ItemTemplates/Dashboard/App_Plugins/UmbracoPackage.1/dashboard/dashboard.controller.js
new file mode 100644
index 000000000000..a6445b22fcaa
--- /dev/null
+++ b/templates/ItemTemplates/Dashboard/App_Plugins/UmbracoPackage.1/dashboard/dashboard.controller.js
@@ -0,0 +1,41 @@
+/**
+ * @ngdoc
+ *
+ * @name: dashboardController
+ * @description: code for a dashboard in the umbraco back office
+ *
+ */
+(function () {
+ 'use strict';
+
+ function dashboardController($scope,
+ notificationsService,
+ umbracopackage__1DashboardService) {
+
+ var vm = this;
+ vm.loading = true;
+ vm.info = {};
+
+ function init() {
+ getServerInfo();
+ }
+
+ // ask the server what version it is and what time it things it is.
+ function getServerInfo() {
+ umbracopackage__1DashboardService.getServerInfo()
+ .then(function (result) {
+ vm.info = result.data;
+ vm.loading = false;
+ }, function (error) {
+ console.warn(error);
+ notificationsService.error('Error', 'Unable to get the server info');
+ });
+ }
+
+ // call init, when controller is loaded
+ init();
+ }
+
+ angular.module('umbraco')
+ .controller('umbracopackage__1DashboardController', dashboardController);
+})();
diff --git a/templates/ItemTemplates/Dashboard/App_Plugins/UmbracoPackage.1/dashboard/dashboard.html b/templates/ItemTemplates/Dashboard/App_Plugins/UmbracoPackage.1/dashboard/dashboard.html
new file mode 100644
index 000000000000..e522487c472f
--- /dev/null
+++ b/templates/ItemTemplates/Dashboard/App_Plugins/UmbracoPackage.1/dashboard/dashboard.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+ Server Time : {{vm.info | date:'medium'}}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/ItemTemplates/Dashboard/App_Plugins/UmbracoPackage.1/dashboard/dashboard.service.js b/templates/ItemTemplates/Dashboard/App_Plugins/UmbracoPackage.1/dashboard/dashboard.service.js
new file mode 100644
index 000000000000..9557a601051a
--- /dev/null
+++ b/templates/ItemTemplates/Dashboard/App_Plugins/UmbracoPackage.1/dashboard/dashboard.service.js
@@ -0,0 +1,28 @@
+/**
+ * @ngdoc
+ *
+ * @name: dashboardService
+ * @description: provides an interface between the javascript dashboard and our
+ * backoffice api.
+ */
+(function () {
+ 'use strict';
+
+ function dashboardService($http) {
+
+ var serviceRoot = Umbraco.Sys.ServerVariables.umbracopackage__1.dashboardController;
+
+ return {
+ getServerInfo: getServerInfo
+ }
+
+ /////
+
+ function getServerInfo() {
+ return $http.get(serviceRoot + "GetServerInfo");
+ }
+ };
+
+ angular.module('umbraco')
+ .factory('umbracopackage__1DashboardService', dashboardService);
+})();
\ No newline at end of file
diff --git a/templates/ItemTemplates/Dashboard/App_Plugins/UmbracoPackage.1/dashboard/package.manifest b/templates/ItemTemplates/Dashboard/App_Plugins/UmbracoPackage.1/dashboard/package.manifest
new file mode 100644
index 000000000000..dc01209ee5a5
--- /dev/null
+++ b/templates/ItemTemplates/Dashboard/App_Plugins/UmbracoPackage.1/dashboard/package.manifest
@@ -0,0 +1,15 @@
+{
+ "javascript": [
+ "~/App_Plugins/UmbracoPackage.1/dashboard/dashboard.service.js",
+ "~/App_Plugins/UmbracoPackage.1/dashboard/dashboard.controller.js"
+ ],
+ "dashboards": [
+ {
+ "alias": "umbracopackage._1-dashboard",
+ "sections": [
+ "content"
+ ],
+ "view": "~/App_Plugins/UmbracoPackage.1/dashboard/dashboard.html"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/templates/ItemTemplates/Dashboard/Controllers/DashboardApiController.cs b/templates/ItemTemplates/Dashboard/Controllers/DashboardApiController.cs
new file mode 100644
index 000000000000..2271410f12f1
--- /dev/null
+++ b/templates/ItemTemplates/Dashboard/Controllers/DashboardApiController.cs
@@ -0,0 +1,21 @@
+using Microsoft.AspNetCore.Mvc;
+using Umbraco.Cms.Web.BackOffice.Controllers;
+
+namespace UmbracoPackage._1.Controllers;
+
+public class DashboardApiController : UmbracoAuthorizedApiController
+{
+ ///
+ /// GetApi - Called in our ServerVariablesParser.Parsing event handler
+ /// this gets the URL of this API, so we don't have to hardwire it anywhere
+ ///
+ [HttpGet]
+ public bool GetApi() => true;
+
+ ///
+ /// Simple call return the time,
+ ///
+ ///
+ [HttpGet]
+ public DateTime GetServerInfo() => DateTime.UtcNow;
+}
\ No newline at end of file
diff --git a/templates/ItemTemplates/Dashboard/Controllers/DashboardComposer.cs b/templates/ItemTemplates/Dashboard/Controllers/DashboardComposer.cs
new file mode 100644
index 000000000000..9742a47ad916
--- /dev/null
+++ b/templates/ItemTemplates/Dashboard/Controllers/DashboardComposer.cs
@@ -0,0 +1,34 @@
+using Umbraco.Cms.Core.Composing;
+using Umbraco.Cms.Core.DependencyInjection;
+using Umbraco.Cms.Core.Events;
+using Umbraco.Cms.Core.Notifications;
+using Umbraco.Extensions;
+
+namespace UmbracoPackage._1.Controllers;
+
+public class DashboardComposer : IComposer
+{
+ public void Compose(IUmbracoBuilder builder)
+ {
+ builder
+ .AddNotificationHandler();
+ }
+}
+
+public class DashboardServerVariablesParserNotificationHandler : INotificationHandler
+{
+ private readonly LinkGenerator _linkGenerator;
+
+ public DashboardServerVariablesParserNotificationHandler(LinkGenerator linkGenerator)
+ {
+ _linkGenerator = linkGenerator;
+ }
+ public void Handle(ServerVariablesParsingNotification notification)
+ {
+ notification.ServerVariables.Add("umbracopackage__1", new Dictionary
+ {
+ { "dashboardController", _linkGenerator.GetUmbracoApiServiceBaseUrl(controller => controller.GetApi()) }
+ });
+ }
+}
\ No newline at end of file
diff --git a/templates/ItemTemplates/PropertyEditor/.template.config/template.json b/templates/ItemTemplates/PropertyEditor/.template.config/template.json
new file mode 100644
index 000000000000..06404bcad85e
--- /dev/null
+++ b/templates/ItemTemplates/PropertyEditor/.template.config/template.json
@@ -0,0 +1,22 @@
+{
+ "$schema": "http://json.schemastore.org/template",
+ "author": "UmbracoPackageTeam",
+ "classifications": [
+ "Web",
+ "Umbraco",
+ "PropertyEditor"
+ ],
+ "tags": {
+ "language": "JavaScript",
+ "type": "item"
+ },
+
+ "identity": "Umbraco.Templates.Items.PropertyEditor",
+ "groupIdentity": "Umbraco.Templates.Items.PropertyEditor",
+
+ "name": "Umbraco Property Editor Item",
+ "shortName": "umbraco-property-editor",
+ "description": "Umbraco property editor files",
+
+ "sourceName": "UmbracoPackage.1"
+}
\ No newline at end of file
diff --git a/templates/ItemTemplates/PropertyEditor/App_Plugins/UmbracoPackage.1/PropertyEditor/editor.controller.js b/templates/ItemTemplates/PropertyEditor/App_Plugins/UmbracoPackage.1/PropertyEditor/editor.controller.js
new file mode 100644
index 000000000000..459dda0d76f8
--- /dev/null
+++ b/templates/ItemTemplates/PropertyEditor/App_Plugins/UmbracoPackage.1/PropertyEditor/editor.controller.js
@@ -0,0 +1,24 @@
+/**
+ * @ngdoc
+ *
+ * @name: editorController
+ * @description: code for a property editor in the umbraco back office
+ *
+ */
+(function () {
+ 'use strict';
+
+ function editorController() {
+
+ var vm = this;
+
+ function init() {
+ }
+
+ // call init, when controller is loaded
+ init();
+ }
+
+ angular.module('umbraco')
+ .controller('umbracopackage__1EditorController', editorController);
+})();
\ No newline at end of file
diff --git a/templates/ItemTemplates/PropertyEditor/App_Plugins/UmbracoPackage.1/PropertyEditor/editor.html b/templates/ItemTemplates/PropertyEditor/App_Plugins/UmbracoPackage.1/PropertyEditor/editor.html
new file mode 100644
index 000000000000..190bb7bacb5d
--- /dev/null
+++ b/templates/ItemTemplates/PropertyEditor/App_Plugins/UmbracoPackage.1/PropertyEditor/editor.html
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/templates/ItemTemplates/PropertyEditor/App_Plugins/UmbracoPackage.1/PropertyEditor/package.manifest b/templates/ItemTemplates/PropertyEditor/App_Plugins/UmbracoPackage.1/PropertyEditor/package.manifest
new file mode 100644
index 000000000000..dbc6ac447998
--- /dev/null
+++ b/templates/ItemTemplates/PropertyEditor/App_Plugins/UmbracoPackage.1/PropertyEditor/package.manifest
@@ -0,0 +1,21 @@
+{
+ "javascript": [
+ "~/App_Plugins/UmbracoPackage.1/PropertyEditor/editor.controller.js"
+ ],
+ "propertyEditors": [
+ {
+ /*this must be a unique alias*/
+ "alias": "umbracopackage._1-editor",
+ /*the name*/
+ "name": "My editor",
+ /*the icon*/
+ "icon": "icon-code",
+ /*grouping for "Select editor" dialog*/
+ "group": "Rich Content",
+ /*the HTML file we will load for the editor*/
+ "editor": {
+ "view": "~/App_Plugins/UmbracoPackage.1/PropertyEditor/editor.html"
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/templates/Umbraco.Templates.csproj b/templates/Umbraco.Templates.csproj
index 47b2246835a9..a206ef87b296 100644
--- a/templates/Umbraco.Templates.csproj
+++ b/templates/Umbraco.Templates.csproj
@@ -16,7 +16,9 @@
+
+