Portal files
Every key of config/portal/portal.yaml (the member portal's install defaults, member report rules and invitation timings), config/sites/<key>/portal.yaml (a site's portal, screens and actions) and config/portal/roles.yaml (partner roles), all engine-dmo.
engine-dmo
The member portal is where the people behind partner businesses sign in to update their listings, see their report and manage their membership. Three files configure it. Partners and the portal and Portal screens and actions explain the portal; this page lists every key.
portal/portal.yaml
The install’s portal. A portal: block in engine.yaml is still read, with a warning that it belongs here.
portal:
mode: both
invitations:
expiry: 30d
reminder_after: 7d
report:
peer_comparison: true
peer_min_cohort: 5 A project on engine-dmo has the portal on by default (engine-dmo describe project shows portal /members, both). A site with no partner businesses turns it off with one file:
# config/portal/portal.yaml
portal:
mode: "off" Quote "off", or YAML may read it as a boolean in other tools; the engine accepts either.
| Key | Type | Default | Meaning |
|---|---|---|---|
portal.mode | string | both | templated (the engine renders the portal through your templates), api (the member API only, for an app of your own), both, or off |
portal.templated.enabled | boolean | true | Serve the templated portal |
portal.templated.template_dir | string | portal | The portal’s template directory in each template root |
portal.templated.routes | map of strings | {} | A screen’s path under server.portal_path, by screen key; a screen left out keeps its default path |
portal.invitations.expiry | retention | 30d | How long an invitation works. Whole days |
portal.invitations.reminder_after | retention | 7d | When an unanswered invitation is chased. Whole days, before the expiry |
portal.report.peer_comparison | boolean | true | Compare a member’s figures with similar businesses |
portal.report.peer_min_cohort | integer | 5 | The fewest peers a comparison needs; below it the comparison is left out |
portal.report.improvement_prompts.enabled | boolean | true | Show “make your listing work harder” prompts in the report |
portal.report.improvement_prompts.min_impressions | integer | 100 | Impressions a listing needs before prompts are shown |
portal.report.improvement_prompts.uplift_min_cohort | integer | 20 | The fewest listings an uplift claim is computed from |
portal.report.improvement_prompts.uplift_min_percent | integer | 10 | The smallest uplift worth quoting |
portal.report.improvement_prompts.max_shown | integer | 4 | The most prompts shown at once |
portal.report.improvement_prompts.filter_min_searches | integer | 50 | Searches the window must hold before a filter’s share is quoted as evidence |
portal.report.improvement_prompts.rules | map | See below | The thresholds each prompt uses |
portal.report.email_digest.enabled | boolean | true | Email members their monthly report |
portal.report.email_digest.report | string | member-monthly | The report (from analytics/reports.yaml) the digest sends |
portal.report.email_digest.skip_when_no_data | boolean | true | Send nothing for a period with no data |
The default rules:
rules:
accessibility: { required: true }
booking_link: {}
description_words: { min: 150 }
opening_hours: { filter: open_now, required: true }
photos: { min: 4, target: 8 }
stale_after: 180d
summary_words: { min: 40 }
website: { required: true }
zero_result_terms: { min_searches: 10, radius_km: 10 } sites/<key>/portal.yaml
One site’s portal, over the install’s: its mode and path, the reference screens it hides, and its own screens and actions.
| Key | Type | Default | Meaning |
|---|---|---|---|
mode | string | portal.mode | templated, api, both or off for this site |
path | string | server.portal_path | The portal’s path on this site |
template_dir | string | portal.templated.template_dir | The portal template directory for this site |
routes | map of strings | Screen paths for this site, by screen key | |
hide | list of strings | [] | Reference screens this site does not offer: contact_details, contact_team, enquiries, events, hours, listing_edit, membership, people, photos, promotions, report |
screens | list | [] | The site’s own screens |
screens[].key | string | Required | The screen’s key. A reference screen’s key replaces that screen’s template and takes only template |
screens[].id | string | Written for you | Its stable id |
screens[].path | string | /organisations/{org}/<key> | Its path under the portal path, with {org}, {id} or neither |
screens[].template | string | <key>.html | Its template in the portal template directory |
screens[].title | map of strings | Its title per locale | |
screens[].nav | any | Where it appears in the portal navigation | |
screens[].can | string | screen.<key> | The partner permission it needs |
screens[].tiers | any | Every tier | The tiers whose organisations see it: a list or { min: <tier> } |
screens[].data | map | Declared data the screen reads, scoped to the partner’s organisation: each a name and a source (documents, document, published, report, enquiries, pending, people, membership, organisation, promotions, first_session) with its parameters | |
actions | list | [] | Forms the portal posts to, at <portal path>/actions/<key> |
actions[].key | string | Required | <subject>.<verb>, such as listing.update_offer |
actions[].id | string | Written for you | Its stable id |
actions[].label | map of strings | The key | How a screen lists it |
actions[].target | any | Required | What it writes: a document of the organisation, the organisation’s custom fields, or the signed-in person’s |
actions[].fields | list of strings | The fields it may write | |
actions[].can | string | action.<key> | The partner permission it needs |
actions[].tiers | any | Every tier | The tiers whose organisations may use it |
actions[].approval | string | For a document target: tier (the tier’s member_editable rule decides) or required (every change waits for staff) | |
actions[].input, validation, steps, respond, rate_limit | any | As in an endpoint (see endpoints.yaml) |
engine-dmo dev portal screen add and dev portal action add declare these with their ids. engine-dmo portal check checks the portal templates against the portal’s context, and portal scaffold copies the reference portal into the project to restyle.
portal/roles.yaml
Partner roles: what a person can do for an organisation in the portal. The built-in owner, manager, contact and billing may be restated with new grants.
| Key | Type | Default | Meaning |
|---|---|---|---|
roles[].key | string | Required | The role’s key; a built-in key restates that role |
roles[].id | string | Written for you | Its stable id |
roles[].label | map of strings | Its name per locale | |
roles[].can | list of strings | The partner permissions it grants, including screen.<key> and action.<key> permissions the sites declare |
engine-dmo dev role add declares one with its id.
access/roles.yaml and grants.yaml
Every key of config/access/roles.yaml (staff roles and their permissions) and config/access/grants.yaml (roles granted to staff groups under a scope).
paidlistings.yaml
Every key of config/paidlistings.yaml (engine-dmo), the paid listings payment provider (Stripe or none) with its secrets, and each site's tier prices and how promotions are paid.