<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://wiki.socialstack.dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=2A02%3AC7F%3A22BE%3AA500%3A498%3A3225%3A1A16%3AA72D</id>
	<title>SocialStack - User contributions [en-gb]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.socialstack.dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=2A02%3AC7F%3A22BE%3AA500%3A498%3A3225%3A1A16%3AA72D"/>
	<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=Special:Contributions/2A02:C7F:22BE:A500:498:3225:1A16:A72D"/>
	<updated>2026-10-16T01:20:24Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.36.2</generator>
	<entry>
		<id>https://wiki.socialstack.dev/index.php?title=Canvas&amp;diff=106</id>
		<title>Canvas</title>
		<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=Canvas&amp;diff=106"/>
		<updated>2022-07-06T01:48:43Z</updated>

		<summary type="html">&lt;p&gt;2A02:C7F:22BE:A500:498:3225:1A16:A72D: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Canvas is SocialStack&amp;#039;s main mechanism for representing configurable structured content - that&amp;#039;s mainly things like pages of your site and emails. It is stored as a JSON format and the JSON is passed to the React &amp;lt;Canvas&amp;gt; element usually as a child.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;js&amp;quot;&amp;gt;&lt;br /&gt;
import Canvas from &amp;#039;UI/Canvas&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
..&lt;br /&gt;
&lt;br /&gt;
&amp;lt;Canvas&amp;gt;{&amp;quot;t&amp;quot;:&amp;quot;UI/Header&amp;quot;}&amp;lt;/Canvas&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Canvas Json=&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;t&amp;quot;: &amp;quot;UI/HelloWorld&amp;quot;,&lt;br /&gt;
    &amp;quot;d&amp;quot;: {&lt;br /&gt;
        &amp;quot;customProp&amp;quot;: &amp;quot;This is a prop value passed to UI/HelloWorld&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;c&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;t&amp;quot;: &amp;quot;b&amp;quot;,&lt;br /&gt;
            &amp;quot;c&amp;quot;: &amp;quot;This is bold text as a child of UI/HelloWorld.&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    ]&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The JSON that Canvas uses is a very thin system for representing a tree of elements. A json object with these fields we&amp;#039;ll refer to as a &amp;quot;canvas node&amp;quot; here. It has 3 main fields:&lt;br /&gt;
&lt;br /&gt;
* t (type): The type of this element. It is either an absolute component path or the name of a HTML element usually in lowercase.&lt;br /&gt;
&lt;br /&gt;
* d (data): Any custom data for the element. In React these are passed to your element as props as-is. Importantly though, HTML elements are not expected to support data (but where they do, the values are as-is attributes). This is such that canvas JSON is safe for use by frontend users to create and is not overly tied to HTML itself. I.e. &amp;quot;t&amp;quot;: &amp;quot;b&amp;quot; indicates bold.&lt;br /&gt;
&lt;br /&gt;
* c (children): Any child nodes of the element. These are processed as canvas nodes then passed as the children prop in React. It can be an array of canvas nodes/ strings, a single canvas node or a single string. Strings are treated as raw text.&lt;br /&gt;
&lt;br /&gt;
There are some additional fields which can be used for diffing canvas JSON amongst other things:&lt;br /&gt;
&lt;br /&gt;
* s (string): An object containing &amp;quot;s&amp;quot;: &amp;quot;some text&amp;quot; works the same way as just a text string in children, but with the advantage of being able to have additional fields on it such as an id.&lt;br /&gt;
&lt;br /&gt;
* i (id): A unique number for this particular node. Particularly useful for comparing changes in canvases. Editors must not reuse a removed id; it must only ever increase.&lt;br /&gt;
&lt;br /&gt;
* ti (template ID): If a canvas node was imported from another canvas, it can be given both an ID and a template ID to identify where it originated from. This allows these remote nodes to have custom overrideable data values but are still easily diffable with the source canvas that they came from.&lt;br /&gt;
&lt;br /&gt;
* r (roots): Sometimes you may want your props to be canvas formatted. You could pass a JSON string via data and then have your component internally render it but that is not particularly friendly for editors - it&amp;#039;s nice if a canvas editor is aware that your prop is something it can edit too, potentially even inline. This is what roots are for - they are canvas root nodes which are then passed to your component as a prop after it has been rendered. I.e. in React, the value of the prop that you receive is a React node. A canvas root node has the restriction that it must be an object, not a string, but it can still contain strings as its child nodes.&lt;/div&gt;</summary>
		<author><name>2A02:C7F:22BE:A500:498:3225:1A16:A72D</name></author>
	</entry>
	<entry>
		<id>https://wiki.socialstack.dev/index.php?title=Getting_Started&amp;diff=105</id>
		<title>Getting Started</title>
		<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=Getting_Started&amp;diff=105"/>
		<updated>2022-07-06T01:38:14Z</updated>

		<summary type="html">&lt;p&gt;2A02:C7F:22BE:A500:498:3225:1A16:A72D: /* Creating frontend UI modules */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
