[{"data":1,"prerenderedAt":1233},["ShallowReactive",2],{"app-page-pluralspace":3},{"id":4,"title":5,"app_id":6,"apple_store":7,"body":8,"description":1128,"export":77,"export_shape":1129,"extension":1130,"google_play":7,"import":77,"last_verified":1131,"license":1132,"links":1133,"logo":1137,"mapping":1138,"meta":1173,"modules":1174,"name":545,"navigation":77,"order":56,"path":1225,"platform":1226,"repo":42,"self_reported":77,"seo":1227,"spec_version":488,"status":1228,"stem":1229,"summary":1230,"website":1231,"__hash__":1232},"apps\u002Fapps\u002Fpluralspace.md","Pluralspace","pluralspace",null,{"type":9,"value":10,"toc":1114},"minimark",[11,16,20,23,27,30,33,36,385,389,392,400,422,433,440,455,724,728,743,749,755,758,768,772,815,820,824,850,861,1021,1028,1032,1037,1060,1064,1078,1082,1093,1097,1100,1107,1110],[12,13,15],"h2",{"id":14},"what-pluralspace-is","What PluralSpace is",[17,18,19],"p",{},"PluralSpace is an app for plural systems (web, PWA, and mobile soon). It is a monolithic Laravel setup with\nInertiaJS and VueJS as the current UI. Mobile apps are being written in CapacitorJS, and use an on-device\nencrypted SQLite database for offline support with sync to PluralSpace's API.",[17,21,22],{},"PluralSpace helped shape several PluralPort modules. The provisional relationships module for example\nwas first mapped against PluralSpace's data model and then generalized.",[12,24,26],{"id":25},"infrastructure","Infrastructure",[17,28,29],{},"PluralSpace runs on a cluster of servers with a load balancer in front of them. 3 servers run the web app, api, feedback\nportal, support portal, and public profiles (public profiles are deprecated, and will be removed in a future release).",[17,31,32],{},"2 servers are dedicated to queue workers, which handle background tasks like sending emails, generating exports, and\nprocessing imports, and any request that would take longer than a few seconds to complete. The queue workers are also\nresponsible for generating the ZIP files for exports, and for processing the ZIP files for imports.",[17,34,35],{},"This may seem overkill, but it allows PluralSpace to support the ~5.5 million requests per day (~150 million requests per month)\nthe app receives and the ~16,000 daily active users (1.3-2k concurrent at any time), while still being able to process everything.",[37,38,43],"pre",{"className":39,"code":40,"language":41,"meta":42,"style":42},"language-mermaid shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","flowchart LR\n    web[\"Web users\"]\n    api[\"API requests\"]\n    mobile[\"Mobile apps\"]\n\n    cloudflare[\"Cloudflare\u003Cbr\u002F>Proxy enabled\"]\n    r2[(\"Cloudflare R2\u003Cbr\u002F>Object storage\")]\n\n    web -->|\"HTTPS\u002FWSS\"| cloudflare\n    api -->|\"HTTPS\"| cloudflare\n    mobile -->|\"API\u002FOTA\u002FWSS\"| cloudflare\n\n    subgraph vpc[\"VPC - DigitalOcean infrastructure\"]\n        lb[\"Load balancer\u003Cbr\u002F>Only public endpoint\"]\n\n        subgraph private[\"Private Infra\"]\n            subgraph apps[\"3 application servers (Web\u002FAPI)\"]\n                app1[\"App server 1\"]\n                app2[\"App server 2\"]\n                app3[\"App server 3\"]\n            end\n\n            websocket[\"WebSocket server\u003Cbr\u002F>1 server\"]\n            ota[\"OTA update server\u003Cbr\u002F>Upcoming mobile infrastructure\"]\n\n            subgraph workers[\"Queue workers and cron jobs\"]\n                worker1[\"Worker server 1\"]\n                worker2[\"Worker server 2\"]\n            end\n\n            postgres[(\"PostgreSQL 18\")]\n            redis[(\"Redis\")]\n            meili[\"Meilisearch\"]\n            sentry[\"Sentry\u003Cbr\u002F>Backend errors only no PII\u003Cbr\u002F>Self hosted w\u002Fo telemetry\"]\n        end\n\n        lb -->|\"Web\u002FAPI\"| apps\n        lb \u003C-->|\"WebSocket traffic\"| websocket\n        lb -->|\"OTA requests\"| ota\n\n        apps \u003C--> postgres\n        apps \u003C--> redis\n        apps \u003C--> meili\n        apps --> websocket\n\n        redis \u003C-->|\"Queued jobs\"| workers\n        workers \u003C--> postgres\n        workers \u003C--> meili\n        workers --> websocket\n\n        apps -.-> sentry\n        workers -.-> sentry\n    end\n\n    cloudflare -->|\"HTTPS\u002FWSS\"| lb\n    cloudflare \u003C--> r2\n    apps --> r2\n    workers --> r2\n","mermaid","",[44,45,46,54,60,66,72,79,85,91,96,102,108,114,119,125,131,136,142,148,154,160,166,172,177,183,189,194,200,206,212,217,222,228,234,240,246,252,257,263,269,275,280,286,292,298,304,309,315,321,327,333,338,344,350,356,361,367,373,379],"code",{"__ignoreMap":42},[47,48,51],"span",{"class":49,"line":50},"line",1,[47,52,53],{},"flowchart LR\n",[47,55,57],{"class":49,"line":56},2,[47,58,59],{},"    web[\"Web users\"]\n",[47,61,63],{"class":49,"line":62},3,[47,64,65],{},"    api[\"API requests\"]\n",[47,67,69],{"class":49,"line":68},4,[47,70,71],{},"    mobile[\"Mobile apps\"]\n",[47,73,75],{"class":49,"line":74},5,[47,76,78],{"emptyLinePlaceholder":77},true,"\n",[47,80,82],{"class":49,"line":81},6,[47,83,84],{},"    cloudflare[\"Cloudflare\u003Cbr\u002F>Proxy enabled\"]\n",[47,86,88],{"class":49,"line":87},7,[47,89,90],{},"    r2[(\"Cloudflare R2\u003Cbr\u002F>Object storage\")]\n",[47,92,94],{"class":49,"line":93},8,[47,95,78],{"emptyLinePlaceholder":77},[47,97,99],{"class":49,"line":98},9,[47,100,101],{},"    web -->|\"HTTPS\u002FWSS\"| cloudflare\n",[47,103,105],{"class":49,"line":104},10,[47,106,107],{},"    api -->|\"HTTPS\"| cloudflare\n",[47,109,111],{"class":49,"line":110},11,[47,112,113],{},"    mobile -->|\"API\u002FOTA\u002FWSS\"| cloudflare\n",[47,115,117],{"class":49,"line":116},12,[47,118,78],{"emptyLinePlaceholder":77},[47,120,122],{"class":49,"line":121},13,[47,123,124],{},"    subgraph vpc[\"VPC - DigitalOcean infrastructure\"]\n",[47,126,128],{"class":49,"line":127},14,[47,129,130],{},"        lb[\"Load balancer\u003Cbr\u002F>Only public endpoint\"]\n",[47,132,134],{"class":49,"line":133},15,[47,135,78],{"emptyLinePlaceholder":77},[47,137,139],{"class":49,"line":138},16,[47,140,141],{},"        subgraph private[\"Private Infra\"]\n",[47,143,145],{"class":49,"line":144},17,[47,146,147],{},"            subgraph apps[\"3 application servers (Web\u002FAPI)\"]\n",[47,149,151],{"class":49,"line":150},18,[47,152,153],{},"                app1[\"App server 1\"]\n",[47,155,157],{"class":49,"line":156},19,[47,158,159],{},"                app2[\"App server 2\"]\n",[47,161,163],{"class":49,"line":162},20,[47,164,165],{},"                app3[\"App server 3\"]\n",[47,167,169],{"class":49,"line":168},21,[47,170,171],{},"            end\n",[47,173,175],{"class":49,"line":174},22,[47,176,78],{"emptyLinePlaceholder":77},[47,178,180],{"class":49,"line":179},23,[47,181,182],{},"            websocket[\"WebSocket server\u003Cbr\u002F>1 server\"]\n",[47,184,186],{"class":49,"line":185},24,[47,187,188],{},"            ota[\"OTA update server\u003Cbr\u002F>Upcoming mobile infrastructure\"]\n",[47,190,192],{"class":49,"line":191},25,[47,193,78],{"emptyLinePlaceholder":77},[47,195,197],{"class":49,"line":196},26,[47,198,199],{},"            subgraph workers[\"Queue workers and cron jobs\"]\n",[47,201,203],{"class":49,"line":202},27,[47,204,205],{},"                worker1[\"Worker server 1\"]\n",[47,207,209],{"class":49,"line":208},28,[47,210,211],{},"                worker2[\"Worker server 2\"]\n",[47,213,215],{"class":49,"line":214},29,[47,216,171],{},[47,218,220],{"class":49,"line":219},30,[47,221,78],{"emptyLinePlaceholder":77},[47,223,225],{"class":49,"line":224},31,[47,226,227],{},"            postgres[(\"PostgreSQL 18\")]\n",[47,229,231],{"class":49,"line":230},32,[47,232,233],{},"            redis[(\"Redis\")]\n",[47,235,237],{"class":49,"line":236},33,[47,238,239],{},"            meili[\"Meilisearch\"]\n",[47,241,243],{"class":49,"line":242},34,[47,244,245],{},"            sentry[\"Sentry\u003Cbr\u002F>Backend errors only no PII\u003Cbr\u002F>Self hosted w\u002Fo telemetry\"]\n",[47,247,249],{"class":49,"line":248},35,[47,250,251],{},"        end\n",[47,253,255],{"class":49,"line":254},36,[47,256,78],{"emptyLinePlaceholder":77},[47,258,260],{"class":49,"line":259},37,[47,261,262],{},"        lb -->|\"Web\u002FAPI\"| apps\n",[47,264,266],{"class":49,"line":265},38,[47,267,268],{},"        lb \u003C-->|\"WebSocket traffic\"| websocket\n",[47,270,272],{"class":49,"line":271},39,[47,273,274],{},"        lb -->|\"OTA requests\"| ota\n",[47,276,278],{"class":49,"line":277},40,[47,279,78],{"emptyLinePlaceholder":77},[47,281,283],{"class":49,"line":282},41,[47,284,285],{},"        apps \u003C--> postgres\n",[47,287,289],{"class":49,"line":288},42,[47,290,291],{},"        apps \u003C--> redis\n",[47,293,295],{"class":49,"line":294},43,[47,296,297],{},"        apps \u003C--> meili\n",[47,299,301],{"class":49,"line":300},44,[47,302,303],{},"        apps --> websocket\n",[47,305,307],{"class":49,"line":306},45,[47,308,78],{"emptyLinePlaceholder":77},[47,310,312],{"class":49,"line":311},46,[47,313,314],{},"        redis \u003C-->|\"Queued jobs\"| workers\n",[47,316,318],{"class":49,"line":317},47,[47,319,320],{},"        workers \u003C--> postgres\n",[47,322,324],{"class":49,"line":323},48,[47,325,326],{},"        workers \u003C--> meili\n",[47,328,330],{"class":49,"line":329},49,[47,331,332],{},"        workers --> websocket\n",[47,334,336],{"class":49,"line":335},50,[47,337,78],{"emptyLinePlaceholder":77},[47,339,341],{"class":49,"line":340},51,[47,342,343],{},"        apps -.-> sentry\n",[47,345,347],{"class":49,"line":346},52,[47,348,349],{},"        workers -.-> sentry\n",[47,351,353],{"class":49,"line":352},53,[47,354,355],{},"    end\n",[47,357,359],{"class":49,"line":358},54,[47,360,78],{"emptyLinePlaceholder":77},[47,362,364],{"class":49,"line":363},55,[47,365,366],{},"    cloudflare -->|\"HTTPS\u002FWSS\"| lb\n",[47,368,370],{"class":49,"line":369},56,[47,371,372],{},"    cloudflare \u003C--> r2\n",[47,374,376],{"class":49,"line":375},57,[47,377,378],{},"    apps --> r2\n",[47,380,382],{"class":49,"line":381},58,[47,383,384],{},"    workers --> r2\n",[12,386,388],{"id":387},"export-shape","Export shape",[17,390,391],{},"A per-system export is a ZIP, with a layout like this:",[37,393,398],{"className":394,"code":396,"language":397},[395],"language-text","pluralspace-export-2026-09-06.zip\n├── manifest.json\n├── openplural.json\n└── media\u002F\n    ├── member-avatar-018f2c3a-....webp\n    └── system-banner-018f2c41-....webp\n","text",[44,399,396],{"__ignoreMap":42},[17,401,402,403,406,407,410,411,414,415,418,419,421],{},"The implementation currently uses the legacy OpenPlural naming: ",[44,404,405],{},"openplural.json"," for the document and\n",[44,408,409],{},"openplural_version"," for its version marker. This applies to current exports as well as older ones.\n",[44,412,413],{},"manifest.json"," contains export metadata such as the date, format version, system name, and account email.\nMedia paths and SHA-256 checksums live in ",[44,416,417],{},"assets[]"," inside ",[44,420,405],{},".",[17,423,424,425,428,429,432],{},"A whole-account export contains account-level data plus one document at ",[44,426,427],{},"systems\u002F{slug}\u002Fopenplural.json","\nand a separate ",[44,430,431],{},"media\u002F"," directory inside each owned system's folder.",[17,434,435,436,439],{},"An abbreviated example of the current envelope is below. The exporter currently lists only the optional modules\nin ",[44,437,438],{},"capabilities.modules","; the other exported sections are still included in the document.",[17,441,442,446,447,450,451,454],{},[443,444,445],"strong",{},"NOTE:"," Upcoming update will include both ",[44,448,449],{},"pluralport.json"," and ",[44,452,453],{},"pluralport_version"," alongside the legacy OpenPlural fields,\nso that other apps can detect the PluralPort version without needing to rely solely on the legacy OpenPlural fields.",[37,456,460],{"className":457,"code":458,"language":459,"meta":42,"style":42},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"openplural_version\": \"0.1\",\n  \"exported_at\": \"2026-09-06T18:00:00Z\",\n  \"producer\": {\n    \"app\": \"PluralSpace\",\n    \"app_id\": \"pluralspace\",\n    \"app_version\": \"unknown\",\n    \"exporter_version\": \"0.1\"\n  },\n  \"capabilities\": {\n    \"modules\": [\n      \"chat\",\n      \"relationships\",\n      \"polls\",\n      \"boards\"\n    ]\n  },\n  \"systems\": [],\n  \"members\": []\n}\n","json",[44,461,462,468,494,514,528,550,569,589,607,612,625,639,651,662,673,682,687,691,705,719],{"__ignoreMap":42},[47,463,464],{"class":49,"line":50},[47,465,467],{"class":466},"sMK4o","{\n",[47,469,470,473,476,479,482,485,489,491],{"class":49,"line":56},[47,471,472],{"class":466},"  \"",[47,474,409],{"class":475},"spNyl",[47,477,478],{"class":466},"\"",[47,480,481],{"class":466},":",[47,483,484],{"class":466}," \"",[47,486,488],{"class":487},"sfazB","0.1",[47,490,478],{"class":466},[47,492,493],{"class":466},",\n",[47,495,496,498,501,503,505,507,510,512],{"class":49,"line":62},[47,497,472],{"class":466},[47,499,500],{"class":475},"exported_at",[47,502,478],{"class":466},[47,504,481],{"class":466},[47,506,484],{"class":466},[47,508,509],{"class":487},"2026-09-06T18:00:00Z",[47,511,478],{"class":466},[47,513,493],{"class":466},[47,515,516,518,521,523,525],{"class":49,"line":68},[47,517,472],{"class":466},[47,519,520],{"class":475},"producer",[47,522,478],{"class":466},[47,524,481],{"class":466},[47,526,527],{"class":466}," {\n",[47,529,530,533,537,539,541,543,546,548],{"class":49,"line":74},[47,531,532],{"class":466},"    \"",[47,534,536],{"class":535},"sBMFI","app",[47,538,478],{"class":466},[47,540,481],{"class":466},[47,542,484],{"class":466},[47,544,545],{"class":487},"PluralSpace",[47,547,478],{"class":466},[47,549,493],{"class":466},[47,551,552,554,557,559,561,563,565,567],{"class":49,"line":81},[47,553,532],{"class":466},[47,555,556],{"class":535},"app_id",[47,558,478],{"class":466},[47,560,481],{"class":466},[47,562,484],{"class":466},[47,564,6],{"class":487},[47,566,478],{"class":466},[47,568,493],{"class":466},[47,570,571,573,576,578,580,582,585,587],{"class":49,"line":87},[47,572,532],{"class":466},[47,574,575],{"class":535},"app_version",[47,577,478],{"class":466},[47,579,481],{"class":466},[47,581,484],{"class":466},[47,583,584],{"class":487},"unknown",[47,586,478],{"class":466},[47,588,493],{"class":466},[47,590,591,593,596,598,600,602,604],{"class":49,"line":93},[47,592,532],{"class":466},[47,594,595],{"class":535},"exporter_version",[47,597,478],{"class":466},[47,599,481],{"class":466},[47,601,484],{"class":466},[47,603,488],{"class":487},[47,605,606],{"class":466},"\"\n",[47,608,609],{"class":49,"line":98},[47,610,611],{"class":466},"  },\n",[47,613,614,616,619,621,623],{"class":49,"line":104},[47,615,472],{"class":466},[47,617,618],{"class":475},"capabilities",[47,620,478],{"class":466},[47,622,481],{"class":466},[47,624,527],{"class":466},[47,626,627,629,632,634,636],{"class":49,"line":110},[47,628,532],{"class":466},[47,630,631],{"class":535},"modules",[47,633,478],{"class":466},[47,635,481],{"class":466},[47,637,638],{"class":466}," [\n",[47,640,641,644,647,649],{"class":49,"line":116},[47,642,643],{"class":466},"      \"",[47,645,646],{"class":487},"chat",[47,648,478],{"class":466},[47,650,493],{"class":466},[47,652,653,655,658,660],{"class":49,"line":121},[47,654,643],{"class":466},[47,656,657],{"class":487},"relationships",[47,659,478],{"class":466},[47,661,493],{"class":466},[47,663,664,666,669,671],{"class":49,"line":127},[47,665,643],{"class":466},[47,667,668],{"class":487},"polls",[47,670,478],{"class":466},[47,672,493],{"class":466},[47,674,675,677,680],{"class":49,"line":133},[47,676,643],{"class":466},[47,678,679],{"class":487},"boards",[47,681,606],{"class":466},[47,683,684],{"class":49,"line":138},[47,685,686],{"class":466},"    ]\n",[47,688,689],{"class":49,"line":144},[47,690,611],{"class":466},[47,692,693,695,698,700,702],{"class":49,"line":150},[47,694,472],{"class":466},[47,696,697],{"class":475},"systems",[47,699,478],{"class":466},[47,701,481],{"class":466},[47,703,704],{"class":466}," [],\n",[47,706,707,709,712,714,716],{"class":49,"line":156},[47,708,472],{"class":466},[47,710,711],{"class":475},"members",[47,713,478],{"class":466},[47,715,481],{"class":466},[47,717,718],{"class":466}," []\n",[47,720,721],{"class":49,"line":162},[47,722,723],{"class":466},"}\n",[12,725,727],{"id":726},"import-behaviour","Import behaviour",[17,729,730,731,733,734,736,737,739,740,742],{},"PluralSpace accepts the legacy OpenPlural document shape as a JSON file or a ZIP containing ",[44,732,405],{},".\nThe document must include ",[44,735,409],{},"; a document containing only ",[44,738,453],{},", or a ZIP\ncontaining only ",[44,741,449],{},", is not currently accepted. A JSON-only import skips bundled media.",[17,744,745,746,421],{},"Unsupported modules and extension namespaces are not imported. Known unsupported modules and unrecognised\ntop-level extensions produce warnings, but there is no complete report of every dropped field. The synchronous\nimporter returns created and skipped counts per step. Queued imports show completion status and warning or error\nmessages instead of returning a structured PluralPort ",[44,747,748],{},"ImportResult",[17,750,751,752,754],{},"Records are matched using stored source references, with the file's record ID under the producer's ",[44,753,556],{}," as a\nfallback identity. Members and groups can also match upstream references from another app. Otherwise PluralSpace\ncreates new IDs. Matching records are generally skipped rather than updated, so re-importing is not a sync operation.",[17,756,757],{},"Fields inside a known record are imported only where PluralSpace has an explicit mapping. Unknown fields and\nunsupported extensions are not stored for a later export.",[17,759,760,762,763,450,765,767],{},[443,761,445],{}," Upcoming update will look for ",[44,764,449],{},[44,766,453],{}," and fall back to the legacy OpenPlural\nspec name.",[12,769,771],{"id":770},"known-loss","Known loss",[773,774,775,779,782,785,788,791,794,797,800,808],"ul",{},[776,777,778],"li",{},"Chat attachments and message reactions are not exported. Message text and member author references are exported,\nbut references to members in systems the exporting user does not own are removed.",[776,780,781],{},"Member profile visibility and field visibility overrides are exported but not restored on import. Only the first\nproxy-tag pair is imported.",[776,783,784],{},"Separate front events and front comments are not imported. Front interval notes are carried on the periods.",[776,786,787],{},"Text, textarea, and link custom-field types all export as text, so their original type distinction is lost.",[776,789,790],{},"Partner-only note and journal visibility becomes trusted. Imports do not restore the source system's visibility\nor public profile.",[776,792,793],{},"Board imports retain body, author, pinned state, and creation time, but do not retain target member, title, or audience.",[776,795,796],{},"Asset support covers member and system avatars and banners, plus the system media library. JSON-only imports\ncannot restore bundled files.",[776,798,799],{},"Unknown fields and unsupported extensions are dropped on import.",[776,801,802,803,450,805,807],{},"The ",[44,804,657],{},[44,806,668],{}," modules are still provisional. PluralSpace exports its current field interpretation,\nwhich may not match the final v0.1 shape.",[776,809,810,811,814],{},"Mood history is not a standard module. It lives in ",[44,812,813],{},"extensions[\"pluralspace:moods\"]",", so other importers may\nignore or drop it unless they preserve unsupported extensions.",[17,816,817,819],{},[443,818,445],{}," We are working on updates that will improve import\u002Fexport fidelity, preventing as much loss as possible.",[12,821,823],{"id":822},"extensions-namespace","Extensions namespace",[17,825,826,827,830,831,834,835,838,839,838,842,845,846,849],{},"Mood history is namespaced under ",[44,828,829],{},"pluralspace:moods",". Other PluralSpace-specific fields currently use unprefixed\nkeys inside record-level ",[44,832,833],{},"extensions",", such as ",[44,836,837],{},"kind",", ",[44,840,841],{},"is_pinned",[44,843,844],{},"profile_visibility",", and ",[44,847,848],{},"is_multiple",".\nThe implementation does not yet namespace every app-specific field.",[17,851,852,853,856,857,860],{},"Mood entries describe intervals. A null ",[44,854,855],{},"member_id"," means a whole-system mood, and a null ",[44,858,859],{},"ended_at"," means the\ninterval is still open:",[37,862,864],{"className":457,"code":863,"language":459,"meta":42,"style":42},"{\n  \"extensions\": {\n    \"pluralspace:moods\": [\n      {\n        \"id\": \"018f2c3a-3270-7df0-8a94-74293079c4d1\",\n        \"mood\": \"content\",\n        \"member_id\": null,\n        \"started_at\": \"2026-09-01T14:02:00Z\",\n        \"ended_at\": null,\n        \"created_at\": \"2026-09-01T14:02:00Z\"\n      }\n    ]\n  }\n}\n",[44,865,866,870,882,894,899,921,941,954,974,986,1003,1008,1012,1017],{"__ignoreMap":42},[47,867,868],{"class":49,"line":50},[47,869,467],{"class":466},[47,871,872,874,876,878,880],{"class":49,"line":56},[47,873,472],{"class":466},[47,875,833],{"class":475},[47,877,478],{"class":466},[47,879,481],{"class":466},[47,881,527],{"class":466},[47,883,884,886,888,890,892],{"class":49,"line":62},[47,885,532],{"class":466},[47,887,829],{"class":535},[47,889,478],{"class":466},[47,891,481],{"class":466},[47,893,638],{"class":466},[47,895,896],{"class":49,"line":68},[47,897,898],{"class":466},"      {\n",[47,900,901,904,908,910,912,914,917,919],{"class":49,"line":74},[47,902,903],{"class":466},"        \"",[47,905,907],{"class":906},"sbssI","id",[47,909,478],{"class":466},[47,911,481],{"class":466},[47,913,484],{"class":466},[47,915,916],{"class":487},"018f2c3a-3270-7df0-8a94-74293079c4d1",[47,918,478],{"class":466},[47,920,493],{"class":466},[47,922,923,925,928,930,932,934,937,939],{"class":49,"line":81},[47,924,903],{"class":466},[47,926,927],{"class":906},"mood",[47,929,478],{"class":466},[47,931,481],{"class":466},[47,933,484],{"class":466},[47,935,936],{"class":487},"content",[47,938,478],{"class":466},[47,940,493],{"class":466},[47,942,943,945,947,949,951],{"class":49,"line":87},[47,944,903],{"class":466},[47,946,855],{"class":906},[47,948,478],{"class":466},[47,950,481],{"class":466},[47,952,953],{"class":466}," null,\n",[47,955,956,958,961,963,965,967,970,972],{"class":49,"line":93},[47,957,903],{"class":466},[47,959,960],{"class":906},"started_at",[47,962,478],{"class":466},[47,964,481],{"class":466},[47,966,484],{"class":466},[47,968,969],{"class":487},"2026-09-01T14:02:00Z",[47,971,478],{"class":466},[47,973,493],{"class":466},[47,975,976,978,980,982,984],{"class":49,"line":98},[47,977,903],{"class":466},[47,979,859],{"class":906},[47,981,478],{"class":466},[47,983,481],{"class":466},[47,985,953],{"class":466},[47,987,988,990,993,995,997,999,1001],{"class":49,"line":104},[47,989,903],{"class":466},[47,991,992],{"class":906},"created_at",[47,994,478],{"class":466},[47,996,481],{"class":466},[47,998,484],{"class":466},[47,1000,969],{"class":487},[47,1002,606],{"class":466},[47,1004,1005],{"class":49,"line":110},[47,1006,1007],{"class":466},"      }\n",[47,1009,1010],{"class":49,"line":116},[47,1011,686],{"class":466},[47,1013,1014],{"class":49,"line":121},[47,1015,1016],{"class":466},"  }\n",[47,1018,1019],{"class":49,"line":127},[47,1020,723],{"class":466},[17,1022,1023,1024,1027],{},"Importers that do not understand these keys can ignore them, but will lose the associated mood history or\napp-specific detail. For example, ",[44,1025,1026],{},"extensions.kind"," distinguishes a journal entry from a member note.",[12,1029,1031],{"id":1030},"how-to-get-an-export","How to get an export",[1033,1034,1036],"h3",{"id":1035},"system-export","System Export",[1038,1039,1040,1050,1057],"ol",{},[776,1041,1042,1043,1046,1047,421],{},"Open ",[443,1044,1045],{},"System Settings",", then ",[443,1048,1049],{},"Data Export",[776,1051,1052,1053,1056],{},"Pick ",[443,1054,1055],{},"OpenPlural"," and request the export.",[776,1058,1059],{},"Exports are queued, and you will receive a notification when the ZIP is ready for download.",[1033,1061,1063],{"id":1062},"account-export","Account Export",[1038,1065,1066,1073,1076],{},[776,1067,1042,1068,1046,1071,421],{},[443,1069,1070],{},"Account Settings",[443,1072,1049],{},[776,1074,1075],{},"Request the export. The account page uses OpenPlural automatically and does not have a format picker.",[776,1077,1059],{},[12,1079,1081],{"id":1080},"architecture","Architecture",[773,1083,1084,1087,1090],{},[776,1085,1086],{},"Structured data lives in Postgres. Media lives in Cloudflare R2. Bundled media is streamed from object storage into\na temporary directory, then added to the ZIP. Large record collections are written incrementally, so the full export\ndoes not need to fit in app memory, but temporary disk space is still required for the staged files and archive.",[776,1088,1089],{},"Exports are generated on a queue worker instead of in the request cycle. A system with hundreds of thousands of\nrecords can take minutes.",[776,1091,1092],{},"Media checksums use SHA-256 and are computed from the staged files during export. Bundling reads the media files\nand does not rely on checksums saved at upload time.",[12,1094,1096],{"id":1095},"privacy-handling","Privacy handling",[17,1098,1099],{},"Data is encrypted in transit. Journal content, note content, and other sensitive data is encrypted by the application\nbefore storage, but the export contains their decrypted content in a plaintext ZIP. Treat it as sensitive. Any encryption\nprovided by the hosting or storage layer is separate.",[17,1101,1102,1103,1106],{},"Privacy flags on systems, members, and custom fields are exported as ",[44,1104,1105],{},"Privacy"," objects. Notes also carry their\nvisibility, but this does not preserve the complete visibility model. Partner-only note visibility becomes trusted,\nand PluralSpace's importer does not restore system visibility or member profile and field visibility overrides.",[17,1108,1109],{},"An upcoming update (TBD when) will introduce privacy buckets, mimicking what was available through SimplyPlural. This\nwill allow for more granular privacy control and better preservation of visibility settings during import\u002Fexport operations.",[1111,1112,1113],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":42,"searchDepth":56,"depth":56,"links":1115},[1116,1117,1118,1119,1120,1121,1122,1126,1127],{"id":14,"depth":56,"text":15},{"id":25,"depth":56,"text":26},{"id":387,"depth":56,"text":388},{"id":726,"depth":56,"text":727},{"id":770,"depth":56,"text":771},{"id":822,"depth":56,"text":823},{"id":1030,"depth":56,"text":1031,"children":1123},[1124,1125],{"id":1035,"depth":62,"text":1036},{"id":1062,"depth":62,"text":1063},{"id":1080,"depth":56,"text":1081},{"id":1095,"depth":56,"text":1096},"Web app targeting PluralPort v0.1 with legacy OpenPlural import and export, bundled media, relationships, boards, polls, and PluralSpace-specific mood preservation.","Per-system ZIP containing manifest.json, openplural.json, and media\u002F. Whole-account exports contain account data plus one OpenPlural document per owned system.","md","2026-09-06","Proprietary",[1134],{"label":1135,"href":1136},"Implementation profile","https:\u002F\u002Fgithub.com\u002Fpluralport\u002Fspec\u002Fblob\u002Fmain\u002Fdocs\u002Fapps\u002Fpluralspace.md","https:\u002F\u002Fpluralspace.app\u002Ficons\u002Fpluralspace_icon.svg",[1139,1141,1144,1147,1150,1153,1156,1159,1162,1165,1168,1170],{"source":711,"target":1140},"Member records with proxy tags, privacy, profile visibility, pinned state, and template state",{"source":1142,"target":1143},"fronts and system front types","FrontPeriod with one member assignment per interval; front types become status TaxonomyTerms and TaxonomyAssignments",{"source":1145,"target":1146},"member roles","Role TaxonomyTerms and TaxonomyAssignments",{"source":1148,"target":1149},"member groups and memberships","Group with parent_group_id plus GroupMembership records",{"source":1151,"target":1152},"custom fields and custom field values","CustomFieldDefinition and CustomFieldValue records",{"source":1154,"target":1155},"journal entries and notes","Note records distinguished by extensions.kind as journal or note",{"source":1157,"target":1158},"chat channels and messages","Conversation and ChatMessage records with member author IDs",{"source":1160,"target":1161},"relationship types and member relationships","Provisional relationships module with RelationshipType and MemberRelationship records",{"source":1163,"target":1164},"polls, options, and votes","Provisional polls module using PluralSpace's current field interpretation",{"source":1166,"target":1167},"thought of the day entries","System-wide BoardPost records with extensions.kind set to thought_of_the_day",{"source":1169,"target":813},"system and member mood entries",{"source":1171,"target":1172},"member and system media","Asset records with bundled files, source references, and checksums",{},[1175,1178,1180,1183,1187,1190,1193,1196,1199,1202,1204,1206,1208,1210,1214,1217,1220,1223],{"key":697,"support":1176,"note":1177},"partial","System records export; imports fill selected settings in an existing system without restoring its identity, visibility, or public profile.",{"key":711,"support":1176,"note":1179},"Exports proxy tags, privacy, profile visibility, pinned and template state; imports keep one proxy-tag pair and do not restore profile visibility or field visibility overrides.",{"key":1181,"support":1176,"note":1182},"fronting","One assignment per exported interval; overlapping periods represent co-fronting. Separate front events and front comments are not imported.",{"key":1184,"support":1185,"note":1186},"groups","full","Nested groups preserve parent_group_id; memberships exported separately.",{"key":1188,"support":1185,"note":1189},"taxonomy","Carries front types and member roles.",{"key":1191,"support":1176,"note":1192},"custom_fields","Definitions and populated values, including privacy and multi-value metadata; text, textarea, and link types all export as text.",{"key":1194,"support":1176,"note":1195},"notes","Journals and notes share notes[], distinguished by extensions.kind; partner-only visibility becomes trusted.",{"key":1197,"support":1176,"note":1198},"assets","Member and system avatars and banners, plus system library files, bundle with SHA-256 checksums and source references. Media import requires the ZIP.",{"key":1200,"support":1176,"note":1201},"privacy","Exported for systems, members, and custom fields; notes carry visibility. Imports do not restore system visibility or member profile visibility overrides, and some note tiers are combined.",{"key":646,"support":1176,"note":1203},"Channels and messages export; attachments and reactions do not.",{"key":679,"support":1176,"note":1205},"Thought of the day becomes system-wide BoardPost records; imports keep body, author, pinned state, and creation time, but not target member, title, or audience.",{"key":657,"support":1176,"note":1207},"Provisional module; shape may change before v0.1 is final.",{"key":668,"support":1176,"note":1209},"Provisional module; uses PluralSpace's current field interpretation.",{"key":1211,"support":1212,"note":1213},"reminders","none","PluralSpace has reminder is early testing, but they are not mapped for import or export.",{"key":1215,"support":1212,"note":1216},"habits","No equivalent concept in PluralSpace.",{"key":1218,"support":1212,"note":1219},"proxy","The standalone proxy module is not mapped; member proxy tags are carried on Member records.",{"key":1221,"support":1212,"note":1222},"sharing","Sharing is handled differently in PluralSpace, no exact path to export yet.",{"key":1224,"support":1212,"note":1216},"safety","\u002Fapps\u002Fpluralspace","Web (hosted)",{"description":1128},"adopter","apps\u002Fpluralspace","Hosted web app targeting PluralPort v0.1, currently using OpenPlural filenames and version markers. Covers systems, members, front intervals, groups, taxonomy, custom fields, notes, chat, boards, assets, and privacy, plus the provisional relationships and polls modules, with some loss on import. Mood history is preserved under extensions[\"pluralspace:moods\"].","https:\u002F\u002Fpluralspace.app","gxqG9Y6bh4347Ll4HFbH5QFUZw8y6d9pQp8nVV39a44",1792272242370]