{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"client-portal","type":"registry:block","title":"Client Portal","description":"A published page with intake form, status board and a synced header.","author":"Notion Arena","categories":["docs"],"tags":["native","pro","portal","client","form","synced-block","publish"],"meta":{"kind":"native","tier":"pro","version":"1.2.0","updatedAt":"2026-09-26","notionPlan":"Business","emoji":"🚪","delivery":["api","duplicate","guide"],"capabilities":{"interactive":false,"offlineSafe":true,"persistsLocally":false,"writesToNotion":true,"needsNetwork":false},"recipe":"client-portal","installUrl":"https://notionarena.vercel.app/api/install"},"files":[{"path":"recipes/client-portal.json","type":"registry:file","target":"notion/recipes/client-portal.json","content":"{\n  \"$schema\": \"https://notionarena.vercel.app/r/schema.json\",\n  \"notionVersion\": \"2026-03-11\",\n  \"id\": \"client-portal\",\n  \"summary\": \"A publishable client page: intake form, a client-filtered board of deliverables, a synced portal header, and a milestone countdown.\",\n  \"databases\": [\n    {\n      \"ref\": \"clients\",\n      \"title\": \"Clients\",\n      \"icon\": \"🤝\",\n      \"properties\": {\n        \"Name\": {\n          \"title\": {}\n        },\n        \"Status\": {\n          \"status\": {\n            \"options\": [\n              {\n                \"name\": \"Onboarding\",\n                \"color\": \"blue\",\n                \"group\": \"To-do\"\n              },\n              {\n                \"name\": \"Active\",\n                \"color\": \"green\",\n                \"group\": \"In progress\"\n              },\n              {\n                \"name\": \"Paused\",\n                \"color\": \"yellow\",\n                \"group\": \"In progress\"\n              },\n              {\n                \"name\": \"Offboarded\",\n                \"color\": \"gray\",\n                \"group\": \"Complete\"\n              }\n            ]\n          }\n        },\n        \"Primary contact\": {\n          \"people\": {}\n        },\n        \"Email\": {\n          \"email\": {}\n        },\n        \"Portal URL\": {\n          \"url\": {}\n        },\n        \"Kickoff date\": {\n          \"date\": {}\n        },\n        \"Next milestone\": {\n          \"date\": {}\n        },\n        \"Retainer\": {\n          \"number\": {\n            \"format\": \"dollar\"\n          }\n        },\n        \"Deliverables\": {\n          \"relation\": {\n            \"type\": \"dual_property\",\n            \"dual_property\": {\n              \"synced_property_name\": \"Client\"\n            }\n          },\n          \"__relationRef\": \"deliverables\"\n        },\n        \"Requests\": {\n          \"relation\": {\n            \"type\": \"dual_property\",\n            \"dual_property\": {\n              \"synced_property_name\": \"Client\"\n            }\n          },\n          \"__relationRef\": \"intake\"\n        },\n        \"Open items\": {\n          \"rollup\": {\n            \"relation_property_name\": \"Deliverables\",\n            \"rollup_property_name\": \"Status\",\n            \"function\": \"count\"\n          }\n        },\n        \"Days to milestone\": {\n          \"formula\": {\n            \"expression\": \"if(empty(prop(\\\"Next milestone\\\")), 0, dateBetween(prop(\\\"Next milestone\\\"), now(), \\\"days\\\"))\"\n          }\n        }\n      },\n      \"seed\": [\n        {\n          \"name\": \"Northwind Logistics\",\n          \"props\": {\n            \"Status\": \"Active\",\n            \"Retainer\": 6500\n          }\n        }\n      ]\n    },\n    {\n      \"ref\": \"deliverables\",\n      \"title\": \"Deliverables\",\n      \"icon\": \"📦\",\n      \"properties\": {\n        \"Name\": {\n          \"title\": {}\n        },\n        \"Status\": {\n          \"status\": {\n            \"options\": [\n              {\n                \"name\": \"Queued\",\n                \"color\": \"gray\",\n                \"group\": \"To-do\"\n              },\n              {\n                \"name\": \"In progress\",\n                \"color\": \"yellow\",\n                \"group\": \"In progress\"\n              },\n              {\n                \"name\": \"In client review\",\n                \"color\": \"blue\",\n                \"group\": \"In progress\"\n              },\n              {\n                \"name\": \"Changes requested\",\n                \"color\": \"orange\",\n                \"group\": \"In progress\"\n              },\n              {\n                \"name\": \"Delivered\",\n                \"color\": \"green\",\n                \"group\": \"Complete\"\n              }\n            ]\n          }\n        },\n        \"Client\": {\n          \"relation\": {\n            \"type\": \"single_property\",\n            \"single_property\": {}\n          },\n          \"__relationRef\": \"clients\"\n        },\n        \"Owner\": {\n          \"people\": {}\n        },\n        \"Due\": {\n          \"date\": {}\n        },\n        \"Client visible\": {\n          \"checkbox\": {},\n          \"description\": \"Only deliverables with this ticked appear on the portal page.\"\n        },\n        \"Link\": {\n          \"url\": {}\n        },\n        \"Notes\": {\n          \"rich_text\": {}\n        },\n        \"Timeline\": {\n          \"formula\": {\n            \"expression\": \"ifs(prop(\\\"Status\\\") == \\\"Delivered\\\", \\\"✅ Delivered\\\", empty(prop(\\\"Due\\\")), \\\"⚪ No date\\\", prop(\\\"Due\\\") < now(), \\\"🔴 Late\\\", true, \\\"🟢 Due \\\" + formatDate(prop(\\\"Due\\\"), \\\"MMM D\\\"))\"\n          }\n        }\n      },\n      \"seed\": [\n        {\n          \"name\": \"Brand refresh · round 1\",\n          \"props\": {\n            \"Status\": \"In client review\",\n            \"Client visible\": true\n          }\n        },\n        {\n          \"name\": \"Internal pricing model\",\n          \"props\": {\n            \"Status\": \"In progress\",\n            \"Client visible\": false\n          }\n        }\n      ]\n    },\n    {\n      \"ref\": \"intake\",\n      \"title\": \"Intake Requests\",\n      \"icon\": \"📥\",\n      \"properties\": {\n        \"Name\": {\n          \"title\": {}\n        },\n        \"Client\": {\n          \"relation\": {\n            \"type\": \"single_property\",\n            \"single_property\": {}\n          },\n          \"__relationRef\": \"clients\"\n        },\n        \"Type\": {\n          \"select\": {\n            \"options\": [\n              {\n                \"name\": \"New request\",\n                \"color\": \"blue\"\n              },\n              {\n                \"name\": \"Change request\",\n                \"color\": \"yellow\"\n              },\n              {\n                \"name\": \"Question\",\n                \"color\": \"gray\"\n              },\n              {\n                \"name\": \"Bug\",\n                \"color\": \"red\"\n              }\n            ]\n          }\n        },\n        \"Priority\": {\n          \"select\": {\n            \"options\": [\n              {\n                \"name\": \"Low\",\n                \"color\": \"gray\"\n              },\n              {\n                \"name\": \"Normal\",\n                \"color\": \"blue\"\n              },\n              {\n                \"name\": \"Urgent\",\n                \"color\": \"red\"\n              }\n            ]\n          }\n        },\n        \"Detail\": {\n          \"rich_text\": {}\n        },\n        \"Submitted\": {\n          \"created_time\": {}\n        },\n        \"Status\": {\n          \"status\": {}\n        },\n        \"Attachment\": {\n          \"files\": {}\n        },\n        \"Answer\": {\n          \"rich_text\": {}\n        }\n      },\n      \"seed\": []\n    }\n  ],\n  \"views\": [\n    {\n      \"on\": \"intake\",\n      \"name\": \"Client intake form\",\n      \"type\": \"form\",\n      \"configuration\": {\n        \"type\": \"form\",\n        \"properties\": [\n          {\n            \"property_name\": \"Name\",\n            \"visible\": true,\n            \"label\": \"What do you need?\",\n            \"required\": true\n          },\n          {\n            \"property_name\": \"Type\",\n            \"visible\": true,\n            \"label\": \"Request type\"\n          },\n          {\n            \"property_name\": \"Priority\",\n            \"visible\": true,\n            \"label\": \"How urgent?\"\n          },\n          {\n            \"property_name\": \"Detail\",\n            \"visible\": true,\n            \"label\": \"Details\",\n            \"required\": true\n          },\n          {\n            \"property_name\": \"Attachment\",\n            \"visible\": true,\n            \"label\": \"Attach a file\"\n          }\n        ],\n        \"submit_label\": \"Send request\"\n      }\n    },\n    {\n      \"on\": \"deliverables\",\n      \"name\": \"Portal board\",\n      \"type\": \"board\",\n      \"configuration\": {\n        \"type\": \"board\",\n        \"card_layout\": \"comfortable\"\n      },\n      \"filter\": {\n        \"and\": [\n          {\n            \"property\": \"Client visible\",\n            \"checkbox\": {\n              \"equals\": true\n            }\n          },\n          {\n            \"property\": \"Client\",\n            \"relation\": {\n              \"contains\": \"REPLACE_WITH_CLIENT_PAGE_ID\"\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"on\": \"deliverables\",\n      \"name\": \"Delivery timeline\",\n      \"type\": \"timeline\",\n      \"configuration\": {\n        \"type\": \"timeline\"\n      },\n      \"filter\": {\n        \"property\": \"Client visible\",\n        \"checkbox\": {\n          \"equals\": true\n        }\n      }\n    },\n    {\n      \"on\": \"deliverables\",\n      \"name\": \"Delivered gallery\",\n      \"type\": \"gallery\",\n      \"configuration\": {\n        \"type\": \"gallery\",\n        \"card_layout\": \"cover_dominant\"\n      }\n    },\n    {\n      \"on\": \"clients\",\n      \"name\": \"All clients\",\n      \"type\": \"table\"\n    },\n    {\n      \"on\": \"intake\",\n      \"name\": \"Requests queue\",\n      \"type\": \"table\",\n      \"sorts\": [\n        {\n          \"property\": \"Submitted\",\n          \"direction\": \"descending\"\n        }\n      ]\n    }\n  ],\n  \"pages\": [\n    {\n      \"title\": \"Client portal page\",\n      \"icon\": \"🚪\",\n      \"blocks\": [\n        {\n          \"object\": \"block\",\n          \"type\": \"synced_block\",\n          \"synced_block\": {\n            \"synced_from\": null\n          },\n          \"children\": [\n            {\n              \"object\": \"block\",\n              \"type\": \"column_list\",\n              \"column_list\": {},\n              \"children\": [\n                {\n                  \"object\": \"block\",\n                  \"type\": \"column\",\n                  \"column\": {},\n                  \"children\": [\n                    {\n                      \"object\": \"block\",\n                      \"type\": \"heading_2\",\n                      \"heading_2\": {\n                        \"rich_text\": [\n                          {\n                            \"type\": \"text\",\n                            \"text\": {\n                              \"content\": \"👋 Welcome\",\n                              \"link\": null\n                            }\n                          }\n                        ],\n                        \"color\": \"default\",\n                        \"is_toggleable\": false\n                      }\n                    },\n                    {\n                      \"object\": \"block\",\n                      \"type\": \"paragraph\",\n                      \"paragraph\": {\n                        \"rich_text\": [\n                          {\n                            \"type\": \"text\",\n                            \"text\": {\n                              \"content\": \"Everything about our work together, in one place. Updated as it happens. No weekly status email.\",\n                              \"link\": null\n                            }\n                          }\n                        ],\n                        \"color\": \"default\"\n                      }\n                    }\n                  ]\n                },\n                {\n                  \"object\": \"block\",\n                  \"type\": \"column\",\n                  \"column\": {},\n                  \"children\": [\n                    {\n                      \"object\": \"block\",\n                      \"type\": \"paragraph\",\n                      \"paragraph\": {\n                        \"rich_text\": [\n                          {\n                            \"type\": \"text\",\n                            \"text\": {\n                              \"content\": \"Your contact\",\n                              \"link\": null\n                            },\n                            \"annotations\": {\n                              \"bold\": true\n                            }\n                          }\n                        ],\n                        \"color\": \"default\"\n                      }\n                    },\n                    {\n                      \"object\": \"block\",\n                      \"type\": \"paragraph\",\n                      \"paragraph\": {\n                        \"rich_text\": [\n                          {\n                            \"type\": \"text\",\n                            \"text\": {\n                              \"content\": \"@you\",\n                              \"link\": null\n                            }\n                          }\n                        ],\n                        \"color\": \"default\"\n                      }\n                    },\n                    {\n                      \"object\": \"block\",\n                      \"type\": \"paragraph\",\n                      \"paragraph\": {\n                        \"rich_text\": [\n                          {\n                            \"type\": \"text\",\n                            \"text\": {\n                              \"content\": \"Next milestone\",\n                              \"link\": null\n                            },\n                            \"annotations\": {\n                              \"bold\": true\n                            }\n                          }\n                        ],\n                        \"color\": \"default\"\n                      }\n                    },\n                    {\n                      \"object\": \"block\",\n                      \"type\": \"paragraph\",\n                      \"paragraph\": {\n                        \"rich_text\": [\n                          {\n                            \"type\": \"text\",\n                            \"text\": {\n                              \"content\": \"· linked Days to milestone\",\n                              \"link\": null\n                            }\n                          }\n                        ],\n                        \"color\": \"default\"\n                      }\n                    }\n                  ]\n                }\n              ]\n            }\n          ]\n        },\n        {\n          \"object\": \"block\",\n          \"type\": \"divider\",\n          \"divider\": {}\n        },\n        {\n          \"object\": \"block\",\n          \"type\": \"heading_2\",\n          \"heading_2\": {\n            \"rich_text\": [\n              {\n                \"type\": \"text\",\n                \"text\": {\n                  \"content\": \"Where things stand\",\n                  \"link\": null\n                }\n              }\n            ],\n            \"color\": \"default\",\n            \"is_toggleable\": false\n          }\n        },\n        {\n          \"object\": \"block\",\n          \"type\": \"paragraph\",\n          \"paragraph\": {\n            \"rich_text\": [\n              {\n                \"type\": \"text\",\n                \"text\": {\n                  \"content\": \"Linked view: Deliverables → Portal board, filtered to this client and Client visible = checked.\",\n                  \"link\": null\n                }\n              }\n            ],\n            \"color\": \"default\"\n          }\n        },\n        {\n          \"object\": \"block\",\n          \"type\": \"callout\",\n          \"callout\": {\n            \"rich_text\": [\n              {\n                \"type\": \"text\",\n                \"text\": {\n                  \"content\": \"Embed the Countdown widget here, pointed at the Next milestone date. It is the one thing clients actually look at.\",\n                  \"link\": null\n                }\n              }\n            ],\n            \"icon\": {\n              \"type\": \"emoji\",\n              \"emoji\": \"⏳\"\n            },\n            \"color\": \"blue_background\"\n          }\n        },\n        {\n          \"object\": \"block\",\n          \"type\": \"embed\",\n          \"embed\": {\n            \"url\": \"https://example.com/widgets/countdown.html?label=Next%20milestone&to=2026-12-01\",\n            \"caption\": []\n          }\n        },\n        {\n          \"object\": \"block\",\n          \"type\": \"divider\",\n          \"divider\": {}\n        },\n        {\n          \"object\": \"block\",\n          \"type\": \"heading_2\",\n          \"heading_2\": {\n            \"rich_text\": [\n              {\n                \"type\": \"text\",\n                \"text\": {\n                  \"content\": \"Request something\",\n                  \"link\": null\n                }\n              }\n            ],\n            \"color\": \"default\",\n            \"is_toggleable\": false\n          }\n        },\n        {\n          \"object\": \"block\",\n          \"type\": \"paragraph\",\n          \"paragraph\": {\n            \"rich_text\": [\n              {\n                \"type\": \"text\",\n                \"text\": {\n                  \"content\": \"Publish the Client intake form view and embed it here. Submitters need no Notion account.\",\n                  \"link\": null\n                }\n              }\n            ],\n            \"color\": \"default\"\n          }\n        },\n        {\n          \"object\": \"block\",\n          \"type\": \"heading_2\",\n          \"heading_2\": {\n            \"rich_text\": [\n              {\n                \"type\": \"text\",\n                \"text\": {\n                  \"content\": \"What we have delivered\",\n                  \"link\": null\n                }\n              }\n            ],\n            \"color\": \"default\",\n            \"is_toggleable\": false\n          }\n        },\n        {\n          \"object\": \"block\",\n          \"type\": \"paragraph\",\n          \"paragraph\": {\n            \"rich_text\": [\n              {\n                \"type\": \"text\",\n                \"text\": {\n                  \"content\": \"Linked view: Deliverables → Delivered gallery.\",\n                  \"link\": null\n                }\n              }\n            ],\n            \"color\": \"default\"\n          }\n        },\n        {\n          \"object\": \"block\",\n          \"type\": \"divider\",\n          \"divider\": {}\n        },\n        {\n          \"object\": \"block\",\n          \"type\": \"callout\",\n          \"callout\": {\n            \"rich_text\": [\n              {\n                \"type\": \"text\",\n                \"text\": {\n                  \"content\": \"Before you publish: \",\n                  \"link\": null\n                },\n                \"annotations\": {\n                  \"bold\": true\n                }\n              },\n              {\n                \"type\": \"text\",\n                \"text\": {\n                  \"content\": \"audit every linked view on this page. Anything not filtered to this client and not marked Client visible will leak. Publishing exposes the page body, not the properties of the rows, but a linked view shows whatever its filter allows.\",\n                  \"link\": null\n                }\n              }\n            ],\n            \"icon\": {\n              \"type\": \"emoji\",\n              \"emoji\": \"🔒\"\n            },\n            \"color\": \"red_background\"\n          }\n        }\n      ]\n    }\n  ]\n}"},{"path":"recipes/client-portal.manual.md","type":"registry:file","target":"notion/recipes/client-portal.manual.md","content":"## Automation: notify on new intake\n\n**Why this cannot be scripted:** Database automations have no public API surface. They are configured per-database in the Notion app under ••• → Automations.\n\n1. Intake Requests → Automations → New automation.\n2. Trigger: Page created.\n3. Action: Send a Slack message to #client-requests with the Name, Client and Priority.\n4. Action: set Status to In progress and Owner to the account lead.\n\n## Automation: tell the client when a deliverable lands\n\n**Why this cannot be scripted:** Database automations have no public API surface. They are configured per-database in the Notion app under ••• → Automations.\n\n1. Deliverables → Automations → New automation.\n2. Trigger: Status changes to “In client review”.\n3. Action: add a comment @mentioning the client's contact; if they are a guest on the page, they are notified by email.\n\n## Publish the portal\n\n**Why this cannot be scripted:** Share settings and public publishing are workspace-level and not exposed on the pages API.\n\n1. Share → Publish, and enable “Allow duplicate as template” only if you want clients to copy the structure.\n2. Invite the client as a Guest on the portal page rather than on the whole workspace.\n3. Turn off comments if you do not want client comments landing in your notification feed.\n4. Put the Countdown widget embed in the page before publishing, so the milestone date is visible immediately.\n"}]}