{"id":26576480,"url":"https://github.com/getsentry/vanguard","last_synced_at":"2025-03-23T03:21:07.700Z","repository":{"id":45680367,"uuid":"476048976","full_name":"getsentry/vanguard","owner":"getsentry","description":null,"archived":false,"fork":false,"pushed_at":"2025-02-18T16:51:10.000Z","size":3899,"stargazers_count":40,"open_issues_count":26,"forks_count":3,"subscribers_count":39,"default_branch":"main","last_synced_at":"2025-03-22T06:47:12.699Z","etag":null,"topics":["tag-production"],"latest_commit_sha":null,"homepage":null,"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/getsentry.png","metadata":{"funding":{"custom":["https://sentry.io/pricing/","https://sentry.io/"]},"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"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}},"created_at":"2022-03-30T20:57:24.000Z","updated_at":"2025-02-18T16:51:14.000Z","dependencies_parsed_at":"2023-02-18T15:30:56.914Z","dependency_job_id":"8c411137-7fdb-4fee-bc41-02cc4f18fb70","html_url":"https://github.com/getsentry/vanguard","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getsentry%2Fvanguard","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getsentry%2Fvanguard/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getsentry%2Fvanguard/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getsentry%2Fvanguard/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/getsentry","download_url":"https://codeload.github.com/getsentry/vanguard/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245049599,"owners_count":20552707,"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":["tag-production"],"created_at":"2025-03-23T03:21:07.021Z","updated_at":"2025-03-23T03:21:07.680Z","avatar_url":"https://github.com/getsentry.png","language":"TypeScript","readme":"# Vanguard\n\nVanguard is an internal blog-like platform, inspired by [PlanetScale's Beam](https://github.com/planetscale/beam).\n\nAn excerpt in how we describe this at Sentry:\n\n\u003e Vanguard has been designed to provide a way to create permanence around\n\u003e timely internal moments at Sentry. While the core of it is a simple\n\u003e blog, it's intending to continuously enable the culture of sharing what\n\u003e we're building at Sentry. Additionally we have recognized the need to\n\u003e create more long lasting moments out of things that are top of mind,\n\u003e which we're dubbing as 'Strategy' in this context. You'll see several\n\u003e historical posts by myself of this nature.\n\nIt is built on top of [Remix](https://github.com/remix-run/remix), and intended to be deployed on private GCP infrastructure.\n\n**Note: This project is a work in progress, and is primarily intended for Sentry use. Our hope is that we can keep it generic enough that its usable elsewhere, but that may require effort from the open source community.**\n\n![screenshot of vanguard](/screenshot.png?raw=true)\n\n## Deployment\n\nWhile we at Sentry deploy this to GCP (using a combination of Cloud Run, Cloud Storage, and SQL), we have included the stock [blues-stack Fly config](https://github.com/remix-run/blues-stack). You will still need to configure an image storage service.\n\nYou will need to ensure a few key values are set in production:\n\n```sh\n# generate a random secret using `openssl rand -hex 32`\nSESSION_SECRET=\nDATABASE_URL=\n```\n\n### Google Auth\n\nGoogle Auth is the primary provider, although email/password is supported for local development. To configure Google, you will need to set the following value:\n\n```sh\nGOOGLE_CLIENT_ID=\nGOOGLE_CLIENT_SECRET=\nGOOGLE_IAP_AUDIENCE=\n# preferably restrict it to your domain\nGOOGLE_HD=your-google-workspace-domain.com\n```\n\nTo disable email/password authentication, you can set this option:\n\n```sh\nUSE_BASIC_LOGIN=false\n```\n\n### Sentry\n\nFor Sentry to work, you will also need the following defined:\n\n```sh\nSENTRY_DSN=\nSENTRY_ORG=\nSENTRY_PROJECT=\nSENTRY_AUTH_TOKEN=\n```\n\nFor more details on deploying to Fly, we recommend taking a look at the guide in [blues-stack](https://github.com/remix-run/blues-stack#deployment).\n\n### Images Hosting\n\nTo support avatars and image attachments on posts you will need to configure an image hosting service. This is done using environment variables:\n\n```sh\nUSE_GCS_STORAGE=1\nGCS_BUCKET_NAME=your-bucket-name\nGCS_BUCKET_PATH=images\n```\n\nYou can enable signed URLs for images by setting the expiration time in the `GCS_EXPIRES_IN` variable. In this case, you will have to provide a GCP service account, either with the Workload Identity (recommended), or with a static key (with the `GOOGLE_APPLICATION_CREDENTIALS` environment variable).\n\n```sh\n# 1 hour expiration time\nGCS_EXPIRES_IN=3600000\n```\n\nCurrently we only support Google's Cloud Storage service, but would happily take contributions to enable other services such as S3.\n\n### Outbound Email\n\nYou'll have to figure this one out. Outbound email is used for publishing new posts, as well as receiving notifications of new comments. We suggest something like Sendgrid to make it easy.\n\n```sh\nSMTP_FROM=vanguard@example.com\nSMTP_HOST=\nSMTP_PORT=\nSMTP_USER=\nSMTP_PASS=\n```\n\n## Development\n\n- Make sure you have all required tooling:\n\n  - [pre-commit](https://pre-commit.com/)\n  - [pnpm](https://pnpm.io/)\n\n- Bootstrap the environment:\n\n  ```sh\n  # this will copy the default config to .env\n  make\n  ```\n\n- Start the Postgres Database in [Docker](https://www.docker.com/get-started):\n\n  ```sh\n  docker-compose up -d\n  ```\n\n- Initial setup:\n\n  ```sh\n  make\n  ```\n\n- Create a user (assuming you've not setup Google Auth):\n\n  ```sh\n  pnpm user create \u003cemail\u003e \u003cpassword\u003e --admin\n  ```\n\n  - Create at least one category\n\n  ```sh\n  pnpm category create \u003cslug\u003e \u003cname\u003e\n  ```\n\n- Run the first build:\n\n  ```sh\n  pnpm build\n  ```\n\n- Start dev server:\n\n  ```sh\n  pnpm dev\n  ```\n\n### Authentication\n\nAuthentication is enforced per-route via the Remix loaders. All routes **must** enforce authentication unless they are intended to be publicly accessible.\n\n```typescript\nexport const loader: LoaderFunction = async ({ request, context }) =\u003e {\n  await requireUserId(request, context);\n};\n```\n\nIf you are also using actions on the route, you need to define the same check in the action:\n\n```typescript\nexport const action: ActionFunction = async ({ request, context }) =\u003e {\n  await requireUserId(request, context);\n};\n```\n\nAll endpoints which require auth must also contain a test asserting that authentication is enforced.\n\n## Testing\n\n### Vitest\n\nFor lower level tests of utilities and individual components, we use `vitest`. We have DOM-specific assertion helpers via [`@testing-library/jest-dom`](https://testing-library.com/jest-dom).\n\n### Type Checking\n\nThis project uses TypeScript. It's recommended to get TypeScript set up for your editor to get a really great in-editor experience with type checking and auto-complete. To run type checking across the whole project, run `npm run typecheck`.\n\n### Linting\n\nThis project uses ESLint for linting. That is configured in `.eslintrc.js`.\n\n### Formatting\n\nWe use [Prettier](https://prettier.io/) for auto-formatting in this project. It's recommended to install an editor plugin (like the [VSCode Prettier plugin](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)) to get auto-formatting on save. There's also a `npm run format` script you can run to format all files in the project.\n\n## License\n\nSee `LICENSE`, with an asterisk that Gazpacho is currently bundled in the repository and requires a commercial license. We'll fix this to make it optional in the future.\n","funding_links":["https://sentry.io/pricing/","https://sentry.io/"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgetsentry%2Fvanguard","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgetsentry%2Fvanguard","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgetsentry%2Fvanguard/lists"}