尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证Source code for policeconduct.org
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗Astro static site with AWS infrastructure managed by Terraform.
PoliceConduct.org helps residents evaluate whether law-enforcement agencies and the people working there appear safe, accountable, transparent, and improving. The site also aims to identify positive deviance: officers, supervisors, units, agencies, policies, and practices that produce unusually good public-trust and public-safety outcomes under comparable constraints. Positive examples must be evidence-backed and framed as practices to investigate or learn from, not as blanket endorsements.
./scripts/bootstrap-dev.sh
npm run doctor
npm run
npm ci
npm run dev
Set FORMS_API_PROXY_TARGET to the preview forms API URL in .env-policeconduct
for local UI testing against deployed forms infrastructure.
npm run is the project command surface. Common setup and validation commands:
npm run setup: interactive developer bootstrap.npm run doctor: read-only readiness check for local tools and agent workflow files.npm run openspec:status -- <change-name>: show OpenSpec change status.npm run validate:openspec: validate all OpenSpec artifacts.npm run validate: run the aggregate validation gate.package.json defines the executable gates. Keep this checklist and the PR
template synchronized whenever those scripts change. All items below apply to
the final PR head, including documentation-only PRs.
mise exec -- node --version and mise exec -- npm --version to record
the configured runtime (mise.toml, currently Node 24). Install with
mise exec -- npm ci; use the nested lockfile for any nested package.
Compare every installed package version to its package-lock.json entry
(including transitive packages); do not borrow shared node_modules.git rev-parse HEAD, then run mise exec -- npm run validate in
full. Preserve complete output and command exit status. Re-run the entire
command after fixes or any head change. Scoped checks do not replace it.| Aggregate stage | Current scripts / required evidence |
|---|---|
| Repository formatting | format:check: repository-wide Prettier |
| JavaScript and SQL lint | lint → lint:es (ESLint), lint:sql (pinned SQLFluff through mise) |
| Astro/type diagnostics | validate:types: errors, warnings, and individually reviewed hints |
| Shell syntax | validate:shell: hooks and deployment/bootstrap scripts |
| Database schema contract | validate:schema: configured local database and table outcome |
| OpenSpec | validate:openspec: all changes/specs, including warning output |
| Personal-data scan | scan:personal-data: tracked tree, finding count |
| Redirect tests | test:redirects: coverage, router, loading, map generation, release guard |
| Media tests | test:media: video and personnel photos |
| Forms API tests | test:lambda: nested locked dependencies and Lambda suite |
| CSS tests | test:css: built CSS purging |
| Personal-data tests | test:personal-data: scanner regressions |
| Coverage tests | test:coverage: coverage calculations |
| Browser tests | test:e2e: all Playwright suites, including built-index search |
validate:no-inline-css checks appropriate to the
change. Record commands and outcomes. A full final build and sitemap
verification are production-release gates, not PR merge prerequisites.This repo uses Codex App, OpenSpec, Superpowers, and the OpenSpec Superpowers
bridge for behavior-changing work. OpenSpec captures the intended behavior;
Superpowers supplies the development discipline; the bridge keeps brainstorming,
plans, verification, and retrospectives in openspec/changes/<change-name>/.
Recommended flow:
npm run doctor
npm run validate:openspec
npx openspec schemas
npx openspec status --change <change-name>
Then brainstorm the outcome, reuse the active branch and worktree (creating
another requires explicit human permission), and ask Codex to turn the brainstorm into an
OpenSpec change. Use /opsx:continue <change-name> until proposal/spec/task/plan
artifacts are coherent, then /opsx:apply <change-name>, /opsx:verify <change-name>, /opsx:continue <change-name> for the retrospective, and
/opsx:archive <change-name>.
Direct PR-sized changes are acceptable for documentation-only edits, formatting, tooling tweaks, and internal refactors that preserve specified behavior.
Build requires RECAPTCHA_SITE_KEY. The build script loads .env,
.env-recaptcha, and .env-policeconduct before validating env.
npm run build
The build pipeline:
validate-build-env.mjs)GIT_COMMIT_SHA and GIT_COMMIT_DIRTY from git stateCSS is externalized (inlineStylesheets: "never") and tree-shaken via PurgeCSS
so that Bootstrap and custom styles ship as a single shared file instead of being
inlined into every page.
Build metadata is derived from git state automatically:
GIT_COMMIT_SHA defaults to the current git commit.GIT_COMMIT_DIRTY defaults to 1 when tracked or untracked changes exist.The current layout does not emit these values as page meta tags. Record the build's commit and clean/dirty state in the verification evidence; compare served artifacts with that build rather than assuming a page exposes its source SHA.
Production deploys also attach build metadata to each uploaded S3 object as
build-commit and build-dirty. build.json is not part of the standard
build, audit, preview deploy, or production deploy flow.
Audits run against the existing dist/ output. dist/ is not checked in, and
audits require a fresh full build first. Stale or partial build output is not a
supported audit baseline.
npm run build
npm run audit
Run either audit directly when needed:
npm run audit:seo
npm run audit:a11y
Optional tuning for large sites:
| Variable | Default | Description |
|---|---|---|
SEO_AUDIT_MAX_PAGES | 5000 | HTML files checked by seo:audit |
A11Y_MAX_URLS | 200 | URLs sampled from sitemap for headless a11y |
A11Y_PORT | 4173 | Local audit server port |
Required search coverage needs generated assets. With the intended local database, intake fixtures, environment, and Playwright browsers configured, generate the HTML needed by the tests and its Pagefind index, then serve on loopback before the full validation gate. A full build is one way to prepare those assets:
mise exec -- npm run build
mise exec -- npm run preview -- --host 127.0.0.1 --port 4321
# In another terminal with the same configured environment:
mise exec -- npm run validate
The browser runner reuses the server on port 4321. Confirm it serves this head's
matching generated HTML and index, not an unrelated or stale process. Existing
assets may be reused when their source matches the final head (for example,
a documentation-only change). npm run build:search-index generates the index
from rendered dist/ HTML. Required browser assertions must actually run;
preparing their assets does not make the complete build or sitemap a merge gate. Without a built server the runner
starts the development server, which cannot satisfy required Pagefind coverage;
missing search assets fail instead of skipping. Scoped npm run test:e2e -- ...
runs remain useful development feedback only.
These tests mock reCAPTCHA and /api/forms/* responses to keep runs stable and
independent from external services.
Preview deploy builds the site with a PR-specific SITE_URL, syncs dist/ to
the preview S3 prefix, and invalidates the preview CloudFront path for that PR.
export PR_NUMBER=<pr-number>
export S3_BUCKET_PREVIEW=<preview-bucket>
export CLOUDFRONT_DIST_PREVIEW=<preview-distribution-id>
npm run deploy:preview
Before production release, require an error-free full final build and sitemap verification for the release artifact. Record these separately from PR merge evidence; merging a PR does not satisfy or waive either release check.
Production deploy uses the incremental deploy script. It runs a fresh build by
default, uploads only changed files from dist/, deletes removed objects, and
invalidates only the affected CloudFront paths.
export S3_BUCKET=<prod-bucket>
export CLOUDFRONT_DIST_ID=<prod-distribution-id>
npm run deploy:prod
To deploy an existing dist/ without rebuilding:
export S3_BUCKET=<prod-bucket>
export CLOUDFRONT_DIST_ID=<prod-distribution-id>
npm run deploy:prod -- --skip-build
If .deploy-cache/d is empty and you already synced the current production site
locally, seed the incremental baseline manifest before the first run:
bash scripts/seed-deploy-manifest.sh /path/to/synced-site
Then compare your current dist/ against that baseline:
export S3_BUCKET=<prod-bucket>
export CLOUDFRONT_DIST_ID=<prod-distribution-id>
bash scripts/deploy-incremental.sh --skip-build --dry-run
After the baseline exists, npm run deploy:prod and
bash scripts/deploy-incremental.sh use the same production deploy flow.
Required for production:
| Variable | Description |
|---|---|
S3_BUCKET | Production S3 bucket |
CLOUDFRONT_DIST_ID | Production CloudFront distribution |
Required for preview:
| Variable | Description |
|---|---|
PR_NUMBER | Pull request number used in the preview URL and S3 prefix |
S3_BUCKET_PREVIEW | Preview S3 bucket |
CLOUDFRONT_DIST_PREVIEW | Preview CloudFront distribution |
Optional:
| Variable | Description |
|---|---|
GIT_COMMIT_SHA | Override commit hash (default: auto-detected from git) |
GIT_COMMIT_DIRTY | Override dirty flag (default: auto-detected from git) |
Terraform bootstrap stack in infrastructure/bootstrap-policeconduct/.
Provisions:
POST /forms/draft, POST /forms/submit, GET /status/{submissionId})Bootstrap usage:
cp infrastructure/bootstrap-policeconduct/terraform.tfvars.example \
infrastructure/bootstrap-policeconduct/terraform.tfvars
export GITHUB_TOKEN=<github-token-with-repo-admin-access>
terraform -chdir=infrastructure/bootstrap-policeconduct init
bash infrastructure/bootstrap-policeconduct/scripts/apply.sh
See infrastructure/README.md and infrastructure/bootstrap-policeconduct/README.md.
After running:
bash infrastructure/bootstrap-recaptcha/scripts/apply.shbash infrastructure/bootstrap-policeconduct/scripts/apply.shyour .env-recaptcha and .env-policeconduct should include the canonical
runtime/build variables below.
.env-policeconduct is the assembled runtime file for site/forms local runs.
bootstrap-policeconduct sync merges Terraform outputs and required reCAPTCHA
values (fallback from .env-recaptcha) and fails if required keys are missing.
DRAFTS_BUCKETDRAFTS_KMS_KEY_IDSUBMISSIONS_BUCKETSUBMISSIONS_KMS_KEY_IDRECAPTCHA_PROJECT_IDRECAPTCHA_SITE_KEYRECAPTCHA_SERVICE_ACCOUNT_EMAILRECAPTCHA_WIF_PROVIDER_RESOURCE_NAMERECAPTCHA_WIF_AUDIENCERECAPTCHA_SITE_KEY/status//api/status/{submissionId}200 with JSON.
If no status file exists, response falls back to:
{ "submissionId": "<id>", "status": "pending" }.TF_VAR env names)RECAPTCHA_PROJECT_IDRECAPTCHA_SITE_KEYRECAPTCHA_SERVICE_ACCOUNT_EMAILRECAPTCHA_WIF_PROVIDER_RESOURCE_NAMERECAPTCHA_WIF_AUDIENCEOptional examples:
GA_MEASUREMENT_ID_PRODUCTIONGA_MEASUREMENT_ID_PREVIEWSENTRY_DSN_PRODUCTIONSENTRY_DSN_PREVIEWSENTRY_ORGSENTRY_PROJECTSENTRY_AUTH_TOKENTF_STATE_BUCKETAWS_ROLE_ARNS3_BUCKETS3_BUCKET_PREVIEWCLOUDFRONT_DIST_IDCLOUDFRONT_DIST_PREVIEWDRAFTS_BUCKETSUBMISSIONS_BUCKETTF_OUT_* keys are generated automatically for every Terraform output.Frontend Sentry is enabled when these are set:
PUBLIC_SENTRY_DSNPUBLIC_SENTRY_ENVIRONMENTTerraform bootstrap can manage GitHub environment vars/secrets for the same org and project:
TF_VAR_sentry_org (set to your Sentry org slug)TF_VAR_sentry_project (set to PoliceConduct)TF_VAR_sentry_auth_token (for source-map upload during deploys)https://8cantwait.org/ https://clean.calmatters.org https://clearinghouse.net https://endqi.org/ https://ij.org/report/policing-for-profit-4\ https://invisible.institute https://legalaidnyc.org/law-enforcement-look-up https://mappingpoliceviolence.org/ https://mappingpoliceviolence.us https://nixthe6.org/ https://openoversight.com https://policecrime.bgsu.edu https://policedata.org https://policescorecard.org/ https://policeviolencereport.org/ https://safecitiesproject.org/ (sans economic info) https://www.minneapolismn.gov/government/government-data/datasource/officer-payouts-dashboard/ https://www.policefilesny.com