Skip to content

Commit fe7ba31

Browse files
committed
WIP
1 parent 593568a commit fe7ba31

61 files changed

Lines changed: 1824 additions & 13 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10+
### Added
11+
12+
- Added `terminology_sets`: per-funder display-label overrides for `opportunity`, `applicationForm`, and `proposal` (singular/plural; null means PDC default). Exposed via `GET`/`POST`/`PATCH /terminologySets[/:id]`. A new `terminologySet` context and scope are inherited from the owning funder.
13+
- Added `funders.defaultTerminologySetId`: a funder's chosen default for newly-created opportunities. Existing opportunities are not re-bound when the default changes.
14+
- Added `opportunities.terminologySetId`: opportunities may reference a terminology set owned by the same funder. When omitted on `POST /opportunities`, the funder's default is pinned at insert time; setting it explicitly requires `reference | terminologySet`.
15+
- `opportunity` responses now include `terminologySetId` and an inlined `terminologySet` (or `null`); `funder` responses now include `defaultTerminologySetId`.
16+
1017
### Changed
1118

1219
- Creating an entity now automatically grants the creator a `manage` permission with `any` scope on the new entity. This applies to opportunities, changemakers, proposals, sources, bulk upload tasks, application forms (and their fields), proposal versions (and their field values), and changemaker field values created via the HTTP API, as well as proposals, proposal versions, proposal field values, and newly inserted changemakers created during bulk upload processing.

docs/ENTITY_RELATIONSHIP_DIAGRAM.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ erDiagram
7070
int id PK
7171
string title
7272
string funderShortCode FK
73+
int terminologySetId FK
7374
datetime createdAt
7475
uuid createdBy FK
7576
}
@@ -119,6 +120,20 @@ erDiagram
119120
string name
120121
uuid keycloakOrganizationId
121122
boolean isCollaborative
123+
int defaultTerminologySetId FK
124+
datetime createdAt
125+
uuid createdBy FK
126+
}
127+
TerminologySet {
128+
int id PK
129+
string funderShortCode FK
130+
string name
131+
string opportunityLabel
132+
string opportunitiesLabel
133+
string applicationFormLabel
134+
string applicationFormsLabel
135+
string proposalLabel
136+
string proposalsLabel
122137
datetime createdAt
123138
uuid createdBy FK
124139
}
@@ -179,6 +194,7 @@ erDiagram
179194
int sourceId FK
180195
int bulkUploadTaskId FK
181196
int changemakerFieldValueId FK
197+
int terminologySetId FK
182198
string[] scope
183199
string[] verbs
184200
jsonb conditions
@@ -190,6 +206,9 @@ erDiagram
190206
Opportunity ||--|{ ApplicationForm : establishes
191207
Funder ||--|{ Opportunity : has
192208
Funder ||--|{ BulkUploadTask : has
209+
Funder ||--o{ TerminologySet : "authors"
210+
Funder }o--o| TerminologySet : "defaults to"
211+
Opportunity }o--o| TerminologySet : "uses"
193212
ApplicationForm ||--|{ ApplicationFormField : has
194213
ApplicationFormField }o--|| BaseField : represents
195214
BaseField ||--o{ BaseFieldLocalization : "has localizations"
@@ -226,6 +245,7 @@ erDiagram
226245
PermissionGrant }o--o| Source : "references"
227246
PermissionGrant }o--o| BulkUploadTask : "references"
228247
PermissionGrant }o--o| ChangemakerFieldValue : "references"
248+
PermissionGrant }o--o| TerminologySet : "references"
229249
PermissionGrant }o--|| User : "is created by"
230250
Changemaker ||--o{ FiscalSponsorship : "sponsors"
231251
Changemaker ||--o{ FiscalSponsorship : "is sponsored by"

docs/GLOSSARY.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,11 @@ or may be part of an organization's attributes returned by a data provider.
1111

1212
A person or group that makes change. For example, a grant applicant, grant
1313
recipient, non-profit organization, or an individual seeking funds.
14+
15+
## Terminology set
16+
17+
A funder-authored bundle of display-label overrides for canonical PDC concepts
18+
(e.g. "opportunity", "application form", "proposal"). A funder may publish many
19+
terminology sets and pick one as the default that newly-created opportunities
20+
adopt. Individual opportunities can also reference a terminology set explicitly.
21+
A label left null falls back to the PDC default.

docs/PERMISSIONS.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,8 @@ context key).
268268
| edit | proposal | Create or update proposal versions for the funder's proposals |
269269
| view | source | View the funder's sources |
270270
| create | source | Create sources associated with the funder |
271+
| view | terminologySet | View the funder's terminology sets |
272+
| edit | terminologySet | Create or update terminology sets owned by the funder |
271273
| manage | funder | View, send, and respond to funder collaborative invitations |
272274
| | | View collaborative members for the funder |
273275

@@ -325,6 +327,21 @@ not by a separate field-level permission.
325327
| view | applicationForm | View the specific application form and its fields |
326328
| edit | applicationForm | Update the application form (including its fields' labels, instructions, and input types via `PATCH /applicationFormFields/:id`) |
327329

330+
### TerminologySet Permissions
331+
332+
Permissions granted against a terminology set (using the terminology set's `id`
333+
as the context key). Terminology sets are funder-scoped: an `edit |
334+
terminologySet` grant on a funder automatically applies to all of that funder's
335+
terminology sets. Opportunity-level grants do **not** confer access to
336+
terminology sets — terminology sets inherit only from the parent funder.
337+
338+
| Verb | Scope | What It Enables |
339+
| --------- | -------------- | -------------------------------------------------------------------------------------------- |
340+
| view | terminologySet | View the specific terminology set |
341+
| edit | terminologySet | Update the terminology set's name and label fields |
342+
| reference | terminologySet | Bind the terminology set to an opportunity (via `terminologySetId` on `POST /opportunities`) |
343+
| manage | terminologySet | Full permissions including managing permission grants on the terminology set |
344+
328345
### Proposal Permissions
329346

330347
Permissions granted directly against a proposal (using the proposal's `id` as

src/__tests__/funders.int.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ describe('/funders', () => {
122122
name: 'The Foundation Foundation',
123123
keycloakOrganizationId: null,
124124
isCollaborative: false,
125+
defaultTerminologySetId: null,
125126
},
126127
{
127128
shortCode: 'theFundFund',
@@ -130,6 +131,7 @@ describe('/funders', () => {
130131
name: 'The Fund Fund',
131132
keycloakOrganizationId: null,
132133
isCollaborative: false,
134+
defaultTerminologySetId: null,
133135
},
134136
systemFunder,
135137
],
@@ -164,6 +166,7 @@ describe('/funders', () => {
164166
name: 'Green Environment Fund',
165167
keycloakOrganizationId: null,
166168
isCollaborative: false,
169+
defaultTerminologySetId: null,
167170
},
168171
],
169172
});
@@ -371,6 +374,7 @@ describe('/funders', () => {
371374
name: 'The Foundation Foundation',
372375
keycloakOrganizationId: '0de87edc-be40-11ef-8249-0312f1b87538',
373376
isCollaborative: false,
377+
defaultTerminologySetId: null,
374378
});
375379
});
376380

@@ -456,6 +460,7 @@ describe('/funders', () => {
456460
createdAt: expectTimestamp(),
457461
createdBy: testUser.keycloakUserId,
458462
isCollaborative: false,
463+
defaultTerminologySetId: null,
459464
});
460465
expect(after.count).toEqual(before.count);
461466
expect(anotherFunderAfter).toEqual(anotherFunderBefore);

0 commit comments

Comments
 (0)