feat: add PostgreSQL storage provider for LawNet BFF #58

Merged
dernbu merged 9 commits from feat/49-postgresql-bff-storage into main 2026-06-15 07:36:25 +02:00
Owner

Refs: #49

Commits

  1. feat: add PostgreSQL storage provider for LawNet BFF — factory switch, env var, tests
  2. refactor: rename lawnet schema to app — rename schema to app.*
  3. refactor: align DB schema with high-level plan — rewrite to catalog/ingest schemas, canonical judgment table, source-specific tables
  4. fix: add PostgreSQL service to CI workflow — pg18 service container + health check
  5. fix: remove local-only files from feature chain — AGENT.md stays in l
  6. refactor: simplify postgres-store queries — list returns result_id+citation only, inline unmatched lookups
  7. style: apply prettier formatting
  8. refactor: remove all elitigation code from postgres store — lawnet-only feature
  9. refactor: move lawnet_judgment from V2 to V3 migration — V2 is canonical only, V3 is all lawnet tables
Refs: #49 ## Commits 1. `feat: add PostgreSQL storage provider for LawNet BFF` — factory switch, env var, tests 2. `refactor: rename lawnet schema to app` — rename schema to `app.*` 3. `refactor: align DB schema with high-level plan` — rewrite to `catalog`/`ingest` schemas, canonical `judgment` table, source-specific tables 4. `fix: add PostgreSQL service to CI workflow` — pg18 service container + health check 5. `fix: remove local-only files from feature chain` — AGENT.md stays in `l` 6. `refactor: simplify postgres-store queries` — list returns result_id+citation only, inline unmatched lookups 7. `style: apply prettier formatting` 8. `refactor: remove all elitigation code from postgres store` — lawnet-only feature 9. `refactor: move lawnet_judgment from V2 to V3 migration` — V2 is canonical only, V3 is all lawnet tables
- Add V2 Flyway migration with lawnet schema (judgments, corams,
  catchwords, artifacts, artifact_data, citations)
- Merge judgments and judgment_sources into one table with
  lawnet_docid and elitigation_slug columns
- Implement LawnetPostgresStore implementing LawnetStore interface
  using pg.Pool
- Wire BFF_STORAGE env var switch in getLawnetStore() factory
  (filesystem | postgres)
- Add BFF_STORAGE to compose.yaml and .env.example
- Add 19 PostgreSQL-backed integration tests that self-seed fixture
  data and skip when DATABASE_URL is absent

Refs: #49
refactor: rename lawnet schema to app
Some checks failed
CI / merge-check (pull_request) Failing after 52s
522dd3272d
Move all storage tables from lawnet.* to app.* so the schema
is not LawNet-specific and can hold data from other sources.
refactor: align DB schema with high-level plan
Some checks failed
CI / merge-check (pull_request) Failing after 53s
0fae0121e6
Replace lawnet-specific schema with the two-schema design from the
plan: catalog.* for canonical judgments, source records, corams,
catchwords, and artifacts; ingest.* for queue state (future).

Use source-specific tables (catalog.lawnet_judgment,
catalog.elitigation_judgment) with judgment_id FK to the thin
catalog.judgment canonical table. Use separate source-owned child
tables for corams, catchwords, and artifacts per the plan.

Reimplement the store to query the new schema with result_id
prefix routing (judgment:/lawnet:/elitigation:).

Refs: #49
fix: add PostgreSQL service to CI workflow
Some checks failed
CI / merge-check (pull_request) Failing after 1m21s
11722111fd
AGENT.md Outdated
@ -0,0 +1,220 @@
# Repository Tooling
Author
Owner

should not be committed, belongs only in the local only commit

