{ "description": "Space-apps registry vectors: which apps are installed FOR THE WHOLE SPACE. The registry is fold state from wire events in the hidden all-members space thread's encrypted log — the server never learns which app was installed. Source of truth: web/static/apps.js (the spaceapps system app); design: docs/space-apps.md.", "app": "spaceapps", "source": "web/static/apps.js (installsApp — one registry for every shared place; this file pins its spaceapps event family)", "state_shape": { "apps": [ { "id": "string (the installed app's name, e.g. \"bookmarks\")", "by": "string (installer's sender name)", "ts": "number (epoch ms)", "uid": "string (the installer's user id — \"\" on pre-uid logs; the admins-only policy filters by it at read time)" } ] }, "notes": [ "The fold is the groupapps registry's twin, one level up: the item id IS the app name, so a duplicate install (any member, any refold) is a no-op and a remove needs no lookup.", "Unknown app names fold into state unchanged in shape — clients filter to registered, spaceCapable apps at READ time (spaceAppsFor), so old and new clients converge on the same log.", "No chat projection: the space thread has no chat view and no sidebar row, so spaceapps declares no chatMessage/preview — the Apps sheet's \"Installed for everyone by …\" line is the visible record.", "A space-installed app's own events posted into the space thread fold with the app's ordinary vectors — same events, same reducer, keyed by the space thread instead of a personal or group one." ], "vectors": [ { "name": "spaceapps_install", "description": "A member installs an app for everyone in the space.", "event": { "type": "spaceapps.add", "app": "bookmarks", "name": "Ana", "ts": 1700000000000, "uid": "u-ana" }, "expected_state_update": { "apps": [ { "id": "bookmarks", "by": "Ana", "ts": 1700000000000, "uid": "u-ana" } ] } }, { "name": "spaceapps_install_duplicate", "description": "Re-installing an already-installed app is a no-op (idempotent by app name).", "event": { "type": "spaceapps.add", "app": "bookmarks", "name": "Bob", "ts": 1700000005000, "uid": "u-bob" }, "initial_state": { "apps": [ { "id": "bookmarks", "by": "Ana", "ts": 1700000000000, "uid": "u-ana" } ] }, "expected_state_update": { "apps": [ { "id": "bookmarks", "by": "Ana", "ts": 1700000000000, "uid": "u-ana" } ] } }, { "name": "spaceapps_install_unknown_app", "description": "An install naming an app this client doesn't know still folds — it stays inert at read time, so clients on different versions converge on the same log.", "event": { "type": "spaceapps.add", "app": "someday-app", "name": "Ana", "ts": 1700000010000, "uid": "u-ana" }, "initial_state": { "apps": [ { "id": "bookmarks", "by": "Ana", "ts": 1700000000000, "uid": "u-ana" } ] }, "expected_state_update": { "apps": [ { "id": "bookmarks", "by": "Ana", "ts": 1700000000000, "uid": "u-ana" }, { "id": "someday-app", "by": "Ana", "ts": 1700000010000, "uid": "u-ana" } ] } }, { "name": "spaceapps_remove", "description": "Any member removes a space-wide install.", "event": { "type": "spaceapps.remove", "app": "bookmarks", "name": "Bob", "ts": 1700000020000 }, "initial_state": { "apps": [ { "id": "bookmarks", "by": "Ana", "ts": 1700000000000, "uid": "u-ana" } ] }, "expected_state_update": { "apps": [] } }, { "name": "spaceapps_remove_absent", "description": "Removing an app that isn't installed is a no-op (a remove can race another member's remove).", "event": { "type": "spaceapps.remove", "app": "bookmarks", "name": "Bob", "ts": 1700000030000 }, "initial_state": { "apps": [] }, "expected_state_update": { "apps": [] } }, { "name": "spaceapps_add_malformed", "description": "A hostile or malformed install (missing/non-string app) folds to a no-op, never a crash.", "event": { "type": "spaceapps.add", "name": "Mallory", "ts": 1700000040000 }, "initial_state": { "apps": [] }, "expected_state_update": { "apps": [] } } ] }