Skip to content

feat(aws): add DynamoDB Cloud Explorer#143

Open
thomhurst wants to merge 3 commits into
floci-io:mainfrom
thomhurst:agent/feat-aws-dynamodb
Open

feat(aws): add DynamoDB Cloud Explorer#143
thomhurst wants to merge 3 commits into
floci-io:mainfrom
thomhurst:agent/feat-aws-dynamodb

Conversation

@thomhurst

@thomhurst thomhurst commented Jul 18, 2026

Copy link
Copy Markdown

Summary

  • add an account-scoped AWS DynamoDB adapter and schema for list, create, inspect, and delete
  • expose the provider-neutral NoSQL category in Cloud Explorer navigation and routing
  • add a read-only table explorer that scans records, shows primary keys and summaries, and renders full JSON contents
  • normalize DynamoDB sets, binary values, and large integers into JSON-safe responses
  • update service documentation and dependency lockfiles

Validation

  • pnpm lint
  • pnpm type-check
  • pnpm test (170 tests)
  • pnpm build
  • Playwright CLI against Floci 1.5.33: created and inspected a table, listed and inspected two records, deleted the table, and confirmed zero browser console errors or warnings

Closes #76

image image

@thomhurst
thomhurst requested a review from hectorvent as a code owner July 18, 2026 11:17
@greptile-apps

greptile-apps Bot commented Jul 18, 2026

Copy link
Copy Markdown

Greptile Summary

This PR introduces a fully schema-driven DynamoDB Cloud Explorer, adding list, create, inspect, and delete operations for AWS DynamoDB tables along with a read-only record browser that scans items up to a 100-record limit and normalises DynamoDB-specific types (sets, binary, large integers) into JSON-safe values.

  • Backend: AwsDynamoDbAdapter fans out DescribeTable calls in bounded batches of 10 to respect throttle limits, paginates ListTables and Scan commands correctly, and uses a wrapNumbers callback on unmarshall to preserve large-integer fidelity without losing precision on floats.
  • Frontend: DynamoDbTableExplorer wires the scan endpoint through React Query, gates fetches on runtimeReachable, resets selected-row state on table change, and shows a split-panel layout (records table + JSON viewer).
  • Routing & Nav: nosql is added to every validator/switch that guards CloudServiceType on both the API and the frontend, keeping all existing routes intact.

Confidence Score: 5/5

The change is safe to merge. It adds a new read-mostly DynamoDB surface behind the existing runtime gate and does not touch any existing adapters, routes, or data paths.

All changed paths are additive. The adapter follows the same schema-driven pattern as every other service in the repo, the pagination and batching logic is covered by dedicated tests, and the large-number normalisation is exercised end-to-end through the real AWS SDK unmarshaller. No existing behaviour is modified.

No files require special attention.

Important Files Changed

