{"id":51615747,"url":"https://github.com/anchildress1/dev-community-dashboard","last_synced_at":"2026-07-12T13:01:28.912Z","repository":{"id":341076353,"uuid":"1168793282","full_name":"anchildress1/dev-community-dashboard","owner":"anchildress1","description":"Community behavior analytics dashboard for DEV.to. Observes activity patterns, engagement dynamics, and moderation signals without judging individual users.","archived":false,"fork":false,"pushed_at":"2026-06-27T21:00:16.000Z","size":7747,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-27T21:11:34.553Z","etag":null,"topics":["analytics","community-analytics","conversation-analysis","dashboard","devchallenge","developer-community","devto","engagement-metrics","weekend-challenge"],"latest_commit_sha":null,"homepage":"https://dev-signal.checkmarkdevtools.dev","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/anchildress1.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":".github/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":"AGENTS.md","dco":null,"cla":null},"funding":{"github":"anchildress1","buy_me_a_coffee":"anchildress1"}},"created_at":"2026-02-27T20:01:39.000Z","updated_at":"2026-06-21T14:11:05.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/anchildress1/dev-community-dashboard","commit_stats":null,"previous_names":["checkmarkdevtools/forem-community-dashboard","checkmarkdevtools/dev-community-dashboard","anchildress1/dev-community-dashboard"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/anchildress1/dev-community-dashboard","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anchildress1%2Fdev-community-dashboard","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anchildress1%2Fdev-community-dashboard/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anchildress1%2Fdev-community-dashboard/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anchildress1%2Fdev-community-dashboard/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anchildress1","download_url":"https://codeload.github.com/anchildress1/dev-community-dashboard/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anchildress1%2Fdev-community-dashboard/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35392296,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-12T02:00:06.386Z","response_time":87,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["analytics","community-analytics","conversation-analysis","dashboard","devchallenge","developer-community","devto","engagement-metrics","weekend-challenge"],"created_at":"2026-07-12T13:01:27.891Z","updated_at":"2026-07-12T13:01:28.904Z","avatar_url":"https://github.com/anchildress1.png","language":"TypeScript","funding_links":["https://github.com/sponsors/anchildress1","https://buymeacoffee.com/anchildress1"],"categories":[],"sub_categories":[],"readme":"![DEV Community Dashboard Banner](https://raw.githubusercontent.com/ChecKMarKDevTools/forem-community-dashboard/main/public/dev-weekend-challenge-banner-community-dashboard.png)\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cb\u003eCommunity\u003c/b\u003e\u003c/td\u003e\n\u003ctd\u003e\n\n[![GitHub Stars](https://img.shields.io/github/stars/ChecKMarKDevTools/dev-community-dashboard?style=flat\u0026logo=github\u0026logoColor=white)](https://github.com/ChecKMarKDevTools/dev-community-dashboard/stargazers) [![License](https://img.shields.io/badge/License-PolyForm_Shield_1.0.0-blue?style=flat)](./LICENSE) [![DEV.to](https://img.shields.io/badge/DEV.to-anchildress1-0A0A0A?style=flat\u0026logo=devdotto\u0026logoColor=white)](https://dev.to/anchildress1)\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cb\u003ePipeline\u003c/b\u003e\u003c/td\u003e\n\u003ctd\u003e\n\n[![CI Build \u0026 Test](https://img.shields.io/github/actions/workflow/status/ChecKMarKDevTools/dev-community-dashboard/ci.yml?branch=main\u0026style=flat\u0026logo=githubactions\u0026logoColor=white\u0026label=CI)](https://github.com/ChecKMarKDevTools/dev-community-dashboard/actions/workflows/ci.yml) [![DEV Post Sync](https://img.shields.io/github/actions/workflow/status/ChecKMarKDevTools/dev-community-dashboard/cron.yml?branch=main\u0026style=flat\u0026logo=githubactions\u0026logoColor=white\u0026label=Cron%20Sync)](https://github.com/ChecKMarKDevTools/dev-community-dashboard/actions/workflows/cron.yml) [![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=ChecKMarKDevTools_forem-community-dashboard\u0026metric=alert_status)](https://sonarcloud.io/summary/overall?id=ChecKMarKDevTools_forem-community-dashboard) [![SonarCloud Coverage](https://sonarcloud.io/api/project_badges/measure?project=ChecKMarKDevTools_forem-community-dashboard\u0026metric=coverage)](https://sonarcloud.io/summary/overall?id=ChecKMarKDevTools_forem-community-dashboard)\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cb\u003eScans\u003c/b\u003e\u003c/td\u003e\n\u003ctd\u003e\n\n[![TruffleHog](https://img.shields.io/badge/TruffleHog-Secret_Scan-000000?style=flat\u0026logo=trufflehog\u0026logoColor=white)](https://trufflesecurity.com/trufflehog) [![Semgrep](https://img.shields.io/badge/Semgrep-SAST-4B11A8?style=flat\u0026logo=semgrep\u0026logoColor=white)](https://semgrep.dev) [![CodeQL](https://img.shields.io/badge/CodeQL-Security_Analysis-222222?style=flat\u0026logo=github\u0026logoColor=white)](https://github.com/ChecKMarKDevTools/dev-community-dashboard/security/code-scanning) [![Hadolint](https://img.shields.io/badge/Hadolint-Dockerfile_Lint-2496ED?style=flat\u0026logo=docker\u0026logoColor=white)](https://github.com/hadolint/hadolint) [![actionlint](https://img.shields.io/badge/actionlint-GHA_Lint-2088FF?style=flat\u0026logo=githubactions\u0026logoColor=white)](https://github.com/rhysd/actionlint) [![Stylelint](https://img.shields.io/badge/Stylelint-CSS_Lint-263238?style=flat\u0026logo=stylelint\u0026logoColor=white)](https://stylelint.io) [![Lighthouse](https://img.shields.io/badge/Lighthouse-A11y_100%25-F44B21?style=flat\u0026logo=lighthouse\u0026logoColor=white)](https://developer.chrome.com/docs/lighthouse)\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cb\u003eStack\u003c/b\u003e\u003c/td\u003e\n\u003ctd\u003e\n\n[![Next.js](https://img.shields.io/badge/Next.js-16-000000?style=flat\u0026logo=nextdotjs\u0026logoColor=white)](https://nextjs.org) [![TypeScript](https://img.shields.io/badge/TypeScript-5-3178C6?style=flat\u0026logo=typescript\u0026logoColor=white)](https://www.typescriptlang.org) [![Tailwind CSS](https://img.shields.io/badge/Tailwind_CSS-4-06B6D4?style=flat\u0026logo=tailwindcss\u0026logoColor=white)](https://tailwindcss.com) [![Supabase](https://img.shields.io/badge/Supabase-PostgreSQL-3FCF8E?style=flat\u0026logo=supabase\u0026logoColor=white)](https://supabase.com) [![Vitest](https://img.shields.io/badge/Vitest-Testing-6E9F18?style=flat\u0026logo=vitest\u0026logoColor=white)](https://vitest.dev) [![pnpm](https://img.shields.io/badge/pnpm-Package_Manager-F69220?style=flat\u0026logo=pnpm\u0026logoColor=white)](https://pnpm.io) [![Docker](https://img.shields.io/badge/Docker-Container-2496ED?style=flat\u0026logo=docker\u0026logoColor=white)](https://www.docker.com) [![Google Cloud Run](https://img.shields.io/badge/Cloud_Run-Deployment-4285F4?style=flat\u0026logo=googlecloud\u0026logoColor=white)](https://cloud.google.com/run)\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cb\u003eCode Quality\u003c/b\u003e\u003c/td\u003e\n\u003ctd\u003e\n\n[![ESLint](https://img.shields.io/badge/ESLint-Linting-4B32C3?style=flat\u0026logo=eslint\u0026logoColor=white)](https://eslint.org) [![Prettier](https://img.shields.io/badge/Prettier-Formatting-F7B93E?style=flat\u0026logo=prettier\u0026logoColor=black)](https://prettier.io) [![Conventional Commits](https://img.shields.io/badge/Conventional_Commits-1.0.0-FE5196?style=flat\u0026logo=conventionalcommits\u0026logoColor=white)](https://www.conventionalcommits.org) [![Lefthook](https://img.shields.io/badge/Lefthook-Git_Hooks-FF1E1E?style=flat\u0026logo=git\u0026logoColor=white)](https://github.com/evilmartians/lefthook) [![Makefile](https://img.shields.io/badge/Makefile-Build-427819?style=flat\u0026logo=gnu\u0026logoColor=white)](https://www.gnu.org/software/make/)\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cb\u003eAI\u003c/b\u003e\u003c/td\u003e\n\u003ctd\u003e\n\n[![Claude](https://img.shields.io/badge/Claude-Anthropic-D97757?style=flat\u0026logo=anthropic\u0026logoColor=white)](https://claude.ai) [![ChatGPT](https://img.shields.io/badge/ChatGPT-OpenAI-74AA9C?style=flat\u0026logo=openai\u0026logoColor=white)](https://chat.openai.com) [![gpt-5-nano](https://img.shields.io/badge/gpt--5--nano-Interaction_Signal-74AA9C?style=flat\u0026logo=openai\u0026logoColor=white)](https://platform.openai.com/docs/models) [![Google Gemini](https://img.shields.io/badge/Gemini-Antigravity-8E75B2?style=flat\u0026logo=googlegemini\u0026logoColor=white)](https://deepmind.google/models/gemini/) [![Leonardo.ai](https://img.shields.io/badge/Leonardo.ai-Seedream_4.5-7C3AED?style=flat\u0026logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiPjxjaXJjbGUgY3g9IjEyIiBjeT0iMTIiIHI9IjEwIi8+PC9zdmc+\u0026logoColor=white)](https://leonardo.ai)\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cb\u003eSupport\u003c/b\u003e\u003c/td\u003e\n\u003ctd\u003e\n\n[![Sponsor](https://img.shields.io/badge/Sponsor-GitHub_Sponsors-EA4AAA?style=flat\u0026logo=githubsponsors\u0026logoColor=white)](https://github.com/sponsors/anchildress1) [![Buy Me a Coffee](https://img.shields.io/badge/Buy_Me_a_Coffee-Support-FFDD00?style=flat\u0026logo=buymeacoffee\u0026logoColor=black)](https://buymeacoffee.com/anchildress1)\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n# DEV Community Dashboard\n\nA signal-surfacing tool for [Forem](https://forem.com/) communities (dev.to and self-hosted instances). It ingests the latest posts via the public Forem API, classifies each one into seven attention categories (Needs Support, Awaiting Collaboration, Anomalous Signal, Trending Signal, Rapid Discussion, Silent Signal, Steady Signal), and persists the results in Supabase so community helpers can see where conversations need a human eye.\n\nThis is **not** a moderation tool or a scorecard. It is designed to help helpers know where to look.\n\n**Production:** [https://dev-signal.checkmarkdevtools.dev](https://dev-signal.checkmarkdevtools.dev) _(Cloud Run -- deployed post-initial-release)_\n\nv1.1.0 adds LLM interaction scoring, NEEDS_SUPPORT detection, and incremental caching and was created for the [DEV Weekend Challenge](https://dev.to/devteam/happening-now-dev-weekend-challenge-submissions-due-march-2-at-759am-utc-5fg8).\n\n---\n\n## Documentation\n\n| Document                                               | Description                                                                                                                       |\n| ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- |\n| **[Architecture](./docs/architecture.md)**             | System overview, data flow diagrams, deployment, API routes, guardrails                                                           |\n| **[Interaction Signal](./docs/interaction-signal.md)** | Composite signal formula, LLM scoring pipeline, model cascade, heuristic fallback, incremental scoring, signal spread, topic tags |\n| **[Metrics Reference](./docs/metrics.md)**             | Full `ArticleMetrics` field reference, risk components, velocity, participation, attention categories, chart mappings             |\n| **[Database Migrations](./supabase/README.md)**        | Migration history and schema notes                                                                                                |\n| **[Project Conventions](./AGENTS.md)**                 | AI rules, testing requirements, commit conventions, CI policies                                                                   |\n\n---\n\n## Quick Start\n\n### Prerequisites\n\n- Node.js \u003e= 22 (matches Volta pin and CI/Docker toolchain)\n- pnpm\n- A [Supabase](https://supabase.com/) project with RLS migrations applied\n\n```bash\nsupabase db push\n# or run supabase/migrations/0001_rls_policies.sql manually in the SQL editor\n```\n\n### Environment Variables\n\nCreate a `.env` file in the project root:\n\n| Variable                   | Required | Description                                                  |\n| -------------------------- | -------- | ------------------------------------------------------------ |\n| `NEXT_PUBLIC_SUPABASE_URL` | Yes      | Supabase project URL                                         |\n| `SUPABASE_SECRET_KEY`      | Yes      | Server-only key; bypasses RLS for sync writes                |\n| `CRON_SECRET`              | Yes      | Bearer token for `/api/cron` and `/api/admin/seed`           |\n| `DEV_API_KEY`              | No       | Raises Forem API rate limits                                 |\n| `OPENAI_API_KEY`           | No       | Enables LLM interaction scoring; absent = heuristic fallback |\n\n\u003e `SUPABASE_SECRET_KEY` is intentionally **not** prefixed with `NEXT_PUBLIC_` -- it is never sent to the browser.\n\n### Commands\n\n```bash\npnpm install          # install dependencies\npnpm dev              # development server -\u003e http://localhost:3000\npnpm test             # run full Vitest test suite\npnpm build            # type-check + Next.js production build\n```\n\n---\n\n## API Reference\n\n| Method | Path              | Auth   | Description                                                                 |\n| ------ | ----------------- | ------ | --------------------------------------------------------------------------- |\n| `GET`  | `/api/posts`      | None   | Top 50 articles (7-day window), non-NORMAL first, score desc, oldest first  |\n| `GET`  | `/api/posts/:id`  | None   | Article detail + 5 most recent posts by same author                         |\n| `POST` | `/api/cron`       | Bearer | Purge articles \u003e 10 days, then sync articles in the 5-day window from Forem |\n| `POST` | `/api/admin/seed` | Bearer | Same as cron -- populate the database on first deploy                       |\n\n---\n\n## Deployment (Cloud Run)\n\nRun `./deploy.sh` from the repo root. The script handles Secret Manager secrets, Artifact Registry, Cloud Build, and Cloud Run deployment.\n\n```bash\ngcloud auth login\ngcloud config set project checkmarkdevtools\n```\n\nSet `APP_URL` as a **GitHub repository variable** and `CRON_SECRET` as a **GitHub secret** so the cron workflow can reach the deployed endpoint.\n\n---\n\n## GitHub Actions Workflows\n\nAll CI checks run in `ci.yml`; do not create additional workflow files for individual checks.\n\n| Workflow           | File                 | Trigger                        | What It Does                                                             |\n| ------------------ | -------------------- | ------------------------------ | ------------------------------------------------------------------------ |\n| **CI**             | `ci.yml`             | Push to `main`, Pull Request   | Format, lint, Vitest + coverage, SonarCloud scan, Lighthouse CI          |\n| **Hourly Sync**    | `cron.yml`           | Schedule (`0 * * * *`), manual | POSTs to `/api/cron`; skips if `APP_URL` or `CRON_SECRET` is unset       |\n| **Release Please** | `release-please.yml` | Push to `main`                 | Automated release PRs (Conventional Commits -\u003e CHANGELOG + version bump) |\n\n### Required Repository Configuration\n\n| Name           | Type     | Used by           | Notes                                                                |\n| -------------- | -------- | ----------------- | -------------------------------------------------------------------- |\n| `APP_URL`      | Variable | `cron.yml`        | Public Cloud Run URL                                                 |\n| `CRON_SECRET`  | Secret   | `cron.yml`        | Must match the `CRON_SECRET` env var on the deployed service         |\n| `SONAR_TOKEN`  | Secret   | `ci.yml`          | SonarCloud token                                                     |\n| `GITHUB_TOKEN` | Built-in | `ci.yml`, release | `release-please.yml` needs `contents: write`, `pull-requests: write` |\n\n---\n\n## Contributing\n\nThis project is built for community helpers -- people who want to know where to look, not what to do. The dashboard surfaces conversations that may need a human eye; it does not assign blame, issue warnings, or score individuals.\n\n| Area                                 | Where to Look                                        |\n| ------------------------------------ | ---------------------------------------------------- |\n| Scoring and classification logic     | `src/lib/sync.ts`                                    |\n| LLM interaction analysis (OpenAI)    | `src/lib/openai.ts`                                  |\n| Dashboard UI components              | `src/components/Dashboard.tsx`, `src/components/ui/` |\n| Chart components (custom SVG)        | `src/components/ui/charts/`                          |\n| Chart data transformation helpers    | `src/lib/metrics-helpers.ts`                         |\n| Display helpers (labels, narratives) | `src/lib/dashboard-helpers.ts`                       |\n| API routes                           | `src/app/api/`                                       |\n| Tests                                | Co-located `*.test.ts` / `*.test.tsx`                |\n| CI checks                            | `.github/workflows/ci.yml`                           |\n| Project conventions                  | `AGENTS.md`                                          |\n\n---\n\n## AI and Guardrails\n\nThis project uses AI tooling to generate code -- and that is precisely why the guardrails are as strict as they are. AI writes plausible-looking code that is sometimes subtly wrong. The CI pipeline, Sonar analysis, test coverage requirements, and pre-commit hooks all exist to catch what AI misses.\n\nAI use is encouraged here, not discouraged. But it is not a standalone solution. Use it with the safety net on.\n\n---\n\n## Connect and Support\n\n\u003cdiv align=\"center\"\u003e\n\n[![DEV.to](https://img.shields.io/badge/DEV.to-anchildress1-0A0A0A?style=flat\u0026logo=devdotto\u0026logoColor=white)](https://dev.to/anchildress1) [![LinkedIn](https://img.shields.io/badge/LinkedIn-anchildress1-0A66C2?style=flat\u0026logo=linkedin\u0026logoColor=white)](https://linkedin.com/in/anchildress1) [![Medium](https://img.shields.io/badge/Medium-@anchildress1-000000?style=flat\u0026logo=medium\u0026logoColor=white)](https://medium.com/@anchildress1) [![Reddit](https://img.shields.io/badge/Reddit-anchildress1-FF4500?style=flat\u0026logo=reddit\u0026logoColor=white)](https://reddit.com/user/anchildress1)\n\n[![Sponsor on GitHub](https://img.shields.io/badge/Sponsor-GitHub_Sponsors-EA4AAA?style=flat\u0026logo=githubsponsors\u0026logoColor=white)](https://github.com/sponsors/anchildress1) [![Buy Me a Coffee](https://img.shields.io/badge/Buy_Me_a_Coffee-Support-FFDD00?style=flat\u0026logo=buymeacoffee\u0026logoColor=black)](https://buymeacoffee.com/anchildress1)\n\n\u003c/div\u003e\n\n---\n\n## License\n\nThis project is licensed under the **[Polyform Shield License 1.0.0](https://polyformproject.org/licenses/shield/1.0.0/)**.\n\nCopyright (c) 2026 ChecKMarK DevTools \u0026 Ashley Childress\n\n**In brief:**\n\n- **You CAN** use, copy, fork, or adapt this for your own workflows, inside your company, for client projects, demos, education, or anything else -- as long as you are not selling the code, charging for it, or making money from the project itself.\n- **You CANNOT** resell, offer as a paid service, or monetize this project or its derivatives without prior written approval from Ashley Childress.\n- Any public fork, copy, or substantial reuse must include the `LICENSE` file and a clear attribution statement in your documentation or README:\n  \u003e \"Based on original work by ChecKMarK DevTools \u0026 Ashley Childress -- see [https://github.com/checkmarkdevtools/dev-community-dashboard](https://github.com/checkmarkdevtools/dev-community-dashboard).\"\n\nFor exceptions or monetization/commercialization questions, contact Ashley Childress at [human@checkmarkdevtools.dev](mailto:human@checkmarkdevtools.dev).\n\nSee the full [LICENSE](./LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanchildress1%2Fdev-community-dashboard","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanchildress1%2Fdev-community-dashboard","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanchildress1%2Fdev-community-dashboard/lists"}