Publishing checklist
Run through this list before you send a package to anyone, whichever way you built it. Where App Studio checks something for you, the row says so, and says where you see it. With gfpkg the checks are the ones build and verify run.
What App Studio checks for you
App Studio reads the draft's manifest as you work and shows the result in three places. None of them replaces testing, but they catch most of what the sections below list.
| Where | What it says |
|---|---|
| Ready to publish? on the Overview (with a pill: Ready or "N to look at") | The manifest problems, each with a link to the part that fixes it (for example Open data, Open views); "The view compiles" or "All N views compile"; "Every model has a title field and a list layout", or which model has no text field to title a record or no list layout; a step "cannot be taken by anyone"; a state with "no way out"; a required setting that is not set; and an info line "Runs server code". |
| The status line of the visual editor | "Compiles", or the compile problems; what the view reads, what it may run, and a Permissions link. |
| Before you publish in Test & publish | "The draft has no problems.", or each blocker: manifest problems, "View <id> does not compile", "Version X is not greater than the installed Y"; and "Tried in the preview" or "Not tried in the preview yet". Sign and publish stays disabled while there is a blocker, or no key, or no certificate. |
| The process checks in Processes | Nobody may take a step; a state is never entered or cannot be reached from where records start; no step leaves the start; a process with one state. |
Below, a row marked Studio is one the Studio reports; the others are yours to check in either way.
1. Manifest
| Check | Checked by |
|---|---|
format is 1, and every field is one groupforce knows. An unknown field is an error, so an old gfpkg rejects a newer manifest. Rebuild the tool from the checkout you package for. |
Studio (it writes the manifest); gfpkg build |
id is reverse-DNS, such as com.acme.field-ops, at most 100 characters. The Studio proposes one from the app's name. |
Studio; gfpkg build |
name is 1 to 80 characters, version is a semantic version such as 1.2.0, and description is at most 500 characters. |
Studio; gfpkg build |
Exactly one view has "home": true, if the app has views. It is what the app's icon opens. |
Studio (the HOME mark); gfpkg build |
Every file the manifest names exists: view and component sources, styles, icon (an .svg or a built-in icon name), server module, print templates. |
Studio; gfpkg build |
| Ids of views, components and models are lower-case letters, digits and hyphens, at most 40 characters; field keys use letters, digits and underscores. | Studio; gfpkg build |
Hooks name only your own models, as model.<id>.created, .updated or .deleted, or an event of the platform's work items or projects that you subscribed to (contract 8). |
gfpkg build |
| Every extension names a point from the list of places and one of your own components. | gfpkg build |
Each view's actions and records fit inside the app's permissions. This one is checked when the package is installed, not by gfpkg. In the Studio, What it may do shows the permissions and the editor's status line the view's needs. |
At install (and the Studio's preview install) |
Validation reports every problem at once, sorted, rather than the first one.
2. Namespace, class and contract
| Check | What to confirm |
|---|---|
Namespace |
Your app id equals a namespace on your certificate or starts with it plus a dot. A certificate for com.acme signs com.acme.field-ops, never com.other.x. Keys page: Namespaces. |
Class |
A manifest with a server section needs a certificate that carries the server class. A certificate with only ui is refused at build and at install. Keys page: May ship. |
Contract |
requires.groupforce is at least the contract of the newest feature you use and at most 8. Statuses need 2; rows, layout hints, sections, steps and window size need 3; settings 4; editors 5; print templates 6; model-bound blocks and a step's rules 7; subscriptions, timers, editable_by and custom fields 8. A feature used under a lower declared contract is a problem; a higher number than the platform offers is refused. |
3. Server code
- The manifest has a
serversection:module,routes,hooksand the names oftimersit sets. Every handler named anywhere (route, hook, guard,after, timer, automationcall) is a function in the module. groupforce checks that at install by loading the module in a test engine. - The certificate carries the
serverclass. In production that is an operator-issued certificate (CLI or hardware key). A browser key from the Studio normally hasuionly; a development installation with automatic issuing may give it both. The Keys page's May ship line says which you have. - Test it in a preview first: server code runs there only when the test engine (container engine) is on, on the preview's own test records, and its notifications reach only you, titled "[Preview] ...".
- The module is at most 1 MiB. The module runs under limits and the sandbox described in Server code & sandboxing.
4. Apps that reach work items
- The manifest asks for work items or projects through
subscriptionsandpermissions, and needs contract 8. See Work items, events and timers. - Nothing reaches until the administrator chooses. The install review says "an app that asks to reach your work items or projects reaches none of them" and that you choose under the app's menu, What it may reach: work items, projects. The choices per entity are Nothing, Only the items of chosen projects and Every item in the workspace, which includes items people cannot see. Say in your app's description what it needs and why, and test that it behaves sensibly when it is given nothing.
5. Size limits
These are enforced while the package is read, so a file that unpacks larger than its header claims is still caught.
| What | Limit |
|---|---|
The package (.gfpkg) |
50 MB |
One file, unpacked |
20 MB |
All files, unpacked |
100 MB |
Files in the package |
2,000 entries |
A file name |
At most 200 characters, relative, forward slashes, no .., unique when case is ignored, nothing else under META-INF/ |
A view or component source |
200 KB, and 600 KB once compiled |
A stylesheet |
100 KB |
Server module |
1 MiB |
A record |
256 KiB, at most 100 fields per model, 500 characters for a text field, 100,000 for a long text, 100,000 records per model |
Apps per workspace |
50 |
The build includes every regular file in the folder you point it at, including editor backups and node_modules. A symlink or socket is an error. Build from a clean folder or a staging copy.
6. Signing
Sign with a certificate and key the operator's authority issued: in App Studio a key made in your browser (Signed here, in your browser. The key and password never leave it.), with gfpkg a certificate and key you hold. The signature covers your app id, version and the SHA-256 of every file, so changing a file afterwards makes the package fail with "tampered". Two builds of the same folder do not give identical bytes, because the signing time is part of the statement.
- The key exists and its file is saved and checked (Keys page, steps 1 and 2). There is no reset.
- A certificate is installed ("Certificate installed"), is valid, and lists the namespace of your app.
- It will not run out before you need to update: certificates last 365 days by default, and verification uses the current time. An expired certificate refuses a new install or update; an installed app keeps running.
Details are in Keys, certificates & signing.
7. Testing before you ship
Both ways, and you can use both.
| Step | What it proves |
|---|---|
| In App Studio: Start preview, Open preview | The draft installed into your own preview slot, on test data, signed with a 24-hour development certificate. Compiles the views, loads the server module (container engine only) and shows what the automations did under Recent runs. Reset test data and Remove preview start over. "Tried in the preview" appears in Before you publish. |
gfpkg inspect field-ops.gfpkg |
Shows what the package claims, marked NOT VERIFIED: id, version, needed class, counts and permissions. Trusts nothing. |
gfpkg verify --root groupforce-root.pem field-ops.gfpkg |
Runs the same checks an installing workspace runs: size and shape, chain to the root, expiry, class, namespace, file hashes, manifest. |
| Install it in a test workspace | The only code-path step that compiles your views, scopes your styles, loads your server module and checks that each handler exists. The install dialog is a review that stores nothing until you choose Install. |
A package can build and verify and still be refused at install, for example because a view asks to run an action that permissions.actions does not include, or because a view uses something the compiler does not allow. The refusal names the file, line and column.
8. Updates
| Situation | Result |
|---|---|
| Same id, same signing organization, higher version | Installed as an update. The app keeps its on/off state and settings. |
| Same version already installed | Refused (409). |
| Lower version than installed | Refused (409). There is no downgrade. |
| Same id signed by a different organization | Refused (409). The administrator would have to uninstall the app first. |
In the Studio, Publish offers a patch, minor or major bump, shows Changes since the installed version, and will not publish a version that is not greater than the installed one. The previous version stays in Versions.
Version order follows semantic versioning: a release is newer than its pre-releases. Because there is no downgrade, ship a fixed higher version instead of asking people to go back. Uninstalling is the only way back, and it deletes the app's records. When you remove a field from a model in a new version, data already stored under it is kept untouched and does not block old records from being edited or moved on in their workflow.
9. Revocation
If a certificate's key leaks, tell the operator. The certificate is added to a revocation list that servers re-read without a restart, and packages signed with it stop installing. Revoking an authority revokes everything it issued.
Revocation is checked when a package is installed or updated. It does not remove an app that is already installed. If a compromised app is installed in your workspace, an administrator has to switch it off or uninstall it under Workspace settings, Apps.