{"id":45904770,"url":"https://github.com/linuxfoundation/lfx-changelog","last_synced_at":"2026-04-02T11:35:16.128Z","repository":{"id":340860188,"uuid":"1167830233","full_name":"linuxfoundation/lfx-changelog","owner":"linuxfoundation","description":null,"archived":false,"fork":false,"pushed_at":"2026-04-02T01:20:16.000Z","size":1566,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-02T04:38:55.875Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/linuxfoundation.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-26T18:21:53.000Z","updated_at":"2026-04-02T01:20:18.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/linuxfoundation/lfx-changelog","commit_stats":null,"previous_names":["linuxfoundation/lfx-changelog"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/linuxfoundation/lfx-changelog","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linuxfoundation%2Flfx-changelog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linuxfoundation%2Flfx-changelog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linuxfoundation%2Flfx-changelog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linuxfoundation%2Flfx-changelog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/linuxfoundation","download_url":"https://codeload.github.com/linuxfoundation/lfx-changelog/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linuxfoundation%2Flfx-changelog/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31305645,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T09:48:21.550Z","status":"ssl_error","status_checked_at":"2026-04-02T09:48:19.196Z","response_time":89,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2026-02-28T01:49:05.810Z","updated_at":"2026-04-02T11:35:16.122Z","avatar_url":"https://github.com/linuxfoundation.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LFX Changelog\n\nA centralized changelog platform for [LFX](https://lfx.linuxfoundation.org/) products. Provides a unified, public-facing timeline of product updates and an admin interface for teams to draft, review, and publish release notes with AI-assisted generation.\n\n## Features\n\n### Public\n\n- 📰 **Changelog feed** — filterable timeline of published entries across all LFX products\n- 📦 **Per-product views** — dedicated changelog pages for each of the 9 LFX products\n- 🔗 **Pretty URLs** — human-readable slugs (e.g., `/entry/security-march-2026-patches`)\n- 🔍 **Full-text search** — OpenSearch-powered with fuzzy matching, highlighting, and product faceting\n- 👁️ **Changelog views** — unseen-count tracking so external LFX apps can show notification badges\n- 🌙 **Dark mode** — light/dark dual-theme with system preference detection\n\n### Admin\n\n- 📊 **Dashboard** — overview of drafts, published entries, and recent activity\n- ✏️ **Changelog editor** — Markdown-based editor with live preview and category tagging\n- 🔐 **Role-based access** — super admin, product admin, and editor roles with per-product scoping\n\n### AI\n\n- 🤖 **Changelog agent** — Claude Agent SDK pipeline that auto-generates drafts from GitHub commits, merged PRs, and releases\n- 📝 **Blog generation** — monthly roundup blog posts synthesized from recent changelogs, with admin editor and public feed\n- 💬 **Chat assistant** — conversational AI that answers questions about changelog data with streaming responses\n\n### Integrations\n\n- 🐙 **GitHub** — GitHub App for repository tracking, release syncing, and webhook-driven changelog generation\n- 💬 **Slack** — share published changelogs to Slack channels with rich BlockKit messages\n- 🔌 **MCP server** — AI tool integration via the Model Context Protocol (Claude Desktop, Cursor, etc.)\n\n### Infrastructure\n\n- 🔑 **Auth0 + API keys** — OAuth sessions and scoped API keys for programmatic access (CI/CD, scripts, external tools)\n- ⚡ **Server-side rendering** — Angular SSR for fast initial loads and SEO\n- 📈 **Observability** — Datadog APM, RUM with session replay, and structured HTTP request logging\n- 🧪 **E2E test suite** — Playwright tests covering public pages, admin flows, RBAC, and API endpoints\n\n## Tech Stack\n\n| Layer       | Technology                                            |\n| ----------- | ----------------------------------------------------- |\n| Monorepo    | Turborepo + Yarn 4 workspaces                         |\n| Frontend    | Angular 20 (standalone components, signals, zoneless) |\n| Backend     | Express 5 (via Angular SSR server)                    |\n| Database    | PostgreSQL 16                                         |\n| ORM         | Prisma 7 with driver adapter                          |\n| Validation  | Zod 4 + OpenAPI 3.1 (Swagger UI at `/docs`)           |\n| Auth        | Auth0 (`express-openid-connect`)                      |\n| Styling     | Tailwind CSS 4 (CSS-first config, custom components)  |\n| Testing     | Playwright (E2E, API)                                 |\n| Integration | MCP SDK 1.x (Model Context Protocol)                  |\n| CI/CD       | GitHub Actions, ArgoCD, Helm, GHCR                    |\n\n## Prerequisites\n\n- **Node.js** \u003e= 22\n- **Yarn** 4.12.0 (managed via Corepack)\n- **Docker** and **Docker Compose** (for PostgreSQL)\n\n## Getting Started\n\n### 1. Clone and install\n\n```bash\ngit clone https://github.com/linuxfoundation/lfx-changelog.git\ncd lfx-changelog\ncorepack enable\nyarn install\n```\n\n### 2. Set up environment variables\n\n```bash\ncp apps/lfx-changelog/.env.example apps/lfx-changelog/.env\n```\n\nEdit `apps/lfx-changelog/.env` with your values. See the [Environment Variables](#environment-variables) section below for details.\n\n### 3. Start the database\n\n```bash\nyarn docker:up\n```\n\n### 4. Run database migrations and seed\n\n```bash\nyarn db:generate\nyarn db:migrate\nyarn db:seed\n```\n\n### 5. Start the dev server\n\n```bash\nyarn start\n```\n\nThe app runs at `http://localhost:4204`\n\n## Environment Variables\n\nThe server supports two ways to configure the database connection: a single `DATABASE_URL` connection string, or individual `DB_*` variables (which the server assembles at runtime via `buildConnectionString`). Provide one or the other.\n\n| Variable                     | Required | Description                                                                                              |\n| ---------------------------- | -------- | -------------------------------------------------------------------------------------------------------- |\n| `DATABASE_URL`               | Yes\\*    | PostgreSQL connection string (e.g., `postgresql://changelog:changelog_dev@localhost:5432/lfx_changelog`) |\n| `DB_HOST`                    | Yes\\*    | Database host (e.g., `localhost`)                                                                        |\n| `DB_PORT`                    | No       | Database port (default: `5432`)                                                                          |\n| `DB_NAME`                    | Yes\\*    | Database name (e.g., `lfx_changelog`)                                                                    |\n| `DB_USER`                    | Yes\\*    | Database user (e.g., `changelog`)                                                                        |\n| `DB_PASSWORD`                | Yes\\*    | Database password                                                                                        |\n| `AUTH0_CLIENT_ID`            | Yes      | Auth0 application client ID                                                                              |\n| `AUTH0_CLIENT_SECRET`        | Yes      | Auth0 application client secret                                                                          |\n| `AUTH0_ISSUER_BASE_URL`      | Yes      | Auth0 tenant URL (e.g., `https://your-tenant.auth0.com`)                                                 |\n| `AUTH0_SECRET`               | Yes      | Session encryption secret (min 32 characters)                                                            |\n| `BASE_URL`                   | Yes      | Application base URL (e.g., `http://localhost:4204`)                                                     |\n| `GITHUB_APP_ID`              | No       | GitHub App ID for repository integration                                                                 |\n| `GITHUB_PRIVATE_KEY`         | No       | GitHub App RSA private key                                                                               |\n| `GITHUB_WEBHOOK_SECRET`      | No       | Secret for verifying GitHub webhook signatures (see [Webhook Testing](docs/webhook-testing.md))          |\n| `LITELLM_API_KEY`            | No       | API key for AI changelog generation and AI chat                                                          |\n| `AI_API_URL`                 | No       | AI service endpoint URL (LiteLLM proxy)                                                                  |\n| `OPENSEARCH_URL`             | No       | OpenSearch endpoint for full-text search (e.g., `https://search.example.com`)                            |\n| `SLACK_CLIENT_ID`            | No       | Slack OAuth client ID for Slack integration                                                              |\n| `SLACK_CLIENT_SECRET`        | No       | Slack OAuth client secret                                                                                |\n| `SLACK_TOKEN_ENCRYPTION_KEY` | No       | AES-256-GCM key for encrypting Slack tokens at rest (64 hex chars)                                       |\n| `WEBHOOK_STATE_SECRET`       | No       | HMAC secret for OAuth state CSRF protection (Slack + GitHub)                                             |\n| `DATADOG_RUM_APPLICATION_ID` | No       | Datadog RUM application ID (client-side monitoring)                                                      |\n| `DATADOG_RUM_CLIENT_ID`      | No       | Datadog RUM client token                                                                                 |\n| `NODE_ENV`                   | No       | `development` or `production` (default: `development`)                                                   |\n| `PORT`                       | No       | Server port (default: `4000`)                                                                            |\n| `LOG_LEVEL`                  | No       | Logging level: `debug`, `info`, `warn`, `error` (default: `info`)                                        |\n\n\\*Provide either `DATABASE_URL` **or** the `DB_HOST`/`DB_NAME`/`DB_USER`/`DB_PASSWORD` group.\n\n## Scripts\n\n### Root (monorepo-level)\n\n| Script                  | Description                         |\n| ----------------------- | ----------------------------------- |\n| `yarn build`            | Build all packages (shared + app)   |\n| `yarn start`            | Start the SSR server                |\n| `yarn lint`             | Run ESLint across all packages      |\n| `yarn format`           | Format all files with Prettier      |\n| `yarn format:check`     | Check formatting without writing    |\n| `yarn markdownlint`     | Lint markdown files                 |\n| `yarn markdownlint:fix` | Auto-fix markdown lint issues       |\n| `yarn docker:up`        | Start PostgreSQL via Docker Compose |\n| `yarn docker:down`      | Stop PostgreSQL                     |\n| `yarn db:generate`      | Generate Prisma client              |\n| `yarn db:migrate`       | Run database migrations             |\n| `yarn db:seed`          | Seed the database with sample data  |\n| `yarn db:studio`        | Open Prisma Studio (database GUI)   |\n| `yarn test`             | Run tests across all workspaces     |\n| `yarn watch`            | Build all packages in watch mode    |\n\n### App-level (`apps/lfx-changelog`)\n\n| Script             | Description                          |\n| ------------------ | ------------------------------------ |\n| `yarn start`       | Angular dev server with live reload  |\n| `yarn build:dev`   | Development build                    |\n| `yarn build:prod`  | Production build                     |\n| `yarn lint`        | Lint the Angular app                 |\n| `yarn test`        | Run Playwright E2E tests             |\n| `yarn test:headed` | Run E2E tests with browser visible   |\n| `yarn test:ui`     | Run E2E tests in Playwright UI mode  |\n| `yarn test:report` | Open the last Playwright HTML report |\n\n## Project Structure\n\n```text\nlfx-changelog/\n├── apps/lfx-changelog/           # Angular 20 SSR application\n│   ├── src/\n│   │   ├── app/\n│   │   │   ├── layouts/           # Public and admin layout shells\n│   │   │   ├── modules/           # Feature modules (public + admin)\n│   │   │   └── shared/            # Components, services, interfaces\n│   │   ├── server/                # Express backend\n│   │   │   ├── controllers/       # Request handlers\n│   │   │   ├── services/          # Business logic + Prisma queries\n│   │   │   ├── routes/            # Route definitions\n│   │   │   ├── middleware/        # Auth, RBAC, validation, error handling\n│   │   │   ├── swagger/           # OpenAPI path definitions\n│   │   │   ├── helpers/           # Shared utilities (DB connection, etc.)\n│   │   │   └── errors/            # Custom error classes\n│   │   └── environments/          # Environment configs\n│   ├── prisma/                    # Schema, migrations, seed\n│   └── e2e/                       # Playwright E2E tests\n│       ├── setup/                 # DB + auth setup projects\n│       ├── helpers/               # Test utilities (API, DB, Docker, fixtures)\n│       ├── pages/                 # Page Object Model classes\n│       └── specs/                 # Test specs (public/, admin/, api/)\n├── packages/shared/               # @lfx-changelog/shared (Zod schemas, types, enums)\n├── packages/mcp-server/           # @lfx-changelog/mcp-server (MCP tools \u0026 resources)\n├── charts/lfx-changelog/          # Helm chart for Kubernetes deployment\n├── docs/                          # Additional documentation\n├── docker-compose.yml             # Local PostgreSQL (dev + test)\n├── Dockerfile                     # Multi-stage production build\n└── turbo.json                     # Turborepo task config\n```\n\n## Architecture\n\nThe application uses an Angular SSR server that also hosts the Express API backend. This single-server approach means:\n\n- **Public API** (`/public/api/*`) --- unauthenticated endpoints for reading published changelogs and products\n- **Protected API** (`/api/*`) --- authenticated endpoints for CRUD operations, supporting both OAuth sessions and [API keys](docs/api-authentication.md)\n- **API docs** (`/docs`) --- interactive Swagger UI generated from Zod schemas via `@asteasolutions/zod-to-openapi`\n- **MCP** (`/mcp`) --- Model Context Protocol endpoint for AI tool integration (Streamable HTTP)\n- **SSR** --- Angular pages are server-rendered for all routes\n\n### Authentication\n\nThe API supports two authentication methods:\n\n- **OAuth sessions** --- browser-based login via Auth0 (session cookies)\n- **API keys** --- programmatic access via `Authorization: Bearer lfx_...` or `X-API-Key: lfx_...` headers\n\nAPI keys are scoped (`changelogs:read`, `changelogs:write`, `products:read`, `products:write`) and enforce the same role checks as OAuth sessions. See [API Authentication](docs/api-authentication.md) for details on creating keys, endpoint permissions, and usage examples.\n\n### Roles\n\n| Role            | Scope       | Permissions                                         |\n| --------------- | ----------- | --------------------------------------------------- |\n| `super_admin`   | Global      | Full access to all products, users, and settings    |\n| `product_admin` | Per-product | Manage changelogs and editors for assigned products |\n| `editor`        | Per-product | Create and edit changelogs for assigned products    |\n\n## Database\n\nThe PostgreSQL schema is managed by Prisma:\n\n- **Product** --- LFX products with activation status, Font Awesome icons, and optional GitHub App installation\n- **ProductRepository** --- GitHub repositories linked to products for release syncing and changelog generation\n- **GitHubRelease** --- release metadata synced from GitHub (tag, notes, author, publish date)\n- **ChangelogEntry** --- individual changelog entries with markdown content, versioning, slugs, and source tracking (`manual` or `automated`)\n- **User** --- users synced from Auth0 on first login\n- **UserRoleAssignment** --- maps users to roles, optionally scoped to a product\n- **ApiKey** --- scoped API keys for programmatic access, storing SHA-256 hashes with expiration and revocation tracking\n- **ChatConversation** / **ChatMessage** --- AI chat conversation history with tool call persistence\n- **AutoChangelogLock** --- distributed lock for concurrent auto-changelog generation across replicas\n- **SlackIntegration** / **SlackChannel** / **SlackNotification** --- Slack workspace connections, channel config, and delivery tracking\n\n### Useful commands\n\n```bash\nyarn db:studio          # Browse data in Prisma Studio\nyarn db:migrate         # Apply pending migrations\nyarn db:seed            # Reset and seed sample data\n```\n\n## Testing\n\nEnd-to-end tests use [Playwright](https://playwright.dev/) to verify the application from a user's perspective. Tests run against a real Angular SSR server backed by a test PostgreSQL database and authenticate through Auth0.\n\n```bash\ncd apps/lfx-changelog\nyarn test               # Run all tests (headless)\nyarn test:headed        # Run with browser visible\nyarn test:ui            # Run with Playwright UI mode\n```\n\nTests automatically start a test database container on port 5433, run migrations, seed data, and launch the dev server --- no manual setup needed.\n\nThe test suite covers:\n\n- **Public pages** --- changelog feed, product changelogs, theme toggle\n- **Admin flows** --- dashboard, changelog editor, product and user management\n- **RBAC** --- per-role access (super admin, product admin, editor, no-role)\n- **API endpoints** --- public and protected REST endpoints via direct HTTP\n\nSee [docs/testing/e2e-testing.md](docs/testing/e2e-testing.md) for the full testing guide.\n\n## CI/CD\n\nGitHub Actions runs on every push to `main` and on pull requests:\n\n| Job             | Description                                                        |\n| --------------- | ------------------------------------------------------------------ |\n| License headers | Verifies all source files include the required SPDX license header |\n| Secret scan     | Scans for leaked secrets using Trufflehog                          |\n| E2E tests       | Runs the full Playwright test suite against a test database        |\n\n### Docker Builds\n\n| Workflow                | Trigger                        | Image Tag               |\n| ----------------------- | ------------------------------ | ----------------------- |\n| `docker-build-main.yml` | Push to `main`                 | `development`           |\n| `docker-build-tag.yml`  | Git tag push (`v*`)            | Semver (e.g., `1.2.3`)  |\n| `docker-build-pr.yml`   | PR with `deploy-preview` label | `changelog-pr-\u003cnumber\u003e` |\n\nAll images are pushed to **GHCR** (`ghcr.io/linuxfoundation/lfx-changelog`).\n\n### Deployment\n\nThe application deploys to **Kubernetes** via **ArgoCD**:\n\n- **Dev:** merge to `main` builds image tagged `development` --- ArgoCD syncs and runs the migration Job before updating pods\n- **Prod:** git tag push builds a versioned image + publishes a signed Helm chart (with [Cosign](https://docs.sigstore.dev/cosign/overview/) and [SLSA provenance](https://slsa.dev/)) --- ArgoCD syncs the new chart\n\nDatabase migrations run automatically as a Helm pre-upgrade Job. See [docs/database-migrations.md](docs/database-migrations.md) for details.\n\nThe production container runs as a non-root user on port 4000.\n\n### PR Deploy Previews\n\nAdding the `deploy-preview` label to a PR builds and pushes a branch-specific image. ArgoCD provisions an isolated namespace (`changelog-pr-\u003cnumber\u003e`) with its own deployment. The preview is removed when the PR is closed or the label is removed.\n\n## Documentation\n\n| Document                                                 | Description                                                       |\n| -------------------------------------------------------- | ----------------------------------------------------------------- |\n| [AI Chat](docs/ai-chat.md)                               | Agentic chat assistant, SSE streaming, conversation persistence   |\n| [API Authentication](docs/api-authentication.md)         | API keys, OAuth sessions, scopes, and usage examples              |\n| [Changelog Agent](docs/changelog-agent.md)               | Claude Agent SDK pipeline, MCP tools, job tracking, webhooks      |\n| [Changelog Views](docs/changelog-views.md)               | Unseen-count tracking API for external LFX product apps           |\n| [Database Migrations](docs/database-migrations.md)       | Automated (CI/CD) and manual migration workflows                  |\n| [GitHub Integration](docs/github-integration.md)         | GitHub App, repo tracking, release sync, auto-changelog, webhooks |\n| [MCP Server](docs/mcp-server.md)                         | MCP tools, resources, and client setup                            |\n| [Observability](docs/observability.md)                   | Datadog APM, RUM, session replay, HTTP logging, pretty URLs       |\n| [OpenSearch](docs/opensearch.md)                         | Full-text search, indexing, reindexing, MCP search tools          |\n| [Remote Database Access](docs/remote-database-access.md) | Connecting to RDS via kubectl port-forward                        |\n| [Slack Integration](docs/slack-integration.md)           | OAuth flow, token encryption, posting changelogs to Slack         |\n| [E2E Testing](docs/testing/e2e-testing.md)               | Test architecture, patterns, and how to add tests                 |\n| [Webhook Testing](docs/webhook-testing.md)               | Testing GitHub release webhooks locally                           |\n| [Contributing](CONTRIBUTING.md)                          | License headers, code style, commit conventions                   |\n| [Security](SECURITY.md)                                  | Vulnerability reporting                                           |\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on submitting changes, license header requirements, and commit conventions.\n\n## License\n\n[MIT](LICENSE) --- Copyright The Linux Foundation and each contributor to LFX.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinuxfoundation%2Flfx-changelog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flinuxfoundation%2Flfx-changelog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinuxfoundation%2Flfx-changelog/lists"}