{"id":13880982,"url":"https://github.com/TNG/virtual-office","last_synced_at":"2025-07-16T17:31:35.980Z","repository":{"id":37012057,"uuid":"252733634","full_name":"TNG/virtual-office","owner":"TNG","description":"Virtual Office gives you transparency on what Zoom.us rooms are currently occupied and who is present","archived":false,"fork":false,"pushed_at":"2025-07-02T16:26:28.000Z","size":7714,"stargazers_count":124,"open_issues_count":28,"forks_count":13,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-07-02T17:36:27.605Z","etag":null,"topics":["collaboration","conference","office","remote","video","virtual","zoom"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TNG.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE-OF-CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-04-03T13:01:33.000Z","updated_at":"2025-03-16T17:53:57.000Z","dependencies_parsed_at":"2024-04-06T02:33:11.725Z","dependency_job_id":"806c2241-1b1a-41fb-9363-89e7892e90f6","html_url":"https://github.com/TNG/virtual-office","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/TNG/virtual-office","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TNG%2Fvirtual-office","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TNG%2Fvirtual-office/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TNG%2Fvirtual-office/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TNG%2Fvirtual-office/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TNG","download_url":"https://codeload.github.com/TNG/virtual-office/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TNG%2Fvirtual-office/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265527552,"owners_count":23782480,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["collaboration","conference","office","remote","video","virtual","zoom"],"created_at":"2024-08-06T08:03:43.983Z","updated_at":"2025-07-16T17:31:34.880Z","avatar_url":"https://github.com/TNG.png","language":"TypeScript","readme":"Virtual Office\n===============================\n\nDid you ever wonder where your colleague currently is? In what Zoom.us room they hide?\n\nVirtual Office tries to give you transparency on what Zoom.us rooms are occupied and who is currently there.\n\n![Virtual Office Screenshot](/screenshot.png?raw=true)\n\n### Features\n\n* React Web UI\n* Uses [Zoom.us Webhooks](https://marketplace.zoom.us/docs/guides/tools-resources/webhooks) to give a real-time status update on who currently participates in what Zoom.us room\n* Login via Slack\n\nAt TNG we've also hosted a big company internal event with 450 participants using Virtual Office. If you're interested,\nyou can find our experiences in two articles (German only):\n\n* [Strategische Firmenevents zu Zeiten von Corona – Virtueller Sommerretreat 2020 bei TNG](https://www.linkedin.com/pulse/strategische-firmenevents-zu-zeiten-von-corona-2020-bei-mueller)\n* [Strategische Firmenevents auch remote technisch richtig gestalten – Virtueller Sommerretreat 2020 bei TNG](https://www.linkedin.com/pulse/strategische-firmenevents-auch-remote-technisch-richtig-mueller)\n\n\n### Installation\n\n0. Checkout the repository.\n    ```\n    git clone https://github.com/TNG/virtual-office\n    ```\n\n0. Install all dependencies.\n    ```\n    npm run installAll\n    ```\n\n0. Create a new Slack App, as currently the only authentication option is Slack (https://api.slack.com/apps).\n\n    * Extract `Basic Information`\n      * You will need the `Client ID` and `Client Secret` in the server config\n    * Configure `OAuth \u0026 Permissions`\n      * Redirect URL: `${YOUR_BASE_URL_COMES_HERE}/auth/slack/callback`\n      * User Token Scope: `identity.basic`, `identity.avatar`, `identity.email`\n\n0. Adapt the Virtual Office configuration.\n\n    * via `.env` file: Copy `\u003cclient|server\u003e/.env-example` to `\u003cclient|server\u003e/.env` and adapt the content. All entries will be available to the app as environment variables.\n    * set the environment variables manually, i.e. for using it via some deployment plan in a CI server.\n\n0. Configure the Zoom.us webhooks\n\n    * Navigate to the [Zoom.us Marketplace](https://marketplace.zoom.us/)\n    * Click `Manage` and create a new webhook application\n    * Fill out the usual information, go to `Feature` and enable `Event Subscriptions`, add a new subscription with\n        * Events:\n            * End Meeting\n            * Participant/Host joined meeting\n            * Participant/Host left meeting\n        * Notification endpoint URL: \\\n            `${YOUR_BASE_URL_COMES_HERE}/api/zoomus/webhook`\n\n0. Compile and start the application in production mode\n    ```\n    npm run buildAll\n    cd server \u0026\u0026 npm start\n    ```\n\n0. (Alternative) Serve the application in development mode\n    ```\n    cd server \u0026\u0026 npm run dev\n    cd client \u0026\u0026 npm start\n    ```\n\n#### Available Environment Variables\n\n| Variable name                              | Usage\n| --------------------                       |:----------------\n| `PORT`                                     | Port the app is running on, defaults to 9000\n| `SLACK_CLIENT_ID`                          | The Client ID you got when creating the Slack application\n| `SLACK_SECRET`                             | The Client Secret you got when creating the Slack application\n| `CONFIG` OR `CONFIG_LOCATION`              | A office config as JSON string `OR`\u003cbr\u003eA file system location to the office configuration\n| `SESSION_SECRET`                           | Secret that is used to encrypt cookies that are stored on client side. If you omit this option, a new secret will be generated on each server start (meaning that users will have to re-login after each server restart!)\n| `ADMIN_USERNAME`                           | Username for accessing admin endpoints\n| `ADMIN_PASSWORD`                           | Password for accessing admin endpoints\n| `VIEW_MODE`                                | Determines how the frontend will show the rooms, either `list` or `grid`\n| `THEME`                                    | Either `light` or `dark`\n| `BACKGROUND_URL`                           | URL to a background image\n| `LOGO_URL`                                 | URL to a logo image to be included in the header\n| `FAVICON_URL`                              | URL to a favicon\n| `WRITE_OFFICE_UPDATES_TO_FILE_SYSTEM`      | When replacing the office via the /admin API, write the changes to the filesstem. Will only be done when set to `true`\n| `TIMEZONE`                                 | Timezone determining the start and end dates of sessions. If unset, the server will use the server timezone and the clients will use the client timezone. Timezone is in format \"Europe/Berlin\", a list can be found [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)\n| `TITLE`                                    | Title of the app\n| `DISABLE_AUTH`                             | When hosting public events that do not require a login, set this to `true`\n| `SESSION_START_MINUTES_OFFSET`             | Number of minutes the session is considered active (so events will be sent to the client, people can join)\n| `HIDE_ENDED_SESSIONS`                      | When sessions shall be hidden after they have ended, set this to `true`\n\n#### Office Configuration\n\nYou can find an example office definition in `server/office.json`.\n\nAn example looks like this:\n\n```json\n{\n  \"groups\": [\n    {\n      \"id\": \"star_wars\",\n      \"name\": \"Star Wars\",\n      \"groupJoin\": {\n        \"minimumParticipantCount\": 3\n      },\n      \"disabledBefore\": \"2020-05-29T17:15:00.000+02:00\",\n      \"disabledAfter\": \"2020-05-29T19:00:00.000+02:00\"\n    }\n  ],\n  \"rooms\": [\n    {\n      \"meetingId\": \"1\",\n      \"name\": \"Lobby\",\n      \"subtitle\": \"This is where everything starts.\",\n      \"joinUrl\": \"https://zoom.us/j/1\",\n      \"links\": [\n        {\n          \"href\": \"http://www.google.de\",\n          \"text\": \"Google\",\n          \"icon\": \"https://upload.wikimedia.org/wikipedia/commons/5/53/Google_%22G%22_Logo.svg\"\n        }\n      ],\n      \"icon\": \"https://cdn.pixabay.com/photo/2015/11/03/09/03/meeting-1019995_960_720.jpg\"\n    },\n    {\n      \"meetingId\": \"2\",\n      \"name\": \"Alderaan\",\n      \"joinUrl\": \"https://zoom.us/j/2\",\n      \"links\": [\n        {\n          \"href\": \"https://www.atlassian.com\",\n          \"text\": \"Issue Tracker\",\n          \"icon\": \"https://pbs.twimg.com/profile_images/1026572523230515200/Qifq4jpS_400x400.jpg\"\n        },\n        {\n          \"href\": \"http://www.miro.com\",\n          \"text\": \"Whiteboard\",\n          \"icon\": \"https://avatars.slack-edge.com/2019-03-07/570928183895_30458630978ac1eccde9_512.png\"\n        }\n      ],\n      \"groupId\": \"star_wars\",\n      \"icon\": \"https://cdn.pixabay.com/photo/2015/11/03/09/03/meeting-1019995_960_720.jpg\"\n    }\n  ]\n}\n```\n**Important:**\nFor the Zoom.us webhooks to work, the meetingId has to be the zoom.us meeting ID, as this id acts as correlation id for webhook events from zoom.\n\n`groupJoin` within the `groups` property is optional and defines whether existing rooms will be filled up by a separate\njoin button on the group.\n\n#### Admin Endpoints\n\nYou can view all available endpoints at `/api-docs`.\n\n### Development\n\nYou have to provide configuration parameters to the server by environment variables.\nAs a convenient alternative you can provide it via an `.env` file (see `.env-example`) that will be loaded by [dotenv](https://www.npmjs.com/package/dotenv).\n\n### Contributing\n\nSee [CONTRIBUTING](CONTRIBUTING.md) for details.\n\n### License\n\nVirtual Office is published under the Apache License 2.0, see\nhttps://www.apache.org/licenses/LICENSE-2.0 for details.\n","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTNG%2Fvirtual-office","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FTNG%2Fvirtual-office","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTNG%2Fvirtual-office/lists"}