Hello! Welcome to SocialStack, a fully open source modular collection of C# and javascript code used to create modern, ultra high throughput projects which has been tried and tested by big name brands. This guide is targeted at developers so with that in mind, let&amp;#039;s get in to it!&lt;br /&gt;
&lt;br /&gt;
= Installing dependencies =&lt;br /&gt;
&lt;br /&gt;
So, to get started, you&amp;#039;ll need a few things first. Whilst SocialStack does support using multiple database engines, we currently reccommend starting with MySQL. Here&amp;#039;s what you&amp;#039;ll need:&lt;br /&gt;
&lt;br /&gt;
* An editor capable of working with dotnet 6. For example, Visual Studio Code or Visual Studio 2022.&lt;br /&gt;
* Node.js 8+ which is used to run the command line tools&lt;br /&gt;
* MySQL version 8 is reccommended&lt;br /&gt;
* Git, as a new project will also be created as a git repository.&lt;br /&gt;
&lt;br /&gt;
= Setting up the command line tools =&lt;br /&gt;
&lt;br /&gt;
Once you&amp;#039;ve got the dependencies ready, it&amp;#039;s time to setup the [https://www.npmjs.com/package/socialstack command line tools] which we&amp;#039;ll shortly use to create a project. In a nutshell, it is an optional npm package which can be installed globally by running this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
npm i -g socialstack&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this command line tool set (and node.js) are not required by production sites. It&amp;#039;s just a convenience system for installing modules and creating projects.&lt;br /&gt;
&lt;br /&gt;
It&amp;#039;s recommended to configure socialstack tools with the ability to create MySQL databases for you on your development computer. To do this, you&amp;#039;ll need to create a MySQL account on your MySQL instance which it can use and which has the permission to create databases and users. Here&amp;#039;s an example of how to do that:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- Create the user account:&lt;br /&gt;
CREATE USER &amp;#039;sstools&amp;#039;@&amp;#039;localhost&amp;#039; IDENTIFIED BY &amp;#039;ssto0ls.dev&amp;#039;; -- Invent a password here!&lt;br /&gt;
-- Grant that user full access to the db:&lt;br /&gt;
GRANT ALL PRIVILEGES ON *.* TO &amp;#039;sstools&amp;#039;@&amp;#039;localhost&amp;#039; WITH GRANT OPTION;&lt;br /&gt;
FLUSH PRIVILEGES;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can then add this account to your command line tools like so, making sure the password and username matches what you used:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
socialstack configure -u &amp;quot;sstools&amp;quot; -p &amp;quot;ssto0ls.dev&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a global thing, so once you&amp;#039;ve done it you won&amp;#039;t need to do it again. You&amp;#039;re ready to create a project!&lt;br /&gt;
&lt;br /&gt;
= Creating a project =&lt;br /&gt;
&lt;br /&gt;
With the command line tools ready to go, you can then go ahead and create a project like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd myProjectDirectory&lt;br /&gt;
socialstack create helloworld&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will ask if you want to install any additional modules straight away. Just skip this by pressing enter. If your configuration is ok, a database will be created for you as well as the project.&lt;br /&gt;
&lt;br /&gt;
= Starting it up =&lt;br /&gt;
&lt;br /&gt;
With your project created, start it up in a suitable editor (typically that is Visual Studio Code, or Visual Studio 2022) or via the command line by starting the Api.csproj project. Whilst it starts, it will give you a few bits of information:&lt;br /&gt;
&lt;br /&gt;
* It will list which services (provided by modules) are installed and starting up.&lt;br /&gt;
* It will create the database tables and any initial data needed by those services. This is fully automated.&lt;br /&gt;
* It will let you know that a default administration account was created, and what its details are. This happens once; if you missed it you can check the site_user table in your database as it will have one row and the default password is simply &amp;#039;&amp;#039;&amp;#039;admin&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* It lets you know how to get to the instance. This defaults to http://localhost:5050/ which you can navigate to in a browser.&lt;br /&gt;
* It compiles the UI and indicates when its done. This is usually the very last thing that appears and the UI won&amp;#039;t display to you until it completes.&lt;br /&gt;
&lt;br /&gt;
= Going exploring =&lt;br /&gt;
&lt;br /&gt;
With your project started, head over to http://localhost:5050/ in a browser and you should see a barebones homepage with a welcome message. This brings us to the first key point:&lt;br /&gt;
&lt;br /&gt;
&amp;gt;  Pages in SocialStack entirely come from the editable CMS area - this includes administration panel pages too. There&amp;#039;s no fighting against surrounding page templates as the root component(s) on the page are whatever you choose. More on components later!&lt;br /&gt;
&lt;br /&gt;
So, let&amp;#039;s head in to the administration panel and make some changes. Head over to http://localhost:5050/en-admin/ in a browser and you should see a login panel. At this point use the generated administration account to login which will currently default to:&lt;br /&gt;
&lt;br /&gt;
* Username: &amp;#039;&amp;#039;&amp;#039;admin&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* Password: &amp;#039;&amp;#039;&amp;#039;admin&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Once you&amp;#039;ve logged in, in the top left corner is a menu which you can use to get to the list of pages. On this list, find the homepage and open the page editor. [[Editing Pages|Editing a page]] (and more generally how they actually work) is a broad topic on its own so please take a moment to check out [[Editing Pages|that article]] first, then head back here when you&amp;#039;re ready.&lt;br /&gt;
&lt;br /&gt;
= Creating API modules =&lt;br /&gt;
&lt;br /&gt;
Next is a good point to have a go at creating your own API module. A video version of this part of the guide is [https://www.youtube.com/watch?v=4rrfyg4Wk_g available here]. We&amp;#039;ll make something like a list of frequently asked questions. SocialStack tools has a [[generate|generate command]] which creates the basic scaffolding of a new API module for you, so let&amp;#039;s generate that now:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
socialstack generate Api/FrequentlyAskedQuestions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All this does is create a directory with some generated files; i.e. copy/pasting or manually creating one of those directories has the same outcome as there are no hidden indexes or other files to update. In this case, it will be in the directory ProjectRoot/Api/FrequentlyAskedQuestions. It should also appear in the explorer inside an IDE such as Visual Studio. Inside this folder, you&amp;#039;ll see a small collection of files with different purposes, which are explored in [[API Modules|this section of the wiki]]. Take a look there, then head back here when you&amp;#039;re ready.&lt;br /&gt;
&lt;br /&gt;
Next we&amp;#039;ll need to add fields to the generated FAQ type as so far it is just an empty shell. To do that, edit FrequentlyAskedQuestion.cs and add 2 fields:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
/// &amp;lt;summary&amp;gt;&lt;br /&gt;
/// The question people ask.&lt;br /&gt;
/// &amp;lt;/summary&amp;gt;&lt;br /&gt;
[Localized]&lt;br /&gt;
public string Question;&lt;br /&gt;
&lt;br /&gt;
/// &amp;lt;summary&amp;gt;&lt;br /&gt;
/// The answer.&lt;br /&gt;
/// &amp;lt;/summary&amp;gt;&lt;br /&gt;
[Localized]&lt;br /&gt;
public string AnswerJson;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It would also help to be able to see and edit these FAQ&amp;#039;s via the admin panel, so edit FrequentlyAskedQuestionService.cs and uncomment the admin panel pages line.&lt;br /&gt;
&lt;br /&gt;
As you have made changes to C#, you&amp;#039;ll need to restart the API for the changes to take effect. The easiest way is to stop/ start the running project in your IDE. When it starts back up, head back in to the admin panel at http://localhost:5050/en-admin/ and you should see a new link in the menu to your newly created FAQ&amp;#039;s. Have a go at creating and editing some, and then when you&amp;#039;re ready head back over here.&lt;br /&gt;
&lt;br /&gt;
We now have some data in your database and an ability to see and manipulate it with the admin panel. So far so good!&lt;br /&gt;
&lt;br /&gt;
= Creating frontend UI modules =&lt;br /&gt;
&lt;br /&gt;
Next it would be great if you could also list out your FAQs on the actual website so let&amp;#039;s explore that next. This part of the guide is also covered in [https://www.youtube.com/watch?v=YyFNVPwbIz4 a video about Loop], however just like before, it all starts with a generate command:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
socialstack generate UI/Faq/List&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will create a directory in ProjectRoot/UI/Source/Faq/List containing 2 files; a React component and some CSS to go with it.&lt;br /&gt;
&lt;br /&gt;
Note: Changes to the UI are compiled immediately whenever the API is running. That includes creating files, generating modules, editing files and so on - and the updates are usually near instant too.&lt;br /&gt;
&lt;br /&gt;
There&amp;#039;s 3 main convenience ways to access data from the API via a React component - [[Loop|Loop]], [[Content]] and webRequest. [[Loop|Loop]] is for a list of things, [[Content]] is for just one and webRequest is for any other situation in e.g. useEffect or componentDidMount where you need to grab data without being in a React render function. [[Loop|Loop]] and Content simply sit on top of webRequest and use the [[Public API|public part of the projects API]] (that&amp;#039;s controllers in your API, which use the services to return the data). We want a list of FAQs here, so we&amp;#039;ll use Loop. Here&amp;#039;s an example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;js&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
import Canvas from &amp;#039;UI/Canvas&amp;#039;;&lt;br /&gt;
import Loop from &amp;#039;UI/Loop&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
export default function List(props){&lt;br /&gt;
    // Loops over the FAQs from the API and also uses a &lt;br /&gt;
    // canvas to display the answer which is visual editor content.&lt;br /&gt;
    return &amp;lt;Loop over=&amp;#039;frequentlyaskedquestion&amp;#039;&amp;gt;{&lt;br /&gt;
        faq =&amp;gt; {&lt;br /&gt;
            return &amp;lt;div&amp;gt;&lt;br /&gt;
                &amp;lt;h1&amp;gt;{faq.question}&amp;lt;/h1&amp;gt;&lt;br /&gt;
                &amp;lt;Canvas&amp;gt;{faq.answerJson}&amp;lt;/Canvas&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;;&lt;br /&gt;
        }&lt;br /&gt;
    }&amp;lt;/Loop&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Loop.propTypes = {}; // No props used on this list.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save the file, and then because we specified an empty propTypes object, the page editor will now recognise the component and list it in the add window. So if you head back over to the admin panel, you&amp;#039;ll then be able to add this component to the page. Alternatively if you prefer writing the JSON, the page JSON looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&amp;quot;t&amp;quot;:&amp;quot;UI/Faq/List&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice that the name matches what you generated, and is the same as the filepath minus the &amp;quot;Source&amp;quot; folder.&lt;/div&gt;</summary>
		<author><name>2A02:C7F:22BE:A500:498:3225:1A16:A72D</name></author>
	</entry>
	<entry>
		<id>https://wiki.socialstack.dev/index.php?title=API_Modules&amp;diff=104</id>
		<title>API Modules</title>
		<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=API_Modules&amp;diff=104"/>
		<updated>2022-07-06T01:30:48Z</updated>

		<summary type="html">&lt;p&gt;2A02:C7F:22BE:A500:498:3225:1A16:A72D: /* ThingController.cs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A newly regularly generated API module has 5 files. Assuming you did &amp;#039;&amp;#039;&amp;#039;socialstack generate Api/Things&amp;#039;&amp;#039;&amp;#039;, here&amp;#039;s what each of them is for:&lt;br /&gt;
&lt;br /&gt;
= Events.cs =&lt;br /&gt;
&lt;br /&gt;
When something happens in your API, an event is triggered. By default all entities have a common set of events for things like creation/ updates/ deletion etc, but it can be extended by defining a custom event type. This is detailed more on [[Events|the page about events]]. One of the core goals of events in SocialStack is for them to be extremely fast and also easy to use with IDE autofilling, so these auto generated files exist to enable those statically typed naming in the form of Events.Thing.BeforeCreate and so on.&lt;br /&gt;
&lt;br /&gt;
Event handlers, including for a services own content type, are typically added inside service constructors.&lt;br /&gt;
&lt;br /&gt;
= Thing.cs =&lt;br /&gt;
&lt;br /&gt;
This is the entity description file. It describes what fields are on the entity. In a nutshell, fields are stored in the database and properties are not. There are some conveniences around field naming which is described on [[Entities|the entities page]].&lt;br /&gt;
&lt;br /&gt;
= ThingService.cs =&lt;br /&gt;
&lt;br /&gt;
The [[services|service]], a singleton (instanced once at startup), is used for getting/ listing/ deleting/ updating/ creating an entity. For example if you want to get hold of a user&amp;#039;s information, you would ask the UserService. Services support C# dependency injection but can also be obtained via &amp;#039;&amp;#039;&amp;#039;Services.Get&amp;lt;UserService&amp;gt;()&amp;#039;&amp;#039;&amp;#039;, with Services in the Startup namespace.&lt;br /&gt;
&lt;br /&gt;
Often, event handlers are placed inside the service&amp;#039;s constructor in order to validate your entity or e.g. add custom field values to it whilst it is being created. It&amp;#039;s very common for e.g. ThingService to have Events.Thing.BeforeUpdate and so on inside its own constructor - this allows flexibility in the form of other modules actually unregistering those handlers, if it has a goal of heavily overriding default behaviours.&lt;br /&gt;
&lt;br /&gt;
= ThingController.cs =&lt;br /&gt;
&lt;br /&gt;
Controllers are the web API endpoints and effectively represent the main user facing frontage of your site. Just like with services, the controllers have a series of [[public API|common convenience endpoints]] which are usually accessed with webRequest or [[Loop|Loop]] on the frontend.&lt;br /&gt;
&lt;br /&gt;
= Permissions.cs =&lt;br /&gt;
&lt;br /&gt;
This file is used to define the installable, base permissions for your module. It should represent the most common scenario that you expect to happen. For example, password resets should never be publicly visible - and that is going to be quite universal on most websites. These base permission grants can however be overridden in the admin panel, or with other event listeners. When creating permission grants in code, they should target the core roles, particularly if the intent is to make a portable module which can be copied or installed easily on to other projects.&lt;br /&gt;
&lt;br /&gt;
For more information on what the roles are and how the grants work, take a look at the [[permissions|permissions article]].&lt;/div&gt;</summary>
		<author><name>2A02:C7F:22BE:A500:498:3225:1A16:A72D</name></author>
	</entry>
	<entry>
		<id>https://wiki.socialstack.dev/index.php?title=API_Modules&amp;diff=103</id>
		<title>API Modules</title>
		<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=API_Modules&amp;diff=103"/>
		<updated>2022-07-06T01:30:34Z</updated>

		<summary type="html">&lt;p&gt;2A02:C7F:22BE:A500:498:3225:1A16:A72D: /* ThingController.cs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A newly regularly generated API module has 5 files. Assuming you did &amp;#039;&amp;#039;&amp;#039;socialstack generate Api/Things&amp;#039;&amp;#039;&amp;#039;, here&amp;#039;s what each of them is for:&lt;br /&gt;
&lt;br /&gt;
= Events.cs =&lt;br /&gt;
&lt;br /&gt;
When something happens in your API, an event is triggered. By default all entities have a common set of events for things like creation/ updates/ deletion etc, but it can be extended by defining a custom event type. This is detailed more on [[Events|the page about events]]. One of the core goals of events in SocialStack is for them to be extremely fast and also easy to use with IDE autofilling, so these auto generated files exist to enable those statically typed naming in the form of Events.Thing.BeforeCreate and so on.&lt;br /&gt;
&lt;br /&gt;
Event handlers, including for a services own content type, are typically added inside service constructors.&lt;br /&gt;
&lt;br /&gt;
= Thing.cs =&lt;br /&gt;
&lt;br /&gt;
This is the entity description file. It describes what fields are on the entity. In a nutshell, fields are stored in the database and properties are not. There are some conveniences around field naming which is described on [[Entities|the entities page]].&lt;br /&gt;
&lt;br /&gt;
= ThingService.cs =&lt;br /&gt;
&lt;br /&gt;
The [[services|service]], a singleton (instanced once at startup), is used for getting/ listing/ deleting/ updating/ creating an entity. For example if you want to get hold of a user&amp;#039;s information, you would ask the UserService. Services support C# dependency injection but can also be obtained via &amp;#039;&amp;#039;&amp;#039;Services.Get&amp;lt;UserService&amp;gt;()&amp;#039;&amp;#039;&amp;#039;, with Services in the Startup namespace.&lt;br /&gt;
&lt;br /&gt;
Often, event handlers are placed inside the service&amp;#039;s constructor in order to validate your entity or e.g. add custom field values to it whilst it is being created. It&amp;#039;s very common for e.g. ThingService to have Events.Thing.BeforeUpdate and so on inside its own constructor - this allows flexibility in the form of other modules actually unregistering those handlers, if it has a goal of heavily overriding default behaviours.&lt;br /&gt;
&lt;br /&gt;
= ThingController.cs =&lt;br /&gt;
&lt;br /&gt;
Controllers are the web API endpoints and effectively represent the main user facing frontage of your site. Just like with services, the controllers have a series of [[public Api|common convenience endpoints]] which are usually accessed with webRequest or [[Loop|Loop]] on the frontend.&lt;br /&gt;
&lt;br /&gt;
= Permissions.cs =&lt;br /&gt;
&lt;br /&gt;
This file is used to define the installable, base permissions for your module. It should represent the most common scenario that you expect to happen. For example, password resets should never be publicly visible - and that is going to be quite universal on most websites. These base permission grants can however be overridden in the admin panel, or with other event listeners. When creating permission grants in code, they should target the core roles, particularly if the intent is to make a portable module which can be copied or installed easily on to other projects.&lt;br /&gt;
&lt;br /&gt;
For more information on what the roles are and how the grants work, take a look at the [[permissions|permissions article]].&lt;/div&gt;</summary>
		<author><name>2A02:C7F:22BE:A500:498:3225:1A16:A72D</name></author>
	</entry>
	<entry>
		<id>https://wiki.socialstack.dev/index.php?title=Loop&amp;diff=102</id>
		<title>Loop</title>
		<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=Loop&amp;diff=102"/>
		<updated>2022-07-05T18:26:36Z</updated>

		<summary type="html">&lt;p&gt;2A02:C7F:22BE:A500:498:3225:1A16:A72D: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;Loop&amp;gt; is a very commonly used [https://reactjs.org/docs/react-component.html React component] installed by default in SocialStack projects. It is used to loop over lists of items typically from the API.&lt;br /&gt;
&lt;br /&gt;
=Sample Usage=&lt;br /&gt;
&lt;br /&gt;
Simple loop over everything of a given type (user in this case). Note that it will always be restricted by what you are permitted to see.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;dart&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
import Loop from &amp;#039;UI/Loop&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
     &amp;lt;Loop over=&amp;#039;user&amp;#039;&amp;gt;&lt;br /&gt;
       {&lt;br /&gt;
           user=&amp;gt; {&lt;br /&gt;
                  return &amp;lt;p&amp;gt;{user.username}&amp;lt;/p&amp;gt;;&lt;br /&gt;
           }&lt;br /&gt;
       }&lt;br /&gt;
     &amp;lt;/Loop&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Optionally you can filter your results based on some particular [[Filters|where filter]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;dart&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
import Loop from &amp;#039;UI/Loop&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
     &amp;lt;Loop over=&amp;#039;page&amp;#039; filter={&lt;br /&gt;
       {&lt;br /&gt;
              where: {&lt;br /&gt;
                     url: {&lt;br /&gt;
                            startsWith: &amp;#039;/en-admin/&amp;#039;&lt;br /&gt;
                     }&lt;br /&gt;
              }&lt;br /&gt;
       }&lt;br /&gt;
     }&amp;gt;&lt;br /&gt;
       {&lt;br /&gt;
           page =&amp;gt; {&lt;br /&gt;
                  return &amp;lt;p&amp;gt;{page.title}&amp;lt;/p&amp;gt;;&lt;br /&gt;
           }&lt;br /&gt;
       }&lt;br /&gt;
     &amp;lt;/Loop&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Live loops=&lt;br /&gt;
&lt;br /&gt;
Sometimes you&amp;#039;ll want a loop to update in realtime - whenever someone else on the site sends you a message, for example. By default any loop can update live like this, and all it takes is the live prop:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;dart&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
import Loop from &amp;#039;UI/Loop&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
     &amp;lt;Loop over=&amp;#039;user&amp;#039; live&amp;gt;&lt;br /&gt;
       {&lt;br /&gt;
           user=&amp;gt; {&lt;br /&gt;
                  return &amp;lt;p&amp;gt;{user.username}&amp;lt;/p&amp;gt;;&lt;br /&gt;
           }&lt;br /&gt;
       }&lt;br /&gt;
     &amp;lt;/Loop&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Try creating a new user account - you&amp;#039;ll see it appear on this loop without needing to do anything else, again assuming that you are permitted to see the content.&lt;br /&gt;
&lt;br /&gt;
=Sorting=&lt;br /&gt;
&lt;br /&gt;
Filters support an order clause - see the [[Filters|page on filters]] for more information here.&lt;br /&gt;
&lt;br /&gt;
=Pagination=&lt;br /&gt;
&lt;br /&gt;
A loop can be automatically paginated using the UI/Paginator component. This is done using the paged prop:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;dart&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
import Loop from &amp;#039;UI/Loop&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
     &amp;lt;Loop over=&amp;#039;user&amp;#039; paged={10}&amp;gt;&lt;br /&gt;
       {&lt;br /&gt;
           user=&amp;gt; {&lt;br /&gt;
                  return &amp;lt;p&amp;gt;{user.username}&amp;lt;/p&amp;gt;;&lt;br /&gt;
           }&lt;br /&gt;
       }&lt;br /&gt;
     &amp;lt;/Loop&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Paged itself has multiple configuration options, including the ability to specify which pagination component to use. At its basics though, just setting it to the number of items to display per page will get things moving.&lt;br /&gt;
&lt;br /&gt;
For advanced usage, the available configuration options are like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;dart&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
import Loop from &amp;#039;UI/Loop&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;Loop paged={{&lt;br /&gt;
    pageSize: 10,&lt;br /&gt;
    showInput: false,&lt;br /&gt;
    maxLinks: 3,&lt;br /&gt;
    module: &amp;#039;UI/MyCustomPaginator&amp;#039;&lt;br /&gt;
}} ...&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The module option should be used carefully to avoid inconsistency (i.e. a need to specify it on every loop would potentially arise). Instead, it&amp;#039;s recommended to uninstall the default UI/Paginator and create a custom component of the same name.&lt;br /&gt;
&lt;br /&gt;
=Includes=&lt;br /&gt;
&lt;br /&gt;
[[Includes]] are a mechanism in SocialStack for obtaining related data in the same API call. They are a feature of the [[public API]] but are exposed via Loop too:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;js&amp;quot;&amp;gt;&lt;br /&gt;
    import Loop from &amp;#039;UI/Loop&amp;#039;;&lt;br /&gt;
    &lt;br /&gt;
    ...&lt;br /&gt;
    &lt;br /&gt;
    &amp;lt;Loop over=&amp;#039;page&amp;#039; includes={[&amp;#039;creatorUser&amp;#039;]}&amp;gt;&lt;br /&gt;
        {page =&amp;gt; {&lt;br /&gt;
            return &amp;lt;div&amp;gt;&lt;br /&gt;
                The page &amp;quot;{page.title}&amp;quot; was created by {page.creatorUser.username}&lt;br /&gt;
            &amp;lt;/div&amp;gt;;&lt;br /&gt;
        }}&lt;br /&gt;
    &amp;lt;/Loop&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>2A02:C7F:22BE:A500:498:3225:1A16:A72D</name></author>
	</entry>
	<entry>
		<id>https://wiki.socialstack.dev/index.php?title=Public_API&amp;diff=101</id>
		<title>Public API</title>
		<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=Public_API&amp;diff=101"/>
		<updated>2022-07-05T18:24:52Z</updated>

		<summary type="html">&lt;p&gt;2A02:C7F:22BE:A500:498:3225:1A16:A72D: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SocialStack API&amp;#039;s (the C# binary) have a REST web API whose available endpoints originate from the set of controllers in the project. For more detail on the controllers, see the page about [[API Modules|API modules]].&lt;br /&gt;
&lt;br /&gt;
Note that it is somewhat uncommon to directly use the API. Most of the time people use [[Loop]], Content and occasionally webRequest.&lt;br /&gt;
&lt;br /&gt;
The controllers themselves are extendible - for example if you wanted /v1/user/say-hello to exist, you can do so without editing the underlying default UserController as it is a partial class. Controllers for entity types, which is to say for most parts of a typical SocialStack API, have some common endpoints which are as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;In all cases if you don&amp;#039;t have permission, it will error on you.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* GET /v1/thing/list - Lists everything of this entity type.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* POST /v1/thing/list - Lists based on a POSTed [[Filters|filter]], where the post payload is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&amp;quot;query&amp;quot;:&amp;quot;Token=?&amp;quot;, &amp;quot;args&amp;quot;:[&amp;quot;the-token-value&amp;quot;]}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* POST /v1/thing - Creates a new entity of the given type. The payload is simply the fields and properties of the entity.&lt;br /&gt;
&lt;br /&gt;
Properties are set as well if you need some more advanced temporary values. This is used by, for example, &amp;quot;password&amp;quot; on User which is not directly stored but instead a hash of it is.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* POST /v1/thing/14 - Where 14 is an ID. Updates the entity with the given ID. The payload is the same as for creation.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* DELETE /v1/thing/14 - Deletes the given entity by its ID. Returns the entity as it was just before it was deleted.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* GET /v1/thing/14 - Loads a single item by its ID. This is what &amp;lt;[[Content]]&amp;gt; uses internally, via webRequest.&lt;br /&gt;
&lt;br /&gt;
= Includes =&lt;br /&gt;
&lt;br /&gt;
[[Includes]] are a mechanism in SocialStack for getting related data in the same API call. They are available on core endpoints such as load and list, and are simply a query string parameter of the includable fields that you would like to obtain.&lt;br /&gt;
&lt;br /&gt;
GET /v1/thing/14?includes=creatorUser&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you&amp;#039;re not sure what includes the API currently has, you can use a wildcard:&lt;br /&gt;
&lt;br /&gt;
GET /v1/thing/14?includes=*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If there is more than one that you would like, they are comma separated:&lt;br /&gt;
&lt;br /&gt;
GET /v1/thing/14?includes=creatorUser,tags&lt;/div&gt;</summary>
		<author><name>2A02:C7F:22BE:A500:498:3225:1A16:A72D</name></author>
	</entry>
	<entry>
		<id>https://wiki.socialstack.dev/index.php?title=Content&amp;diff=100</id>
		<title>Content</title>
		<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=Content&amp;diff=100"/>
		<updated>2022-07-05T18:21:03Z</updated>

		<summary type="html">&lt;p&gt;2A02:C7F:22BE:A500:498:3225:1A16:A72D: Created page with &amp;quot;&amp;lt;Content&amp;gt; is a React component which is closely related to &amp;lt;Loop&amp;gt;. They both are convenience components for obtaining data from your API; unlike Loop, Content is for grabb...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;Content&amp;gt; is a React component which is closely related to &amp;lt;[[Loop]]&amp;gt;. They both are convenience components for obtaining data from your API; unlike Loop, Content is for grabbing a singular item.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;js&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
import Content from &amp;#039;UI/Content&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
     &amp;lt;Content type=&amp;#039;user&amp;#039; id={14}&amp;gt;&lt;br /&gt;
       {&lt;br /&gt;
           (user, loading) =&amp;gt; {&lt;br /&gt;
                  if(loading) {&lt;br /&gt;
                      return &amp;#039;Getting user data..&amp;#039;;&lt;br /&gt;
                  }&lt;br /&gt;
                  &lt;br /&gt;
                  if(!user){&lt;br /&gt;
                      return &amp;#039;User was not found.&amp;#039;;&lt;br /&gt;
                  }&lt;br /&gt;
                  &lt;br /&gt;
                  return &amp;lt;p&amp;gt;{user.username}&amp;lt;/p&amp;gt;;&lt;br /&gt;
           }&lt;br /&gt;
       }&lt;br /&gt;
     &amp;lt;/Content&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Primary Content =&lt;br /&gt;
&lt;br /&gt;
On [[Editing_Pages|pages with primary content]], &amp;lt;Content&amp;gt; can be used to directly obtain the primary content object:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;js&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
import Content from &amp;#039;UI/Content&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
     &amp;lt;Content primary&amp;gt;&lt;br /&gt;
       {&lt;br /&gt;
           (blogPost, loading) =&amp;gt; {&lt;br /&gt;
                  if(loading) {&lt;br /&gt;
                      return &amp;#039;Getting post..&amp;#039;;&lt;br /&gt;
                  }&lt;br /&gt;
                  &lt;br /&gt;
                  if(!blogPost){&lt;br /&gt;
                      return &amp;#039;Post was not found.&amp;#039;;&lt;br /&gt;
                  }&lt;br /&gt;
                  &lt;br /&gt;
                  return &amp;lt;h1&amp;gt;{blogPost.title}&amp;lt;/h1&amp;gt;;&lt;br /&gt;
           }&lt;br /&gt;
       }&lt;br /&gt;
     &amp;lt;/Content&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Includes =&lt;br /&gt;
&lt;br /&gt;
[[Includes]] are a mechanism in SocialStack for obtaining related data in the same API call. They are a feature of the [[public API]] but are exposed via Content too:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;js&amp;quot;&amp;gt;&lt;br /&gt;
    import Content from &amp;#039;UI/Content&amp;#039;;&lt;br /&gt;
    &lt;br /&gt;
    ...&lt;br /&gt;
    &lt;br /&gt;
    &amp;lt;Content type=&amp;#039;page&amp;#039; id={1} includes={[&amp;#039;creatorUser&amp;#039;]}&amp;gt;&lt;br /&gt;
        {(page, loading) =&amp;gt; {&lt;br /&gt;
            if(loading){&lt;br /&gt;
                // Just an example.&lt;br /&gt;
                return &amp;#039;Loading..&amp;#039;;&lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
            if(!page){&lt;br /&gt;
                return &amp;#039;Page does not exist&amp;#039;;&lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
            return &amp;lt;div&amp;gt;&lt;br /&gt;
                The page &amp;quot;{page.title}&amp;quot; was created by {page.creatorUser.username}&lt;br /&gt;
            &amp;lt;/div&amp;gt;;&lt;br /&gt;
        }}&lt;br /&gt;
    &amp;lt;/Content&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>2A02:C7F:22BE:A500:498:3225:1A16:A72D</name></author>
	</entry>
	<entry>
		<id>https://wiki.socialstack.dev/index.php?title=Public_API&amp;diff=99</id>
		<title>Public API</title>
		<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=Public_API&amp;diff=99"/>
		<updated>2022-07-05T18:14:47Z</updated>

		<summary type="html">&lt;p&gt;2A02:C7F:22BE:A500:498:3225:1A16:A72D: Created page with &amp;quot;SocialStack API&amp;#039;s (the C# binary) have a REST web API whose available endpoints originate from the set of controllers in the project. For more detail on the controllers, see t...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SocialStack API&amp;#039;s (the C# binary) have a REST web API whose available endpoints originate from the set of controllers in the project. For more detail on the controllers, see the page about [[API Modules|API modules]].&lt;br /&gt;
&lt;br /&gt;
Note that it is somewhat uncommon to directly use the API. Most of the time people use [[Loop]], Content and occasionally webRequest.&lt;br /&gt;
&lt;br /&gt;
The controllers themselves are extendible - for example if you wanted /v1/user/say-hello to exist, you can do so without editing the underlying default UserController as it is a partial class. Controllers for entity types, which is to say for most parts of a typical SocialStack API, have some common endpoints which are as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;In all cases if you don&amp;#039;t have permission, it will error on you.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
* GET /v1/thing/list - Lists everything of this entity type.&lt;br /&gt;
&lt;br /&gt;
* POST /v1/thing/list, lists based on a POSTed [[filter]], where the post payload is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&amp;quot;query&amp;quot;:&amp;quot;Token=?&amp;quot;, &amp;quot;args&amp;quot;:[&amp;quot;the-token-value&amp;quot;]}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* POST /v1/thing - Creates a new entity of the given type. The payload is simply the fields and properties of the entity.&lt;br /&gt;
&lt;br /&gt;
Properties are set as well if you need some more advanced temporary values. This is used by, for example, &amp;quot;password&amp;quot; on User which is not directly stored but instead a hash of it is.&lt;br /&gt;
&lt;br /&gt;
* POST /v1/thing/14 - Where 14 is an ID. Updates the entity with the given ID. The payload is the same as for creation.&lt;br /&gt;
&lt;br /&gt;
* DELETE /v1/thing/14 - Deletes the given entity by its ID. Returns the entity as it was just before it was deleted.&lt;br /&gt;
&lt;br /&gt;
* GET /v1/thing/14 - Gets a single item by its ID. This is what &amp;lt;[[Content]]&amp;gt; uses internally, via webRequest.&lt;/div&gt;</summary>
		<author><name>2A02:C7F:22BE:A500:498:3225:1A16:A72D</name></author>
	</entry>
	<entry>
		<id>https://wiki.socialstack.dev/index.php?title=Getting_Started&amp;diff=98</id>
		<title>Getting Started</title>
		<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=Getting_Started&amp;diff=98"/>
		<updated>2022-07-05T17:54:06Z</updated>

		<summary type="html">&lt;p&gt;2A02:C7F:22BE:A500:498:3225:1A16:A72D: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
Hello! Welcome to SocialStack, a fully open source modular collection of C# and javascript code used to create modern, ultra high throughput projects which has been tried and tested by big name brands. This guide is targeted at developers so with that in mind, let&amp;#039;s get in to it!&lt;br /&gt;
&lt;br /&gt;
= Installing dependencies =&lt;br /&gt;
&lt;br /&gt;
So, to get started, you&amp;#039;ll need a few things first. Whilst SocialStack does support using multiple database engines, we currently reccommend starting with MySQL. Here&amp;#039;s what you&amp;#039;ll need:&lt;br /&gt;
&lt;br /&gt;
* An editor capable of working with dotnet 6. For example, Visual Studio Code or Visual Studio 2022.&lt;br /&gt;
* Node.js 8+ which is used to run the command line tools&lt;br /&gt;
* MySQL version 8 is reccommended&lt;br /&gt;
* Git, as a new project will also be created as a git repository.&lt;br /&gt;
&lt;br /&gt;
= Setting up the command line tools =&lt;br /&gt;
&lt;br /&gt;
Once you&amp;#039;ve got the dependencies ready, it&amp;#039;s time to setup the [https://www.npmjs.com/package/socialstack command line tools] which we&amp;#039;ll shortly use to create a project. In a nutshell, it is an optional npm package which can be installed globally by running this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
npm i -g socialstack&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this command line tool set (and node.js) are not required by production sites. It&amp;#039;s just a convenience system for installing modules and creating projects.&lt;br /&gt;
&lt;br /&gt;
It&amp;#039;s recommended to configure socialstack tools with the ability to create MySQL databases for you on your development computer. To do this, you&amp;#039;ll need to create a MySQL account on your MySQL instance which it can use and which has the permission to create databases and users. Here&amp;#039;s an example of how to do that:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- Create the user account:&lt;br /&gt;
CREATE USER &amp;#039;sstools&amp;#039;@&amp;#039;localhost&amp;#039; IDENTIFIED BY &amp;#039;ssto0ls.dev&amp;#039;; -- Invent a password here!&lt;br /&gt;
-- Grant that user full access to the db:&lt;br /&gt;
GRANT ALL PRIVILEGES ON *.* TO &amp;#039;sstools&amp;#039;@&amp;#039;localhost&amp;#039; WITH GRANT OPTION;&lt;br /&gt;
FLUSH PRIVILEGES;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can then add this account to your command line tools like so, making sure the password and username matches what you used:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
socialstack configure -u &amp;quot;sstools&amp;quot; -p &amp;quot;ssto0ls.dev&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a global thing, so once you&amp;#039;ve done it you won&amp;#039;t need to do it again. You&amp;#039;re ready to create a project!&lt;br /&gt;
&lt;br /&gt;
= Creating a project =&lt;br /&gt;
&lt;br /&gt;
With the command line tools ready to go, you can then go ahead and create a project like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd myProjectDirectory&lt;br /&gt;
socialstack create helloworld&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will ask if you want to install any additional modules straight away. Just skip this by pressing enter. If your configuration is ok, a database will be created for you as well as the project.&lt;br /&gt;
&lt;br /&gt;
= Starting it up =&lt;br /&gt;
&lt;br /&gt;
With your project created, start it up in a suitable editor (typically that is Visual Studio Code, or Visual Studio 2022) or via the command line by starting the Api.csproj project. Whilst it starts, it will give you a few bits of information:&lt;br /&gt;
&lt;br /&gt;
* It will list which services (provided by modules) are installed and starting up.&lt;br /&gt;
* It will create the database tables and any initial data needed by those services. This is fully automated.&lt;br /&gt;
* It will let you know that a default administration account was created, and what its details are. This happens once; if you missed it you can check the site_user table in your database as it will have one row and the default password is simply &amp;#039;&amp;#039;&amp;#039;admin&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* It lets you know how to get to the instance. This defaults to http://localhost:5050/ which you can navigate to in a browser.&lt;br /&gt;
* It compiles the UI and indicates when its done. This is usually the very last thing that appears and the UI won&amp;#039;t display to you until it completes.&lt;br /&gt;
&lt;br /&gt;
= Going exploring =&lt;br /&gt;
&lt;br /&gt;
With your project started, head over to http://localhost:5050/ in a browser and you should see a barebones homepage with a welcome message. This brings us to the first key point:&lt;br /&gt;
&lt;br /&gt;
&amp;gt;  Pages in SocialStack entirely come from the editable CMS area - this includes administration panel pages too. There&amp;#039;s no fighting against surrounding page templates as the root component(s) on the page are whatever you choose. More on components later!&lt;br /&gt;
&lt;br /&gt;
So, let&amp;#039;s head in to the administration panel and make some changes. Head over to http://localhost:5050/en-admin/ in a browser and you should see a login panel. At this point use the generated administration account to login which will currently default to:&lt;br /&gt;
&lt;br /&gt;
* Username: &amp;#039;&amp;#039;&amp;#039;admin&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* Password: &amp;#039;&amp;#039;&amp;#039;admin&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Once you&amp;#039;ve logged in, in the top left corner is a menu which you can use to get to the list of pages. On this list, find the homepage and open the page editor. [[Editing Pages|Editing a page]] (and more generally how they actually work) is a broad topic on its own so please take a moment to check out [[Editing Pages|that article]] first, then head back here when you&amp;#039;re ready.&lt;br /&gt;
&lt;br /&gt;
= Creating API modules =&lt;br /&gt;
&lt;br /&gt;
Next is a good point to have a go at creating your own API module. A video version of this part of the guide is [https://www.youtube.com/watch?v=4rrfyg4Wk_g available here]. We&amp;#039;ll make something like a list of frequently asked questions. SocialStack tools has a [[generate|generate command]] which creates the basic scaffolding of a new API module for you, so let&amp;#039;s generate that now:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
socialstack generate Api/FrequentlyAskedQuestions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All this does is create a directory with some generated files; i.e. copy/pasting or manually creating one of those directories has the same outcome as there are no hidden indexes or other files to update. In this case, it will be in the directory ProjectRoot/Api/FrequentlyAskedQuestions. It should also appear in the explorer inside an IDE such as Visual Studio. Inside this folder, you&amp;#039;ll see a small collection of files with different purposes, which are explored in [[API Modules|this section of the wiki]]. Take a look there, then head back here when you&amp;#039;re ready.&lt;br /&gt;
&lt;br /&gt;
Next we&amp;#039;ll need to add fields to the generated FAQ type as so far it is just an empty shell. To do that, edit FrequentlyAskedQuestion.cs and add 2 fields:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
/// &amp;lt;summary&amp;gt;&lt;br /&gt;
/// The question people ask.&lt;br /&gt;
/// &amp;lt;/summary&amp;gt;&lt;br /&gt;
[Localized]&lt;br /&gt;
public string Question;&lt;br /&gt;
&lt;br /&gt;
/// &amp;lt;summary&amp;gt;&lt;br /&gt;
/// The answer.&lt;br /&gt;
/// &amp;lt;/summary&amp;gt;&lt;br /&gt;
[Localized]&lt;br /&gt;
public string AnswerJson;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It would also help to be able to see and edit these FAQ&amp;#039;s via the admin panel, so edit FrequentlyAskedQuestionService.cs and uncomment the admin panel pages line.&lt;br /&gt;
&lt;br /&gt;
As you have made changes to C#, you&amp;#039;ll need to restart the API for the changes to take effect. The easiest way is to stop/ start the running project in your IDE. When it starts back up, head back in to the admin panel at http://localhost:5050/en-admin/ and you should see a new link in the menu to your newly created FAQ&amp;#039;s. Have a go at creating and editing some, and then when you&amp;#039;re ready head back over here.&lt;br /&gt;
&lt;br /&gt;
We now have some data in your database and an ability to see and manipulate it with the admin panel. So far so good!&lt;br /&gt;
&lt;br /&gt;
= Creating frontend UI modules =&lt;br /&gt;
&lt;br /&gt;
Next it would be great if you could also list out your FAQs on the actual website so let&amp;#039;s explore that next. This part of the guide is also covered in [https://www.youtube.com/watch?v=YyFNVPwbIz4 a video about Loop], however just like before, it all starts with a generate command:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
socialstack generate UI/Faq/List&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will create a directory in ProjectRoot/UI/Source/Faq/List containing 2 files; a React component and some CSS to go with it.&lt;br /&gt;
&lt;br /&gt;
Note: Changes to the UI are compiled immediately whenever the API is running. That includes creating files, generating modules, editing files and so on - and the updates are usually near instant too.&lt;br /&gt;
&lt;br /&gt;
There&amp;#039;s 3 main convenience ways to access data from the API via a React component - [[Loop|Loop]], Content and webRequest. [[Loop|Loop]] is for a list of things, Content is for just one and webRequest is for any other situation in e.g. useEffect or componentDidMount where you need to grab data without being in a React render function. [[Loop|Loop]] and Content simply sit on top of webRequest and use the [[Public API|public part of the projects API]] (that controllers in your API, which use the services to return the data). We want a list of FAQs here, so we&amp;#039;ll use Loop. Here&amp;#039;s an example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;js&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
import Canvas from &amp;#039;UI/Canvas&amp;#039;;&lt;br /&gt;
import Loop from &amp;#039;UI/Loop&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
export default function List(props){&lt;br /&gt;
    // Loops over the FAQs from the API and also uses a &lt;br /&gt;
    // canvas to display the answer which is visual editor content.&lt;br /&gt;
    return &amp;lt;Loop over=&amp;#039;frequentlyaskedquestion&amp;#039;&amp;gt;{&lt;br /&gt;
        faq =&amp;gt; {&lt;br /&gt;
            return &amp;lt;div&amp;gt;&lt;br /&gt;
                &amp;lt;h1&amp;gt;{faq.question}&amp;lt;/h1&amp;gt;&lt;br /&gt;
                &amp;lt;Canvas&amp;gt;{faq.answerJson}&amp;lt;/Canvas&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;;&lt;br /&gt;
        }&lt;br /&gt;
    }&amp;lt;/Loop&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Loop.propTypes = {}; // No props used on this list.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save the file, and then because we specified an empty propTypes object, the page editor will now recognise the component and list it in the add window. So if you head back over to the admin panel, you&amp;#039;ll then be able to add this component to the page. Alternatively if you prefer writing the JSON, the page JSON looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&amp;quot;t&amp;quot;:&amp;quot;UI/Faq/List&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice that the name matches what you generated, and is the same as the filepath minus the &amp;quot;Source&amp;quot; folder.&lt;/div&gt;</summary>
		<author><name>2A02:C7F:22BE:A500:498:3225:1A16:A72D</name></author>
	</entry>
	<entry>
		<id>https://wiki.socialstack.dev/index.php?title=Services&amp;diff=97</id>
		<title>Services</title>
		<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=Services&amp;diff=97"/>
		<updated>2022-07-05T17:37:29Z</updated>

		<summary type="html">&lt;p&gt;2A02:C7F:22BE:A500:498:3225:1A16:A72D: Created page with &amp;quot;Services are the way how parts of a SocialStack API communicate with each other. They are essentially the code to code interfaces between different content types or bits of fu...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Services are the way how parts of a SocialStack API communicate with each other. They are essentially the code to code interfaces between different content types or bits of functionality inside your API. They are instanced once at startup and can can use dependency injection to access other services:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public ThingService(UserService userService) {&lt;br /&gt;
&lt;br /&gt;
    Events.Thing.BeforeCreate.AddEventListener(async (Context context, Thing thing) =&amp;gt; {&lt;br /&gt;
        if(thing == null){&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        // Get the creator user (this is likely the same as context.User).&lt;br /&gt;
        // Throws if context user is not permitted to access this data.&lt;br /&gt;
        var aUser = await userService.Get(context, thing.UserId);&lt;br /&gt;
        &lt;br /&gt;
        // Do something with aUser here!&lt;br /&gt;
        &lt;br /&gt;
        return thing;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Getting a service =&lt;br /&gt;
&lt;br /&gt;
There&amp;#039;s two ways to get a service - either by C# dependency injection:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
    public ThingService(UserService userService) {&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or when dependency injection isn&amp;#039;t available due to either a cyclical dependency or simply being outside the scope of another service, you can use Services.Get. Note that this call will return null if the services have not been instanced yet; you can guarantee success if you wait until at least the Events.Service.AfterStart event triggers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
    var userService = Services.Get&amp;lt;UserService&amp;gt;(); // In Startup namespace&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Common Features =&lt;br /&gt;
&lt;br /&gt;
Services contain a variety of common features for doing common tasks such as getting an object, creating one etc. Here&amp;#039;s the main usage examples of each:&lt;br /&gt;
&lt;br /&gt;
* Get - Get an entity from the service by its ID which is usually a uint.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
    uint entityId = 14;&lt;br /&gt;
    var entity = await aService.Get(context, entityId);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
entityId could be e.g. a user ID, aService is the UserService and entity is therefore a User object.&lt;br /&gt;
&lt;br /&gt;
* Delete - Deletes an entity by its ID which is usually a uint.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
    uint entityId = 14;&lt;br /&gt;
    await aService.Delete(context, entityId);&lt;br /&gt;
    &lt;br /&gt;
    // Or:&lt;br /&gt;
    await aService.Delete(context, entity);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
entityId could be e.g. a user ID, aService is the UserService and entity is therefore a User object.&lt;br /&gt;
&lt;br /&gt;
* Where - Used to list multiple entities from the service with a [[filter|filter string]]. Note that it is possible to entirely avoid all allocations with this part of the API - ListAll is just one of the available methods.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
    string token = &amp;quot;&amp;quot;;&lt;br /&gt;
    var listOfResults = await aService.Where(&amp;quot;Token=?&amp;quot;).Bind(tokenString).ListAll(context);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Create - Creates an entity in the target service.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    var thingEntity = await aService.Create(context, new Thing(){&lt;br /&gt;
        Token = &amp;quot;123123&amp;quot;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Update - Updates an entity in the target service. Update uses a callback mechanism as this helps avoid allocations and allows internal field comparisons to happen to be able to easily identify which fields have changed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
    var thingEntity = await aService.Update(context, thingEntity, (Context context, Thing toUpdate, Thing original) =&amp;gt; {&lt;br /&gt;
        toUpdate.Token = &amp;quot;something-else&amp;quot;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Service Permissions =&lt;br /&gt;
&lt;br /&gt;
The permissions system is also modular in that it adds an event handler on the various core events (like create, delete and so on) for a particular content type. This means that when you access a service from some other part of the code, your current [[API Context|context]] must be permitted to access it. It also means that the event handler can be removed should you wish to do so, although naturally, removing the permission system is likely not a good idea on any project!&lt;br /&gt;
&lt;br /&gt;
== Ignoring the permissions ==&lt;br /&gt;
&lt;br /&gt;
You can, however, ask a particular request to ignore the permission system all together. This effectively just makes the above event handler skip itself. This happens in situations where the incoming user is not permitted to generally access a certain piece of data, but the API internally needs to check something. Password resets are one example - the user (and their context) is anonymous, and anonymous users certainly shouldn&amp;#039;t be able to publicly view any password resets. They can however potentially access one of them if a token value is correct, so that token lookup can be done by ignoring the permission system. That is done like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// Won&amp;#039;t throw with a permissions failure&lt;br /&gt;
var aUser = await userService.Get(context, thing.UserId, DataOptions.IgnorePermissions);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
DataOptions is generally available on many service methods - Create, Get, Where and so on - so you can skip over the permission check whenever necessary.&lt;/div&gt;</summary>
		<author><name>2A02:C7F:22BE:A500:498:3225:1A16:A72D</name></author>
	</entry>
	<entry>
		<id>https://wiki.socialstack.dev/index.php?title=API_Modules&amp;diff=96</id>
		<title>API Modules</title>
		<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=API_Modules&amp;diff=96"/>
		<updated>2022-07-05T17:16:43Z</updated>

		<summary type="html">&lt;p&gt;2A02:C7F:22BE:A500:498:3225:1A16:A72D: Created page with &amp;quot;A newly regularly generated API module has 5 files. Assuming you did &amp;#039;&amp;#039;&amp;#039;socialstack generate Api/Things&amp;#039;&amp;#039;&amp;#039;, here&amp;#039;s what each of them is for:  = Events.cs =  When something hap...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A newly regularly generated API module has 5 files. Assuming you did &amp;#039;&amp;#039;&amp;#039;socialstack generate Api/Things&amp;#039;&amp;#039;&amp;#039;, here&amp;#039;s what each of them is for:&lt;br /&gt;
&lt;br /&gt;
= Events.cs =&lt;br /&gt;
&lt;br /&gt;
When something happens in your API, an event is triggered. By default all entities have a common set of events for things like creation/ updates/ deletion etc, but it can be extended by defining a custom event type. This is detailed more on [[Events|the page about events]]. One of the core goals of events in SocialStack is for them to be extremely fast and also easy to use with IDE autofilling, so these auto generated files exist to enable those statically typed naming in the form of Events.Thing.BeforeCreate and so on.&lt;br /&gt;
&lt;br /&gt;
Event handlers, including for a services own content type, are typically added inside service constructors.&lt;br /&gt;
&lt;br /&gt;
= Thing.cs =&lt;br /&gt;
&lt;br /&gt;
This is the entity description file. It describes what fields are on the entity. In a nutshell, fields are stored in the database and properties are not. There are some conveniences around field naming which is described on [[Entities|the entities page]].&lt;br /&gt;
&lt;br /&gt;
= ThingService.cs =&lt;br /&gt;
&lt;br /&gt;
The [[services|service]], a singleton (instanced once at startup), is used for getting/ listing/ deleting/ updating/ creating an entity. For example if you want to get hold of a user&amp;#039;s information, you would ask the UserService. Services support C# dependency injection but can also be obtained via &amp;#039;&amp;#039;&amp;#039;Services.Get&amp;lt;UserService&amp;gt;()&amp;#039;&amp;#039;&amp;#039;, with Services in the Startup namespace.&lt;br /&gt;
&lt;br /&gt;
Often, event handlers are placed inside the service&amp;#039;s constructor in order to validate your entity or e.g. add custom field values to it whilst it is being created. It&amp;#039;s very common for e.g. ThingService to have Events.Thing.BeforeUpdate and so on inside its own constructor - this allows flexibility in the form of other modules actually unregistering those handlers, if it has a goal of heavily overriding default behaviours.&lt;br /&gt;
&lt;br /&gt;
= ThingController.cs =&lt;br /&gt;
&lt;br /&gt;
Controllers are the web API endpoints and effectively represent the main user facing frontage of your site. Just like with services, the controllers have a series of common convenience endpoints which are usually accessed with webRequest or [[Loop|Loop]] on the frontend.&lt;br /&gt;
&lt;br /&gt;
= Permissions.cs =&lt;br /&gt;
&lt;br /&gt;
This file is used to define the installable, base permissions for your module. It should represent the most common scenario that you expect to happen. For example, password resets should never be publicly visible - and that is going to be quite universal on most websites. These base permission grants can however be overridden in the admin panel, or with other event listeners. When creating permission grants in code, they should target the core roles, particularly if the intent is to make a portable module which can be copied or installed easily on to other projects.&lt;br /&gt;
&lt;br /&gt;
For more information on what the roles are and how the grants work, take a look at the [[permissions|permissions article]].&lt;/div&gt;</summary>
		<author><name>2A02:C7F:22BE:A500:498:3225:1A16:A72D</name></author>
	</entry>
	<entry>
		<id>https://wiki.socialstack.dev/index.php?title=Getting_Started&amp;diff=95</id>
		<title>Getting Started</title>
		<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=Getting_Started&amp;diff=95"/>
		<updated>2022-07-05T16:59:57Z</updated>

		<summary type="html">&lt;p&gt;2A02:C7F:22BE:A500:498:3225:1A16:A72D: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
Hello! Welcome to SocialStack, a fully open source modular collection of C# and javascript code used to create modern, ultra high throughput projects which has been tried and tested by big name brands. This guide is targeted at developers so with that in mind, let&amp;#039;s get in to it!&lt;br /&gt;
&lt;br /&gt;
= Installing dependencies =&lt;br /&gt;
&lt;br /&gt;
So, to get started, you&amp;#039;ll need a few things first. Whilst SocialStack does support using multiple database engines, we currently reccommend starting with MySQL. Here&amp;#039;s what you&amp;#039;ll need:&lt;br /&gt;
&lt;br /&gt;
* An editor capable of working with dotnet 6. For example, Visual Studio Code or Visual Studio 2022.&lt;br /&gt;
* Node.js 8+ which is used to run the command line tools&lt;br /&gt;
* MySQL version 8 is reccommended&lt;br /&gt;
* Git, as a new project will also be created as a git repository.&lt;br /&gt;
&lt;br /&gt;
= Setting up the command line tools =&lt;br /&gt;
&lt;br /&gt;
Once you&amp;#039;ve got the dependencies ready, it&amp;#039;s time to setup the [https://www.npmjs.com/package/socialstack command line tools] which we&amp;#039;ll shortly use to create a project. In a nutshell, it is an optional npm package which can be installed globally by running this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
npm i -g socialstack&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this command line tool set (and node.js) are not required by production sites. It&amp;#039;s just a convenience system for installing modules and creating projects.&lt;br /&gt;
&lt;br /&gt;
It&amp;#039;s recommended to configure socialstack tools with the ability to create MySQL databases for you on your development computer. To do this, you&amp;#039;ll need to create a MySQL account on your MySQL instance which it can use and which has the permission to create databases and users. Here&amp;#039;s an example of how to do that:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- Create the user account:&lt;br /&gt;
CREATE USER &amp;#039;sstools&amp;#039;@&amp;#039;localhost&amp;#039; IDENTIFIED BY &amp;#039;ssto0ls.dev&amp;#039;; -- Invent a password here!&lt;br /&gt;
-- Grant that user full access to the db:&lt;br /&gt;
GRANT ALL PRIVILEGES ON *.* TO &amp;#039;sstools&amp;#039;@&amp;#039;localhost&amp;#039; WITH GRANT OPTION;&lt;br /&gt;
FLUSH PRIVILEGES;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can then add this account to your command line tools like so, making sure the password and username matches what you used:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
socialstack configure -u &amp;quot;sstools&amp;quot; -p &amp;quot;ssto0ls.dev&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a global thing, so once you&amp;#039;ve done it you won&amp;#039;t need to do it again. You&amp;#039;re ready to create a project!&lt;br /&gt;
&lt;br /&gt;
= Creating a project =&lt;br /&gt;
&lt;br /&gt;
With the command line tools ready to go, you can then go ahead and create a project like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd myProjectDirectory&lt;br /&gt;
socialstack create helloworld&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will ask if you want to install any additional modules straight away. Just skip this by pressing enter. If your configuration is ok, a database will be created for you as well as the project.&lt;br /&gt;
&lt;br /&gt;
= Starting it up =&lt;br /&gt;
&lt;br /&gt;
With your project created, start it up in a suitable editor (typically that is Visual Studio Code, or Visual Studio 2022) or via the command line by starting the Api.csproj project. Whilst it starts, it will give you a few bits of information:&lt;br /&gt;
&lt;br /&gt;
* It will list which services (provided by modules) are installed and starting up.&lt;br /&gt;
* It will create the database tables and any initial data needed by those services. This is fully automated.&lt;br /&gt;
* It will let you know that a default administration account was created, and what its details are. This happens once; if you missed it you can check the site_user table in your database as it will have one row and the default password is simply &amp;#039;&amp;#039;&amp;#039;admin&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* It lets you know how to get to the instance. This defaults to http://localhost:5050/ which you can navigate to in a browser.&lt;br /&gt;
* It compiles the UI and indicates when its done. This is usually the very last thing that appears and the UI won&amp;#039;t display to you until it completes.&lt;br /&gt;
&lt;br /&gt;
= Going exploring =&lt;br /&gt;
&lt;br /&gt;
With your project started, head over to http://localhost:5050/ in a browser and you should see a barebones homepage with a welcome message. This brings us to the first key point:&lt;br /&gt;
&lt;br /&gt;
&amp;gt;  Pages in SocialStack entirely come from the editable CMS area - this includes administration panel pages too. There&amp;#039;s no fighting against surrounding page templates as the root component(s) on the page are whatever you choose. More on components later!&lt;br /&gt;
&lt;br /&gt;
So, let&amp;#039;s head in to the administration panel and make some changes. Head over to http://localhost:5050/en-admin/ in a browser and you should see a login panel. At this point use the generated administration account to login which will currently default to:&lt;br /&gt;
&lt;br /&gt;
* Username: &amp;#039;&amp;#039;&amp;#039;admin&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* Password: &amp;#039;&amp;#039;&amp;#039;admin&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Once you&amp;#039;ve logged in, in the top left corner is a menu which you can use to get to the list of pages. On this list, find the homepage and open the page editor. [[Editing Pages|Editing a page]] (and more generally how they actually work) is a broad topic on its own so please take a moment to check out [[Editing Pages|that article]] first, then head back here when you&amp;#039;re ready.&lt;br /&gt;
&lt;br /&gt;
= Creating components and API modules =&lt;br /&gt;
&lt;br /&gt;
Next is a good point to have a go at creating your own API module. A video version of this part of the guide is [https://www.youtube.com/watch?v=4rrfyg4Wk_g available here]. We&amp;#039;ll make something like a list of frequently asked questions. SocialStack tools has a [[generate|generate command]] which creates the basic scaffolding of a new API module for you, so let&amp;#039;s generate that now:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
socialstack generate Api/FrequentlyAskedQuestions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All this does is create a directory with some generated files; i.e. copy/pasting or manually creating one of those directories has the same outcome as there are no hidden indexes or other files to update. In this case, it will be in the directory ProjectRoot/Api/FrequentlyAskedQuestions. It should also appear in the explorer inside an IDE such as Visual Studio. Inside this folder, you&amp;#039;ll see a small collection of files with different purposes, which are explored in [[API Modules|this section of the wiki]]. Take a look there, then head back here when you&amp;#039;re ready.&lt;br /&gt;
&lt;br /&gt;
Next we&amp;#039;ll need to add fields to the generated FAQ type as so far it is just an empty shell. To do that, edit FrequentlyAskedQuestion.cs and add 2 fields:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
/// &amp;lt;summary&amp;gt;&lt;br /&gt;
/// The question people ask.&lt;br /&gt;
/// &amp;lt;/summary&amp;gt;&lt;br /&gt;
[Localized]&lt;br /&gt;
public string Question;&lt;br /&gt;
&lt;br /&gt;
/// &amp;lt;summary&amp;gt;&lt;br /&gt;
/// The answer.&lt;br /&gt;
/// &amp;lt;/summary&amp;gt;&lt;br /&gt;
[Localized]&lt;br /&gt;
public string AnswerJson;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>2A02:C7F:22BE:A500:498:3225:1A16:A72D</name></author>
	</entry>
	<entry>
		<id>https://wiki.socialstack.dev/index.php?title=Modules&amp;diff=94</id>
		<title>Modules</title>
		<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=Modules&amp;diff=94"/>
		<updated>2022-07-05T13:00:04Z</updated>

		<summary type="html">&lt;p&gt;2A02:C7F:22BE:A500:498:3225:1A16:A72D: Created page with &amp;quot;Modules in SocialStack are the main way to create small, portable, easy to test units of code. The best way to create a new one is via the generate command, but y...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Modules in SocialStack are the main way to create small, portable, easy to test units of code. The best way to create a new one is via the [[generate|generate command]], but you can also install public ones. Importantly a module should be self-contained as much as possible with the smallest dependency footprint.&lt;br /&gt;
&lt;br /&gt;
= Making C# code modular =&lt;br /&gt;
&lt;br /&gt;
As C# is a statically typed language, it is inherently more rigid than languages like Javascript on the frontend. However, &amp;#039;&amp;#039;&amp;#039;partial classes&amp;#039;&amp;#039;&amp;#039; are very useful for this end goal of making extensible units of code. For this reason, every class outputted by the generate command is partial.&lt;br /&gt;
&lt;br /&gt;
Why are partial classes useful? Let&amp;#039;s take the User type for example. Modules want to extend this one all the time - a 2 factor authentication plugin may want to store some data in the user objects, modules for adding names and addresses and so on. Because the installed User class is partial, you can add fields to it without editing the original file. By adding fields to the User type, any User reference you end up with - either via the API, admin panel, events etc - will then have that field on it. Because the database storage mechanism is also generic, it will get automatically stored too. Therefore, adding a field to the User type is as simple as adding a file like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
namespace Api.Users;&lt;br /&gt;
&lt;br /&gt;
public partial class User{&lt;br /&gt;
    public string MyCustomField;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Secondly, we also have a very fast and flexible events system inside the API. When a user object is created, an event is triggered (specifically that is Events.User.BeforeCreate and AfterCreate), which then any module can subscribe to. Just like with the content type itself, common events are fully automatic but you can also create your own.&lt;br /&gt;
&lt;br /&gt;
Event listeners should be added once at startup. This means you&amp;#039;ll either put them in service constructors, or in special EventListener classes which are constructed as a singleton for you.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[EventListener]&lt;br /&gt;
public class MyEventListener {&lt;br /&gt;
    &lt;br /&gt;
    public MyEventListener(){&lt;br /&gt;
&lt;br /&gt;
        Events.User.BeforeCreate.AddEventListener(async (Context context, User user) =&amp;gt; {&lt;br /&gt;
            if(user == null){&lt;br /&gt;
                return null;&lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
            // can await something here if needed!&lt;br /&gt;
            // Because we&amp;#039;re in a beforeCreate, we can edit the object including populating custom fields or validating them.&lt;br /&gt;
            // If we have a validation failure, throw a PublicException.&lt;br /&gt;
            // throw new PublicException(&amp;quot;Incorrect date of birth&amp;quot;, &amp;quot;dob/invalid&amp;quot;);&lt;br /&gt;
            return user;&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>2A02:C7F:22BE:A500:498:3225:1A16:A72D</name></author>
	</entry>
	<entry>
		<id>https://wiki.socialstack.dev/index.php?title=Editing_Pages&amp;diff=93</id>
		<title>Editing Pages</title>
		<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=Editing_Pages&amp;diff=93"/>
		<updated>2022-07-05T12:39:57Z</updated>

		<summary type="html">&lt;p&gt;2A02:C7F:22BE:A500:498:3225:1A16:A72D: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Pages in SocialStack are a [[Entities|content type]] with a JSON structure that describes the [[Components|components]] on the page. We call this JSON structure [[Canvas|canvas JSON]]. A page can be both a singular URL, such as an about page on your website, or multiple, such as a page which displays blog posts.&lt;br /&gt;
&lt;br /&gt;
That&amp;#039;s quite a bit to unpack, so let&amp;#039;s get into the details.&lt;br /&gt;
&lt;br /&gt;
= What actually is a page anyway? =&lt;br /&gt;
&lt;br /&gt;
Pages started life like most other modules in SocialStack - via the [[Generate|generate command]]. This means it fundamentally is no different from other modules, aside from it is simply included in the list of default modules as &amp;quot;Api/Pages&amp;quot;. You can actually uninstall this module and you&amp;#039;ll end up with an API only headless instance. This also means that they use an automated database structure as well as a service.&lt;br /&gt;
&lt;br /&gt;
Pages have a database stored field called BodyJson which is a textual value that contains JSON. [[Canvas|Canvas JSON]] is a very light representation of a tree of components which, when rendered by the Canvas component on the frontend, results in your page on the screen.&lt;br /&gt;
&lt;br /&gt;
Pages also have a URL field which indicates simply which URL(s) this page will be served for. For example, a page with a url of &amp;#039;&amp;#039;&amp;#039;/about&amp;#039;&amp;#039;&amp;#039; will be served on example.com/about. URLs can also support tokens such that one page can be used to display multiple dynamic objects - a blog or forum for example. See the section about tokens below for more information on this.&lt;br /&gt;
&lt;br /&gt;
Canvas JSON is not specific to pages - it is used by emails too for example. The canvas JSON editor can be used by any content type by creating a string field which ends with &amp;quot;Json&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
= How the editor works =&lt;br /&gt;
&lt;br /&gt;
The editor itself is designed to be a what-you-see-is-what-you-get experience, but there are some things to be aware of.&lt;br /&gt;
&lt;br /&gt;
Firstly, it has an add component window which lists available components on the site. This window will only display components which have React propTypes set. It can be an empty object; it just needs to be not null. When generating a new UI component with the [[Generate|generate command]], it will also include a commented out propTypes too.&lt;br /&gt;
&lt;br /&gt;
Secondly, the propTypes are directly used to establish what options a component has. For example if you drop an image onto the canvas, the UI/Image component has propTypes which include which actual file to display. A generated component also has some examples of these too.&lt;br /&gt;
&lt;br /&gt;
Finally, the editor does also have a source view which lets you see and edit the underlying canvas JSON instead. This can often be useful for quickly fixing a layout which is otherwise awkward or ambiguous in the visual view. Check out the guide on [[Canvas|canvas JSON]] for more details on valid content here.&lt;br /&gt;
&lt;br /&gt;
= URL Tokens =&lt;br /&gt;
&lt;br /&gt;
You may have a page which displays, for example, blog posts. This is achieved by using tokens in your URL, like this:&lt;br /&gt;
&lt;br /&gt;
/blog/{blogpost.slug}/&lt;br /&gt;
&lt;br /&gt;
The value of a token is usually {contentType.fieldName} meaning tokens will work for most content including custom types. It doesn&amp;#039;t have to be a content type though - you can also use arbritrary token values, like this:&lt;br /&gt;
&lt;br /&gt;
/password-reset/{token}/&lt;br /&gt;
&lt;br /&gt;
The value of this token is accessible in the same way (see the section below).&lt;br /&gt;
&lt;br /&gt;
You can use multiple tokens in a single URL too, like this:&lt;br /&gt;
&lt;br /&gt;
/blog/{blog.slug}/{blogpost.slug}/&lt;br /&gt;
&lt;br /&gt;
== Accessing the values ==&lt;br /&gt;
&lt;br /&gt;
On the frontend the token values are available via the page router, which can be used via a React hook or consumer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;js&amp;quot;&amp;gt;&lt;br /&gt;
import {useRouter} from &amp;#039;UI/Session&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
var {pageState} = useRouter();&lt;br /&gt;
&lt;br /&gt;
// pageState.tokens, pageState.tokenValues&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The tokens is an array of each token discovered from the URL.&lt;br /&gt;
&lt;br /&gt;
== Primary content type ==&lt;br /&gt;
&lt;br /&gt;
If you use at least one content type token (such as {blogpost.slug}) in your URL, the &amp;#039;&amp;#039;&amp;#039;very last&amp;#039;&amp;#039;&amp;#039; of these tokens in the URL will be resolved to the content object it refers to, and this object is then called the primary content of the page.&lt;br /&gt;
&lt;br /&gt;
For example going back to blog posts:&lt;br /&gt;
&lt;br /&gt;
/blog/{blogpost.slug}/&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;primary content&amp;quot; of the page at /blog/hello-world/ will be a BlogPost with the field called &amp;quot;Slug&amp;quot; equal to the value &amp;quot;hello-world&amp;quot;. The primary content on the page has some special use as it can be used in the page title, description etc amongst other things.&lt;br /&gt;
&lt;br /&gt;
For convenience in React, you can quickly access the current primary content on a page like this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;js&amp;quot;&amp;gt;&lt;br /&gt;
import Content from &amp;#039;UI/Content&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;Content primary&amp;gt;&lt;br /&gt;
{primaryObject =&amp;gt; {&lt;br /&gt;
  if(!primaryObject) {&lt;br /&gt;
    return &amp;#039;Loading..&amp;#039;;&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  // primaryObject is e.g. a BlogPost, depending on which page we&amp;#039;re on&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/Content&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Page title =&lt;br /&gt;
&lt;br /&gt;
The title field of a page is used for setting the title bar of the page and will also appear on e.g. search results. If your page has primary content on it (see above), you can use tokens in the page title as well. Again continuing with the BlogPost example, that may be simply the title of the post:&lt;br /&gt;
&lt;br /&gt;
My Great Site | {blogpost.title}&lt;/div&gt;</summary>
		<author><name>2A02:C7F:22BE:A500:498:3225:1A16:A72D</name></author>
	</entry>
	<entry>
		<id>https://wiki.socialstack.dev/index.php?title=Editing_Pages&amp;diff=92</id>
		<title>Editing Pages</title>
		<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=Editing_Pages&amp;diff=92"/>
		<updated>2022-07-05T12:39:37Z</updated>

		<summary type="html">&lt;p&gt;2A02:C7F:22BE:A500:498:3225:1A16:A72D: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Pages in SocialStack are a [[Content Types|content type]] with a JSON structure that describes the [[Components|components]] on the page. We call this JSON structure [[Canvas|canvas JSON]]. A page can be both a singular URL, such as an about page on your website, or multiple, such as a page which displays blog posts.&lt;br /&gt;
&lt;br /&gt;
That&amp;#039;s quite a bit to unpack, so let&amp;#039;s get into the details.&lt;br /&gt;
&lt;br /&gt;
= What actually is a page anyway? =&lt;br /&gt;
&lt;br /&gt;
Pages started life like most other modules in SocialStack - via the [[Generate|generate command]]. This means it fundamentally is no different from other modules, aside from it is simply included in the list of default modules as &amp;quot;Api/Pages&amp;quot;. You can actually uninstall this module and you&amp;#039;ll end up with an API only headless instance. This also means that they use an automated database structure as well as a service.&lt;br /&gt;
&lt;br /&gt;
Pages have a database stored field called BodyJson which is a textual value that contains JSON. [[Canvas|Canvas JSON]] is a very light representation of a tree of components which, when rendered by the Canvas component on the frontend, results in your page on the screen.&lt;br /&gt;
&lt;br /&gt;
Pages also have a URL field which indicates simply which URL(s) this page will be served for. For example, a page with a url of &amp;#039;&amp;#039;&amp;#039;/about&amp;#039;&amp;#039;&amp;#039; will be served on example.com/about. URLs can also support tokens such that one page can be used to display multiple dynamic objects - a blog or forum for example. See the section about tokens below for more information on this.&lt;br /&gt;
&lt;br /&gt;
Canvas JSON is not specific to pages - it is used by emails too for example. The canvas JSON editor can be used by any content type by creating a string field which ends with &amp;quot;Json&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
= How the editor works =&lt;br /&gt;
&lt;br /&gt;
The editor itself is designed to be a what-you-see-is-what-you-get experience, but there are some things to be aware of.&lt;br /&gt;
&lt;br /&gt;
Firstly, it has an add component window which lists available components on the site. This window will only display components which have React propTypes set. It can be an empty object; it just needs to be not null. When generating a new UI component with the [[Generate|generate command]], it will also include a commented out propTypes too.&lt;br /&gt;
&lt;br /&gt;
Secondly, the propTypes are directly used to establish what options a component has. For example if you drop an image onto the canvas, the UI/Image component has propTypes which include which actual file to display. A generated component also has some examples of these too.&lt;br /&gt;
&lt;br /&gt;
Finally, the editor does also have a source view which lets you see and edit the underlying canvas JSON instead. This can often be useful for quickly fixing a layout which is otherwise awkward or ambiguous in the visual view. Check out the guide on [[Canvas|canvas JSON]] for more details on valid content here.&lt;br /&gt;
&lt;br /&gt;
= URL Tokens =&lt;br /&gt;
&lt;br /&gt;
You may have a page which displays, for example, blog posts. This is achieved by using tokens in your URL, like this:&lt;br /&gt;
&lt;br /&gt;
/blog/{blogpost.slug}/&lt;br /&gt;
&lt;br /&gt;
The value of a token is usually {contentType.fieldName} meaning tokens will work for most content including custom types. It doesn&amp;#039;t have to be a content type though - you can also use arbritrary token values, like this:&lt;br /&gt;
&lt;br /&gt;
/password-reset/{token}/&lt;br /&gt;
&lt;br /&gt;
The value of this token is accessible in the same way (see the section below).&lt;br /&gt;
&lt;br /&gt;
You can use multiple tokens in a single URL too, like this:&lt;br /&gt;
&lt;br /&gt;
/blog/{blog.slug}/{blogpost.slug}/&lt;br /&gt;
&lt;br /&gt;
== Accessing the values ==&lt;br /&gt;
&lt;br /&gt;
On the frontend the token values are available via the page router, which can be used via a React hook or consumer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;js&amp;quot;&amp;gt;&lt;br /&gt;
import {useRouter} from &amp;#039;UI/Session&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
var {pageState} = useRouter();&lt;br /&gt;
&lt;br /&gt;
// pageState.tokens, pageState.tokenValues&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The tokens is an array of each token discovered from the URL.&lt;br /&gt;
&lt;br /&gt;
== Primary content type ==&lt;br /&gt;
&lt;br /&gt;
If you use at least one content type token (such as {blogpost.slug}) in your URL, the &amp;#039;&amp;#039;&amp;#039;very last&amp;#039;&amp;#039;&amp;#039; of these tokens in the URL will be resolved to the content object it refers to, and this object is then called the primary content of the page.&lt;br /&gt;
&lt;br /&gt;
For example going back to blog posts:&lt;br /&gt;
&lt;br /&gt;
/blog/{blogpost.slug}/&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;primary content&amp;quot; of the page at /blog/hello-world/ will be a BlogPost with the field called &amp;quot;Slug&amp;quot; equal to the value &amp;quot;hello-world&amp;quot;. The primary content on the page has some special use as it can be used in the page title, description etc amongst other things.&lt;br /&gt;
&lt;br /&gt;
For convenience in React, you can quickly access the current primary content on a page like this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;js&amp;quot;&amp;gt;&lt;br /&gt;
import Content from &amp;#039;UI/Content&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;Content primary&amp;gt;&lt;br /&gt;
{primaryObject =&amp;gt; {&lt;br /&gt;
  if(!primaryObject) {&lt;br /&gt;
    return &amp;#039;Loading..&amp;#039;;&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  // primaryObject is e.g. a BlogPost, depending on which page we&amp;#039;re on&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/Content&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Page title =&lt;br /&gt;
&lt;br /&gt;
The title field of a page is used for setting the title bar of the page and will also appear on e.g. search results. If your page has primary content on it (see above), you can use tokens in the page title as well. Again continuing with the BlogPost example, that may be simply the title of the post:&lt;br /&gt;
&lt;br /&gt;
My Great Site | {blogpost.title}&lt;/div&gt;</summary>
		<author><name>2A02:C7F:22BE:A500:498:3225:1A16:A72D</name></author>
	</entry>
	<entry>
		<id>https://wiki.socialstack.dev/index.php?title=Generate&amp;diff=91</id>
		<title>Generate</title>
		<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=Generate&amp;diff=91"/>
		<updated>2022-07-05T12:34:25Z</updated>

		<summary type="html">&lt;p&gt;2A02:C7F:22BE:A500:498:3225:1A16:A72D: Created page with &amp;quot;SocialStack generate is probably the most convenient command to know and use. Based on the name of the module you want to make, it will generate the files for eith...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SocialStack generate is probably the most convenient command to know and use. Based on the name of the [[Modules|module]] you want to make, it will generate the files for either a React component (a function hook based one by default) or a C# Api one, optionally as a content type.&lt;br /&gt;
&lt;br /&gt;
The command is either the full word &amp;quot;generate&amp;quot; or &amp;quot;g&amp;quot; for short.&lt;br /&gt;
&lt;br /&gt;
== React component ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
socialstack g UI/AboutUs&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
socialstack g Admin/MaintenanceArea&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
socialstack g Email/MarketingGrid&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The files are placed in ProjectRoot/UI/Source, ProjectRoot/Admin/Source or ProjectRoot/Email/Source respectively.&lt;br /&gt;
&lt;br /&gt;
By default it will create the component and a scss styling file too. Both files contain examples of commonly used features from there.&lt;br /&gt;
&lt;br /&gt;
== C# Content type called &amp;quot;Cars&amp;quot; ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
socialstack g Api/Cars&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The files are placed in ProjectRoot/Api. When creating a content type like this, the main file you edit next is the e.g. CarService.cs where you can then comment out the line which generates admin panel pages for you, and then e.g. Car.cs which describes the fields to store (and edit in the admin panel) for the content type. The content type file contains commented out examples of common fields too, like a name.&lt;br /&gt;
&lt;br /&gt;
== C# basic service ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
socialstack g Api/MarketingEmailTimer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The files are placed in ProjectRoot/Api. These things simply start when the services do and are a good place to put generic contentless behaviour which can optionally have configuration via GetConfig.&lt;/div&gt;</summary>
		<author><name>2A02:C7F:22BE:A500:498:3225:1A16:A72D</name></author>
	</entry>
	<entry>
		<id>https://wiki.socialstack.dev/index.php?title=Editing_Pages&amp;diff=90</id>
		<title>Editing Pages</title>
		<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=Editing_Pages&amp;diff=90"/>
		<updated>2022-07-05T12:24:36Z</updated>

		<summary type="html">&lt;p&gt;2A02:C7F:22BE:A500:498:3225:1A16:A72D: Created page with &amp;quot;Pages in SocialStack are a content type with a JSON structure that describes the components on the page. We call this JSON structure Canvas...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Pages in SocialStack are a [[Content Types|content type]] with a JSON structure that describes the [[Components|components]] on the page. We call this JSON structure [[Canvas JSON|canvas JSON]]. A page can be both a singular URL, such as an about page on your website, or multiple, such as a page which displays blog posts.&lt;br /&gt;
&lt;br /&gt;
That&amp;#039;s quite a bit to unpack, so let&amp;#039;s get into the details.&lt;br /&gt;
&lt;br /&gt;
= What actually is a page anyway? =&lt;br /&gt;
&lt;br /&gt;
Pages started life like most other modules in SocialStack - via the [[Generate|generate command]]. This means it fundamentally is no different from other modules, aside from it is simply included in the list of default modules as &amp;quot;Api/Pages&amp;quot;. You can actually uninstall this module and you&amp;#039;ll end up with an API only headless instance. This also means that they use an automated database structure as well as a service.&lt;br /&gt;
&lt;br /&gt;
Pages have a database stored field called BodyJson which is a textual value that contains JSON. [[Canvas JSON|Canvas JSON]] is a very light representation of a tree of components which, when rendered by the Canvas component on the frontend, results in your page on the screen.&lt;br /&gt;
&lt;br /&gt;
Pages also have a URL field which indicates simply which URL(s) this page will be served for. For example, a page with a url of &amp;#039;&amp;#039;&amp;#039;/about&amp;#039;&amp;#039;&amp;#039; will be served on example.com/about. URLs can also support tokens such that one page can be used to display multiple dynamic objects - a blog or forum for example. See the section about tokens below for more information on this.&lt;br /&gt;
&lt;br /&gt;
Canvas JSON is not specific to pages - it is used by emails too for example. The canvas JSON editor can be used by any content type by creating a string field which ends with &amp;quot;Json&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
= How the editor works =&lt;br /&gt;
&lt;br /&gt;
The editor itself is designed to be a what-you-see-is-what-you-get experience, but there are some things to be aware of.&lt;br /&gt;
&lt;br /&gt;
Firstly, it has an add component window which lists available components on the site. This window will only display components which have React propTypes set. It can be an empty object; it just needs to be not null. When generating a new UI component with the [[Generate|generate command]], it will also include a commented out propTypes too.&lt;br /&gt;
&lt;br /&gt;
Secondly, the propTypes are directly used to establish what options a component has. For example if you drop an image onto the canvas, the UI/Image component has propTypes which include which actual file to display. A generated component also has some examples of these too.&lt;br /&gt;
&lt;br /&gt;
Finally, the editor does also have a source view which lets you see and edit the underlying canvas JSON instead. This can often be useful for quickly fixing a layout which is otherwise awkward or ambiguous in the visual view. Check out the guide on [[Canvas JSON|canvas JSON]] for more details on valid content here.&lt;br /&gt;
&lt;br /&gt;
= URL Tokens =&lt;br /&gt;
&lt;br /&gt;
You may have a page which displays, for example, blog posts. This is achieved by using tokens in your URL, like this:&lt;br /&gt;
&lt;br /&gt;
/blog/{blogpost.slug}/&lt;br /&gt;
&lt;br /&gt;
The value of a token is usually {contentType.fieldName} meaning tokens will work for most content including custom types. It doesn&amp;#039;t have to be a content type though - you can also use arbritrary token values, like this:&lt;br /&gt;
&lt;br /&gt;
/password-reset/{token}/&lt;br /&gt;
&lt;br /&gt;
The value of this token is accessible in the same way (see the section below).&lt;br /&gt;
&lt;br /&gt;
You can use multiple tokens in a single URL too, like this:&lt;br /&gt;
&lt;br /&gt;
/blog/{blog.slug}/{blogpost.slug}/&lt;br /&gt;
&lt;br /&gt;
== Accessing the values ==&lt;br /&gt;
&lt;br /&gt;
On the frontend the token values are available via the page router, which can be used via a React hook or consumer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;js&amp;quot;&amp;gt;&lt;br /&gt;
import {useRouter} from &amp;#039;UI/Session&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
var {pageState} = useRouter();&lt;br /&gt;
&lt;br /&gt;
// pageState.tokens, pageState.tokenValues&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The tokens is an array of each token discovered from the URL.&lt;br /&gt;
&lt;br /&gt;
== Primary content type ==&lt;br /&gt;
&lt;br /&gt;
If you use at least one content type token (such as {blogpost.slug}) in your URL, the &amp;#039;&amp;#039;&amp;#039;very last&amp;#039;&amp;#039;&amp;#039; of these tokens in the URL will be resolved to the content object it refers to, and this object is then called the primary content of the page.&lt;br /&gt;
&lt;br /&gt;
For example going back to blog posts:&lt;br /&gt;
&lt;br /&gt;
/blog/{blogpost.slug}/&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;primary content&amp;quot; of the page at /blog/hello-world/ will be a BlogPost with the field called &amp;quot;Slug&amp;quot; equal to the value &amp;quot;hello-world&amp;quot;. The primary content on the page has some special use as it can be used in the page title, description etc amongst other things.&lt;br /&gt;
&lt;br /&gt;
For convenience in React, you can quickly access the current primary content on a page like this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;js&amp;quot;&amp;gt;&lt;br /&gt;
import Content from &amp;#039;UI/Content&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;Content primary&amp;gt;&lt;br /&gt;
{primaryObject =&amp;gt; {&lt;br /&gt;
  if(!primaryObject) {&lt;br /&gt;
    return &amp;#039;Loading..&amp;#039;;&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  // primaryObject is e.g. a BlogPost, depending on which page we&amp;#039;re on&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/Content&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Page title =&lt;br /&gt;
&lt;br /&gt;
The title field of a page is used for setting the title bar of the page and will also appear on e.g. search results. If your page has primary content on it (see above), you can use tokens in the page title as well. Again continuing with the BlogPost example, that may be simply the title of the post:&lt;br /&gt;
&lt;br /&gt;
My Great Site | {blogpost.title}&lt;/div&gt;</summary>
		<author><name>2A02:C7F:22BE:A500:498:3225:1A16:A72D</name></author>
	</entry>
	<entry>
		<id>https://wiki.socialstack.dev/index.php?title=Getting_Started&amp;diff=89</id>
		<title>Getting Started</title>
		<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=Getting_Started&amp;diff=89"/>
		<updated>2022-07-05T11:54:40Z</updated>

		<summary type="html">&lt;p&gt;2A02:C7F:22BE:A500:498:3225:1A16:A72D: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
Hello! Welcome to SocialStack, a fully open source modular collection of C# and javascript code used to create modern, ultra high throughput projects which has been tried and tested by big name brands. This guide is targeted at developers so with that in mind, let&amp;#039;s get in to it!&lt;br /&gt;
&lt;br /&gt;
= Installing dependencies =&lt;br /&gt;
&lt;br /&gt;
So, to get started, you&amp;#039;ll need a few things first. Whilst SocialStack does support using multiple database engines, we currently reccommend starting with MySQL. Here&amp;#039;s what you&amp;#039;ll need:&lt;br /&gt;
&lt;br /&gt;
* An editor capable of working with dotnet 6. For example, Visual Studio Code or Visual Studio 2022.&lt;br /&gt;
* Node.js 8+ which is used to run the command line tools&lt;br /&gt;
* MySQL version 8 is reccommended&lt;br /&gt;
* Git, as a new project will also be created as a git repository.&lt;br /&gt;
&lt;br /&gt;
= Setting up the command line tools =&lt;br /&gt;
&lt;br /&gt;
Once you&amp;#039;ve got the dependencies ready, it&amp;#039;s time to setup the [https://www.npmjs.com/package/socialstack command line tools] which we&amp;#039;ll shortly use to create a project. In a nutshell, it is an optional npm package which can be installed globally by running this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
npm i -g socialstack&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this command line tool set (and node.js) are not required by production sites. It&amp;#039;s just a convenience system for installing modules and creating projects.&lt;br /&gt;
&lt;br /&gt;
It&amp;#039;s recommended to configure socialstack tools with the ability to create MySQL databases for you on your development computer. To do this, you&amp;#039;ll need to create a MySQL account on your MySQL instance which it can use and which has the permission to create databases and users. Here&amp;#039;s an example of how to do that:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- Create the user account:&lt;br /&gt;
CREATE USER &amp;#039;sstools&amp;#039;@&amp;#039;localhost&amp;#039; IDENTIFIED BY &amp;#039;ssto0ls.dev&amp;#039;; -- Invent a password here!&lt;br /&gt;
-- Grant that user full access to the db:&lt;br /&gt;
GRANT ALL PRIVILEGES ON *.* TO &amp;#039;sstools&amp;#039;@&amp;#039;localhost&amp;#039; WITH GRANT OPTION;&lt;br /&gt;
FLUSH PRIVILEGES;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can then add this account to your command line tools like so, making sure the password and username matches what you used:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
socialstack configure -u &amp;quot;sstools&amp;quot; -p &amp;quot;ssto0ls.dev&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a global thing, so once you&amp;#039;ve done it you won&amp;#039;t need to do it again. You&amp;#039;re ready to create a project!&lt;br /&gt;
&lt;br /&gt;
= Creating a project =&lt;br /&gt;
&lt;br /&gt;
With the command line tools ready to go, you can then go ahead and create a project like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd myProjectDirectory&lt;br /&gt;
socialstack create helloworld&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will ask if you want to install any additional modules straight away. Just skip this by pressing enter. If your configuration is ok, a database will be created for you as well as the project.&lt;br /&gt;
&lt;br /&gt;
= Starting it up =&lt;br /&gt;
&lt;br /&gt;
With your project created, start it up in a suitable editor (typically that is Visual Studio Code, or Visual Studio 2022) or via the command line by starting the Api.csproj project. Whilst it starts, it will give you a few bits of information:&lt;br /&gt;
&lt;br /&gt;
* It will list which services (provided by modules) are installed and starting up.&lt;br /&gt;
* It will create the database tables and any initial data needed by those services. This is fully automated.&lt;br /&gt;
* It will let you know that a default administration account was created, and what its details are. This happens once; if you missed it you can check the site_user table in your database as it will have one row and the default password is simply &amp;#039;&amp;#039;&amp;#039;admin&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* It lets you know how to get to the instance. This defaults to http://localhost:5050/ which you can navigate to in a browser.&lt;br /&gt;
* It compiles the UI and indicates when its done. This is usually the very last thing that appears and the UI won&amp;#039;t display to you until it completes.&lt;br /&gt;
&lt;br /&gt;
= Going exploring =&lt;br /&gt;
&lt;br /&gt;
With your project started, head over to http://localhost:5050/ in a browser and you should see a barebones homepage with a welcome message. This brings us to the first key point:&lt;br /&gt;
&lt;br /&gt;
&amp;gt;  Pages in SocialStack entirely come from the editable CMS area - this includes administration panel pages too. There&amp;#039;s no fighting against surrounding page templates as the root component(s) on the page are whatever you choose. More on components later!&lt;br /&gt;
&lt;br /&gt;
So, let&amp;#039;s head in to the administration panel and make some changes. Head over to http://localhost:5050/en-admin/ in a browser and you should see a login panel. At this point use the generated administration account to login which will currently default to:&lt;br /&gt;
&lt;br /&gt;
* Username: &amp;#039;&amp;#039;&amp;#039;admin&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* Password: &amp;#039;&amp;#039;&amp;#039;admin&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Once you&amp;#039;ve logged in, in the top left corner is a menu which you can use to get to the list of pages. On this list, find the homepage and open the page editor. [[Editing Pages|Editing a page]] (and more generally how they actually work) is a broad topic on its own so please take a moment to check out [[Editing Pages|that article]] first, then head back here when you&amp;#039;re ready.&lt;/div&gt;</summary>
		<author><name>2A02:C7F:22BE:A500:498:3225:1A16:A72D</name></author>
	</entry>
	<entry>
		<id>https://wiki.socialstack.dev/index.php?title=Getting_Started&amp;diff=88</id>
		<title>Getting Started</title>
		<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=Getting_Started&amp;diff=88"/>
		<updated>2022-07-05T11:47:51Z</updated>

		<summary type="html">&lt;p&gt;2A02:C7F:22BE:A500:498:3225:1A16:A72D: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
Hello! Welcome to SocialStack, a fully open source modular collection of C# and javascript code used to create modern, ultra high throughput projects which has been tried and tested by big name brands.&lt;br /&gt;
&lt;br /&gt;
= Installing dependencies =&lt;br /&gt;
&lt;br /&gt;
So, to get started, you&amp;#039;ll need a few things first. Whilst SocialStack does support using multiple database engines, we currently reccommend starting with MySQL. Here&amp;#039;s what you&amp;#039;ll need:&lt;br /&gt;
&lt;br /&gt;
* An editor capable of working with dotnet 6. For example, Visual Studio Code or Visual Studio 2022.&lt;br /&gt;
* Node.js 8+ which is used to run the command line tools&lt;br /&gt;
* MySQL version 8 is reccommended&lt;br /&gt;
* Git, as a new project will also be created as a git repository.&lt;br /&gt;
&lt;br /&gt;
= Setting up the command line tools =&lt;br /&gt;
&lt;br /&gt;
Once you&amp;#039;ve got the dependencies ready, it&amp;#039;s time to setup the [https://www.npmjs.com/package/socialstack command line tools] which we&amp;#039;ll shortly use to create a project. In a nutshell, it is an optional npm package which can be installed globally by running this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
npm i -g socialstack&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this command line tool set (and node.js) are not required by production sites. It&amp;#039;s just a convenience system for installing modules and creating projects.&lt;br /&gt;
&lt;br /&gt;
It&amp;#039;s recommended to configure socialstack tools with the ability to create MySQL databases for you on your development computer. To do this, you&amp;#039;ll need to create a MySQL account on your MySQL instance which it can use and which has the permission to create databases and users. Here&amp;#039;s an example of how to do that:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- Create the user account:&lt;br /&gt;
CREATE USER &amp;#039;sstools&amp;#039;@&amp;#039;localhost&amp;#039; IDENTIFIED BY &amp;#039;ssto0ls.dev&amp;#039;; -- Invent a password here!&lt;br /&gt;
-- Grant that user full access to the db:&lt;br /&gt;
GRANT ALL PRIVILEGES ON *.* TO &amp;#039;sstools&amp;#039;@&amp;#039;localhost&amp;#039; WITH GRANT OPTION;&lt;br /&gt;
FLUSH PRIVILEGES;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can then add this account to your command line tools like so, making sure the password and username matches what you used:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
socialstack configure -u &amp;quot;sstools&amp;quot; -p &amp;quot;ssto0ls.dev&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a global thing, so once you&amp;#039;ve done it you won&amp;#039;t need to do it again. You&amp;#039;re ready to create a project!&lt;br /&gt;
&lt;br /&gt;
= Creating a project =&lt;br /&gt;
&lt;br /&gt;
With the command line tools ready to go, you can then go ahead and create a project like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd myProjectDirectory&lt;br /&gt;
socialstack create helloworld&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will ask if you want to install any additional modules straight away. Just skip this by pressing enter. If your configuration is ok, a database will be created for you as well as the project.&lt;br /&gt;
&lt;br /&gt;
= Starting it up =&lt;br /&gt;
&lt;br /&gt;
With your project created, start it up in a suitable editor (typically that is Visual Studio Code, or Visual Studio 2022) or via the command line by starting the Api.csproj project. Whilst it starts, it will give you a few bits of information:&lt;br /&gt;
&lt;br /&gt;
* It will list which services (provided by modules) are installed and starting up.&lt;br /&gt;
* It will create the database tables and any initial data needed by those services. This is fully automated.&lt;br /&gt;
* It will let you know that a default administration account was created, and what its details are. This happens once; if you missed it you can check the site_user table in your database as it will have one row and the default password is simply &amp;#039;&amp;#039;&amp;#039;admin&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* It lets you know how to get to the instance. This defaults to http://localhost:5050/ which you can navigate to in a browser.&lt;br /&gt;
* It compiles the UI and indicates when its done. This is usually the very last thing that appears and the UI won&amp;#039;t display to you until it completes.&lt;br /&gt;
&lt;br /&gt;
= Going exploring =&lt;br /&gt;
&lt;br /&gt;
With your project started, head over to http://localhost:5050/ in a browser and you should see a barebones homepage with a welcome message. This brings us to the first key point:&lt;br /&gt;
&lt;br /&gt;
&amp;gt;  Pages in SocialStack entirely come from the editable CMS area - this includes administration panel pages too. There&amp;#039;s no fighting against surrounding page templates as the root component(s) on the page are whatever you choose. More on components later!&lt;br /&gt;
&lt;br /&gt;
So, let&amp;#039;s head in to the administration panel and make some changes. Head over to http://localhost:5050/en-admin/ in a browser and you should see a login panel. At this point use the generated administration account to login which will currently default to:&lt;br /&gt;
&lt;br /&gt;
* Username: &amp;#039;&amp;#039;&amp;#039;admin&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* Password: &amp;#039;&amp;#039;&amp;#039;admin&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Once you&amp;#039;ve logged in, in the top left corner is a menu which you can use to get to the list of pages.&lt;/div&gt;</summary>
		<author><name>2A02:C7F:22BE:A500:498:3225:1A16:A72D</name></author>
	</entry>
	<entry>
		<id>https://wiki.socialstack.dev/index.php?title=Getting_Started&amp;diff=87</id>
		<title>Getting Started</title>
		<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=Getting_Started&amp;diff=87"/>
		<updated>2022-07-05T11:46:08Z</updated>

		<summary type="html">&lt;p&gt;2A02:C7F:22BE:A500:498:3225:1A16:A72D: /* Introduction */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
Hello! Welcome to SocialStack, a fully open source modular collection of C# and javascript code used to create modern, ultra high throughput projects which has been tried and tested by big name brands.&lt;br /&gt;
&lt;br /&gt;
= Installing dependencies =&lt;br /&gt;
&lt;br /&gt;
So, to get started, you&amp;#039;ll need a few things first. Whilst SocialStack does support using multiple database engines, we currently reccommend starting with MySQL. Here&amp;#039;s what you&amp;#039;ll need:&lt;br /&gt;
&lt;br /&gt;
* An editor capable of working with dotnet 6. For example, Visual Studio Code or Visual Studio 2022.&lt;br /&gt;
* Node.js 8+ which is used to run the command line tools&lt;br /&gt;
* MySQL version 8 is reccommended&lt;br /&gt;
* Git, as a new project will also be created as a git repository.&lt;br /&gt;
&lt;br /&gt;
= Setting up the command line tools =&lt;br /&gt;
&lt;br /&gt;
Once you&amp;#039;ve got the dependencies ready, it&amp;#039;s time to setup the [https://www.npmjs.com/package/socialstack command line tools] which we&amp;#039;ll shortly use to create a project. In a nutshell, it is an optional npm package which can be installed globally by running this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
npm i -g socialstack&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this command line tool set (and node.js) are not required by production sites. It&amp;#039;s just a convenience system for installing modules and creating projects.&lt;br /&gt;
&lt;br /&gt;
It&amp;#039;s recommended to configure socialstack tools with the ability to create MySQL databases for you on your development computer. To do this, you&amp;#039;ll need to create a MySQL account on your MySQL instance which it can use and which has the permission to create databases and users. Here&amp;#039;s an example of how to do that:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- Create the user account:&lt;br /&gt;
CREATE USER &amp;#039;sstools&amp;#039;@&amp;#039;localhost&amp;#039; IDENTIFIED BY &amp;#039;ssto0ls.dev&amp;#039;; -- Invent a password here!&lt;br /&gt;
-- Grant that user full access to the db:&lt;br /&gt;
GRANT ALL PRIVILEGES ON *.* TO &amp;#039;sstools&amp;#039;@&amp;#039;localhost&amp;#039; WITH GRANT OPTION;&lt;br /&gt;
FLUSH PRIVILEGES;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can then add this account to your command line tools like so, making sure the password and username matches what you used:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
socialstack configure -u &amp;quot;sstools&amp;quot; -p &amp;quot;ssto0ls.dev&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a global thing, so once you&amp;#039;ve done it you won&amp;#039;t need to do it again. You&amp;#039;re ready to create a project!&lt;br /&gt;
&lt;br /&gt;
= Creating a project =&lt;br /&gt;
&lt;br /&gt;
With the command line tools ready to go, you can then go ahead and create a project like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd myProjectDirectory&lt;br /&gt;
socialstack create helloworld&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will ask if you want to install any additional modules straight away. Just skip this by pressing enter. If your configuration is ok, a database will be created for you as well as the project.&lt;br /&gt;
&lt;br /&gt;
= Starting it up =&lt;br /&gt;
&lt;br /&gt;
With your project created, start it up in a suitable editor (typically that is Visual Studio Code, or Visual Studio 2022) or via the command line by starting the Api.csproj project. Whilst it starts, it will give you a few bits of information:&lt;br /&gt;
&lt;br /&gt;
* It will list which services (provided by modules) are installed and starting up.&lt;br /&gt;
* It will create the database tables and any initial data needed by those services. This is fully automated.&lt;br /&gt;
* It will let you know that a default administration account was created, and what its details are. This happens once; if you missed it you can check the site_user table in your database as it will have one row and the default password is simply `admin`.&lt;br /&gt;
* It lets you know how to get to the instance. This defaults to http://localhost:5050/ which you can navigate to in a browser.&lt;br /&gt;
* It compiles the UI and indicates when its done. This is usually the very last thing that appears and the UI won&amp;#039;t display to you until it completes.&lt;br /&gt;
&lt;br /&gt;
= Going exploring =&lt;br /&gt;
&lt;br /&gt;
With your project started, head over to http://localhost:5050/ in a browser and you should see a barebones homepage with a welcome message. This brings us to the first key point:&lt;br /&gt;
&lt;br /&gt;
&amp;gt;  Pages in SocialStack entirely come from the editable CMS area - this includes administration panel pages too. There&amp;#039;s no fighting against surrounding page templates as the root component(s) on the page are whatever you choose. More on components later!&lt;br /&gt;
&lt;br /&gt;
So, let&amp;#039;s head in to the administration panel and make some changes. Head over to http://localhost:5050/en-admin/ in a browser and you should see a login panel. At this point use the generated administration account to login which will currently default to:&lt;br /&gt;
&lt;br /&gt;
* Username: `admin`&lt;br /&gt;
* Password: `admin`&lt;/div&gt;</summary>
		<author><name>2A02:C7F:22BE:A500:498:3225:1A16:A72D</name></author>
	</entry>
	<entry>
		<id>https://wiki.socialstack.dev/index.php?title=Architecture&amp;diff=86</id>
		<title>Architecture</title>
		<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=Architecture&amp;diff=86"/>
		<updated>2022-07-05T11:23:11Z</updated>

		<summary type="html">&lt;p&gt;2A02:C7F:22BE:A500:498:3225:1A16:A72D: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SocialStack is primarily a fully open source dotnet core 6 API. By default it comes with a React frontend installed which can also be simply ignored or removed if you wish to use it headless instead.&lt;br /&gt;
&lt;br /&gt;
The structure of all parts of a SocialStack project is designed to be highly modular - all of the core features and functionality are in small, replaceable modules which originate from [https://github.com/socialstack-core/modules this GitHub repository].&lt;br /&gt;
&lt;br /&gt;
Creating projects, which primarily just installs a default package of modules, as well as installing or uninstalling modules, is handled by [https://www.npmjs.com/package/socialstack SocialStack tools] - an open source command line toolset written in javascript which is typically the best place to start when working with SocialStack.&lt;/div&gt;</summary>
		<author><name>2A02:C7F:22BE:A500:498:3225:1A16:A72D</name></author>
	</entry>
</feed>