Nick: A Nearly Headless CMS
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Title of Series | ||
Number of Parts | 44 | |
Author | ||
License | CC Attribution 3.0 Germany: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor. | |
Identifiers | 10.5446/60232 (DOI) | |
Publisher | ||
Release Date | ||
Language | ||
Production Place | Namur, Belgium |
Content Metadata
Subject Area | ||
Genre | ||
Abstract |
|
Plone Conference 202214 / 44
10
14
22
23
26
27
40
00:00
Turtle graphicsContent management systemConfiguration spaceElectric generatorSystem callFormal languageConnected spaceRevision controlCASE <Informatik>Content (media)Software developerTemplate (C++)Block (periodic table)Field (computer science)Dot productLibrary catalogSubject indexingINTEGRALProfil (magazine)Database transactionStapeldateiMedical imagingPlanningPhysical systemPhotographic mosaicSoftware repository1 (number)AuthorizationGraphical user interfaceSocial classDigital photographyMusical ensembleObject (grammar)Computer fileProjective planeMultiplicationLatent heatCodeTheory of relativityTable (information)Electronic mailing listMiniDiscSystem administratorBootstrap aggregatingAdditionEmailLevel (video gaming)Endliche ModelltheorieStudent's t-testBitFront and back endsError messageOperator (mathematics)Generic programmingTranslation (relic)Representational state transferData structureMathematicsPoint (geometry)RootControl flow graphEvent horizonWebsiteLoginSet (mathematics)Software testingInstance (computer science)Multiplication signMappingResultantPolygon meshFunctional (mathematics)Right angleUniform resource locatorRollback (data management)Type theoryInformation securityHuman migrationView (database)CloningNormal (geometry)DampingDefault (computer science)Stress (mechanics)Function (mathematics)Server (computing)Morley's categoricity theoremGoodness of fitInterface (computing)Canadian Mathematical SocietyInformationCategory of beingCombinational logicMoving averageSlide ruleException handlingLibrary (computing)Different (Kate Ryan album)Image registrationProcess (computing)State of matterDescriptive statisticsGroup actionPassword2 (number)Escape characterDependent and independent variablesMetadataQuery languageSoftwareGUI widgetImplementationComputer configurationForm (programming)String (computer science)Computer-assisted translationMessage passingDatabaseScripting languageDisk read-and-write headMoment (mathematics)Stack (abstract data type)CodeWindows RegistryWeb pageRaw image formatUtility softwareData storage deviceLink (knot theory)Core dumpShared memoryInheritance (object-oriented programming)Interactive televisionStructural loadRule of inferenceThermal radiationVariable (mathematics)Internationalization and localizationMereologyLocal ringPresentation of a groupTraverse (surveying)IntegerSound effectBoolean algebraFluid staticsBus (computing)Absolute valueProof theoryRelational databaseFile systemSynchronizationRoutingDemo (music)Perspective (visual)Client (computing)Open sourceDebuggerComputer animationLecture/Conference
00:40
World Wide Web ConsortiumDatabaseImplementationFront and back endsCodeElectronic mailing listLecture/ConferenceComputer animation
01:25
Front and back endsRepresentational state transferLecture/Conference
02:09
BuildingFront and back endsLecture/ConferenceComputer animation
02:50
Representational state transferFunctional (mathematics)Multiplication signProof theoryLecture/ConferenceMeeting/InterviewComputer animation
03:34
Representational state transferLecture/Conference
04:14
Formal languageDifferent (Kate Ryan album)Software developerBitComputer animationLecture/Conference
04:57
CodePhysical systemSoftwareBitComputer animationLecture/ConferenceMeeting/Interview
05:37
Software developerError messageBitGeneric programmingWeb pageLecture/ConferenceComputer animation
06:26
Cloud computingUniformer RaumBitStack (abstract data type)BitCASE <Informatik>Lecture/Conference
07:13
Formal languageGroup actionLibrary catalogQuicksortElasticity (physics)IterationDatabase transactionComputer animationLecture/Conference
08:27
Optical character recognitionDemo (music)Gamma functionNumbering schemeR-ParitätException handlingFront and back endsDatabaseGraphical user interfaceLecture/Conference
09:34
Projective planeRepresentational state transferDatabaseBootstrap aggregatingLecture/ConferenceJSONComputer animation
10:23
Front and back endsDemo (music)PasswordNetwork topologyRight angleUniform resource locatorInterface (computing)Front and back endsLecture/ConferenceXML
11:07
Server (computing)Uniform resource locatorDemo (music)Stress (mechanics)DebuggerLecture/ConferenceComputer animation
11:45
Demo (music)Content management systemAsynchronous Transfer ModeRepresentational state transferSoftware testingCombinational logicRepresentational state transferContent (media)JSONComputer animationLecture/Conference
12:51
Maxima and minimaEvent horizonWorld Wide Web ConsortiumSample (statistics)Software testingRepresentational state transferResultantEmailDependent and independent variablesSystem callCASE <Informatik>BitJSONLecture/ConferenceMeeting/Interview
13:49
Dependent and independent variablesSoftware testingFront and back endsBitLecture/ConferenceSource code
14:28
Hill differential equationAsynchronous Transfer ModeLibrary (computing)Translation (relic)Object (grammar)Endliche ModelltheorieType theoryTheory of relativityTable (information)Computer animationLecture/Conference
15:08
Human migrationHuman migrationMathematicsData structureDatabaseComputer fileLecture/ConferenceMeeting/Interview
15:47
Endliche ModelltheorieTable (information)Revision controlSet (mathematics)Object (grammar)Endliche Modelltheorie
16:42
Data modelAsynchronous Transfer ModeOvalEndliche ModelltheorieTheory of relativityConnected spaceEndliche ModelltheorieMapping
17:32
Gamma functionData modelGroup actionModulo (jargon)Default (computer science)MultiplicationElectronic mailing listSocial classObject-relational mappingJSONXMLUML
18:20
Group actionLatent heatGroup actionObject (grammar)SynchronizationLecture/ConferenceMeeting/Interview
18:59
SimulationType theoryComputer fileType theoryCore dumpRootWebsiteSystem administratorDefault (computer science)Content (media)Lecture/ConferenceMeeting/InterviewComputer animation
20:09
Group actionDatabase transactionLecture/ConferenceMeeting/Interview
20:58
Data storage deviceElectronic data interchangeComputer fileConfiguration spaceLecture/ConferenceComputer animation
21:48
Core dumpCore dumpConfiguration spacePasswordMedical imagingDatabasePhysical systemConnected spaceTemplate (C++)Projective planeProfil (magazine)Computer animation
22:34
Plane (geometry)Type theorySimilarity (geometry)Content (media)Representational state transferComputer fileMiniDiscAdditionLecture/ConferenceJSONComputer animation
23:43
Core dumpBlock (periodic table)Dynamic random-access memoryHill differential equationGamma functionNormal (geometry)Default (computer science)1 (number)Category of beingField (computer science)Morley's categoricity theoremDublin CoreJSONXMLLecture/Conference
24:33
Uniqueness quantificationString (computer science)Menu (computing)Hill differential equationArc (geometry)Function (mathematics)AdditionContent (media)Set (mathematics)Web pageSocial classObject (grammar)Lecture/Conference
25:33
Computer fileContent (media)Data structureBlock (periodic table)Dot productEvent horizonWebsiteLecture/ConferenceMeeting/Interview
26:20
Hill differential equationRevision controlGame theoryContent (media)Revision controlRepresentational state transferLecture/Conference
27:01
Block (periodic table)System callRepresentational state transferPatch (Unix)MultiplicationLatent heatRevision controlJSON
27:40
Group actionView (database)Representational state transferGroup actionFront and back endsLoginContent (media)EmailAuthorization
28:25
Hill differential equationKeilförmige AnordnungLoginRepresentational state transferPoint (geometry)Physical systemLecture/ConferenceJSONXMLUML
29:13
Group actionInteractive televisionState of matterMeeting/InterviewLecture/ConferenceComputer animation
30:25
Electronic mailing listLocal ringLecture/ConferenceMeeting/Interview
31:22
MereologyComputer filePhysical systemGroup actionLecture/Conference
32:12
State of matterSystem administratorDefault (computer science)Profil (magazine)View (database)Group actionState of matterRepresentational state transferCASE <Informatik>JSON
33:07
Image registrationMountain passElectronic meeting systemImage registrationShared memoryQuery languagePasswordGroup actionElectronic mailing listSource codeJSON
34:00
PredictabilityGamma functionState of matterGroup actionObject (grammar)Electronic mailing listShared memoryLibrary catalogLecture/Conference
34:39
MKS system of unitsSubject indexingObject (grammar)Data storage deviceDatabaseLibrary (computing)Projective planeLecture/Conference
35:18
Subject indexingAttribute grammarSubject indexingContent (media)MetadataFormal languageObject (grammar)Computer animationLecture/ConferenceMeeting/Interview
36:08
Maxima and minimaSubject indexingMassLibrary catalogSubject indexingSet (mathematics)Configuration spaceString (computer science)Query languageWindows RegistryComputer configurationTheory of relativityOperator (mathematics)Absolute valueLecture/Conference
37:15
Query languageNormal (geometry)GUI widgetOperator (mathematics)String (computer science)Subject indexingStapeldateiSound effectResultantType theoryRootSource codeJSON
38:26
Group actionDatabaseFluid staticsFunctional (mathematics)Representational state transferLecture/ConferenceMeeting/InterviewJSON
39:20
Group actionLatent heatField (computer science)Functional (mathematics)1 (number)Game controllerGroup actionConfiguration spaceUtility softwareType theoryLecture/Conference
40:31
Menu (computing)Control flowMountain passField (computer science)Default (computer science)Game controllerSet (mathematics)EmailSystem callComputer-assisted translationElectronic mailing listXMLJSONLecture/Conference
41:10
Revision controlEmailPhysical systemForm (programming)DatabaseScripting languageLecture/ConferenceMeeting/Interview
42:04
String (computer science)Message passingInternationalization and localizationFormal languageDefault (computer science)Computer fileCode
42:50
Gamma functionTranslation (relic)String (computer science)Computer fileLecture/ConferenceMeeting/InterviewJSON
43:41
Plane (geometry)Uniformer RaumWeb pageGame theoryInformation securityBitDatabasePresentation of a groupTable (information)Lecture/ConferenceProgram flowchart
44:20
Revision controlType theoryLink (knot theory)Relational database
45:03
Link (knot theory)Group actionType theoryTable (information)MultiplicationGame controllerElectronic mailing listMetadataLibrary catalogComputer animation
46:00
Level (video gaming)Wechselseitige InformationSoftware testingLoginEmailGame controllerSet (mathematics)Lecture/ConferenceMeeting/InterviewComputer animation
46:42
Software developerProjective planeImplementationContent (media)Type theoryRepresentational state transferMeeting/InterviewLecture/Conference
47:25
Slide ruleException handlingLecture/ConferenceComputer animationMeeting/Interview
48:26
Lecture/Conference
49:07
Plane (geometry)Maxima and minimaCategory of beingDescriptive statisticsField (computer science)Process (computing)CloningCanadian Mathematical SocietyData storage deviceCodeFile systemDatabaseState of matterLecture/ConferenceMeeting/Interview
50:00
Hill differential equationPlane (geometry)Turtle graphicsContent management systemComputer fileBitDatabaseLecture/ConferenceComputer animation
Transcript: English(auto-generated)
00:13
Hello, the next talk will be presented by Tom Kiedema, about Nick and early at least
00:22
CMS. Thank you very much, Fred is running, you can't escape, you can't escape. All right, welcome, I'm going to talk a bit about Nick, but first a bit about me.
00:43
I'm Rob, I've been using Plone since, I don't know how long, probably 2005, 2004 I think, mostly doing front-end stuff, so I did a lot of work on initial implementation of TinyMC, Deco, which is then called Mosaic, and I built, I started with Volto, which
01:01
you've probably heard of, but I'm not going to talk about any of the front-end stuff, so it's going to be back-end only, yeah, back-end. So what we'll cover, I'll basically give an introduction of Nick, and it seems like a really long list, and it is, you'll be seeing a lot of listings and code and JSON
01:22
and whatever, so if you're bored then just go to the other talk, it's fine as well, I don't really mind. Anyway, so what is Nick? It's a headless CMS, so basically it's a CMS, it's built with Node.js, sorry, no Python, I'm a JavaScript guy, and it has a RESTful API, which is compatible
01:48
with the Plone REST API, so same as for Guillotina for example, they also have a REST API, which is also compatible with Plone, which also means it's compatible with Volto, because Volto doesn't really care what's back-end you're using, as long as you have
02:04
the same API, and then it just works, if you implement everything that is. So the big reason is why, people ask me that all the time, fun to build, I mean,
02:21
I usually build stuff because I like building it, and whether or not people are going to use it eventually, it's fine if they do, and it's also fine if they don't, but I just like building stuff, and some people find it useful, and some people don't, and that's fine. Another reason is, I think Plone has a great architecture, and being a front-end
02:42
developer, or mostly being a front-end developer, I do know a lot about how the Plone back-end works, but not like all the nitty-gritty details, so by building this, it was a great way to actually know, or actually on a functional level, know how Plone actually works, and especially the details regarding permissions and workflow and all that stuff, that's quite a lot of stuff
03:03
which we take for granted, but it's a lot of functionality which is there in Plone. Next thing is Plone has a great REST API, so the REST API was already there, so there was actually, I knew which I have to implement, so I just needed to build it, and to comply with the same thing, if you start from scratch, and have to come up with
03:20
an API again, that's a lot harder to do, but this was, well, a lot easier for me. Yeah, it started as a proof of concept at the PloneConf in Tokyo in 2018. During the conference, I had some time left, so I was like, yeah, maybe I should try if I can actually implement the REST API in JavaScript,
03:41
because why not, and I worked on it for some hours during the conference, and eventually, I did a lightning talk about it, and it was kind of working, so I had, like, a good login, I didn't have any permissions, of course, but then I could add it, but that was about it, and then later on, I picked it up again to see if I can actually, yeah, get it further,
04:03
and to see how far I could take this pet project, and to see where it actually went. Another big reason why I wanted to build it in JavaScript is, well, basically two reasons, one because I really like JavaScript, and the other one is that if you do, then you'll basically have a front-end
04:24
written in React and JavaScript at this time, and then you have a back-end also written in JavaScript, so I think for a lot of new developers coming into the community, having to learn a lot of different technologies can be quite hard, so if you only have to learn JavaScript, or, well, only,
04:44
I say there's a lot of stuff to learn, obviously, but you don't have to learn a lot of other language as well, so I guess it should be a bit easier for new developers to join in. Yeah, so starting with Plone, issues with Plone, big disclaimer, this is my opinion, don't take it,
05:02
that it is a Plone thingy or whatever, and you'll see a lot of people who have really different opinions, but this is just the issues I have with Plone. Lots of legacy code, I don't think I'm the only one there, but there's a lot of stuff to know, and there's a lot of things to know about the system. It also means there's a lot of code to maintain ourselves,
05:22
so we're usually very good at building stuff, but we also have to maintain it. I mean, if we use software which is already there, then it should be a bit easier, at least, so you have a bigger code stack, and the last one, I mean, as some of you might have known, I really hate deployment and CI and all the other.
05:42
My stuff just needs to work, and then I just want to do development, but so if that could be a bit easier and not run into build out or set up tools or I don't know, build errors or whatever, and then I'm already, then I like it more. Yeah, and if we look at Plone at the moment,
06:01
as I said, it's already, it can be quite hard for new developers to join in, so I tried to make a list, which is definitely not complete, of technologies you actually have to learn before you start Plone or you need to know Python, so generic setup, which XML, CCML, you need to know, page templates, REST, YAML, there's now, JSON is there, some CFG, any file, we have Markdown in Plone as well,
06:23
we have JavaScript, we have Webpack, we have CSS and all the variants because we started with LESS and then we switched to SAS, as I heard. We have some XSLT if you're doing Diaso. We have build out, which I don't think we have anymore, so these are some bit of the older technologies which we luckily we get rid of at some point, KSS, I don't think we use it anymore.
06:41
Portal skins, I heard they are not used but they're still in there. We're stuck to Python, I think that's also gone, hopefully, DTML, that's like old, so as you can see, it's a long list of stuff. It's a full stack, it's a full stack. Yes, indeed, I'll change my notes, I'll just do a complex, I'll just delete it.
07:04
Yeah, so when I wanted to implement it, what my goals are, so the idea was to build it with notes, so in this case JavaScript, one language, then JSON, which for configuration, two languages and markdown, that's the third one for documentation.
07:21
So everything I did was like I'm not gonna use YAML and XML and whatever, just these three and then I should be able to do it, right? We'll see. Next up I needed some data store, so I could use the CO2B of course, but that's Python again, so I wanted to keep it as simple and as easy as possible for people to set up,
07:40
so I chose Postgres. Why? Well, it's a transactional database, so that's really nice if you want to have an actions in transactions, so you can actually roll them back when something weird happens. Other thing which Postgres does really, really well is JSON integration, so you can have, it's an iteration based, but in,
08:02
you can have JSON fields, which you can put lots of data in there, but you can also query the data and you can do anything with it, it's really, really nice. It has some text indexing, well, obviously not as good as like say Elastic Sort or like the talk Ramon's doing downstairs, he probably has a much better solution,
08:21
but for the basic stuff, this is working fine, basically the same as what you can do with the Z catalog. And obviously you needed I18N, so I'm just using a get text variant, same as we do in Flown and in Volto as well.
08:42
So if you want to have a look at Nick, then you can go to this perfectly website, I'll show it, it's just a random commercial, I will say, but it's not commercial because nobody's using Nick except me, but you can see some introduction there, what it does, what features it has,
09:01
but we'll go through them, how you can start it up and obviously how you can contribute. So getting started, so what you can do to get started, the only thing you'll basically need is Postgres and Node and to set it up, you'll create database in Postgres with these commands
09:21
or any fancy GUI tool which you have and then the next thing you do, you can clone the repo, you do yarn bootstrap, yarn start and your backend is running. That should be it. Or if you want to do something more fancy and you want to create your own project using Nick,
09:43
there's a Yeoman generator which I implemented yesterday, I had to update my sheets and you can just create your own project there, so you basically install the generator and you say, yo, in this case, my name, I will not bother you with how to pronounce that,
10:02
and then Nick and then you say your project name and it will just generate the setup for you so you can actually have your own project where you can add all the customizations you want and then for the rest it's the same, you basically create a database again, go to project, bootstrap it and start it up and then it's there.
10:24
Yeah, and then you can go to this URL if you started it all, if you did everything right and you'll end up with this. So this is basically, it's Volto with a slightly modified theme, but it's using Nick in the backend, so that means that all the login,
10:42
all the folder contents, editing, adding content, everything is there, so you can do basically anything you would do. So from a normal user perspective, most people won't notice whether you're using Plone in the backend or Nick or Cuetina for that matter, because the interface is all the same.
11:05
If you want to try it out now, you can do so at this URL. So running on my server at home, so don't stress it too much, but you'll be fine. Yeah, you can just log in and just try it out for yourself, but it's, as I said, it's more or less the same demo
11:22
as the Volto demo because it uses the same front end there. And if you want to contribute, you can obviously go to GitHub, everything is there, everything is open source, obviously. Still in my own repo, maybe we'll move it to Plone or to Collective at some point, we'll see. Anything's fine by me.
11:42
Next up is documentation. So one thing I, Steve, yeah, he's here, yeah. I have docs, see, yeah. So basically, documentation is a combination of documentation and testing as well. So I set up the documentation, and as you can see,
12:01
maybe by the structure, by a lot of the other content, everything is kind of similar to the docs of the Plone REST API. And that is, well, normal because it provides the same API, well, almost the same API, so why not use the same? So I stole a lot of data from there
12:20
to have the same documentation in there. Obviously, the setup is a bit different, but all the rest of the calls, all the content creation, actions, workflow, you name it, everything is there, which you can actually, like for instance, if you go to the content manipulation, you can see all the methods which are there and what the examples are.
12:43
And yeah, basically the same as you have in the Plone REST API. So as I said, documentation. So I combined documentation and testing in the same way as the REST API does. So you basically have your tests specified
13:02
as HTTP requests. So we have a, in this case, with a GET request, we just get the breadcrumbs. We have the URL there, and then we have the results, which says, ta-da, this is the result we wanna get. We use this in the doc, we, me, I use this in the documentation as well.
13:23
And there it's presented, and these tests are also run as you see them. So if you make a mistake in your tests, then your test will obviously fail, and so that means that your documentation will always stay up to date. So the tests are, the documentation is fairly simple. It just has the documentation there
13:42
and it just includes the examples with the request and the response header in there for this case. I mean, some calls are a bit more advanced, of course, but for this, it's just a simple request and response. Tests running, you can just do yarn test,
14:01
and then it would do something like this. It will test all the backend calls, and as you can maybe see on an SR, how small the text is, but they run in 5.83 seconds, so it's, you can develop pretty fast. So I guess it's, I don't know how long the blown tests take, but I'm guessing a bit more.
14:21
But this is really fast, so you can easily update and then run tests again. You can just have them open as well. Yeah, so database, as I said, I'm using Postgres for the database, and I'm using some libraries on top of that. So you have Knex, which is a low-level ORM,
14:40
which does most of the translation between JavaScript objects and SQL. And then you have Objection, which is more a layer which does models and collections and all that stuff. If we look at Knex first, as I said, it's more basically just a layer on top of SQL, so you can just provide, you can create tables
15:03
with all types and all names and stuff like that, and do relations and everything there. And you can add those to migration, so basically Knex provides you a migration path, so you can think of this as upgrade steps in Plone,
15:21
that you can actually just, if you want to have a different structure in your database or you want to add stuff or remove a field or do any change basically, it's just an upgrade step, which you can write, and it will just do it by date, if you name them correctly, obviously, and you can do migrate, and it will just migrate to the latest version,
15:42
or you can do rollbacks, or you can do any of those steps. So what does a migration file look like? Very simple, you basically have two methods, one being an up method and one being a down method, and you just specify, if I go from the previous version to this version, you have to do this,
16:01
and if I go back then down, then you do this, so in this case, we're adding a permission table with an ID and a title, and if we go down to that version, we just drop the table. So that's fairly simple. Then we have objection, as I said, objection provides some information,
16:22
which you can do to specify models, for in this case, if we go to the permission example, again, what I say is, okay, we have a permission class, which inherits from models, and the models is in this case, I will show a base model, which is extended from objection, and then we can have some other settings in there,
16:44
in this case, we're providing some relations between the two, so in this case, we have permissions and role, and there's a connection between roles and permissions, so a role can have multiple permissions, so we just say, okay, we have a role table, we have a permission table, and we have a table in between which links the two,
17:02
so those are easily fetched in your code again, so you don't have to worry about all the SQL underneath. Yeah, base model, so everything is inherited from the base model, and the base model can, well, you can just put anything in there.
17:21
Basically, it has some, it basically, like a model maps to a table, if I didn't mention it yet, and the base model has some nice helper classes, which you can use by default, and obviously, you can override them per model, but these are just stuff for like doing queries, or fetching data, fetching related data,
17:43
fetching one item, fetching all the items, same what you would get in a normal ORM or any other, any other MPC JavaScript library, or Python library, for that matter. Then we have collections. Collections are just a list of objects,
18:03
or a list of models, basically, so you use them for, if you fetch a lot of objects, they return into a collection, and a collection is a class itself, which you can have methods to, so it can return some fancy JSON, if you want to list multiple items in there, and there's like a default one,
18:21
and you can also extend the collection, if you want to have something specific. For instance, this is the actions collection, and it uses the, from the base model, the JSON method to return the JSON to the client, and it does some extra stuff in there to add or remove some fields, basically, synchronization.
18:46
Yeah, as I said, this is the base collection, nothing much there, it's just some helper methods to return it to convert to JSON, or to map over your objects which you have, and stuff like that. Then we have something which is called seeds in Knex,
19:05
and we, in the long world, usually call them profiles, it's basically profile data, which means it can be any setting, or any initial data, or for your own project, or in general.
19:24
I implemented them using the seed method of Knex, but I'm using a profile-based approach, so basically you'll have a lot of files in your profile, you can have multiple profiles, and in this case, in Nick, I've split them up
19:40
between core and default, core meaning all the things you really need, like the content types and permissions, and stuff like that, and in default, you can, that's like if you want to have a default website, it can contain an admin user, and it can also contain contents, like the site root and some news items, and stuff like that. And these are all, they can be JS files,
20:02
or they can be JSON files, and it will work. By default, most are JSON files. Most of them are actually JSON, but I messed it up in the sheets. But you can also add JS in there, so you can actually do some fancy including, or fetch your data from somewhere else.
20:24
Then the layer, we have, as I said, Postgres has transactions, so I'm using that as well, so if you, on a higher level, you basically have a transaction, you start a transaction at the start of your call, then you can do all your operations, and then at the end of the call,
20:41
you'll try to commit it, and if that goes well, then you're done, and if it not, then it will raise an error, and it will send it to the backend, so something went wrong. Yeah, basic transaction support. Yeah, blobs.
21:00
Postgres does support blobs, but I didn't really like them, because I don't know why, it's just slow, and it's in your database, and so I implemented it, and then I was like, nah, maybe this is not the way to go, so I just went for a file system-based approach after that, and it works a lot better, because you can just see the files, and everything is just there,
21:20
so it's just UUDs generated, and storing those there. Yeah, for the rest, we have some helpers in there, so Bootstrap, which you already saw, to bootstrap your project, and you could do a reset, which will clean, it's nice for development, you clean all your database, rerun all the profiles, rerun all your initial data, so you always have a clean setup there.
21:43
For the rest, same as a photo, we have a config file, with all the configuration data in there, there's a template which you can create, with create config, we will just copy over the template, and fill in the details, or if you use the Yeoman generator, it will also just put it there.
22:01
Basic stuff in there, like your database connection setup, where your blobs are located, what secret is for your password generation, what system users are, core setup, so you can also do it there, your image scales, basically all the things you would expect in the configuration to be there,
22:22
and here you can also specify which folders you want to add as profiles, that can be, in this case, profiles in the project itself, but it could also be your own project, or an add-on, or anything for that matter. So first up, content types.
22:43
Yeah, content types are all schema-based, JSON schema, so they are just JSON files, kind of similar as we do in Plone, but there's no class-based content types at all, it's just the only thing which is there is schema-based ones,
23:01
you can have some behaviors with additional methods and stuff like that, but I will show that later, but all the content types are basic, are just JSON files, which are obviously imported into the database, but on disk they are JSON files. Yeah, people will know the REST API and all this stuff, there's nothing new, it's just exactly the same as you will have,
23:21
so you have all the schema data in there, which is just JSON schema, and you have a behaviors field, where you can specify which behaviors you want to include for your content type, and you specify the workflow you want to use for this content type as well.
23:41
Behaviors, same thing, behaviors are also schema-based, so behaviors, in this case, you can just specify JSON schema in there, these are the ones which are by default are NIC, but you can obviously add them yourself, so a basic schema will look, just look normal JSON schema
24:00
with field set properties and required fields, something which Plow nor Dexterity can't do, but NICN is nested behaviors as well, so you can have a behavior, and then you can actually say, okay, I want, for instance, this is a Dublin Core behavior, and it contains these behaviors, so behavior can contain other behaviors,
24:22
so you have, yeah, so you don't have to include all those separate behaviors into one thing, you can just say, I want the Dublin Core, and then you get the basic categorization and ownership there as well. Then you can also have class-based behaviors, or basically kind of like overrides
24:42
of additional things you can add there, for instance, the IE from title is a behavior which you can apply to your content type, and you can write it, it's just an object with methods, and these methods are overridden in the class which you have, so if you have, this will be applied to your object,
25:03
so if you have this set onto, let's say a content, like a page content type, then the set ID normally would just, you have to set the ID yourself, and if you apply this behavior, it will get the ID based on the title.
25:21
Then we have the initial content and the profiles, how many people of you know the Git Concept Content Creator, or use it even? Only Git Concept people, oh boy. So basically, it's a package where you can actually create initial data in JSON on disk,
25:40
so you can just create your whole file structure with example content and everything, and it will run it, so your website has initial data in there, and I made a pretty similar approach, so it's a dotted name, so basically, this is the events in this case,
26:02
it's the folder inside the root, and then you have a sub-item in there, but you can go with dots as far as you want. This will contain all the data, so you have all the separate fields, like the block data,
26:20
and some other things which the Git Concept Content Creator can't do in Plone, it can also do sharing, so you can also have your initial data, you can have your sharing data in there, so you can already say, okay, this document should also only be accessible by this user or by this role and stuff like that, and another thing is you can also add history in there as well,
26:41
so then a content item can already have multiple revisions when you have your initial data in there, so you have these versions, and it will say which is the active version there. Redirects, very simple, nothing much to say there. Yeah, so REST API calls,
27:01
if you already know the Plone REST API, then this is also nothing new for you, so basically, you will have get calls on the content, in this case, in the news, and you get all the data. We have post to create a new item, this is all exactly the same as the Plone REST API. Patch to update, delete, ordering in a folder,
27:24
we have some history calls, where you can just see what the versions are available, get a specific version, revert to a specific version, copy data, move data, copy multiple files, or items in this case, so that's all exactly the same as in Plone,
27:42
and the Plone REST API, I should say. Then we have actions, which is also the same, those are the actions which are available in your Volto toolbar, or in any other frontend you wanna use, so basically, view edits, and these are based on permission as well, so as you can see here, I have the authorization header in there,
28:03
so I only get the actions I actually have permissions for, so in this case, I'm logged in, so apparently I'm an admin, I think, because I've added in a folder content as well, but if you're a normal user, you would only see the view, probably. Logging is implemented as well,
28:22
same as we have in Plone, so if you added an object, it will be logged, and can't be saved until you, or you can save it with the same user, or if you get a log and you update the log, so you can specify the log token in the header, that's also the same as Plone REST API is doing it,
28:43
and deleting one, yeah, no security, because that's the strong point of Plone, so that's also the hardest to grasp for most people if they join, that's at least my case, so logging in is easy, that's just username, password, and you get a JWT token,
29:00
which you can use, and the system will know that it is, you can renew that one, and you can log out. Now the permission system, everybody know how the permission system in Plone works? So if I go to like slash news, what is calculated to know whether or not I am allowed to access that?
29:24
Lots of stuff indeed, yeah, so we have permissions, we have roles, and roles have permissions, we have groups, groups have roles, now we have users, so users have roles, but users can also belong to a group, and group has roles, and roles have permission,
29:41
so eventually it all ends up at permissions, but it's a lot of layers in their interaction. Then we have local roles, so we have a user and a group, which are assigned a role to a specific object, which is also inherited to the parents, so you also have to do a lot of traversing,
30:00
whether or not, or to the children in this case, whether or not you have permission, and to make things worse, you can also disable the inheritance, so you can actually say don't overwrite, don't inherit all the permissions. Then we have workflows, which have states and transitions, and a state also has permissions,
30:27
have permissions per role, and that role, as you can see in the top one, has permissions as well, so there's quite a lot of stuff to do when you actually want to know am I allowed to access this content object,
30:40
so there's a lot of traversing, and a lot of things, so that's why I guess most, I think Giratina doesn't have this fully implemented, probably because of this reason, because this list is so long, and when I tried to implement this at first, I was like oh, and it's so much stuff to implement, but I just went from one to another, to another, and to another, and eventually I got everything working,
31:01
so everything you see here is now implemented in NIC as well, so including workflow and local roles and everything, and it was a long list, and I thought well, this is never gonna happen, but eventually if you just do it step-by-step, and increase from one to another, then it does work, and yeah.
31:21
Fred. I could have, but this is so specific, so then you just have the workflow, which is just a really small part of the permission system, and I haven't seen any permission system, as we haven't blown in any other CMS,
31:41
at least not in this way. Maybe, I haven't seen all CMSs in the world, but like most, I know that don't have it this specific, and this, yeah. Yeah, transitions. Oh yeah, transitions also have permissions. That's not really tied to the object,
32:02
but more if you are able to do transitions. So just the permission system. Yeah, all these things you can set into, in your JSON files as well, in your profiles in this case, so you can just set the default permissions. You can add the roles you wanna use, and which permissions those roles have.
32:22
You can have users, and you can specify what roles they have, or what groups they belong to. We have groups which have roles as well, as I said. Then next up is workflows. That's also pretty similar to Plone. So workflows are defined. They have initial states, and they have multiple states.
32:41
Each state has like a title, description, transitions. Oh yeah, you can see the permissions, so basically the contributor role has the view permission in this case. And then we have the transitions, where you can publish or send back, and those are specified if you want to go from one state to the other.
33:02
REST API calls for all the security-related stuff. So basically you can fetch the roles, which you'll need in the control panels. You can list users, if you have the permission, obviously. You can do queries in the listings, so you can get users with just that specific name,
33:20
used in the sharing tab, for example. You can get the one specific user, if you want to edit that user. Update a user, delete a user. Then we have all the registration calls, so you can actually do, as an anonymous user, you can do registration, if you have that enabled. Then we can reset our passwords. We can set the reset of password.
33:42
We can list groups, get groups. As I said, there's a lot of listings in here. Add a group, update a group, delete a group. Then we have workflows. Same thing, you can also just fetch the workflow, if you want to know what transitions are available.
34:01
You could do a transition, to do a transition between one state to another. We have the sharing. Sharing has the list of all the available roles, which are there, and you can, if you want to share something, you can add it.
34:21
You want to say, okay, this content object now adds the, for administrators, it adds the roles, contributor and reader, for example. You can specify those, and later fetch that same data, obviously, to check if the roles are there. Next up, catalog and search. Also a really nice topic.
34:42
As I said, I didn't implement, I'm not as advanced as an Elasticsearch or a Solr, but this is just to get the basics going, so just to do basic searching and indexing. So what did I do? I looked into some separate projects
35:01
to see if I could maybe find a library or to find something which could do that in JavaScript, to do the indexing and store it somewhere, or some fancy object database or whatever, and I made some implementations, but I didn't like them in the end. We're just doing a lot of stuff there, so I just said, well, I have a SQL database,
35:20
which also kind of uses indexes and everything, so that's why I used it in the end. So I just have Postgres with a catalog table, and for each index, I create a column, which has the field, depending on the path, the UOD integer, text. Postgres can do text indexing really well
35:42
with plurals and languages and stuff like that. So I used that, and then you have both, same as in Plone, you have indexes and you have metadata, so indexes are the one you can search for, and metadata is the one, is the stuff you can return, and they're all indexed for each content object
36:01
if you add or add or delete it or move data, that's even worse. So the catalog JSON, this is the, I think we have the same in Plone, right, or do we use it with,
36:21
I mean, it ends up in the configuration registry, but I'm not sure if we do something like this or we do the whole configuration registry, I think like 99% of the configuration registry is just for the query string. So I try to keep it out, and I don't have a configuration registry, I just store the settings where I want them to be stored,
36:41
so in this case, I have the catalog JSON just uses all those, so I can just have all my catalog indexes, they can be grouped, and they have some operators, so you can say in this case, this is a path index, and I can do absolute path operator or a path or a relative path and stuff like that,
37:02
and then UUD and et cetera, and these are all the, more or less, the same indexes as we have in Plone, like start and end dates and everything, so these are your options which you can use to query. Then if we go to the query string endpoint, then we can obviously fetch all that data again, so that will give us all the indexes back
37:22
and all the operations we can do on that, so we can use that in a search widget or in a search view, and when we actually do the search, we can just add it, in this case, to here, this is the normal search endpoint, there's also a query string search endpoint, same as in Plone, but that's not fully functional yet,
37:42
but the search one is, so you can actually just do, in this case, just a simple searchable text, but you can also do any path index or anything else, I think I have some examples in there, yeah, we can do batching, so with the batch size and offset in there, we can do depth, so we can path index, so we can actually search
38:01
for slash news or in the root, and then depth is one, so you can only see the items in the root and not all sub-items in there. You can do sorting, so you can search your results on effective date or on any of the other indexes. Next up, vocabularies, that's also a really nice thing in Plone,
38:24
so vocabularies, there's two types of vocabularies, one is our vocabularies which are created in JavaScript, so basically, that's fetching data from somewhere, so in this case, actions, behaviors, groups, that's all like a vocabulary of all the available groups,
38:41
it will just fetch the data, the group's data in the database and it will return it that way, if you want to create a vocabulary, you just create a function and you return the vocabulary data in JSON and that's what it will
39:01
return in the rest API call, and in this case, it will just fetch data, but it can also be static data or data fetched from anywhere, depending on what vocabulary you need. Then we have profile vocabularies, which are vocabularies as well,
39:20
but they are just static data, so if you just have a simple, I don't know, like month of the year or Boolean, like yes, no, or whatever, you can just add them in JSON, they are fairly simple, it's just a vocabulary with an id and title, and yep, and two items in this case, yes and a no, that's all.
39:42
And you can list them, you can get all the vocabularies, both the ones which you use as JavaScript functions or in this case, the profile-based ones, and they are just returned here. And if you want to get one specific vocabulary, same as in Plone, you just go to the URL, vocabularies actions in this case,
40:00
and then you will get the data there. Yeah, you have some utility calls which you have in Plone as well, to fetch navigation, breadcrumbs, control panels. Control panels, as I said, I'm not using configuration registries, so it has all the data of the control panel stored in the control panel table, basically.
40:22
So the control panels, when you create them in your profile, they have a schema with all the fields and the type of the fields, and then there's a data field which has the default values in this case, but they can also be updated.
40:40
Jonas, are you still here? Yeah, okay. I was asleep and just wanted to make sure. All right, then if we want to fetch all the control panels, we have the control panels endpoints, and we'll just get a list of those. And if we want to fetch one specific one, we can do with the cat call on that one,
41:02
and update, obviously, we can set the values of our control panel. So if we want to update the mail settings in this case, we just pass on those values there. Then we have some mail endpoints, just to send emails around. Obviously, this is all handled by security, so you're not able to send mail,
41:23
but for a contact form to send to a webmaster, for example, or if you're logged in, sent to another user, or stuff like that. I have done that much times, I'll go through it even faster. We have some system endpoints, database endpoints. I18n, nothing new for most people here.
41:42
I just used PO files, and eventually they, and POT files, and eventually they will be generated into JavaScript, one big JavaScript JSON file, which is then reads the same, exactly the same principle as in Volto, except I rewrote that script in here
42:02
to add some more features because I needed them. Which I will show, so one command to extracting all the strings in your code can be, is the same, so yarn 18n will get all the strings from your code, compile them, combine them, and eventually create a JSON file per language.
42:22
If you want to do internationalization in your code, there's a middleware, which I implemented. It's by default there in the code, so you don't have to do anything, but in your request, there's an I18n method, and you can just pass in any string,
42:41
or if you have variables, you can also do that, and plural, and all that, all the fancy stuff, you can do that as well. You don't have to define any other message there, as long as the extractor sees this, then it will extract the data, and it will also do the translation of that text. Another thing I needed was I18n and JSON files.
43:04
There's no way otherwise to JSON, I mean, you can't do that much with JSON. It's really not as sophisticated, so I came up with this syntax. You basically have the title, and then you have colon I18n, and the extractor will extract this,
43:22
and then the Babel loader, when it uses, it will strip this one out, so it actually can also read the JSON files without the fancy I18n stuff in there, so this way you are easy to translate strings in JSON, or in JSON as well, almost there.
43:40
Okay, now logging, nothing fancy there as well, it's just using log4js, not log4j, with all the security issues, log4js. Then, for those interested, this is a database schema, so if you have everything you need, if you want to build your own blown backend, or blown alike backend, then these are kind of the tables you will need,
44:02
if you implement it the same as I do. I have it a bit zoomed in, I will go to it quickly, it's not, for the people, my presentation will be online, so you can view it there if you want. I can go to run quickly, so basically we have a document here, which has all the document data,
44:20
which you already saw, with an ID, a pass, and all that stuff. It has a link to the type table, which is here, and the type will have a workflow connected to it. This is a loose coupling between types and behaviors, because it's in a JSON, so it's not exactly a relational database link.
44:44
We have the document, can have multiple versions, version has an actor, which is a user in this case, I think that's also different from blown, but blown is mainly just a string, so if a user gets deleted, I think, I'm not sure how that works actually, but in blown. But here you will get an error.
45:02
Then we have users, this whole permission system, so we have users, which have a role, multiple roles, let's see the role permission tables here, and the roles have permissions, which are then here, and you have actions, which also have type permissions, then we have the user group table,
45:20
which connects users to groups. Then we have the sharing, is this one, so basically just a link between a group, a role, and a document, and for the user it's the same. Redirects, fairly easy, and then we have, on this side we have the catalog, so these are all the catalog fields, you will see where we're indexing,
45:41
everything with an underscore is an index, and everything without an underscore is a metadata field, and here we have the list of all the indexes, and the list of control panels, so that's the, like in a couple of seconds, how the data table looks like, but as I said, if you have questions about it,
46:00
then let me know. Yeah, then the roadmap, so there's a lot of stuff I built, and there's also a lot of stuff which is not fully built, or not fully done, as I said, the Quersting widget, Quersting search is not fully done, I will hopefully get that done soon. Test coverage could be improved, currently I'm at 83, but people saw David's talk,
46:24
it's not all about coverage, it's about why you actually want to test stuff, but multilingual is something I want to do, email logins will be nice, maybe add some more control panels, I think most of the settings which are available now in Nick are already there,
46:41
but they can always be added more. Developer documentation, currently I do have all the API documentation in there, and that's an installation and documentation as well, but there's not so much documentation yet about how you can actually create your own project and add custom content types and workflows
47:02
and whatever you want to do. And WebSocket implementation will also be nice, for those who don't know, Guillotina does have WebSocket support, and it actually, you can use Volto without any REST API call, while with just one to set up the initial login, and then you can do the rest with that.
47:24
Two minutes left. Questions, oh, and as I said, my slides are on that location, so you can view that if you want to. Any questions, still here?
47:59
So there's two options, so you can either, if it's just fields,
48:02
then you can just do it in JSON-based, so then the JSON will just be adding fields, and then you don't need to do anything except for providing a JSON schema, and if you want to add some other behavior, like overriding some methods or adding something else, then you can do it class-based, or object-based,
48:22
because JavaScript doesn't really have classes, obviously. Go back some slides, too many slides.
48:55
Re-regs, almost there, almost there. Here we go.
49:00
Just a class-based one, here we go. So this is a behavior. So this is the basic behavior in this case, and it's just a JSON schema, so it has a field set, and then it has a property description and property title.
49:21
That's all. Yes? So if I saw it correctly, deployment question, you mentioned the clone deployment is complex. You have one process serving both the Volto backend, being the Volto SSR server, and the NIC CMS.
49:42
No, but you could. You could. The second deployment one, having everything nice in one Postgres database is much nicer for deployment than getting blob storage back on file system. Now you have local states in your containers. I mean, I still have the code there,
50:01
so I could maybe make it a setting that you could store your blobs into Postgres. But yeah, I don't know. I just like simplicity, so if it's just on file system, I know they're there. But deployment-wise, it would indeed be better if it would be in a database. I agree. And there's a performance hit as well, so from file system, it's a bit faster
50:21
than from Postgres. Any other questions? Oh, we're at time. I'm done. Thank you very much. Thank you very much.