Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
217 commits
Select commit Hold shift + click to select a range
0bc6f26
fix(tests): remove hardcoded group id assumption
ksmuczynski Jul 15, 2026
0bf9e8c
fix(build): package data_migrations with the app
ksmuczynski Jul 15, 2026
ffdfe18
test(fixtures): default shared fixtures to public
ksmuczynski Jul 15, 2026
04e259c
feat(ogc): filter ogc_* views to public records
ksmuczynski Jul 15, 2026
c91c842
feat(data-migrations): publish existing project_areas
ksmuczynski Jul 15, 2026
716ca52
test(ogc): add behave coverage for public-only filter
ksmuczynski Jul 15, 2026
5169404
Formatting changes
ksmuczynski Jul 15, 2026
5bf50c8
feat(ogc): add auth gate for internal OGC mount
ksmuczynski Jul 18, 2026
d2e8749
feat(ogc): add authenticated internal OGC mount
ksmuczynski Jul 18, 2026
9e589ef
feat(ogc): add unfiltered internal OGC views
ksmuczynski Jul 18, 2026
8eae5b1
test(ogc): guard against analyte-mapping drift
ksmuczynski Jul 18, 2026
f59a12a
test(ogc): add behave coverage for internal OGC mount
ksmuczynski Jul 18, 2026
8305a04
merge: production v1.2.0 into staging
github-actions[bot] Jul 22, 2026
36221e7
chore: sync staging release-please manifest to v1.2.0
github-actions[bot] Jul 22, 2026
3bee7d5
chore: sync uv.lock to released version 1.2.0
github-actions[bot] Jul 22, 2026
42f03b2
Merge pull request #792 from DataIntegrationGroup/merge/production-in…
chasetmartin Jul 22, 2026
ed9e4b9
build(deps): bump astral-sh/setup-uv from 8.3.2 to 9.0.0
dependabot[bot] Jul 27, 2026
99c1b5d
build(deps): bump actions/checkout from 7.0.0 to 7.0.1 in the gha-min…
dependabot[bot] Jul 27, 2026
2ddffd7
build(deps): bump the uv-non-major group with 18 updates (#795)
dependabot[bot] Jul 27, 2026
a316d0c
chore: remove unused admin UI
jirhiker Jul 29, 2026
3756dda
Merge pull request #800 from DataIntegrationGroup/chore/deprecate-adm…
jirhiker Jul 29, 2026
2261f49
feat(lexicon): add new "USFS, Cibola NF, Supervisor's Office" organiz…
ksmuczynski Jul 30, 2026
1bbcb01
feat(lexicon): add new "Lightning Dock Zanskar" and "Sparrowhawk Farm…
ksmuczynski Jul 30, 2026
b30bea8
Merge pull request #804 from DataIntegrationGroup/kas-add-'USFS-Cibol…
ksmuczynski Aug 3, 2026
4fe3468
build(deps): bump actions/stale from 10 to 11
dependabot[bot] Aug 3, 2026
2c17ce6
fix(tests): remove hardcoded group id assumption
ksmuczynski Jul 15, 2026
32c6462
fix(build): package data_migrations with the app
ksmuczynski Jul 15, 2026
6f171b8
test(fixtures): default shared fixtures to public
ksmuczynski Jul 15, 2026
dbc760b
feat(ogc): filter ogc_* views to public records
ksmuczynski Jul 15, 2026
70c688f
feat(data-migrations): publish existing project_areas
ksmuczynski Jul 15, 2026
02f8cd3
test(ogc): add behave coverage for public-only filter
ksmuczynski Jul 15, 2026
c286018
Formatting changes
ksmuczynski Jul 15, 2026
3ecf205
Merge remote-tracking branch 'origin/kas-bdms-971-apply-public-filter…
ksmuczynski Aug 3, 2026
8ae9fe1
fix(ogc): re-point migration to new staging head
ksmuczynski Aug 3, 2026
eedf658
Merge branch 'kas-bdms-971-(A1)-apply-public-filter-to-all-OGC-views'…
ksmuczynski Aug 3, 2026
3882a5d
fix(ogc): drop duplicate collections step definition
ksmuczynski Aug 3, 2026
cc5f72c
feat(ogc): mirror EDR views in internal OGC mount
ksmuczynski Aug 3, 2026
ce45b91
Merge pull request #783 from DataIntegrationGroup/kas-bdms-985-intern…
ksmuczynski Aug 3, 2026
02594c3
build(deps): bump cryptography from 48.0.1 to 50.0.0
dependabot[bot] Aug 3, 2026
013fd75
feat(geothermal): normalize OGC view temperatures to Celsius
jirhiker Aug 6, 2026
abcf8ba
test(geothermal): cover temperature unit normalization
jirhiker Aug 7, 2026
54c4ba7
Formatting changes
jirhiker Aug 7, 2026
c6cfb7e
Merge pull request #811 from DataIntegrationGroup/feat/geothermal-tem…
jirhiker Aug 7, 2026
860a3f4
fix(ogc): isolate public and internal pygeoapi module globals
ksmuczynski Aug 6, 2026
5bb2aae
Merge pull request #812 from DataIntegrationGroup/kas-fix-ogc-mount-e…
ksmuczynski Aug 7, 2026
72f26a5
feat(ogc): add public data disclaimer page
ksmuczynski Aug 6, 2026
93206ab
feat(ogc): replace server metadata placeholders
ksmuczynski Aug 6, 2026
14df42b
test(ogc): cover service metadata and disclaimer
ksmuczynski Aug 6, 2026
fd4c446
Merge pull request #810 from DataIntegrationGroup/kas-A2-replace-ogc-…
ksmuczynski Aug 7, 2026
3f10ddb
refactor(domain): extract CSV importer rules into a domain layer
jirhiker Aug 7, 2026
06ac1f8
Merge pull request #814 from DataIntegrationGroup/bdms-domain-extraction
jirhiker Aug 7, 2026
1dab175
Merge pull request #807 from DataIntegrationGroup/dependabot/github_a…
jirhiker Aug 7, 2026
a7a484d
Merge pull request #809 from DataIntegrationGroup/dependabot/uv/crypt…
jirhiker Aug 7, 2026
4adbed6
Merge pull request #794 from DataIntegrationGroup/dependabot/github_a…
jirhiker Aug 7, 2026
83e6604
feat(geothermal): add /thing/geothermal-well endpoints
jirhiker Aug 7, 2026
c60faf8
Merge pull request #815 from DataIntegrationGroup/rescue/geothermal-w…
jirhiker Aug 7, 2026
21090b5
feat(lexicon): add organization and sort organization category alphab…
ksmuczynski Aug 7, 2026
cd75756
build(deps): bump the uv-non-major group with 25 updates (#817)
dependabot[bot] Aug 10, 2026
e5748a5
feat(geothermal): free-text search on the well list endpoint
jirhiker Aug 10, 2026
7e0a259
Merge pull request #820 from DataIntegrationGroup/BDMS-1133-geotherma…
jirhiker Aug 10, 2026
1057c86
Merge pull request #816 from DataIntegrationGroup/kas-new-organizatio…
ksmuczynski Aug 11, 2026
e448741
fix(db): repair EDR water views skipped by a stamped revision
jirhiker Aug 13, 2026
0cc0d93
Merge pull request #824 from DataIntegrationGroup/fix/edr-water-views…
jirhiker Aug 13, 2026
bb447f6
ci: add a workflow_dispatch job for data migrations
jirhiker Aug 13, 2026
65e6bde
Merge pull request #826 from DataIntegrationGroup/ci/data-migrations-…
jirhiker Aug 13, 2026
395a63c
fix: correct water_wells collection name in README examples and Added…
likithabommasani21 Aug 13, 2026
8863430
fix(edr): source water-chemistry EDR from the legacy NMA tables
jirhiker Aug 13, 2026
aac3d87
fix(edr): expose thing_type and materialize the chemistry coverages
jirhiker Aug 13, 2026
a102ad4
Formatting changes
jirhiker Aug 13, 2026
ad37f78
Merge pull request #827 from DataIntegrationGroup/fix/edr-water-chemi…
jirhiker Aug 14, 2026
b6887b2
build(deps): bump astral-sh/setup-uv from 9.0.0 to 10.0.1
dependabot[bot] Aug 17, 2026
e7e89ba
chore(auth): harden Authentik authorization
jirhiker Aug 17, 2026
79cef36
Merge pull request #830 from DataIntegrationGroup/chore/harden-api-au…
jirhiker Aug 17, 2026
fde4c33
build(deps): bump sqlparse from 0.5.5 to 0.6.0 (#831)
dependabot[bot] Aug 17, 2026
ae19526
build(deps): bump the uv-non-major group across 1 directory with 15 u…
dependabot[bot] Aug 17, 2026
865b84d
build(deps): bump gunicorn from 23.0.0 to 26.0.0
dependabot[bot] Aug 17, 2026
4c0099e
feat(ogc): make /ogcapi-internal usable from ArcGIS Pro and QGIS
jirhiker Aug 18, 2026
6041b0f
ci: upload coverage to Codecov and add a review skill
jirhiker Aug 18, 2026
299aa7d
ci: drop Codecov and report coverage from the workflow itself
jirhiker Aug 18, 2026
e48357a
ci: exclude transfers from coverage and comment the summary on PRs
jirhiker Aug 18, 2026
a5f506b
Merge pull request #828 from DataIntegrationGroup/dependabot/github_a…
jirhiker Aug 18, 2026
cfdf146
Merge pull request #833 from DataIntegrationGroup/chore/harden-api-au…
jirhiker Aug 18, 2026
1700761
docs(ingestion): add the automated ingestion pipeline plan
jirhiker Aug 18, 2026
0a2109e
feat(ingestion): scaffold the automated_ingestion Dagster code location
jirhiker Aug 18, 2026
4fd5a57
docs(ingestion): record the Diver-HUB findings; the blocker is cleared
jirhiker Aug 18, 2026
e45b6e4
ci(ingestion): add the Dagster+ code location and its deploy workflows
jirhiker Aug 18, 2026
5188fa4
ci(ingestion): read the Dagster+ org id from a variable, not a secret
jirhiker Aug 18, 2026
475841d
feat(ingestion): add raw-zone infrastructure and database connectivity
jirhiker Aug 18, 2026
fd6e869
fix(ingestion): repair two CI failures the first PR run exposed
jirhiker Aug 18, 2026
23579ea
ci(ingestion): build the code location on python 3.13
jirhiker Aug 18, 2026
e01fd8c
feat(ingestion): add the Diver-HUB client and correct the source mapping
jirhiker Aug 18, 2026
6166171
docs(ingestion): record the probe findings and correct the 500 model
jirhiker Aug 18, 2026
d10b2b4
feat(ingestion): resolve the datum enum and the source unit
jirhiker Aug 18, 2026
aa31edd
ci(ingestion): redeploy the code location when db/ or domain/ change
jirhiker Aug 18, 2026
6c9ab70
feat(ingestion): land San Acacia locations and readings in the raw zone
jirhiker Aug 18, 2026
055b51e
Merge pull request #834 from DataIntegrationGroup/feat/automated-inge…
jirhiker Aug 18, 2026
a8a7400
Add Dagster Cloud deploy actions
jirhiker Aug 18, 2026
8f49736
chore(ci): remove the duplicated Dagster+ deploy workflows
jirhiker Aug 18, 2026
ece7026
Merge pull request #835 from DataIntegrationGroup/chore/remove-duplic…
jirhiker Aug 18, 2026
a4b16b2
chore(ci): track staging for the Dagster+ prod code location
jirhiker Aug 18, 2026
b093232
Merge pull request #836 from DataIntegrationGroup/chore/dagster-prod-…
jirhiker Aug 18, 2026
976a861
chore(ingestion): support dg for code location environment variables
jirhiker Aug 18, 2026
f246d61
fix(ingestion): make the IAM database path internally consistent
jirhiker Aug 18, 2026
a425954
fix(ingestion): make db and domain importable in the deployed image
jirhiker Aug 18, 2026
9198fbb
Merge pull request #837 from DataIntegrationGroup/chore/dagster-env-v…
jirhiker Aug 18, 2026
1df7d8c
fix(ingestion): set PYTHONPATH and report the import environment
jirhiker Aug 18, 2026
5ccb0d6
Merge pull request #838 from DataIntegrationGroup/fix/ingestion-impor…
jirhiker Aug 18, 2026
625b142
chore(ci): keep .git out of the Dagster+ build context
jirhiker Aug 18, 2026
7795959
fix(ingestion): install the repository into the Dagster+ image
jirhiker Aug 19, 2026
63f75f0
Merge pull request #839 from DataIntegrationGroup/chore/tighten-docke…
jirhiker Aug 19, 2026
2799f91
fix(ingestion): supply GCP credentials in a runtime that has none
jirhiker Aug 19, 2026
619cdf3
Merge pull request #840 from DataIntegrationGroup/fix/install-repo-in…
jirhiker Aug 19, 2026
8c1c32d
Merge pull request #841 from DataIntegrationGroup/fix/serverless-gcp-…
jirhiker Aug 19, 2026
affa35c
fix(ingestion): set code location env vars at a scope that reaches th…
jirhiker Aug 19, 2026
a178f90
fix(ingestion): reject a bare Cloud SQL instance name
jirhiker Aug 19, 2026
af78d18
chore(ingestion): put the raw zone in us-west4, beside Cloud SQL
jirhiker Aug 19, 2026
773de45
Merge pull request #842 from DataIntegrationGroup/fix/dg-code-locatio…
jirhiker Aug 19, 2026
9e990ec
Merge pull request #843 from DataIntegrationGroup/chore/raw-zone-in-u…
jirhiker Aug 19, 2026
33b541c
fix(ingestion): make the role grants runnable and drop the CREATE ROLE
jirhiker Aug 19, 2026
fbd715d
chore(ingestion): stop tracking the Terraform state lock file
jirhiker Aug 19, 2026
0bd2213
Merge pull request #844 from DataIntegrationGroup/fix/ingestion-role-…
jirhiker Aug 19, 2026
c390073
fix(ingestion): grant bucket read, and name the pipeline after the bu…
jirhiker Aug 19, 2026
b127f52
Merge pull request #845 from DataIntegrationGroup/fix/raw-zone-bucket…
jirhiker Aug 19, 2026
7b85862
Merge pull request #818 from DataIntegrationGroup/dependabot/uv/stagi…
jirhiker Aug 19, 2026
91f4504
feat(ingestion): add the Van Essen domain rules and adapter
jirhiker Aug 19, 2026
31e0644
feat(ingestion): add the transducer unique constraint and upsert loader
jirhiker Aug 19, 2026
a0af312
feat(ingestion): derive the watermark from Postgres
jirhiker Aug 19, 2026
6d1ced3
feat(ingestion): add the shared backfill primitives
jirhiker Aug 19, 2026
34c4b1f
Merge pull request #846 from DataIntegrationGroup/feat/van-essen-doma…
jirhiker Aug 19, 2026
279ff6e
Merge pull request #849 from DataIntegrationGroup/feat/backfill-primi…
jirhiker Aug 19, 2026
54b0611
chore(ingestion): report duplicate observations without psql
jirhiker Aug 19, 2026
6f3232d
Merge pull request #847 from DataIntegrationGroup/feat/transducer-ups…
jirhiker Aug 19, 2026
87b8e9c
Merge pull request #848 from DataIntegrationGroup/feat/postgres-water…
jirhiker Aug 19, 2026
78bc921
fix(ingestion): write the raw zone as parquet
jirhiker Aug 19, 2026
8ed7784
Merge pull request #850 from DataIntegrationGroup/chore/duplicate-rep…
jirhiker Aug 19, 2026
9aa0eac
Merge pull request #851 from DataIntegrationGroup/fix/raw-zone-parquet
jirhiker Aug 19, 2026
c20e2e3
feat(ingestion): reconcile San Acacia points against Ocotillo wells
jirhiker Aug 19, 2026
50963f4
fix(ingestion): import ThingIdLink from where it actually lives
jirhiker Aug 19, 2026
d102cb7
fix(ingestion): do not match on external ids by default
jirhiker Aug 19, 2026
6d8cf47
docs(ingestion): confirm reconciliation against production
jirhiker Aug 19, 2026
e6de538
docs: record the San Acacia piezometer identifier conflicts
jirhiker Aug 19, 2026
9dff7fb
feat(transducer): add data_maturity to observations
jirhiker Aug 19, 2026
9c38048
Formatting changes
jirhiker Aug 19, 2026
95b9b78
fix(transducer): backfill data_maturity from the legacy QC flag
jirhiker Aug 19, 2026
027632f
Formatting changes
jirhiker Aug 19, 2026
fecbae8
Merge pull request #852 from DataIntegrationGroup/feat/san-acacia-rec…
jirhiker Aug 19, 2026
09926b2
Merge pull request #853 from DataIntegrationGroup/feat/transducer-dat…
jirhiker Aug 19, 2026
5a50381
fix(ingestion): do not overwrite approved observations by default
jirhiker Aug 19, 2026
b522052
Merge pull request #854 from DataIntegrationGroup/fix/protect-approve…
jirhiker Aug 19, 2026
6bf1b00
Merge pull request #855 from DataIntegrationGroup/docs/piezometer-ide…
jirhiker Aug 19, 2026
113fdd6
feat(ingestion): wire the loader end to end
jirhiker Aug 19, 2026
ac7b5e8
fix(ingestion): raise the ingestion floor to 2024
jirhiker Aug 19, 2026
3e38614
Merge pull request #856 from DataIntegrationGroup/feat/wire-san-acaci…
jirhiker Aug 19, 2026
1c97aa2
chore(data): drop unattributed alternate IDs from the ingested San Ac…
jirhiker Aug 19, 2026
c4f6dc5
ci(staging): report data migrations that have not been applied
jirhiker Aug 19, 2026
44d7117
Merge pull request #857 from DataIntegrationGroup/chore/drop-unknown-…
jirhiker Aug 19, 2026
fdc59a3
Merge pull request #858 from DataIntegrationGroup/ci/report-pending-d…
jirhiker Aug 19, 2026
9294f43
ci: unbind the Dagster deploy from the production environment
jirhiker Aug 19, 2026
e4b1880
feat(ingestion): schedule the San Acacia ingest weekly
jirhiker Aug 19, 2026
d7e6cb6
Merge pull request #859 from DataIntegrationGroup/ci/gate-production-…
jirhiker Aug 19, 2026
8c02977
Merge pull request #860 from DataIntegrationGroup/feat/san-acacia-wee…
jirhiker Aug 19, 2026
de296fd
test(ingestion): cover the Dagster assets
jirhiker Aug 19, 2026
dac1519
Merge pull request #861 from DataIntegrationGroup/test/ingest-asset-c…
jirhiker Aug 19, 2026
1405ce9
fix(ingestion): stop duplicate instants reaching one INSERT
jirhiker Aug 19, 2026
ef38ef2
Merge pull request #862 from DataIntegrationGroup/fix/duplicate-rows-…
jirhiker Aug 19, 2026
4a0da42
ci(dagster): deploy code location as PEX instead of an image
jirhiker Aug 19, 2026
b7a6fb3
ci(dagster): add a dispatchable heartbeat smoke test
jirhiker Aug 19, 2026
77195a8
ci(dagster): materialize the heartbeat after a branch deploy
jirhiker Aug 19, 2026
f95ad29
fix(ci): assert the heartbeat run succeeded
jirhiker Aug 19, 2026
3cfae73
Merge pull request #863 from DataIntegrationGroup/ci/dagster-pex-fast…
jirhiker Aug 19, 2026
63bf502
feat(transducer): publish and range-delete for corrected hydrographs
jirhiker Aug 19, 2026
ba73c6b
fix(transducer): spell the block time-order constraint correctly
jirhiker Aug 19, 2026
f950756
Merge origin/staging into claude/hydrograph-corrector-api-f5e30b
jirhiker Aug 19, 2026
4701979
fix(transducer): serialize series writes and scope the publish parameter
jirhiker Aug 20, 2026
cfd9243
Merge pull request #864 from DataIntegrationGroup/claude/hydrograph-c…
jirhiker Aug 20, 2026
5b2cf6f
chore(transfers): deprecate NM_Aquifer/NM_Wells drivers, drop tests f…
jirhiker Aug 20, 2026
e425fa1
Merge pull request #865 from DataIntegrationGroup/claude/deprecate-nm…
jirhiker Aug 20, 2026
7a3915f
feat(transducer): backfill data_maturity on acoustic observations
jirhiker Aug 20, 2026
60ffcf4
Merge pull request #868 from DataIntegrationGroup/feat/backfill-acous…
jirhiker Aug 21, 2026
fb64f68
fix(seed): load reference data even when migrations seeded a term
jirhiker Aug 21, 2026
cdb4246
Merge pull request #869 from DataIntegrationGroup/fix/seed-reference-…
jirhiker Aug 21, 2026
97d7f9f
feat(chemistry): serve legacy water chemistry over REST
jirhiker Aug 21, 2026
67b522c
feat(chemistry): report which legacy table a result came from
jirhiker Aug 21, 2026
bff7faa
fix(thing): a well with no location no longer 500s the listing
jirhiker Aug 21, 2026
8e55d1d
feat(scripts): seed the test DB with real NMA legacy chemistry
jirhiker Aug 21, 2026
51bb35b
Formatting changes
jirhiker Aug 21, 2026
dcb0cb1
Merge pull request #870 from DataIntegrationGroup/feat/bdms-1189-lega…
jirhiker Aug 21, 2026
4c3ba71
chore(ogc): hide four layers from the public catalog
jirhiker Aug 22, 2026
572cf68
chore(ogc): explain what each layer is and how it was built
jirhiker Aug 22, 2026
832b659
feat(ogc): add the field-description source of truth
jirhiker Aug 22, 2026
f6af982
feat(ogc): serve field descriptions from /schema
jirhiker Aug 22, 2026
1d41b56
feat(ogc): carry field descriptions onto /queryables
jirhiker Aug 22, 2026
ac0513d
feat(ogc): document EDR parameters and cover the lot with tests
jirhiker Aug 22, 2026
e3fc68c
docs(ogc): document the field-description layer
jirhiker Aug 22, 2026
598f1ac
fix(ogc): stop EDR field dicts leaking between requests
jirhiker Aug 22, 2026
9fc6966
feat(ogc): populate the schema view's Values column
jirhiker Aug 22, 2026
12ec0b3
Merge pull request #872 from DataIntegrationGroup/chore/ogc-rich-laye…
jirhiker Aug 22, 2026
54289d0
chore(deps): Bump dagster-io/dagster-cloud-action from 1.13.18 to 1.1…
dependabot[bot] Aug 24, 2026
b779661
chore(deps): Bump the uv-non-major group with 10 updates (#881)
dependabot[bot] Aug 24, 2026
550fc18
fix: expand actively_monitored_wells to include wells from all groups…
likithabommasani21 Aug 24, 2026
4cf10fa
docs(ogc): describe actively_monitored_wells as all-groups
jirhiker Aug 22, 2026
02f0fe5
fix(edr): implement pygeoapi's instance contract
jirhiker Aug 23, 2026
c47f481
fix(ogc): gate ogc_waterlevels on the well's release status
jirhiker Aug 23, 2026
04fafce
feat(gis): generate shareable QGIS and ArcGIS Pro artifacts
jirhiker Aug 23, 2026
70b21b8
fix(gis): document the content type the artifact routes actually send
jirhiker Aug 23, 2026
3aa6611
feat(gis): serve the artifact catalogue as JSON for frontend clients
jirhiker Aug 23, 2026
2582492
Formatting changes
jirhiker Aug 23, 2026
7aa1746
feat(ogc): expose last_observation_date on the Group A layers
jirhiker Aug 24, 2026
8a0c3ce
feat(ogc): publish a well water-column layer
jirhiker Aug 24, 2026
1a9361a
Merge pull request #885 from DataIntegrationGroup/feat/ogc-well-water…
jirhiker Aug 24, 2026
30972fe
merge: production v1.2.1 into staging
jirhiker Aug 24, 2026
a51415d
chore: sync staging release-please manifest to v1.2.1
jirhiker Aug 24, 2026
2f48ecc
Merge pull request #887 from DataIntegrationGroup/merge/production-in…
jirhiker Aug 24, 2026
0a46106
chore(staging): release 1.3.0-rc
github-actions[bot] Aug 24, 2026
c52c8db
Merge pull request #806 from DataIntegrationGroup/release-please--bra…
jirhiker Aug 24, 2026
f4516bc
chore(transfers): drop the Procfile that fed the transfer build
jirhiker Aug 24, 2026
e36bd92
Merge pull request #889 from DataIntegrationGroup/chore/drop-transfer…
jirhiker Aug 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1 +1,45 @@
.venv
# Keep the build context to what the image actually runs.
#
# The tracked tree is ~13 MB; the context was ~316 MB, almost entirely .git.
# CI clones full history, and every Dagster+ deploy was transferring it before
# the first layer could build.

# Version control. Nothing in the image reads git metadata.
.git
.github
.gitignore

# Python build and cache artifacts. Stale .pyc from a different interpreter is
# worse than useless in an image built on a pinned base.
__pycache__/
*.py[cod]
*.egg-info/
.pytest_cache/
.ruff_cache/
.mypy_cache/
.coverage
htmlcov/

# Virtualenvs and local tooling state.
.venv
.dg
*.tfstate
*.tfstate.*
.terraform/

# Local-only data from legacy transfer runs. Untracked, machine-specific, and
# the largest thing on a developer checkout by an order of magnitude -- a local
# `docker build` would otherwise ship ~900 MB of CSV cache.
transfers/data/
transfers/logs/
transfers/metrics/

# Test fixtures and BDD features. The image runs the code location, not the
# suite; CI runs the suite outside the image.
tests/
features/

# Editor and OS noise.
.DS_Store
.idea/
.vscode/
33 changes: 31 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,26 @@ POSTGRES_PORT=5432
PYGEOAPI_POSTGRES_PASSWORD=your_password
PYGEOAPI_POSTGRES_USER=your_username

# PYGEOAPI internal mount (/ogcapi-internal) -- authenticated, unfiltered
# (private/draft-inclusive) mirror of /ogcapi. Shares PYGEOAPI_POSTGRES_*
# above; only the mount path, runtime dir, and advertised server URL differ.
PYGEOAPI_INTERNAL_MOUNT_PATH=/ogcapi-internal
PYGEOAPI_INTERNAL_RUNTIME_DIR=/tmp/pygeoapi-internal
# Leave blank to derive from PYGEOAPI_SERVER_URL's application root. Only set
# this when the internal mount is served from a different host than /ogcapi.
PYGEOAPI_INTERNAL_SERVER_URL=

# Static API keys for /ogcapi-internal, for desktop GIS clients that cannot
# refresh an Authentik access token (ArcGIS Pro, QGIS). Comma- or
# whitespace-separated `label:sha256hex` entries; the label is bookkeeping
# only. Blank means bearer-JWT access only. Mint one with:
# python -c "import secrets,hashlib;k=secrets.token_urlsafe(32);print(k,hashlib.sha256(k.encode()).hexdigest())"
# Give the first value to the user, put `label:<second value>` here.
# Deployed environments source this from the Secret Manager secret
# `internal-ogc-api-keys`, not from a GitHub secret.
# See docs/internal-ogc-desktop-gis.md.
INTERNAL_OGC_API_KEYS=

# Connection pool configuration for parallel transfers
# pool_size: number of persistent connections to maintain
# max_overflow: additional connections allowed during peak usage
Expand Down Expand Up @@ -73,19 +93,28 @@ MODE=development
# ENABLE_PG_CRON=0

# disable authentication (for development only)
#
# Honored ONLY when MODE=development. With any other MODE (including unset or
# "staging"), the app refuses to start -- core.permissions.assert_auth_configuration()
# raises AuthConfigurationError rather than serving every endpoint anonymously.
AUTHENTIK_DISABLE_AUTHENTICATION=1

# erase and rebuild the database for step tests
REBUILD_DB=1

# authentik
# AUTHENTIK_URL is both the JWKS base and the expected `iss` claim; trailing
# slash optional, both spellings are accepted.
AUTHENTIK_URL=
AUTHENTIK_CLIENT_ID=
AUTHENTIK_AUTHORIZE_URL=
AUTHENTIK_TOKEN_URL=

# middleware
SESSION_SECRET_KEY=your_secret_key_here
# How long a fetched JWKS document is trusted, in seconds (default 3600).
# An unrecognized `kid` forces one immediate refresh regardless, so this only
# bounds how long a revoked key stays usable.
# AUTHENTIK_JWKS_TTL_SECONDS=3600


# feedback endpoint (POST /feedback) — bug reports and feature requests
JIRA_BASE_URL=https://nmbgmr.atlassian.net
Expand Down
9 changes: 7 additions & 2 deletions .github/app.template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ env_variables:
PYGEOAPI_POSTGRES_PASSWORD: |-
${PYGEOAPI_POSTGRES_PASSWORD}
PYGEOAPI_SERVER_URL: "${PYGEOAPI_SERVER_URL}"
# Hashed static API keys for the authenticated /ogcapi-internal mount, as
# `label:sha256hex` entries, sourced from the Secret Manager secret
# `internal-ogc-api-keys`. Needed because ArcGIS Pro and QGIS cannot refresh
# an Authentik access token; see core/internal_ogc_auth.py and
# docs/internal-ogc-desktop-gis.md. Unset means bearer-JWT access only.
INTERNAL_OGC_API_KEYS: |-
${INTERNAL_OGC_API_KEYS}
CLOUD_SQL_IAM_AUTH: "${CLOUD_SQL_IAM_AUTH}"
GCS_SERVICE_ACCOUNT_KEY: |-
${GCS_SERVICE_ACCOUNT_KEY}
Expand All @@ -42,8 +49,6 @@ env_variables:
AUTHENTIK_CLIENT_ID: "${AUTHENTIK_CLIENT_ID}"
AUTHENTIK_AUTHORIZE_URL: "${AUTHENTIK_AUTHORIZE_URL}"
AUTHENTIK_TOKEN_URL: "${AUTHENTIK_TOKEN_URL}"
SESSION_SECRET_KEY: |-
${SESSION_SECRET_KEY}
APITALLY_CLIENT_ID: "${APITALLY_CLIENT_ID}"
JIRA_BASE_URL: "${JIRA_BASE_URL}"
JIRA_EMAIL: "${JIRA_EMAIL}"
Expand Down
84 changes: 84 additions & 0 deletions .github/skills/code-review/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
name: code-review
description: Repository-specific review rules for OcotilloAPI pull requests. Use this when reviewing a pull request in this repository, so review comments account for the authorization, schema, domain-layer, and migration conventions that are easy to violate silently.
---

# Reviewing OcotilloAPI pull requests

OcotilloAPI is a FastAPI + PostgreSQL/PostGIS geospatial service for the New Mexico
Bureau of Geology and Mineral Resources. Read `CLAUDE.md` at the repository root for
the full architecture; this skill lists the mistakes worth flagging in review because
they fail silently rather than breaking a test.

Use the GitHub MCP server tools (`list_workflow_runs`, `summarize_job_log_failures`,
`get_job_logs`) to check whether the `Test Suite` workflow is failing before commenting
on behavior — a failing `unit-tests` job often explains the diff better than the diff does.

## Authorization is opt-in, so omissions are invisible

Authorization is applied per endpoint via a parameter in the route signature, not by a
router-level `dependencies=[...]`. Two failure modes to flag:

1. A new route with no `user: <role>_dependency` parameter is fully public and raises no
error. If the pull request adds a route, check whether it belongs in the anonymous-route
allowlist in `tests/test_authorization.py`. If it does not, it needs a role dependency.
2. The dependency must be a **type annotation** (`user: viewer_dependency`), never a default
value (`user=viewer_dependency`). The latter silently disables the dependency, and FastAPI
reinterprets it as a query parameter. Flag this every time.

Role families are orthogonal: general `Admin` confers nothing in the `AMP*` or `Lexicon*`
families. Only tiers within one family nest. A diff that treats `Admin` as a superset of
`AMPEditor` is wrong.

`@in_public_schema` controls anonymous OpenAPI visibility only. It grants no access and
removes no dependency; flag any use that appears to be standing in for authorization.

`/ogcapi-internal` is a raw Starlette Mount and is gated at the ASGI layer in
`core/internal_ogc_auth.py`, outside `Depends()`. Changes to its credential paths should
cite `docs/internal-ogc-desktop-gis.md`.

The development auth bypass (`AUTHENTIK_DISABLE_AUTHENTICATION=1`) is honored only when
`MODE=development`. Any change that widens that condition is a security finding.

## Model changes are a five-step workflow

A pull request that edits a model in `db/` is incomplete unless it also covers the matching
Pydantic schemas in `schemas/`, an Alembic migration, test fixtures and payloads in `tests/`,
and the field mappings in `transfers/` when the field is populated from the legacy AMPAPI
data. Flag whichever step is missing.

Schema conventions: `Create` schemas use `<type>` for non-nullable and `<type> | None = None`
for nullable; `Update` schemas make every field optional with a `None` default; `Response`
schemas use `<type>` for non-nullable and `<type> | None` for nullable.

Validation split: input validation belongs in Pydantic validators and produces 422s. Database
constraint checks are manual in the endpoint and produce 409s. Custom exceptions should use
`PydanticStyleException` from `services/exceptions_helper.py` so error bodies stay consistent.

## Layer boundaries

`domain/` holds business rules as plain functions over plain values. Modules there must not
import from `api/`, `db/`, `schemas/`, or `services/`, and must not import `fastapi`,
`sqlalchemy`, `pydantic`, or `httpx`. Flag any new import that breaks this — it is what keeps
the rules testable without a database. Domain errors subclass `ValueError` because the CSV
importers treat a `ValueError` on a row as a per-row validation failure; an exception type
that does not subclass `ValueError` will escape that handling. See `ADR4.md`.

`services/` is the layer that loads data, calls the domain rule, and persists the result.

## Spatial and query specifics

All geometries are WGS84 (SRID 4326). Legacy transfer scripts convert from UTM (SRID 26913);
a missing transformation puts points in the wrong hemisphere rather than raising.

List filters arrive from the Refine UI as repeated `filter` query parameters containing JSON.
Association-backed columns are virtual and map to EXISTS subqueries in
`services/query_helper.py`, not to `ILIKE` on an ORM proxy. Sorting by monitoring status or
well status must use SQL subqueries on `StatusHistory`, because `ORDER BY` cannot see a Python
`@property`. See `docs/refine-json-filters-and-virtual-fields.md`.

## Migrations

Alembic schema migrations run automatically in the deployment pipeline. Registered *data*
migrations do not — they sit unapplied until someone runs them by hand. If a pull request adds
a data migration, ask how and when it will be run.
Loading
Loading