ecoportal-api-graphql 1.3.13 → 1.3.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +87 -0
- data/lib/ecoportal/api/common/graphql/client.rb +0 -2
- data/lib/ecoportal/api/common/graphql/http_client.rb +6 -0
- data/lib/ecoportal/api/graphql/base/ai_summary_version.rb +17 -17
- data/lib/ecoportal/api/graphql/base/file_container.rb +14 -14
- data/lib/ecoportal/api/graphql/base/location_classification_type.rb +15 -15
- data/lib/ecoportal/api/graphql/base/location_structure.rb +27 -27
- data/lib/ecoportal/api/graphql/base/organization.rb +15 -15
- data/lib/ecoportal/api/graphql/base/page/task.rb +24 -0
- data/lib/ecoportal/api/graphql/base/page.rb +17 -16
- data/lib/ecoportal/api/graphql/base/template.rb +35 -0
- data/lib/ecoportal/api/graphql/base.rb +37 -35
- data/lib/ecoportal/api/graphql/builder/contractor_entity.rb +41 -41
- data/lib/ecoportal/api/graphql/compat/response.rb +35 -35
- data/lib/ecoportal/api/graphql/connection/action.rb +11 -11
- data/lib/ecoportal/api/graphql/connection/action_category.rb +11 -11
- data/lib/ecoportal/api/graphql/connection/contractor_entity.rb +11 -11
- data/lib/ecoportal/api/graphql/connection/page.rb +11 -11
- data/lib/ecoportal/api/graphql/connection/person_member.rb +11 -11
- data/lib/ecoportal/api/graphql/connection/preview_page.rb +11 -11
- data/lib/ecoportal/api/graphql/connection.rb +17 -17
- data/lib/ecoportal/api/graphql/file_upload/client.rb +21 -10
- data/lib/ecoportal/api/graphql/fragment/field_configuration.rb +38 -0
- data/lib/ecoportal/api/graphql/fragment/force.rb +14 -10
- data/lib/ecoportal/api/graphql/fragment/location_node.rb +26 -26
- data/lib/ecoportal/api/graphql/fragment/page_task.rb +39 -0
- data/lib/ecoportal/api/graphql/fragment/template.rb +51 -0
- data/lib/ecoportal/api/graphql/fragment.rb +3 -0
- data/lib/ecoportal/api/graphql/input/contractor_entity.rb +14 -14
- data/lib/ecoportal/api/graphql/input/preset_view/update.rb +16 -16
- data/lib/ecoportal/api/graphql/input/workflow_command/add_stage.rb +18 -18
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_field_configuration.rb +21 -21
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_page.rb +28 -28
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_page_creator_permissions.rb +18 -18
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/cross_reference.rb +23 -23
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/date.rb +20 -20
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/image_gallery.rb +20 -20
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/people.rb +24 -24
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/plain_text.rb +20 -20
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/rich_text.rb +20 -20
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/select.rb +20 -20
- data/lib/ecoportal/api/graphql/input/workflow_command/move_field.rb +18 -18
- data/lib/ecoportal/api/graphql/input/workflow_command/reorder_forces.rb +18 -18
- data/lib/ecoportal/api/graphql/input/workflow_command/reorder_section.rb +18 -18
- data/lib/ecoportal/api/graphql/input/workflow_command.rb +251 -251
- data/lib/ecoportal/api/graphql/input.rb +24 -24
- data/lib/ecoportal/api/graphql/logic/connection.rb +34 -34
- data/lib/ecoportal/api/graphql/model/page/task.rb +16 -0
- data/lib/ecoportal/api/graphql/model/page.rb +16 -15
- data/lib/ecoportal/api/graphql/model/person_member.rb +15 -15
- data/lib/ecoportal/api/graphql/model/template.rb +15 -0
- data/lib/ecoportal/api/graphql/model.rb +32 -30
- data/lib/ecoportal/api/graphql/mutation/ai_summary/generate.rb +45 -45
- data/lib/ecoportal/api/graphql/mutation/ai_summary/submit_feedback.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/contractor_entity.rb +14 -14
- data/lib/ecoportal/api/graphql/mutation/page/approve_review_task.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/page/batch_update_review_task.rb +38 -40
- data/lib/ecoportal/api/graphql/mutation/page/create_draft.rb +38 -40
- data/lib/ecoportal/api/graphql/mutation/page/delete_draft.rb +38 -40
- data/lib/ecoportal/api/graphql/mutation/page/execute_force_commands.rb +7 -7
- data/lib/ecoportal/api/graphql/mutation/page/execute_workflow_commands.rb +8 -7
- data/lib/ecoportal/api/graphql/mutation/page/publish_draft.rb +38 -40
- data/lib/ecoportal/api/graphql/mutation/page/reject_review_task.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/page/restart_review_task.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/page/undo_review_task.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/preset_view/destroy.rb +34 -35
- data/lib/ecoportal/api/graphql/mutation/register/destroy.rb +35 -35
- data/lib/ecoportal/api/graphql/mutation/smart_fill/generate.rb +36 -36
- data/lib/ecoportal/api/graphql/mutation/smart_fill/submit_feedback.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/smart_fill.rb +13 -13
- data/lib/ecoportal/api/graphql/mutation/template/create_related_page.rb +46 -46
- data/lib/ecoportal/api/graphql/mutation/template/destroy_related_page.rb +1 -1
- data/lib/ecoportal/api/graphql/mutation/template/update_information.rb +1 -1
- data/lib/ecoportal/api/graphql/mutation.rb +20 -20
- data/lib/ecoportal/api/graphql/payload/contractor_entity.rb +14 -14
- data/lib/ecoportal/api/graphql/payload/ok_payload.rb +36 -21
- data/lib/ecoportal/api/graphql/payload/page/draft.rb +26 -13
- data/lib/ecoportal/api/graphql/payload/page/review_task.rb +13 -13
- data/lib/ecoportal/api/graphql/payload/page/review_task_batch.rb +23 -0
- data/lib/ecoportal/api/graphql/payload/page.rb +20 -19
- data/lib/ecoportal/api/graphql/payload/preset_view.rb +15 -11
- data/lib/ecoportal/api/graphql/payload/register.rb +15 -11
- data/lib/ecoportal/api/graphql/payload/template/create_related_page.rb +1 -1
- data/lib/ecoportal/api/graphql/payload/template/destroy_related_page.rb +1 -1
- data/lib/ecoportal/api/graphql/payload/template/update_information.rb +1 -1
- data/lib/ecoportal/api/graphql/payload.rb +23 -23
- data/lib/ecoportal/api/graphql/query/location_structures.rb +57 -57
- data/lib/ecoportal/api/graphql/query/page.rb +45 -45
- data/lib/ecoportal/api/graphql/query/page_with_forces.rb +9 -3
- data/lib/ecoportal/api/graphql/query/pages_workflow_commands.rb +9 -3
- data/lib/ecoportal/api/graphql/query/register_preset_views.rb +78 -78
- data/lib/ecoportal/api/graphql/query.rb +27 -27
- data/lib/ecoportal/api/graphql.rb +9 -5
- data/lib/ecoportal/api/graphql_version.rb +1 -1
- metadata +9 -180
- data/.ai-assistance/bridge/CLAUDE.md +0 -338
- data/.ai-assistance/bridge/archive/.gitkeep +0 -0
- data/.ai-assistance/bridge/archive/oscar-a1b2c3d-gitlab-mcp-doc-update.inbox.md +0 -29
- data/.ai-assistance/bridge/archive/oscar-a1b2c3d-gitlab-mcp-doc-update.outbox.md +0 -18
- data/.ai-assistance/bridge/archive/oscar-c912c25-gemini-design-review.inbox.md +0 -42
- data/.ai-assistance/bridge/archive/oscar-c912c25-gemini-design-review.outbox.md +0 -115
- data/.ai-assistance/bridge/context/gemini-review-prompt.txt +0 -48
- data/.ai-assistance/bridge/context/gemini-review-response.md +0 -104
- data/.ai-assistance/bridge/context/project.md +0 -42
- data/.ai-assistance/bridge/inbox/.gitkeep +0 -0
- data/.ai-assistance/bridge/outbox/.gitkeep +0 -0
- data/.ai-assistance/bridge/outbox/request-for-standards-discovery.md +0 -48
- data/.ai-assistance/bridge/queue/.gitkeep +0 -1
- data/.ai-assistance/capabilities/CLAUDE.md +0 -27
- data/.ai-assistance/capabilities/assumptions-log.md +0 -80
- data/.ai-assistance/capabilities/code.md +0 -47
- data/.ai-assistance/capabilities/connectors.md +0 -37
- data/.ai-assistance/capabilities/cowork.md +0 -55
- data/.ai-assistance/code/OVERVIEW.md +0 -155
- data/.ai-assistance/code/data_fields.md +0 -242
- data/.ai-assistance/code/dependencies.md +0 -151
- data/.ai-assistance/code/diff_as_input.md +0 -234
- data/.ai-assistance/code/diff_pairing_engine.md +0 -243
- data/.ai-assistance/code/diff_service_deep_dive.md +0 -192
- data/.ai-assistance/code/ecoPortal_architecture/00_overview_and_index.md +0 -55
- data/.ai-assistance/code/ecoPortal_architecture/01_terminology_dictionary.md +0 -181
- data/.ai-assistance/code/ecoPortal_architecture/02_data_model.md +0 -192
- data/.ai-assistance/code/ecoPortal_architecture/03_api_layers.md +0 -147
- data/.ai-assistance/code/ecoPortal_architecture/04_graphql_queries_mutations.md +0 -277
- data/.ai-assistance/code/ecoPortal_architecture/05_page_workflows.md +0 -200
- data/.ai-assistance/code/ecoPortal_architecture/06_search_and_filters.md +0 -228
- data/.ai-assistance/code/ecoPortal_architecture/07_data_fields.md +0 -197
- data/.ai-assistance/code/ecoPortal_architecture/08_stages_sections.md +0 -243
- data/.ai-assistance/code/ecoPortal_architecture/09_people_contractors_locations.md +0 -196
- data/.ai-assistance/code/ecoPortal_architecture/10_forces_workflow_builder.md +0 -132
- data/.ai-assistance/code/ecoPortal_architecture/11_integration_gems.md +0 -187
- data/.ai-assistance/code/ecoPortal_architecture/12_ai_documentation_sources_gaps.md +0 -236
- data/.ai-assistance/code/ecoPortal_architecture/13_ai_infrastructure.md +0 -183
- data/.ai-assistance/code/ecoportal_schema_reference.md +0 -240
- data/.ai-assistance/code/filter_contract_matrix.md +0 -177
- data/.ai-assistance/code/graphql_domain_knowledge.md +0 -240
- data/.ai-assistance/code/refactoring/datafield-readwrite-shape-asymmetry.md +0 -71
- data/.ai-assistance/code/refactoring/opportunities.md +0 -251
- data/.ai-assistance/code/schema_analysis.md +0 -321
- data/.ai-assistance/code/search_filters.md +0 -868
- data/.ai-assistance/code/spec_coverage.md +0 -73
- data/.ai-assistance/code/template_diff_pairing_domain.md +0 -175
- data/.ai-assistance/code/workflow-command-guide.md +0 -466
- data/.ai-assistance/code/workflow-space.md +0 -353
- data/.ai-assistance/conventions/CLAUDE.md +0 -30
- data/.ai-assistance/conventions/code-working-tree-protocol.md +0 -199
- data/.ai-assistance/conventions/gitignore-rules.md +0 -42
- data/.ai-assistance/conventions/permission-guidance.md +0 -120
- data/.ai-assistance/integrations/README.md +0 -70
- data/.ai-assistance/integrations/gitkraken-mcp.md +0 -107
- data/.ai-assistance/integrations/gitlab-mcp.md +0 -123
- data/.ai-assistance/integrations/local-git.md +0 -60
- data/.ai-assistance/local_paths.example.md +0 -17
- data/.ai-assistance/projects/TODO.md +0 -118
- data/.ai-assistance/projects/api-v2-to-graphql-migration/DECISIONS.md +0 -168
- data/.ai-assistance/projects/api-v2-to-graphql-migration/INTENT.md +0 -60
- data/.ai-assistance/projects/api-v2-to-graphql-migration/TODO.md +0 -267
- data/.ai-assistance/projects/api-v2-to-graphql-migration/UPSTREAM.md +0 -53
- data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/csv-template-pipeline-design.md +0 -102
- data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/cutover-usecase-gap-audit.md +0 -139
- data/.ai-assistance/projects/compat-layer-audit/COMPAT_AUDIT.md +0 -244
- data/.ai-assistance/projects/dynamic-model-generation/INTENT.md +0 -93
- data/.ai-assistance/projects/eco-helpers-compat/INTENT.md +0 -244
- data/.ai-assistance/projects/eco-helpers-compat/MIGRATION_GUIDE.md +0 -266
- data/.ai-assistance/projects/eco-helpers-compat/TODO.md +0 -86
- data/.ai-assistance/projects/ecoportal-api-v2-doublemodel-review/INTENT.md +0 -101
- data/.ai-assistance/projects/graphql-agent/GAP_ANALYSIS.md +0 -177
- data/.ai-assistance/projects/ooze-graphql-native-migration/DECISIONS.md +0 -161
- data/.ai-assistance/projects/ooze-graphql-native-migration/INTENT.md +0 -125
- data/.ai-assistance/projects/ooze-graphql-native-migration/INVENTORY.md +0 -136
- data/.ai-assistance/projects/ooze-graphql-native-migration/RISKS.md +0 -126
- data/.ai-assistance/projects/ooze-graphql-native-migration/TODO.md +0 -261
- data/.ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-06-30-cutover-workflow-deep-review.md +0 -122
- data/.ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-07-01-forces-via-workflow-commands-miss-rca.md +0 -148
- data/.ai-assistance/projects/page-model/DECISIONS.md +0 -245
- data/.ai-assistance/projects/page-model/TODO.md +0 -190
- data/.ai-assistance/projects/qa-services-delivery/DECISIONS.md +0 -93
- data/.ai-assistance/projects/qa-services-delivery/INTENT.md +0 -76
- data/.ai-assistance/projects/qa-services-delivery/PHASE3-SCOPE.md +0 -115
- data/.ai-assistance/projects/qa-services-delivery/ROADMAP.md +0 -99
- data/.ai-assistance/projects/qa-services-delivery/TODO.md +0 -81
- data/.ai-assistance/projects/search-filter-builder/INTENT.md +0 -107
- data/.ai-assistance/projects/search-filter-builder/TODO.md +0 -131
- data/.ai-assistance/projects/template-automatic-build-maintenance/INTENT.md +0 -87
- data/.ai-assistance/projects/template-automatic-build-maintenance/TODO.md +0 -108
- data/.ai-assistance/projects/template-diff-deploy/INTENT.md +0 -12
- data/.ai-assistance/projects/template-diff-deploy/TODO.md +0 -9
- data/.ai-assistance/projects/template-maintenance/DESIGN.md +0 -134
- data/.ai-assistance/projects/template-maintenance/PHASE0-FINDINGS.md +0 -93
- data/.ai-assistance/projects/template-maintenance/README.md +0 -14
- data/.ai-assistance/projects/template-model-logic/CATEGORY_CATALOG.md +0 -236
- data/.ai-assistance/projects/template-model-logic/CLASSIFICATION_SPIKE.md +0 -243
- data/.ai-assistance/projects/template-model-logic/DESIGN_NOTE.md +0 -154
- data/.ai-assistance/projects/workflow-space/TODO.md +0 -213
- data/.ai-assistance/reinstall-claude-desktop-windows.md +0 -136
- data/.ai-assistance/scripts/CLAUDE.md +0 -150
- data/.ai-assistance/scripts/bridge-inbox-check.sh +0 -75
- data/.ai-assistance/scripts/bridge-init.sh +0 -86
- data/.ai-assistance/scripts/bridge-status.sh +0 -44
- data/.ai-assistance/scripts/capabilities-check.ts +0 -104
- data/.ai-assistance/scripts/check-outbox.sh +0 -43
- data/.ai-assistance/scripts/dep_graph.rb +0 -91
- data/.ai-assistance/scripts/lock-acquire.sh +0 -103
- data/.ai-assistance/scripts/lock-multi.sh +0 -124
- data/.ai-assistance/scripts/lock-queue.sh +0 -94
- data/.ai-assistance/scripts/setup-mcps.test.ts +0 -188
- data/.ai-assistance/scripts/setup-mcps.ts +0 -234
- data/.ai-assistance/scripts/task-complete.ts +0 -74
- data/.ai-assistance/scripts/task-create.ts +0 -75
- data/.ai-assistance/scripts/task-read.ts +0 -125
- data/.ai-assistance/scripts/token-logger.js +0 -220
- data/.ai-assistance/scripts/token-report.ts +0 -158
- data/.ai-assistance/scripts/token-session-start.js +0 -66
- data/.ai-assistance/skills/ai-instructions/SKILL.md +0 -48
- data/.ai-assistance/skills/code-specs/SKILL.md +0 -69
- data/.ai-assistance/skills/corporate-policies/SKILL.md +0 -201
- data/.ai-assistance/skills/dep-graph/SKILL.md +0 -139
- data/.ai-assistance/skills/ep-ai-manager/SKILL.md +0 -417
- data/.ai-assistance/skills/gemini-assist/SKILL.md +0 -63
- data/.ai-assistance/skills/gemini-assist/gemini-mcp-server.js +0 -205
- data/.ai-assistance/skills/gemini-assist/gemini_ask.py +0 -1
- data/.ai-assistance/skills/gemini-assist/gemini_ask.rb +0 -240
- data/.ai-assistance/skills/gemini-assist/prompts/cycle_end_review.txt +0 -25
- data/.ai-assistance/skills/graphql-schema-analysis/SKILL.md +0 -261
- data/.ai-assistance/skills/procedural-memory/SKILL.md +0 -319
- data/.ai-assistance/skills/project-cycle/SKILL.md +0 -177
- data/.ai-assistance/skills/project-self-docs/SKILL.md +0 -181
- data/.ai-assistance/skills/project-self-docs/scripts/self_docs_scan.py +0 -378
- data/.ai-assistance/skills/refactor/SKILL.md +0 -62
- data/.ai-assistance/skills/rubocop/SKILL.md +0 -93
- data/.ai-assistance/skills/ruby-scripting/SKILL.md +0 -215
- data/.ai-assistance/skills/spec-generation/SKILL.md +0 -72
- data/.ai-assistance/standards-version.json +0 -22
- data/.ai-assistance/token-budget.json +0 -32
- data/.ai-assistance/version.json +0 -39
- data/.claude/settings.json +0 -150
- data/.env.example +0 -18
- data/.gitattributes +0 -15
- data/.gitignore +0 -37
- data/.gitlab-ci.yml +0 -45
- data/.markdownlint.json +0 -4
- data/.rspec +0 -3
- data/.rubocop.yml +0 -121
- data/.ruby-version +0 -1
- data/.yardopts +0 -10
- data/CLAUDE.md +0 -243
- data/Gemfile +0 -30
- data/Rakefile +0 -90
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/bin/setup.ps1 +0 -6
- data/docs/self-docs/ARCHITECTURE.md +0 -88
- data/docs/self-docs/CHANGES.jsonl +0 -12
- data/docs/self-docs/COMPLIANCE.md +0 -79
- data/docs/self-docs/CONVENTIONS.md +0 -74
- data/docs/self-docs/INTEGRATIONS.md +0 -65
- data/docs/self-docs/OPERATIONS.md +0 -76
- data/docs/self-docs/OVERVIEW.md +0 -64
- data/docs/self-docs/STATUS.md +0 -73
- data/docs/self-docs/self-docs-index.json +0 -51
- data/docs/worklog.md +0 -977
- data/ecoportal-api-graphql.gemspec +0 -40
- data/scripts/auto-worker-scheduler.sh +0 -386
- data/tests/actions_get.rb +0 -7
- data/tests/contractor_entities_get.rb +0 -20
- data/tests/contractor_entity_create.rb +0 -19
- data/tests/contractor_entity_udpate.rb +0 -20
- data/tests/dump_page_model.rb +0 -74
- data/tests/dump_template_model.rb +0 -90
- data/tests/loc_structure_get.rb +0 -10
- data/tests/loc_structure_update.rb +0 -51
- data/tests/loc_structures_get.rb +0 -15
- data/tests/local_libs.rb +0 -20
- data/tests/validate_queries.rb +0 -127
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# EcoPortal Architecture — Agent Reference Manual
|
|
2
|
-
|
|
3
|
-
**Purpose:** Enable an AI agent to read this folder, then immediately navigate the
|
|
4
|
-
ecoPortal source code, customer documentation, and integration gems with full context.
|
|
5
|
-
Covers: platform purpose, data model, naming conventions, API layers, workflows,
|
|
6
|
-
search, integrations, and documentation gaps.
|
|
7
|
-
|
|
8
|
-
**Session:** Accumulated 2026-06-07 from developer context, production Insomnia queries,
|
|
9
|
-
corpus documents, eco-helpers source audit, and GraphQL schema introspection.
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Document Index
|
|
14
|
-
|
|
15
|
-
| File | Content |
|
|
16
|
-
|------|---------|
|
|
17
|
-
| `00_overview_and_index.md` | This file — platform summary + index |
|
|
18
|
-
| `01_terminology_dictionary.md` | Every name things are called — Rosetta Stone for disambiguating |
|
|
19
|
-
| `02_data_model.md` | Page hierarchy, types, MongoDB structure, genome, field ID |
|
|
20
|
-
| `03_api_layers.md` | APIv2 vs GraphQL — differences, retirement timeline, access |
|
|
21
|
-
| `04_graphql_queries_mutations.md` | All known queries/mutations, fragments, CommonPageUnion |
|
|
22
|
-
| `05_page_workflows.md` | Create/Update/Archive/Submit — 2-step sequences, stage logic |
|
|
23
|
-
| `06_search_and_filters.md` | Org search vs register search, SearchConf, filter operations |
|
|
24
|
-
| `07_data_fields.md` | All 20+ field types, DataFieldInput, update/addition patterns |
|
|
25
|
-
| `08_stages_sections.md` | Stage lifecycle, permissions, sections, HasSectionsInterface |
|
|
26
|
-
| `09_people_contractors_locations.md` | PersonMember, ContractorEntity, IdDiff, location tags |
|
|
27
|
-
| `10_forces_workflow_builder.md` | Forces (AngularJS legacy), Workflow Builder (in progress) |
|
|
28
|
-
| `11_integration_gems.md` | eco-helpers, ecoportal-api-v2, ecoportal-api-graphql chain |
|
|
29
|
-
| `12_ai_documentation_sources_gaps.md` | All knowledge sources + gaps + improvements for AI agents |
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
## Platform Summary
|
|
34
|
-
|
|
35
|
-
EcoPortal is a SaaS **governance, risk and compliance (GRC)** platform built for
|
|
36
|
-
enterprise customers. It enables organisations to manage:
|
|
37
|
-
- Risk registers (pages = records in a workflow-driven register)
|
|
38
|
-
- Incident reporting
|
|
39
|
-
- Contractor management
|
|
40
|
-
- Action tracking
|
|
41
|
-
- Location/reporting structure management
|
|
42
|
-
- Visitor management (check-in)
|
|
43
|
-
- Notifications, dashboards, analytics
|
|
44
|
-
|
|
45
|
-
**Technology stack:**
|
|
46
|
-
- Backend: Ruby on Rails, MongoDB (NoSQL document store)
|
|
47
|
-
- Frontend: AngularJS (legacy, being replaced) → React (current, in progress)
|
|
48
|
-
- APIs: APIv2 REST (being retired), GraphQL (current standard)
|
|
49
|
-
- Search/analytics: Elasticsearch
|
|
50
|
-
- Deployment: Docker, cloud-hosted
|
|
51
|
-
|
|
52
|
-
**Key architectural principle:** MongoDB's flexible document model means page records
|
|
53
|
-
("instances") are cloned from templates. Field structure is defined in the template;
|
|
54
|
-
field data is stored per-instance. Field IDs are assigned by MongoDB on creation and
|
|
55
|
-
are instance-specific (not predictable from the template alone).
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
# EcoPortal Terminology Dictionary
|
|
2
|
-
|
|
3
|
-
An AI agent MUST read this before working with ecoPortal code or customer requests.
|
|
4
|
-
The same concept has different names depending on who is talking and which layer of
|
|
5
|
-
the system is being discussed. Misunderstanding these leads to wrong assumptions.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Core Entity Names
|
|
10
|
-
|
|
11
|
-
### Pages / Records / Ooze / Forms
|
|
12
|
-
|
|
13
|
-
| Context | Name used | Notes |
|
|
14
|
-
|---------|-----------|-------|
|
|
15
|
-
| Customer-facing (product UI) | **Page**, **Record** | "Page" is the UI term; "Record" used in registers |
|
|
16
|
-
| eco-helpers scripts (internal) | **Ooze** | Internal dev shorthand, from legacy gem name |
|
|
17
|
-
| eco-helpers class names | `OozeBase`, `RegisterUpdate` | Script use case base classes |
|
|
18
|
-
| Confluence docs | **Page** | |
|
|
19
|
-
| APIv2 gem | `Ecoportal::API::V2::Page` | |
|
|
20
|
-
| GraphQL schema | `BasicPage`, `PhasedPage`, `PageUnion` | Two concrete types |
|
|
21
|
-
| GraphQL queries | `page(id:)`, `pages(...)` | |
|
|
22
|
-
| ecoportal-api-graphql gem | `Model::Page::Basic`, `Model::Page::Phased` | |
|
|
23
|
-
|
|
24
|
-
**Disambiguation rule:** When a customer says "record" or "page", they mean a page
|
|
25
|
-
instance — NOT a template. Templates are a separate concept (see below).
|
|
26
|
-
|
|
27
|
-
### Stages / Workflow Steps / Flow Nodes
|
|
28
|
-
|
|
29
|
-
| Context | Name used | Notes |
|
|
30
|
-
|---------|-----------|-------|
|
|
31
|
-
| Customer-facing (product UI) | **Stage** | |
|
|
32
|
-
| Backend Enzyme namespace (old) | **flow_nodes** | Old Rails model name |
|
|
33
|
-
| Backend NewEp namespace (current) | **stages** | |
|
|
34
|
-
| APIv2 | **stages** | |
|
|
35
|
-
| GraphQL schema | `Stage`, `StageIndex`, `StageStateEnum` | |
|
|
36
|
-
| eco-helpers | **stages** | `page.stages[name]`, `page.stages.ordered` |
|
|
37
|
-
|
|
38
|
-
### Sections / Content Containers / Flow Node Sub-elements
|
|
39
|
-
|
|
40
|
-
| Context | Name used | Notes |
|
|
41
|
-
|---------|-----------|-------|
|
|
42
|
-
| Customer-facing (UI) | **Section** | Within a stage |
|
|
43
|
-
| Backend Enzyme namespace (old) | **flow_nodes** sub-elements | No clean separation |
|
|
44
|
-
| Backend NewEp namespace (current) | **sections** | `HasSectionsInterface` |
|
|
45
|
-
| APIv2 | **sections** | `page.sections` |
|
|
46
|
-
| GraphQL schema | `SectionUnion`, `ContentSection`, `SplitSection` | Two section types |
|
|
47
|
-
| eco-helpers | **sections** | `entry.sections.get_by_type(:content_section)` |
|
|
48
|
-
|
|
49
|
-
**Important:** BasicPage (no stages) has sections DIRECTLY. PhasedPage has sections
|
|
50
|
-
WITHIN each stage. This is why `page.sections` on a PhasedPage requires knowing which
|
|
51
|
-
stage you're in.
|
|
52
|
-
|
|
53
|
-
### Data Fields / Components / Membranes / Field Instances
|
|
54
|
-
|
|
55
|
-
| Context | Name used | Notes |
|
|
56
|
-
|---------|-----------|-------|
|
|
57
|
-
| Customer-facing (UI) | **Field** | Form field within a section |
|
|
58
|
-
| Backend Enzyme namespace (old) | **Membrane**, `Enzyme::Membrane` | Old model name |
|
|
59
|
-
| Backend NewEp namespace (current) | **DataField**, `NewEp::DataField` | |
|
|
60
|
-
| APIv2 | **component** | `page.components`, `component.type` |
|
|
61
|
-
| GraphQL schema | `DataFieldUnion`, `DataFieldsInterface` | 20+ concrete types |
|
|
62
|
-
| eco-helpers | **components** | `entry.components.get_by_type(:plain_text)` |
|
|
63
|
-
| ecoportal-api-graphql gem | `DataField::PlainText`, `DataField::Select`, etc. | |
|
|
64
|
-
|
|
65
|
-
**CRITICAL:** A "field" in the UI is an INSTANCE of a field definition. The template
|
|
66
|
-
defines the field structure (label, type, options). The page instance has the actual
|
|
67
|
-
field with server-assigned MongoDB ID and stored value. The instance field ID CANNOT be
|
|
68
|
-
predicted from the template alone — must be fetched after creation via `buildFromTemplate`.
|
|
69
|
-
|
|
70
|
-
### Registers / Registries / Page Collections
|
|
71
|
-
|
|
72
|
-
| Context | Name used | Notes |
|
|
73
|
-
|---------|-----------|-------|
|
|
74
|
-
| Customer-facing (UI) | **Register** | A themed collection of pages with a shared template |
|
|
75
|
-
| GraphQL schema | `Register`, `register(id:)` | |
|
|
76
|
-
| eco-helpers | **register** | `registers.search(register_id, ...)` |
|
|
77
|
-
|
|
78
|
-
### Templates
|
|
79
|
-
|
|
80
|
-
| Context | Name used | Notes |
|
|
81
|
-
|---------|-----------|-------|
|
|
82
|
-
| Customer-facing (UI) | **Template** | A "page type" defining field structure |
|
|
83
|
-
| GraphQL schema | `PageUnion` (templates are also pages), `Template` type | |
|
|
84
|
-
| eco-helpers | **template** | `pages.get_new(template_id)` |
|
|
85
|
-
|
|
86
|
-
**IMPORTANT:** Engineering does NOT want templates updated via GraphQL currently.
|
|
87
|
-
Template editing uses the old AngularJS front-end. Template mutations exist in the
|
|
88
|
-
schema but are not production-approved for scripting.
|
|
89
|
-
|
|
90
|
-
---
|
|
91
|
-
|
|
92
|
-
## Field-Level Terminology
|
|
93
|
-
|
|
94
|
-
### ref / Field ID / ES Key / System ID (future)
|
|
95
|
-
|
|
96
|
-
The `ref` property on a data field (`Enzyme::Membrane` / `NewEp::DataField`) is the
|
|
97
|
-
**Elasticsearch index key** for that field. It determines how analytics, charts, filters,
|
|
98
|
-
and cross-register configurations identify the field.
|
|
99
|
-
|
|
100
|
-
**Composition:** `type_shorthand.hash_of_label`
|
|
101
|
-
- `type_shorthand`: e.g. `plain_text`, `date`, `select_str`, `select_num`, `gauge`,
|
|
102
|
-
`rich_text`, `actions_list`, `files`
|
|
103
|
-
- Hash of the label name (truncated when label > 3 characters)
|
|
104
|
-
- Formula: `Ecoportal::API::Common::Content::StringDigest` in `ecoportal-api-v2`
|
|
105
|
-
|
|
106
|
-
**Future:** The team is planning to formalise this as a user-visible "Field ID" (as
|
|
107
|
-
opposed to the internal MongoDB `id`). Currently it is only used internally.
|
|
108
|
-
|
|
109
|
-
**In search/sorters:** The `key` field in sorters (`{ key: 'updated_at', direction: 'asc' }`)
|
|
110
|
-
references this ref value, not the MongoDB field `id`.
|
|
111
|
-
|
|
112
|
-
### patchVer / Optimistic Concurrency
|
|
113
|
-
|
|
114
|
-
`patchVer: Int!` on every page. The server uses this for optimistic concurrency control.
|
|
115
|
-
**Any update mutation MUST include the current `patchVer` value fetched from the page.**
|
|
116
|
-
If two scripts try to update the same page concurrently, the second will get a stale-patchVer
|
|
117
|
-
error. Scripts must re-fetch the page to get the current `patchVer` before retrying.
|
|
118
|
-
|
|
119
|
-
### Genome Signature (mostly unused)
|
|
120
|
-
|
|
121
|
-
The genome signature was designed to pair fields ACROSS pages and their source templates.
|
|
122
|
-
Purpose: know that "this field in page X is the same field as this field in template Y".
|
|
123
|
-
**Current state:** Mostly unused. The Migrator Rails service that used it was abandoned.
|
|
124
|
-
Not indexed in ES. Many fields have broken genomes due to bulk tech scripts that added
|
|
125
|
-
fields without copying from the template. Do NOT design scripting around genome.
|
|
126
|
-
|
|
127
|
-
### Forces (legacy front-end snippets)
|
|
128
|
-
|
|
129
|
-
Forces are AngularJS embedded code snippets that attach to specific stages via bindings.
|
|
130
|
-
They implement conditional field behaviour (show/hide sections, computed risk matrices).
|
|
131
|
-
**Being replaced** by the Workflow Builder. Not accessible or useful via GraphQL.
|
|
132
|
-
Low scripting priority.
|
|
133
|
-
|
|
134
|
-
---
|
|
135
|
-
|
|
136
|
-
## State / Status Names
|
|
137
|
-
|
|
138
|
-
### Page State (`StateEnum`)
|
|
139
|
-
|
|
140
|
-
| Value | Meaning |
|
|
141
|
-
|-------|---------|
|
|
142
|
-
| `active` | Normal working state |
|
|
143
|
-
| `archived` | Soft-deleted/hidden — can be unarchived |
|
|
144
|
-
| `draft` | Not yet published (also `draft: Boolean` field) |
|
|
145
|
-
| `inprogress` | In a workflow stage (used in some contexts) |
|
|
146
|
-
|
|
147
|
-
### Stage State (`StageStateEnum`)
|
|
148
|
-
|
|
149
|
-
| Value | Meaning |
|
|
150
|
-
|-------|---------|
|
|
151
|
-
| `pending` | Not yet started |
|
|
152
|
-
| `inprogress` | Currently active |
|
|
153
|
-
| `complete` | Completed (all tasks done) |
|
|
154
|
-
|
|
155
|
-
### Task State
|
|
156
|
-
|
|
157
|
-
Tasks (`TaskInterface`, `CompletePage`, `ReviewPage`) have their own states related to
|
|
158
|
-
completion. Stage close-out is triggered by task completion.
|
|
159
|
-
|
|
160
|
-
---
|
|
161
|
-
|
|
162
|
-
## API Layer Names
|
|
163
|
-
|
|
164
|
-
| Layer | Name | Status |
|
|
165
|
-
|-------|------|--------|
|
|
166
|
-
| Legacy REST | **APIv2**, `ecoportal-api-v2` gem | Being retired (3 weeks from 2026-06-07) |
|
|
167
|
-
| Current GraphQL | **GraphQL API**, `ecoportal-api-graphql` gem | Current standard |
|
|
168
|
-
| Internal REST (auth) | **APIv1** (OAuth) | Still in use for authentication only |
|
|
169
|
-
| Future | **APIv3** (page render / custom exports) | In development, not production |
|
|
170
|
-
|
|
171
|
-
---
|
|
172
|
-
|
|
173
|
-
## Backend Namespace Names
|
|
174
|
-
|
|
175
|
-
| Namespace | Description | Location |
|
|
176
|
-
|-----------|-------------|----------|
|
|
177
|
-
| `Enzyme` | Old Rails model namespace (AngularJS era) | `C:\docker\ecoPortal_master\` |
|
|
178
|
-
| `NewEp` | Current Rails model namespace (React era migration) | Same repo |
|
|
179
|
-
| `Ecoportal::API::V2` | REST API gem | `C:\ruby_scripts\git\ecoportal-api-v2` |
|
|
180
|
-
| `Ecoportal::API::GraphQL` | GraphQL gem | THIS REPO |
|
|
181
|
-
| `Eco` (eco-helpers) | Integration scripts helper gem | `C:\ruby_scripts\git\eco-helpers` |
|
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
# EcoPortal Data Model
|
|
2
|
-
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
## Top-Level Hierarchy
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
Organisation
|
|
9
|
-
├── Registers (themed page collections)
|
|
10
|
-
│ ├── Templates (page type definitions)
|
|
11
|
-
│ │ ├── Stages (workflow steps — PhasedPage templates)
|
|
12
|
-
│ │ │ └── Sections
|
|
13
|
-
│ │ │ └── DataField definitions (with label, type, options)
|
|
14
|
-
│ │ └── Sections (for BasicPage templates)
|
|
15
|
-
│ │ └── DataField definitions
|
|
16
|
-
│ └── Pages / Instances (created from templates)
|
|
17
|
-
│ ├── [BasicPage] Sections → DataFields (actual data, server IDs)
|
|
18
|
-
│ └── [PhasedPage] Stages → Sections → DataFields (actual data, server IDs)
|
|
19
|
-
├── People (PersonMember)
|
|
20
|
-
├── Contractor Entities
|
|
21
|
-
├── Location Structure (reporting structure / RS)
|
|
22
|
-
│ └── Location Nodes (hierarchical tree)
|
|
23
|
-
├── Actions (standalone or linked to pages)
|
|
24
|
-
└── User Groups / Permissions
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## `externalId` — per-org unique key for integrations (VERIFIED, Oscar 2026-07-02)
|
|
30
|
-
|
|
31
|
-
`externalId` exists on models (pages, and other objects) as the **integration pairing key**:
|
|
32
|
-
|
|
33
|
-
- **Uniqueness is per-organization, per-model:** an `externalId` must be unique among objects of
|
|
34
|
-
the *same model* within one ecoPortal organization. It is the mechanism the platform uses to
|
|
35
|
-
**prevent double-ups** and to give a customer integration a stable way to **pair its own record
|
|
36
|
-
ids with ecoPortal's objects** (set `externalId` = the customer's key; look up / upsert by it).
|
|
37
|
-
- **Implication for integrations:** when you control the source data, prefer keying create/upsert
|
|
38
|
-
on `externalId` (guaranteed unique, server-enforced) over searching a data-field value. A
|
|
39
|
-
field-value search can miss (wrong key, analyzer semantics — see the cans-upsert dup incident in
|
|
40
|
-
`search_filters.md`) and silently create duplicates; an `externalId` collision is rejected.
|
|
41
|
-
- **Archiving contingency:** clear the `externalId` only when archiving is a *cleanup of a failed /
|
|
42
|
-
duplicate creation* (so the freed id can be reused); a genuine historical archive should **keep**
|
|
43
|
-
its `externalId`. The backend `archivePage` mutation takes only `id` (no clear-externalId arg), so
|
|
44
|
-
this is a **client composition**: `updatePage(page:{externalId:null})` + `archivePage`, in one
|
|
45
|
-
document (the maintainer's Insomnia sample gates the updatePage with `@include(if:$blank_external_id)`).
|
|
46
|
-
WIRED as **`Builder::Page#archive(clear_external_id: false)`** (default keeps it) — implemented as
|
|
47
|
-
two serial mutations (blank-then-archive) reusing the existing update/archive mutations.
|
|
48
|
-
- **Note:** the cans-upsert case does NOT use `externalId` (it keys on the `Identifier:` data
|
|
49
|
-
field) — which is exactly why a wrong search key produced duplicates. An `externalId`-based
|
|
50
|
-
upsert would have been collision-safe.
|
|
51
|
-
|
|
52
|
-
---
|
|
53
|
-
|
|
54
|
-
## Page Types (PageUnion)
|
|
55
|
-
|
|
56
|
-
The GraphQL `PageUnion = BasicPage | PhasedPage`. Both implement `BasePageInterface`.
|
|
57
|
-
|
|
58
|
-
### BasicPage
|
|
59
|
-
|
|
60
|
-
- Has sections DIRECTLY (no stages)
|
|
61
|
-
- Used for: simple forms, non-workflow records
|
|
62
|
-
- `implements: BasePageInterface, HasSectionsInterface`
|
|
63
|
-
- `sections: [SectionUnion!]!` — direct access
|
|
64
|
-
|
|
65
|
-
### PhasedPage
|
|
66
|
-
|
|
67
|
-
- Has stages, each stage has sections
|
|
68
|
-
- Used for: workflow-driven records (risk assessments, incident reports, inspections)
|
|
69
|
-
- `implements: BasePageInterface`
|
|
70
|
-
- `stages: [Stage!]!` — access via StageCollection
|
|
71
|
-
- `stagesIndex: [StageIndex!]!` — lightweight stage summary
|
|
72
|
-
- `currentStage: Stage!` — the currently active stage
|
|
73
|
-
|
|
74
|
-
### Identifying the Type
|
|
75
|
-
|
|
76
|
-
Always include `__typename` in page queries. The server returns `'BasicPage'` or
|
|
77
|
-
`'PhasedPage'`. In the ecoportal-api-graphql gem, `Model::PageUnion.new(doc)` dispatches
|
|
78
|
-
on `__typename` to create the right concrete class.
|
|
79
|
-
|
|
80
|
-
---
|
|
81
|
-
|
|
82
|
-
## MongoDB Document Structure
|
|
83
|
-
|
|
84
|
-
Pages are stored as MongoDB documents. The document structure is flexible — field
|
|
85
|
-
instances are embedded within the stage/section hierarchy.
|
|
86
|
-
|
|
87
|
-
**Key implications:**
|
|
88
|
-
1. **Field IDs are MongoDB ObjectIds** assigned at creation. They are DIFFERENT from
|
|
89
|
-
the template's field IDs. An instance field ID cannot be predicted — must be fetched.
|
|
90
|
-
2. **patchVer** is an integer version counter incremented on every save. Required for
|
|
91
|
-
all update mutations.
|
|
92
|
-
3. **Partial updates** — the GraphQL `updatePage` mutation only changes the fields you
|
|
93
|
-
specify. The rest remain unchanged. This is different from APIv2 which sometimes sent
|
|
94
|
-
the full document.
|
|
95
|
-
4. **Stages are embedded** within the page document. Fetching a page gets all stages.
|
|
96
|
-
|
|
97
|
-
---
|
|
98
|
-
|
|
99
|
-
## Template vs Instance
|
|
100
|
-
|
|
101
|
-
| Aspect | Template | Instance (Page) |
|
|
102
|
-
|--------|----------|-----------------|
|
|
103
|
-
| Created by | Admins via UI | Scripts or end users |
|
|
104
|
-
| Field IDs | Template-specific ObjectIds | NEW ObjectIds assigned on creation |
|
|
105
|
-
| patchVer | Yes | Yes |
|
|
106
|
-
| Stage structure | Defines stage names/order | Inherited at creation, runtime state |
|
|
107
|
-
| DataField content | Default values only | Actual user-entered values |
|
|
108
|
-
| GraphQL access | `templates(...)` query | `pages(...)` or `page(id:)` |
|
|
109
|
-
|
|
110
|
-
**CRITICAL for scripting:** After `buildFromTemplate`, the response contains the
|
|
111
|
-
INSTANCE field IDs. These are the IDs to use for `dataFields.updates` in
|
|
112
|
-
`createFromTemplate`. The template field IDs are irrelevant for instance operations.
|
|
113
|
-
|
|
114
|
-
---
|
|
115
|
-
|
|
116
|
-
## Stage Model (PhasedPage)
|
|
117
|
-
|
|
118
|
-
Each stage in a PhasedPage:
|
|
119
|
-
- Has a unique `id` (MongoDB ObjectId)
|
|
120
|
-
- Has `name` (the stage name configured in the template)
|
|
121
|
-
- Has `ordering` (display order, integer)
|
|
122
|
-
- Has `state` (`StageStateEnum`: pending/inprogress/complete)
|
|
123
|
-
- Has `active: Boolean` (whether stage is currently active for input)
|
|
124
|
-
- Has `started: Boolean` (whether any input has been recorded)
|
|
125
|
-
- Has `sections: [SectionUnion!]!` — the stage's content sections
|
|
126
|
-
- Has task references: `latestCompletePageTask`, `latestReviewPageTask`, `activeTask`
|
|
127
|
-
|
|
128
|
-
**Stage permissions:**
|
|
129
|
-
- Each stage can have user group restrictions
|
|
130
|
-
- People fields can grant direct stage access based on their values
|
|
131
|
-
- Configuration enum on people fields determines scope (stage-specific vs page-wide)
|
|
132
|
-
- GraphQL silently omits stages the user cannot access (no access errors)
|
|
133
|
-
|
|
134
|
-
**Stage transitions:**
|
|
135
|
-
- Triggered by task completion (complete task = stage done → next stage starts)
|
|
136
|
-
- Two task types: `CompletePage` (fill-in) and `ReviewPage` (sign-off)
|
|
137
|
-
- Submitting a stage via GraphQL `updatePage(stageId:, submit: true)` triggers the
|
|
138
|
-
server-side task assignment rules (who gets the next task per workflow config)
|
|
139
|
-
|
|
140
|
-
---
|
|
141
|
-
|
|
142
|
-
## Section Model
|
|
143
|
-
|
|
144
|
-
Two types (`SectionUnion = ContentSection | SplitSection`):
|
|
145
|
-
|
|
146
|
-
### ContentSection
|
|
147
|
-
- `heading: String` — section heading
|
|
148
|
-
- `dataFields: [DataFieldUnion!]!` — fields in this section
|
|
149
|
-
|
|
150
|
-
### SplitSection
|
|
151
|
-
- `heading: String`
|
|
152
|
-
- `leftDataFields: [DataFieldUnion!]!`
|
|
153
|
-
- `rightDataFields: [DataFieldUnion!]!`
|
|
154
|
-
|
|
155
|
-
Both implement `HasSectionsInterface`. When a section's fields need to be accessed
|
|
156
|
-
together, merge `dataFields + leftDataFields + rightDataFields`.
|
|
157
|
-
|
|
158
|
-
---
|
|
159
|
-
|
|
160
|
-
## Genome Signature (Field Pairing — Mostly Unused)
|
|
161
|
-
|
|
162
|
-
Each field definition (in template and in instances) carries a **genome signature** —
|
|
163
|
-
a hash intended to identify that a field is "the same" across template and instances.
|
|
164
|
-
|
|
165
|
-
**Original design:** Enable the Migrator service to propagate template changes to
|
|
166
|
-
existing pages by pairing fields via genome.
|
|
167
|
-
|
|
168
|
-
**Current reality:**
|
|
169
|
-
- Largely abandoned — the Migrator service is inactive
|
|
170
|
-
- Many instances have broken genomes (bulk tech scripts that added fields
|
|
171
|
-
without copying from the template gave them random creation-time genomes)
|
|
172
|
-
- Not indexed in Elasticsearch
|
|
173
|
-
- Unknown whether `NewEp` fully ported the genome from `Enzyme`
|
|
174
|
-
- Do NOT design scripting logic around genome — it cannot be relied upon
|
|
175
|
-
|
|
176
|
-
---
|
|
177
|
-
|
|
178
|
-
## Location Structure (Reporting Structure)
|
|
179
|
-
|
|
180
|
-
The organisation has a hierarchical location tree. Locations are used for:
|
|
181
|
-
- Tagging pages (assigning pages to locations/departments)
|
|
182
|
-
- Filtering in searches (`location_ids` filter)
|
|
183
|
-
- Permissions scoping
|
|
184
|
-
- Analytics/dashboard scoping
|
|
185
|
-
|
|
186
|
-
The location tree is managed via dedicated mutations (`draft` system for structural edits).
|
|
187
|
-
Location nodes have: `id`, `name`, `weight`, `archived`, `archivedToken`, `classifications`,
|
|
188
|
-
`ancestors`, `parent`, `children`.
|
|
189
|
-
|
|
190
|
-
**`baseTags` vs `otherTags`:**
|
|
191
|
-
- `baseTags` — location tags inherited from the base template configuration
|
|
192
|
-
- `otherTags` — additional free-text tags attached to a page instance
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
# EcoPortal API Layers
|
|
2
|
-
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
EcoPortal has three API access layers, each serving different purposes and eras:
|
|
8
|
-
|
|
9
|
-
| Layer | Type | Status | gem |
|
|
10
|
-
|-------|------|--------|-----|
|
|
11
|
-
| APIv1 (OAuth) | REST | Active — auth only | n/a (direct HTTP) |
|
|
12
|
-
| APIv2 | REST | **BEING RETIRED** (~2026-06-07 + 3 weeks) | `ecoportal-api-v2` |
|
|
13
|
-
| GraphQL API | GraphQL | **Current standard** | `ecoportal-api-graphql` |
|
|
14
|
-
| APIv3 (page render) | REST (likely) | In development — custom exports | Not yet public |
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
## Authentication (APIv1 / OAuth)
|
|
19
|
-
|
|
20
|
-
All access goes through OAuth 2.0 password grant:
|
|
21
|
-
|
|
22
|
-
```
|
|
23
|
-
POST https://live.ecoportal.com/oauth/token
|
|
24
|
-
Content-Type: application/json
|
|
25
|
-
|
|
26
|
-
{
|
|
27
|
-
"grant_type": "password",
|
|
28
|
-
"email": "user@example.com",
|
|
29
|
-
"password": "..."
|
|
30
|
-
}
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Response includes `access_token` (Bearer) and `refresh_token`.
|
|
34
|
-
|
|
35
|
-
**Token refresh:**
|
|
36
|
-
```
|
|
37
|
-
POST /oauth/token
|
|
38
|
-
{ "grant_type": "refresh_token", "refresh_token": "..." }
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
The `access_token` is passed as `Authorization: Bearer <token>` on all subsequent calls.
|
|
42
|
-
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
## APIv2 (REST) — Being Retired
|
|
46
|
-
|
|
47
|
-
**Base URL:** `https://live.ecoportal.com/api/<org_id>/`
|
|
48
|
-
|
|
49
|
-
**Ruby gem:** `Ecoportal::API::V2` in `ecoportal-api-v2`
|
|
50
|
-
|
|
51
|
-
**Local path:** `C:\ruby_scripts\git\ecoportal-api-v2`
|
|
52
|
-
|
|
53
|
-
**Key characteristics:**
|
|
54
|
-
- REST API with resource-based endpoints
|
|
55
|
-
- Returns full page documents as JSON
|
|
56
|
-
- Stage rendering: one GET request per stage (pages with stages must be fetched
|
|
57
|
-
stage-by-stage due to access control — each stage can have different user permissions)
|
|
58
|
-
- Only pages WITHOUT stages AND templates can be fetched/updated as a whole document
|
|
59
|
-
- Full document sent on update (partial updates not cleanly supported)
|
|
60
|
-
- Page updates tracked via `as_update` (dirty diff) which generates a JSON patch
|
|
61
|
-
|
|
62
|
-
**eco-helpers interface:**
|
|
63
|
-
```ruby
|
|
64
|
-
apiv2.pages.get(id, stage_id: nil) # fetch page (or specific stage)
|
|
65
|
-
apiv2.pages.get_new(template_id) # build draft from template
|
|
66
|
-
apiv2.pages.create(page, from: template_id) # create instance
|
|
67
|
-
apiv2.pages.update(page) # save changes
|
|
68
|
-
apiv2.registers.search(register_id, opts) { |result| ... } # paginated search
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
---
|
|
72
|
-
|
|
73
|
-
## GraphQL API — Current Standard
|
|
74
|
-
|
|
75
|
-
**Endpoint:** `POST https://live.ecoportal.com/api/<org_id>/external/graphql`
|
|
76
|
-
|
|
77
|
-
**Headers required:**
|
|
78
|
-
- `Content-Type: application/json`
|
|
79
|
-
- `Authorization: Bearer <access_token>`
|
|
80
|
-
|
|
81
|
-
**Request payload:**
|
|
82
|
-
```json
|
|
83
|
-
{
|
|
84
|
-
"query": "query MyQuery($id: ID!) { ... }",
|
|
85
|
-
"variables": { "id": "..." },
|
|
86
|
-
"operationName": "MyQuery"
|
|
87
|
-
}
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
**Key characteristics:**
|
|
91
|
-
- ONE endpoint — no URL variation by resource
|
|
92
|
-
- Client specifies exactly which fields to return
|
|
93
|
-
- Full page fetched in ONE request (all stages included)
|
|
94
|
-
- Stage-specific operations via `stageId` parameter
|
|
95
|
-
- `patchVer` required on all update mutations (optimistic concurrency)
|
|
96
|
-
- Multiple mutations can be combined in one request (executed in declaration order)
|
|
97
|
-
- `searchConf` is a Hash type (`Search`) — not a typed GraphQL input
|
|
98
|
-
|
|
99
|
-
**GraphQL gem:** `Ecoportal::API::GraphQL` in `ecoportal-api-graphql`
|
|
100
|
-
|
|
101
|
-
**Local path:** `C:\ruby_scripts\git\ecoportal-api-graphql` (THIS REPO)
|
|
102
|
-
|
|
103
|
-
**Schema reference:** Live schema at `https://live.ecoportal.com/api-docs/graphql`
|
|
104
|
-
(requires login). Updated on every deployment.
|
|
105
|
-
|
|
106
|
-
---
|
|
107
|
-
|
|
108
|
-
## APIv3 (Page Render / Custom Exports) — In Development
|
|
109
|
-
|
|
110
|
-
**Purpose:** Custom page rendering for exports (PDF, etc.). Provides a page render
|
|
111
|
-
endpoint separate from the main GraphQL API.
|
|
112
|
-
|
|
113
|
-
**Status:** In development as of 2026-06-07. Not yet production-stable for scripting.
|
|
114
|
-
Not covered in this gem.
|
|
115
|
-
|
|
116
|
-
---
|
|
117
|
-
|
|
118
|
-
## APIv2 vs GraphQL: Key Differences for Scripts
|
|
119
|
-
|
|
120
|
-
| Concern | APIv2 | GraphQL |
|
|
121
|
-
|---------|-------|---------|
|
|
122
|
-
| Stage fetch | One request per stage | Full page in one request |
|
|
123
|
-
| Field IDs | Available after get | Available after buildFromTemplate |
|
|
124
|
-
| Update scope | Full doc or stage doc | Partial: only specify what changes |
|
|
125
|
-
| patchVer | Not required (v2 handles internally) | **REQUIRED** on all updates |
|
|
126
|
-
| Filter format | `{ type: "date_filter", lbound:, ubound: }` | `{ operation: "date_filter", params: { gte:, lte: } }` |
|
|
127
|
-
| Archived pages | Search returns them with flag | Default excluded; `includeArchived: true` opt-in |
|
|
128
|
-
| Template update | Supported | **NOT recommended** (Engineering block) |
|
|
129
|
-
| Search result | Full page data | Org: full DB page; Register: ES preview only |
|
|
130
|
-
|
|
131
|
-
---
|
|
132
|
-
|
|
133
|
-
## eco-helpers Compat Layer
|
|
134
|
-
|
|
135
|
-
Since APIv2 is being retired, the `ecoportal-api-graphql` gem provides a compatibility
|
|
136
|
-
layer so existing eco-helpers scripts can work without modification:
|
|
137
|
-
|
|
138
|
-
```ruby
|
|
139
|
-
graphql = Ecoportal::API::GraphQL.new(email:, pass:, org_id:)
|
|
140
|
-
graphql.pages # → Compat::Pages (same interface as apiv2.pages)
|
|
141
|
-
graphql.registers # → Compat::Registers (same interface as apiv2.registers)
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
Page models include `Concerns::SnakeCamelAccess` — all camelCase methods accessible
|
|
145
|
-
as snake_case (`external_id`, `patch_ver`, `source_template_id`, `creator_name`, etc.).
|
|
146
|
-
|
|
147
|
-
See `11_integration_gems.md` for full compat layer details.
|