-
Notifications
You must be signed in to change notification settings - Fork 32
/
directory-structure.liquid
279 lines (198 loc) · 18.9 KB
/
directory-structure.liquid
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
---
converter: markdown
metadata:
title: Directory Structure
description:
---
You develop your site (write code) in your **codebase** in your local environment.
## Required directory structure
In order to correctly communicate with the platformOS engine and API, your codebase should be organized into a specific directory structure. The root directory of your project should contain the app directory.
### Recommended directories and files inside the `app` and `modules/<module name>` directories
| Directory/file | File type | Explanation | Learn more |
|------------------------ |----------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |---------------------------------------------------------------------------------------- |
| .pos | | Configuration file that specifies available endpoints. Usually, you want to have at least two endpoints – staging and production. | [Development Workflow](/developer-guide/platformos-workflow/development-workflow) |
| assets | asset | Directory for static assets, like fonts, images, stylesheets, and scripts. | [Assets](#assets) |
| authorization_policies | Liquid | Directory for .liquid files that contains Authorization Policy configuration files. Authorization Policies define rules that control whether a user has access to a form or page. | [Authorization Policies](#authorization-policies) |
| migrations | Liquid | Directory for migration files. | [Migrations](#migrations) |
| schema | YAML | Directory for .yml files that define Tables. Tables define custom objects, including their fields and associations and allow you to create persistence containers for your custom forms. | [Records](#records) |
| emails | Liquid | Directory for .liquid files that define Email notifications. | [Notifications](/developer-guide/notifications/notifications) |
| api_calls | Liquid | Directory for .liquid files that define API calls notifications. | [Notifications](/developer-guide/notifications/notifications) |
| smses | Liquid | Directory for .liquid files that define SMS notifications. | [Notifications](/developer-guide/notifications/notifications) |
| graphql | GraphQL | Directory for .graphql files, each defining one GraphQL Query. GraphQL queries retrieve information from or insert information into the databases. Retrieved information is made available in Liquid. | [GraphQL](https://graphql.org/learn/) |
| views/pages | Liquid | Directory for files that define pages, the most essential building blocks of a platformOS site. | [Views](#views-pages-layouts-and-partials) |
| views/layouts | Liquid | Directory for layouts. Layouts are wrappers around your page content. They ensure consistent outer content for similarly designed pages. | [Views](#views-pages-layouts-and-partials) |
| views/partials | Liquid | Directory for partials – reusable snippets of Liquid code usually used to render HTML. | [Views](#views-pages-layouts-and-partials) |
| lib | Liquid | Directory for liquid files that implement business logic, and usually are meant to be invoked via [function](/api-reference/liquid/platformos-tags#function) tag | [Lib](#lib) |
| translations | YAML | Directory for .yml files of Translations for multilingual sites, also used to define date format, or flash messages. Each file is a map of translations which can be used in your pages via Liquid. | [Translations](#translations) |
| user_profile_types | YAML | Directory for .yml files that define User Profiles. Each instance includes one user role, called ‘default’, so each instance needs to include the default.yml file inside this directory. | [Users](#users) |
| user.yml | YAML | A yml file containing properties for all users | [Users](#users) |
| config.yml | YAML | A yml file containing configuration flags for backwards incompatible changes | [Config](/developer-guide/platformos-workflow/directory-structure/config) |
## Files in your codebase
### Views: pages, layouts, and partials
Views are divided into three categories in your codebase, each with a mandatory subdirectory: layouts, pages, and partials.
**Pages** are the most essential building blocks of a platformOS site, that define content displayed at a given path. Each page is represented by a single file with a .liquid extension.
platformOS allows Liquid pages to be used to create many different types of endpoints beyond HTML, such as JavaScript, JSON, PDF, RSS, XML, etc. The page type can be specified in the page configuration.
**Layouts** are Liquid views that store code that would normally repeat on a lot of pages and is surrounding page content (e.g. header, footer). Without layouts, pages would share a lot of duplicated code, and changing anything would become a very time consuming and error prone process. You can create as many layouts as you need, and decide which page uses which layout.
**Partials** (partial templates) allow you to easily organize and reuse your code by extracting pieces of code to their own files. They help you improve code readability and follow the principle of DRY (Don’t Repeat Yourself). You can parameterize partials and use them in various places, e.g. layouts, pages.
Example directory structure of `views` with sample files:
```shell
app
└── views
├── layouts
│ └── 1col.html.liquid
├── pages
│ ├── index.html.liquid
│ └── unauthorized.html.liquid
└── partials
└── layout
├── constants.liquid
├── foot.liquid
├── footer.liquid
├── head.liquid
└── header.liquid
```
{% include "alert/tutorial", content: "Follow our step-by-step tutorials to learn more about <a href='/developer-guide/pages/pages'>pages</a> and <a href='/developer-guide/pages/layouts'>layouts</a>." %}
### Lib
Lib directory is meant to help you organize your code by allowing you to place partials not only in `views/partials/`, but also in `lib/`. Both `render` and [function](/api-reference/liquid/platformos-tags#function) tags invoke partial, however semantically they are different. The first one usually is used for presentation layer and include for example HTML, wheras the second one is meant to invoke business logic and return a valule. To not have to mix files for presentation with business logic, we've created a dedicated directory `lib`.
{% render "alert/warning", content: "Please note that it is possible to create a conflict, when using both `views/partials` and `lib` - for example, if you have both `app/views/partials/my_file.liquid` and `app/lib/my_file.liquid` , the system will not know which file you meant to invoke via `render 'my_file'` or `function res = 'my_file'`." %}
Example directory structure of `lib` with sample files:
```shell
app
└── lib
└── commands
├── order
│ ├── create
│ │ ├── build.liquid
│ │ ├── check.liquid
│ │ └── execute.liquid
│ └── cancel
│ ├── build.liquid
│ ├── check.liquid
│ └── execute.liquid
└── item
└── create
├── build.liquid
├── check.liquid
└── execute.liquid
```
### Assets
**Assets** are files that can be served by an HTTP web server without any backend/server processing. They are usually Javascript files, stylesheets (CSS), documents (HTML, pdf, doc), fonts, or media (audio, video) files.
Although only the assets directory is required and you can put your assets there, we recommend you further organize your assets into subdirectories inside the assets directory, e.g. `images`, `scripts` for Javascript files, `styles` for CSS files, etc. This is also how the `pos-cli init` command will create the codebase.
Example directory structure of `assets` with sample files:
```shell
app
└── assets
├── fonts
├── images
│ ├── favicon.ico
├── scripts
│ ├── app.js
│ ├── vendor.js
└── styles
├── app.css
└── vendor.css
```
{% include "alert/tutorial", content: "Follow our step-by-step tutorials to learn more about <a href='/developer-guide/assets/assets'>assets</a>." %}
### Migrations
**Migrations** are liquid files, that are guaranteed to be invoked only once per environment during `deploy`. The file name must follow the pattern `<timestamp>_<name>.liquid`. The timestamp is used for uniqueness and also to know in which order migrations should be executed (which might be important).
To generate a migration with the current timestamp, you can use the following command: `pos-cli migrations generate <env> <name>`
Migrations are useful if you are making changes to schema in a project with existing data and need to slightly modify them, for example initiate the value.
Example directory structure of `migrations` with sample files:
```shell
app
└── migrations
├── 20200811133711_set_superadmins.liquid
└── 20210114080833_set_defaults_for_country.liquid
```
{% include "alert/tutorial", content: "Follow our step-by-step tutorials to learn more about <a href='/developer-guide/data-import-export/migrating-data'>Migrations</a>." %}
### [DEPRECATED] Forms
Just like in every web application, HTML forms are essential in platformOS. Because using plain HTML forms can get difficult to maintain with complex data structures, we provide multiple tools that make working with forms much easier.
**Forms** are the main tool for rendering forms, persisting data, and sending notifications (email/SMS/API) in a secure and customizable way.
They give you full control when defining:
* which fields for a defined resource can be persisted
* what authorization rules apply to be able to submit the form (i.e. if you want to edit a comment, you might want to specify that only the creator or the administrator is able to do it)
* what should happen when the form is submitted successfully (i.e. without validation errors), e.g. send an email/SMS Notifications or API call to a third party system
* where the user should be redirected
On top of that, you can define callbacks (either synchronous or asynchronous) for further modifications to the system using GraphQL mutations. For example, you can define a signup form that creates User records, and if the user input is valid, also creates a few sample products for them, so that they don’t have to start from scratch.
Example directory structure of `forms` with sample files:
```shell
app
└── forms
├── create_contact_request_form.liquid
└── feedback_form.liquid
```
{% include "alert/tutorial", content: "Follow our step-by-step tutorials to learn more about <a href='/developer-guide/forms/forms'>forms</a>." %}
### Users
**Users** are accounts that any of your users can have. Users are identified by their unique email addresses. You can define properties for all users in the user.yml file.
**User Profiles**: This feature is deprecated. We advise to create a table called `profile` with the `user_id` property.
Example directory structure:
```shell
app
├── user.yml
```
{% include "alert/tutorial", content: "Follow our step-by-step tutorials to learn more about <a href='/developer-guide/users/users'>users</a>." %}
### Records
**Table** is an object that describes all Record objects that belong to it. Think of Tables as a custom database table, which allows you to build highly customized features. Use them to group Properties, and allow the user to provide multiple values for each of them.
**Properties** are fields that you attach to a User Profile, Table, etc. Think of them as custom database columns (though complex types, like attachments and images should be treated as separate database tables). We also provide some Properties to jumpstart your development.
Example directory structure of `schema` with sample files:
```shell
app
└── schema
└── blog_post.yml
```
{% include "alert/tutorial", content: "Follow our step-by-step tutorials to learn more about <a href='/developer-guide/records/records-tables'>Tables</a> and <a href='/developer-guide/properties/properties'>Properties</a>." %}
### Notifications
**Notifications** are messages sent to platformOS users (including admins) when something happens. A message can be an email, SMS, or programmatic call to a 3rd party API.
Notifications can be delayed, and you can use Liquid, GraphQL, and trigger conditions to decide if a notification should be sent. They are a powerful mechanism used for example to welcome new users, follow up after they've added their first item, or reach out to them if they have been inactive for a while.
Each notification has its own directory:
```shell
app
└──
├── api_calls
│ └── ping_example_com_on_user_sign_up.liquid
├── emails
│ └── welcome_user.liquid
└── smses
└── welcome_user.liquid
```
{% include "alert/tutorial", content: "Follow our step-by-step tutorials to learn more about <a href='/developer-guide/notifications/notifications'>notifications</a>." %}
### Authorization Policies
**Authorization Policies** allow you to restrict access to forms and pages in a flexible way. Each form or page can have multiple policies attached to it.
Each policy is parsed using Liquid, and the system checks them in order of their appearance in the code. Depending on policy configuration, it redirects the user to a URL provided by the developer if the condition is not met or renders error status, for example 403. You can also add a flash message for the user who failed authorization.
Example directory structure of `authorization_policies` with sample files:
```shell
app
└── authorization_policies
└── example_policy.liquid
```
{% include "alert/tutorial", content: "Follow our step-by-step tutorials to learn more about <a href='/developer-guide/authorization-policy/authorization-policy'>Authorization Policies</a>." %}
### Translations
You can use platformOS to build sites in any language, and each site can have multiple language versions. **Translations** are yml files used for multilingual sites but also used to define date formats, flash messages or system-wide default error messages like "can't be blank".
Example directory structure of `translations` with sample files:
```shell
app
└── translations
├── en.yml
└── pl.yml
```
{% include "alert/tutorial", content: "Follow our step-by-step tutorials to learn more about <a href='/developer-guide/translations/translations'>translations</a>." %}
### Modules
**Modules** allow code reuse and sharing, while protecting the IP of creators.
In your codebase, the `modules` directory needs to be at the same level as the `app` directory.
Module code is split into 2 directories to protect IP. To create a module, split module code into `public` and `private` folders, and place all that code into the `modules/MODULE_NAME` directory.
These directories have the same structure as the standard `app` folder, but if developers try to download files after the module has been deployed to an Instance (`pos-cli pull`), they will only have access to the files from the `public` folder.
Example directory structure of `modules` with sample files:
```shell
app
modules
└──admincms
├── private
│ └── graphql
│ ├── get_records.graphql
│ └── get_pages.graphql
└── public
└── views
└── pages
└── admin.liquid
```
{% include "alert/tutorial", content: "Follow our step-by-step tutorials to learn more about <a href='/developer-guide/modules/modules'>Modules</a>." %}