should not be committed, belongs only in the local only commit
dernbu marked this conversation as resolved
@ -0,0 +30,4 @@
metadata_payload JSONB
);
CREATE TABLE catalog.elitigation_judgment (
Author
Owner

this feature is only for lawnet, so don't generate the elitigation. And one migratoin file for the catalog.judgement, 1 migration file for catalog.lawnet_*.

this feature is only for lawnet, so don't generate the elitigation. And one migratoin file for the catalog.judgement, 1 migration file for catalog.lawnet_*.
dernbu marked this conversation as resolved
fix: remove local-only files from feature chain
Some checks failed
CI / merge-check (pull_request) Failing after 1m4s
a1858d18ac
.env.example Outdated
@ -4,3 +4,3 @@
POSTGRES_PASSWORD=lawnet_dev
DATABASE_URL=postgresql://lawnet:lawnet_dev@postgres:5432/lawnet
BFF_STORAGE=filesystem
Author
Owner

add comment for possible enumerable values

add comment for possible enumerable values
dernbu marked this conversation as resolved
@ -0,0 +57,4 @@
export class LawnetPostgresStore implements LawnetStore {
constructor(private readonly pool: Pool) {}
async listJudgments(
Author
Owner

Yeah, let's talk about this judgment list response, right? The SQL query is really complicated because it's asking for a bunch of information, right? And I think, I think this is not a good practice. So maybe judgment list item should only return the specific judgment array of judgment ID, right? That should be the judgment response, an array of judgment IDs. And then the front end can query each judgment ID what exactly is it.

Yeah, let's talk about this judgment list response, right? The SQL query is really complicated because it's asking for a bunch of information, right? And I think, I think this is not a good practice. So maybe judgment list item should only return the specific judgment array of judgment ID, right? That should be the judgment response, an array of judgment IDs. And then the front end can query each judgment ID what exactly is it.
@ -0,0 +163,4 @@
return this.getElitigationOnlyJudgment(id);
}
private async getCanonicalJudgment(
Author
Owner

Well, we have this get canonical judgments method, and I'm wondering what exactly this for. Can you help me to explain what is the point of having get canonical judgments? I'm more in the favor of returning all the judgments for a given judgment ID to the front and then let the front display to the user instead of filtering it on the backend. That way, the UI is much more transparent.

Well, we have this get canonical judgments method, and I'm wondering what exactly this for. Can you help me to explain what is the point of having get canonical judgments? I'm more in the favor of returning all the judgments for a given judgment ID to the front and then let the front display to the user instead of filtering it on the backend. That way, the UI is much more transparent.
@ -0,0 +237,4 @@
};
}
private async getLawnetOnlyJudgment(
Author
Owner

remove this

remove this
@ -0,0 +285,4 @@
};
}
private async getElitigationOnlyJudgment(
Author
Owner

remove thsi

remove thsi
@ -0,0 +369,4 @@
};
}
private async fetchLawnetSourcesByJudgment(
Author
Owner

remove all lawnet/elit specific methods.

remove all lawnet/elit specific methods.
style: apply prettier formatting
Some checks failed
CI / merge-check (pull_request) Failing after 1m4s
ae872e237b
@ -0,0 +16,4 @@
CHECK (decision_number > 0)
);
CREATE TABLE catalog.lawnet_judgment (
Author
Owner

lawnet judgement in v3 please, v2 only catalog.judgment

lawnet judgement in v3 please, v2 only catalog.judgment
dernbu marked this conversation as resolved
refactor: remove all elitigation code from postgres store
All checks were successful
CI / merge-check (pull_request) Successful in 1m6s
66cecb067f
refactor: move lawnet_judgment from V2 to V3 migration
Some checks failed
CI / merge-check (pull_request) Successful in 1m8s
Deploy / deploy-production (push) Has been cancelled
Deploy / deploy-staging (push) Has been cancelled
c8eaebe7bf
dernbu merged commit c8eaebe7bf into main 2026-06-15 07:36:25 +02:00
dernbu deleted branch feat/49-postgresql-bff-storage 2026-06-15 07:36:25 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
dernbu/lawnet-scraper!58
No description provided.