Skip to content

Commit c0f6c60

Browse files
committed
docs: update md and agent files
1 parent 2ddba29 commit c0f6c60

5 files changed

Lines changed: 209 additions & 82 deletions

File tree

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ tests/AGENTS.md: E2E, API and load suites
1818
wallet connection and transaction building. Main surface.
1919
- govtool/backend: Haskell + Servant, read-only REST over cardano-db-sync. All
2020
endpoints, db-sync queries, response shapes.
21-
- govtool/metadata-validation: NestJS. Rules for what makes CIP-100/108/119 off-chain
21+
- govtool/metadata-validation: NestJS. Rules for what makes CIP-108/119 off-chain
2222
metadata valid.
2323
- govtool/analytics-dashboard: Next.js internal usage dashboard. Not part of the
2424
gov.tools user flow; touch only when asked about analytics.

docs/ai/ARCHITECTURE_MAP.md

Lines changed: 102 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ builds with cardano-serialization-lib and the wallet signs.
2020

2121
Vite aliases: @ for src, plus @pages @consts @context @hooks @models @services @utils
2222
@mock, and @atoms @molecules @organisms for src/components/*. There is no @types or
23-
@config alias, so use @/types/... and @/config/env. Every folder has an index.ts
24-
barrel and new files must be added to it.
23+
@config alias, so use @/types/... and @/config/env. Many feature directories expose files through index.ts barrels. When a directory already uses a barrel, add new public exports to it; otherwise follow the surrounding direct-import pattern.
2524

2625
- App.tsx: the route table. Every route registers here.
2726
- config/env.ts: the only env accessor. Reads window.__ENV__, then import.meta.env.
@@ -30,8 +29,10 @@ barrel and new files must be added to it.
3029
- consts/queryKeys.ts: QUERY_KEYS and MUTATION_KEYS. Every new key registers here.
3130
- consts/governanceAction/fields.ts: GA form schemas, driving both rendering and
3231
hashing
33-
- services/API.ts: the single axios instance, with the 500-to-error-page interceptor
34-
- i18n/locales/en.json: all user-facing copy, about 925 lines, the only locale
32+
- services/API.ts:is the shared Axios instance for the GovTool backend and redirects backend HTTP 500 responses to the error
33+
page.Metadata validation uses a separate Axios client because it has a separate base URL.
34+
- i18n/locales/en.json: is the only locale and should be the source of new user-facing copy. Some existing hardcoded strings
35+
remain.
3536
- components: atomic design. atoms have no GovTool dependencies, molecules compose
3637
atoms without fetching, organisms are feature blocks that may use contexts and hooks.
3738

@@ -46,9 +47,8 @@ Contexts in src/context:
4647
vote totals show for which GA type
4748
- pendingTransaction: in-flight txs, so the UI can poll /transaction/status/:txId
4849
- governanceAction.tsx: GA list and detail state
49-
- contextProviders.tsx composes all of them. modal, snackbar, pagination and
50-
dataActionsBar are UI plumbing; adaHandle, usersnap and proposalDiscussion are
51-
integrations.
50+
- contextProviders.tsx: composes the main application providers. ChatwootProvider is mounted separately in main.tsx, and
51+
pending-transaction state is integrated through the wallet context.
5252

5353
## govtool/backend
5454

@@ -91,34 +91,105 @@ into SQL and cache the result rather than holding a connection.
9191

9292
## govtool/metadata-validation
9393

94-
NestJS. One job: fetch metadata at a URL, canonize the JSON-LD, hash it, validate the
95-
body against a CIP standard. POST /validate is in app.controller.ts, orchestration in
96-
app.service.ts, rules in utils/getStandard.ts, utils/validateCIP108body.ts and
97-
utils/validateMetadataStandard.ts. enums/ValidationError.ts holds the error codes the
98-
frontend switches on, so grep the frontend before renaming one.
94+
A NestJS service that validates off-chain metadata. It fetches metadata from a URL,
95+
parses the JSON, accepts a supplied CIP standard or attempts to identify CIP-108 or
96+
CIP-119, validates the required fields for a recognized standard, and compares a
97+
Blake2b-256 hash of the exact fetched content with the submitted hash.
9998

100-
utils/canonizeJSON.ts is duplicated at govtool/frontend/src/utils/canonizeJSON.ts and
101-
must behave identically: the frontend hashes metadata before submission and this
102-
service re-hashes it. Change one, change both.
99+
POST /validate is defined in app.controller.ts, orchestration is handled by
100+
app.service.ts, and validation logic lives in utils/getStandard.ts,
101+
utils/validateCIP108body.ts, and utils/validateMetadataStandard.ts.
102+
enums/ValidationError.ts defines the validation statuses consumed by the frontend,
103+
so check frontend usage before renaming or removing one.
104+
105+
Both metadata validation and the frontend contain utils/canonizeJSON.ts. The
106+
metadata-validation copy is currently unused by the production validation flow. The
107+
frontend uses canonicalization for signature verification, not for the metadata hash submitted to POST /validate.
103108

104109
## Environment variables
105110

106-
Frontend. .env.example, src/config/env.ts and docker-entrypoint.sh must all agree.
107-
108-
- VITE_BASE_URL: backend REST base URL
109-
- VITE_METADATA_API_URL: metadata-validation service
110-
- VITE_PDF_API_URL, VITE_OUTCOMES_API_URL: pillar APIs
111-
- VITE_IPFS_GATEWAY, VITE_IPFS_PROJECT_ID: IPFS reads
112-
- VITE_NETWORK_FLAG: Cardano network id, 0 is testnet
113-
- VITE_APP_ENV, VITE_IS_DEV: environment banners and dev affordances
114-
- VITE_IS_PROPOSAL_DISCUSSION_FORUM_ENABLED,
115-
VITE_IS_GOVERNANCE_OUTCOMES_PILLAR_ENABLED: pillar flags
116-
- VITE_SENTRY_DSN, VITE_GTM_ID, VITE_USERSNAP_SPACE_API_KEY
117-
118-
Backend. example-config.json, or the same keys as env vars via Conferer:
119-
dbsyncconfig with host, dbname, user, password and port; port 9999; host;
120-
cachedurationseconds; dreplistcachedurationseconds; pinataapijwt; sentrydsn;
121-
sentryenv.
111+
### Frontend application configuration
112+
113+
The frontend reads configuration from window.__ENV__ when running in a container,
114+
falling back to Vite's import.meta.env values for local development and build-time
115+
configuration.
116+
117+
When adding a frontend runtime variable, update all applicable configuration points:
118+
119+
1. govtool/frontend/.env.example
120+
2. govtool/frontend/src/config/env.ts
121+
3. govtool/frontend/docker-entrypoint.sh
122+
4. The govtool-frontend service in docker/docker-compose.yaml
123+
124+
Active frontend variables:
125+
126+
- VITE_BASE_URL: GovTool backend REST API base URL.
127+
- VITE_METADATA_API_URL: metadata-validation service base URL.
128+
- VITE_PDF_API_URL: Proposal Discussion and Budget Discussion API base URL.
129+
- VITE_OUTCOMES_API_URL: Governance Outcomes API base URL.
130+
- VITE_IPFS_GATEWAY: gateway used to resolve ipfs:// resources.
131+
- VITE_IPFS_PROJECT_ID: optional project identifier sent when accessing the
132+
configured IPFS gateway.
133+
- VITE_NETWORK_FLAG: Cardano network ID; 0 selects a test network and 1
134+
selects mainnet.
135+
- VITE_APP_ENV: deployment environment name supplied to services such as Sentry.
136+
- VITE_IS_DEV: enables development behavior, including React Query devtools and
137+
bypassing production maintenance checks.
138+
- VITE_IS_PROPOSAL_DISCUSSION_FORUM_ENABLED: enables the Proposal Discussion
139+
pillar.
140+
- VITE_IS_GOVERNANCE_OUTCOMES_PILLAR_ENABLED: enables the Governance Outcomes
141+
pillar.
142+
- VITE_SENTRY_DSN: optional Sentry data source name.
143+
- VITE_CHATWOOT_URL: base URL from which the Chatwoot SDK is loaded.
144+
- VITE_CHATWOOT_WEBSITE_TOKEN: Chatwoot website token used to initialize the
145+
feedback widget.
146+
147+
### Frontend container and analytics configuration
148+
The frontend container also accepts variables that are handled by
149+
docker-entrypoint.sh and Nginx rather than exposed to React through window.__ENV__:
150+
151+
- UMAMI_URL: base URL of the Umami analytics service.
152+
- UMAMI_WEBSITE_ID: Umami website identifier.
153+
- UMAMI_SSL_VERIFY: controls TLS certificate verification for the Umami proxy;
154+
defaults to true.
155+
- TRUSTED_PROXY_CIDRS: trusted proxy address ranges used when resolving the
156+
original client IP. Set it to none to disable real-IP resolution.
157+
- REAL_IP_HEADER: header used to obtain the original client IP; defaults to
158+
X-Forwarded-For.
159+
160+
Umami is enabled only when both UMAMI_URL and UMAMI_WEBSITE_ID are configured.
161+
162+
### Metadata-validation service
163+
164+
The metadata-validation service reads these variables directly from process.env:
165+
166+
- PORT: HTTP port used by the NestJS service.
167+
- IPFS_GATEWAY: gateway used to resolve ipfs:// metadata URLs.
168+
- IPFS_PROJECT_ID: optional project identifier sent to the configured IPFS
169+
gateway.
170+
171+
The local template is govtool/metadata-validation/.env.example.
172+
173+
### Backend configuration
174+
175+
The Haskell backend loads configuration from example-config.json, or from the file
176+
supplied with --config / -c. Conferer also supports environment-variable overrides
177+
prefixed with VVA_.
178+
179+
Backend configuration keys:
180+
181+
- dbsyncconfig.host: cardano-db-sync PostgreSQL host.
182+
- dbsyncconfig.dbname: database name.
183+
- dbsyncconfig.user: database user.
184+
- dbsyncconfig.password: database password.
185+
- dbsyncconfig.port: PostgreSQL port.
186+
- port: backend HTTP port; example-config.json uses 9999.
187+
- host: backend bind address.
188+
- cachedurationseconds: default endpoint-cache lifetime in seconds.
189+
- dreplistcachedurationseconds: DRep-list cache lifetime in seconds.
190+
- pinataapijwt: optional Pinata API JWT used by the IPFS upload endpoint.
191+
- sentrydsn: backend Sentry data source name.
192+
- sentryenv: backend Sentry environment name.
122193

123194
## CI gates, in .github/workflows
124195

docs/ai/PLAYBOOKS.md

Lines changed: 97 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,29 @@ useGetProposalQuery, keyed on [key, dRepID, proposalId]. Return a named object l
2929
Dashboard element route gets connected chrome, wrapped in PublicRoute redirects
3030
when a wallet is connected.
3131

32-
Keep the page thin. It wires hooks to organisms; markup belongs in organisms.
32+
Route placement controls layout and connected variants, but does not by itself define
33+
all access requirements:
34+
35+
- Public browsing routes are registered at the top level.
36+
- Routes nested under Dashboard receive the connected dashboard layout.
37+
- PublicRoute currently redirects public DRep-directory routes to their
38+
/connected equivalents when a wallet is connected.
39+
- Wallet-dependent transaction pages, including registration and governance-action
40+
creation, are currently top-level routes and enforce their requirements through
41+
their page and wallet logic.
42+
Keep the page thin. It should wire hooks and state to feature components; follow the
43+
surrounding page and organism structure.
3344

3445
## Frontend: add a component
3546

36-
The only real decision is the layer. atoms for anything with no GovTool dependencies,
37-
molecules for compositions of atoms that do not fetch, organisms for feature blocks
38-
that may use contexts and query hooks. Add a .stories.tsx if it is reusable, since
39-
Storybook builds in CI.
47+
Choose the existing component layer whose responsibilities most closely match the new
48+
component. The atoms, molecules and organisms directories express increasing feature
49+
composition, but the boundaries are not strict: existing atoms and molecules may use
50+
shared hooks or contexts. Match nearby components before introducing a new layering
51+
rule.
52+
For a reusable component, add or update a Storybook story under src/stories, using
53+
.stories.ts or .stories.tsx depending on whether the story contains JSX.
54+
Storybook build and interaction tests run in CI.
4055

4156
## Frontend: add user-facing copy
4257

@@ -46,14 +61,21 @@ t("key", { name }). No hardcoded strings in JSX.
4661

4762
## Frontend: add an environment variable
4863

49-
Real only once it is in all four:
64+
A new React-visible `VITE_` runtime variable is complete only after updating all four
65+
applicable configuration points:
5066

5167
1. .env.example
5268
2. src/config/env.ts, as MY_VAR: getEnv("VITE_MY_VAR")
53-
3. docker-entrypoint.sh, into the window.__ENV__ block. This is the forgotten one:
54-
skip it and the var is undefined in every container while working locally.
69+
3. docker-entrypoint.sh, into the window.__ENV__ block.
5570
4. docker/docker-compose.yaml, passed into the govtool-frontend service
5671

72+
The entrypoint is easy to miss: without runtime injection, a variable may work through
73+
import.meta.env during local development but be undefined in a deployed container.
74+
75+
Container-only variables such as Umami and Nginx proxy configuration do not belong in
76+
src/config/env.ts or window.__ENV__; document and wire those through
77+
docker-entrypoint.sh and Compose instead.
78+
5779
## Frontend: add a feature flag
5880

5981
In src/context/featureFlag.tsx: add to FeatureFlagContextType, the createContext
@@ -65,20 +87,34 @@ predicate; exemplar areDRepVoteTotalsDisplayed.
6587

6688
## Frontend: build a new transaction or certificate
6789

68-
All of it lives in src/context/wallet.tsx. Add a buildXCert or
69-
buildXGovernanceAction beside its siblings, hand the certificates to
70-
buildSignSubmitConwayCertTx which owns builder, UTxO selection, change address,
71-
signing and submit, expose it on the context value, and register the result with
72-
pendingTransaction so the UI can poll /transaction/status/:txId.
90+
Shared Cardano serialization, wallet interaction and transaction submission live in
91+
src/context/wallet.tsx. Form-specific validation and selection of the appropriate
92+
builder remain in the calling form hook or page.
93+
94+
Add the appropriate builder beside its siblings:
95+
- buildXCert for certificates
96+
- buildXGovernanceAction for governance-action proposal builders
97+
- A voting builder for votes
98+
99+
Expose the builder through CardanoContextType and the provider value. Pass the
100+
result to buildSignSubmitConwayCertTx through the matching argument:
101+
certBuilder, govActionBuilder or votingBuilder.
102+
103+
buildSignSubmitConwayCertTx owns maintenance checks, UTxO selection, change,
104+
signing, submission and pending-transaction registration. Supply the correct
105+
transaction type and, when applicable, resourceId; it records the submitted hash
106+
so usePendingTransaction can poll /transaction/status/:txId.
73107

74108
Extend an existing builder rather than adding a parallel path, and verify on a
75109
testnet. This code moves real ada and has no unit tests.
76110

77111
## Frontend: write a unit test
78112

79-
Utils go in src/utils/tests/util.test.ts importing from the barrel, as from "..".
80-
Everything else is co-located, e.g. context/featureFlag.test.tsx. Iterate with
81-
npx vitest run and a path. Coverage comes from components, consts, context, hooks,
113+
Utils go in src/utils/tests/<utility>.test.ts and normally import the
114+
utility from the parent barrel with from "..". Other tests are generally colocated
115+
with the code under test, for example context/featureFlag.test.tsx.
116+
117+
Run a focused test with npx vitest run <path>.Coverage comes from components, consts, context, hooks,
82118
services and utils; pages and models are excluded, so do not chase coverage there.
83119

84120
## Backend: add a REST endpoint
@@ -101,18 +137,18 @@ tests/govtool-backend/test_cases.
101137

102138
## Backend: add caching to an endpoint
103139

104-
Two edits plus the call site: a field on CacheEnv in src/VVA/Types.hs, its
105-
initialisation in the cacheEnv block in app/Main.hs using newCache for the standard
106-
TTL or newDRepListCache for the long one, then in the handler:
140+
Add a field to CacheEnv in src/VVA/Types.hs, initialize it in the cacheEnv
141+
block in `app/Main.hs`, and use it at the handler call site.
142+
143+
Use newCache for the standard configured TTL. Use the DRep-list TTL only when the
144+
endpoint is deliberately intended to share that longer cache duration; rename or add
145+
a dedicated constructor binding when introducing another cache category.
107146

108147
```haskell
109148
CacheEnv {myThingCache} <- asks vvaCache
110149
cacheRequest myThingCache cacheKey $ do ...
111150
```
112151

113-
The key must include every parameter affecting the result. cacheRequest needs
114-
Hashable; compound keys use hash or hashWithSalt.
115-
116152
## Backend: change a db-sync query
117153

118154
Change a SELECT list and you must change the domain function's
@@ -124,26 +160,45 @@ db-sync instance, and say so if you could not.
124160
## Add a new governance action type
125161

126162
docs/operations/HANDLE_NEW_GOVERNANCE_ACTION_TYPE.md covers this but its paths and
127-
line numbers are stale. Current locations:
128-
129-
1. src/types/governanceAction.ts: the GovernanceActionType member, any new field type,
130-
a schema extending SharedGovernanceActionFieldSchema, and that schema added to the
131-
GovernanceActionFieldSchemas union
132-
2. src/consts/governanceAction/fields.ts: the field declaration, meaning component,
133-
labelI18nKey, placeholderI18nKey, tipI18nKey and rules. The doc says
134-
src/constants/governanceActionFields.ts, which does not exist.
135-
3. src/i18n/locales/en.json: every key the schema references
136-
4. Custom validation, if any: a helper in src/utils such as numberValidation.ts or
137-
isValidFormat.ts, used as validate in rules. The doc's
138-
src/utils/govActionValidations does not exist.
139-
5. src/context/featureFlag.tsx: how the type behaves in bootstrap versus full
140-
governance. Skipping this is how a new type ships silently unvotable.
141-
6. src/context/wallet.tsx: a buildXGovernanceAction if it needs a new certificate
142-
143-
Verify at /create_governance_action, then fix the ops doc, which asks you to. The
144-
schema drives both rendering in CreateGovernanceActionForm.tsx and hashing and
145-
validation in useCreateGovernanceActionForm.ts, so getting it right is most of the
146-
work. Actions must comply with CIP-100 and CIP-108.
163+
line numbers are stale.A genuinely new governance-action type can affect both frontend and backend.
164+
165+
Frontend locations:
166+
167+
1. src/types/governanceAction.ts: add the GovernanceActionType member, field
168+
types, schema extending SharedGovernanceActionFieldSchema, and the schema union
169+
member.
170+
2. src/consts/governanceAction/fields.ts: define the fields, meaning components,
171+
i18n keys and validation rules.
172+
3. src/consts/governanceAction/filters.ts: add the type when it should appear in
173+
governance-action filters.
174+
4. src/i18n/locales/en.json: add every label, placeholder, tip, error and display
175+
key used by the new type.
176+
5. src/utils: add any custom validation and update exhaustive mappings such as
177+
getGovActionVotingThresholdKey.ts.
178+
6. src/context/featureFlag.tsx: define voting and vote-total behavior for bootstrap
179+
and full-governance phases.
180+
7. src/context/wallet.tsx: add the Cardano serialization builder and expose it
181+
through the wallet context.
182+
8. src/hooks/forms/useCreateGovernanceActionForm.ts: add the new type to the
183+
buildTransaction switch and construct the builder arguments.
184+
9. Update details rendering, tests and Storybook fixtures wherever behavior differs
185+
by governance-action type.
186+
187+
Backend locations:
188+
189+
1. src/VVA/API/Types.hs: add the type to GovernanceActionType. This affects JSON,
190+
query-parameter parsing and the OpenAPI enum.
191+
2. Review src/VVA/API.hs filtering, response conversion and enacted-details logic
192+
for type-specific mappings.
193+
3. Update backend API tests and response examples that enumerate or assume the
194+
existing action types.
195+
196+
Verify creation at /create_governance_action, backend filtering and response
197+
decoding, voting behavior, details rendering and protocol phase visibility.Add
198+
frontend unit tests and backend/E2E coverage where applicable.
199+
Actions must comply with CIP-100 and CIP-108.
200+
Afterward, update the stale operations document rather than preserving conflicting
201+
paths.
147202

148203
## Change metadata validation rules
149204

0 commit comments

Comments
 (0)