Filename Overview
packages/api/src/adapter-aws/AwsDynamoDbAdapter.ts New adapter: pagination, 10-item describe batching, 100-item scan cap, and wrapNumbers-based large-integer normalization are all implemented correctly and verified by tests.
packages/api/src/adapter-aws/AwsDynamoDbAdapter.test.ts 250 lines of thorough tests covering pagination, concurrency batching, validation, error handling, type normalization for large integers, and scan limits — all exercising the real unmarshall path.
packages/api/src/cloud-spi/dynamodbSchema.ts Schema defines table-name, partition-key, and optional sort-key fields with correct validation patterns; columns and capabilities align with the adapter's action set.
packages/api/src/cloud-spi/types.ts Adds nosql to CloudServiceType and dynamodb-table to the resource type union, and introduces the NoSqlItem interface; all consistent with the existing type layout.
packages/api/src/routes/clouds.ts New GET route for nosql items is correctly guarded by withRuntime; nosql is added to the isServiceType validator keeping other routes unaffected.
packages/api/src/service/CloudProxyService.ts nosql service entry and listNoSqlItems dispatch added cleanly; optional-method guard prevents errors if a future adapter omits item listing.
packages/frontend/src/components/DynamoDbTableExplorer.tsx New component: React Query integration with abort-signal support, runtimeReachable gate, table-change reset, and two-panel layout are all implemented correctly.
packages/frontend/src/components/DynamicResourceView.tsx Adds DynamoDbTableExplorer behind an aws+nosql guard, and a create-label branch; narrow and correct.
packages/frontend/src/api/cloudProxyClient.ts Adds listNoSqlItems client function with abort signal support; also removes the duplicate ServerlessInvokeResult interface definition.
packages/frontend/src/pages/CloudExplorerPage.tsx nosql added to normalizeService, serviceLabel, and limitationCopy — all three previously exhaustive switch-equivalents are kept consistent.
packages/frontend/src/components/Layout.tsx NoSQL nav entry added with correct icon and AWS-only availability gate.
packages/api/src/cloudProxy.ts AwsDynamoDbAdapter registered alongside other AWS adapters using the account-scoped dynamodb client.
packages/frontend/src/api/api.ts New nosql.items.list endpoint key and registry entry added correctly with matching path template.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant B as Browser (React)
    participant RQ as React Query
    participant C as cloudProxyClient
    participant H as Hono /clouds/:cloud
    participant S as CloudProxyService
    participant A as AwsDynamoDbAdapter
    participant D as DynamoDB (:4566)

    B->>RQ: useQuery(['nosql-items', cloud, tableName])
    RQ->>C: listNoSqlItems(cloud, tableId, signal)
    C->>H: GET /clouds/aws/services/nosql/resources/:id/items
    H->>S: listNoSqlItems('aws', id)
    S->>A: adapter.listNoSqlItems(id)
    A->>D: DescribeTableCommand(id)
    D-->>A: KeySchema
    loop paginate up to 100 items
        A->>D: "ScanCommand(Limit=remaining)"
        D-->>A: Items + LastEvaluatedKey
    end
    A-->>A: unmarshall + normalizeDocument
    A-->>S: NoSqlItem[]
    S-->>H: NoSqlItem[]
    H-->>C: 200 JSON
    C-->>RQ: NoSqlItem[]
    RQ-->>B: items (cached by [cloud, tableName])
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant B as Browser (React)
    participant RQ as React Query
    participant C as cloudProxyClient
    participant H as Hono /clouds/:cloud
    participant S as CloudProxyService
    participant A as AwsDynamoDbAdapter
    participant D as DynamoDB (:4566)

    B->>RQ: useQuery(['nosql-items', cloud, tableName])
    RQ->>C: listNoSqlItems(cloud, tableId, signal)
    C->>H: GET /clouds/aws/services/nosql/resources/:id/items
    H->>S: listNoSqlItems('aws', id)
    S->>A: adapter.listNoSqlItems(id)
    A->>D: DescribeTableCommand(id)
    D-->>A: KeySchema
    loop paginate up to 100 items
        A->>D: "ScanCommand(Limit=remaining)"
        D-->>A: Items + LastEvaluatedKey
    end
    A-->>A: unmarshall + normalizeDocument
    A-->>S: NoSqlItem[]
    S-->>H: NoSqlItem[]
    H-->>C: 200 JSON
    C-->>RQ: NoSqlItem[]
    RQ-->>B: items (cached by [cloud, tableName])
Loading

Reviews (3): Last reviewed commit: "fix(frontend): remove duplicate invoke t..." | Re-trigger Greptile

Comment thread packages/api/src/adapter-aws/AwsDynamoDbAdapter.ts Outdated
Comment thread packages/api/src/adapter-aws/AwsDynamoDbAdapter.ts Outdated
Comment on lines +55 to +62
<tr>
<th>Key</th>
<th>Contents</th>
</tr>
</thead>
<tbody>
{items.map((item) => (
<tr key={item.id} className={selectedItemId === item.id ? 'selected' : ''}>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 All returned rows are rendered into the DOM without virtualisation

items.map(...) renders every record as a <tr> synchronously. If the backend scan returns even a few thousand rows the browser will build a DOM of that size, causing noticeable jank when selecting or scrolling. Since the listNoSqlItems call has no server-side limit today, pairing a DOM cap or a virtual-scroll list here is worth considering once the backend adds pagination.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(aws): DynamoDB in Cloud Explorer

1 participant