Skip to content

refactor(mirrors): drop denormalized ProductMirror.storage_type - #456

Draft
alukach wants to merge 7 commits into
mainfrom
remove-mirror-storage-type
Draft

refactor(mirrors): drop denormalized ProductMirror.storage_type#456
alukach wants to merge 7 commits into
mainfrom
remove-mirror-storage-type

Conversation

@alukach

@alukach alukach commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Stacked on #455 — review/merge that first; GitHub retargets this to main once it lands.

Why

Nothing branched on storage_type: the data proxy keys off the connection's details.provider, and the only source.coop consumer was a display label. With provider values now equal to the backend vocabulary (#455), the provider→storage_type maps are pure identity.

Changes

  • Drop storage_type from ProductMirrorSchema; delete both STORAGE_TYPE_BY_PROVIDER maps.
  • Mirror "Type" label now reads the provider from connectionInfo (sourced from the connection's details.provider).
  • No migration: ProductMirrorSchema is a plain z.object, so existing records still carrying storage_type parse fine (unknown key stripped).

Verification

tsc clean · jest affected suites 116 · lint clean.

🤖 Generated with Claude Code

alukach and others added 2 commits July 22, 2026 11:46
Creating a GCP data connection persisted `details.provider: "gcp"`, but the
data proxy reads `details.provider` directly and only accepts "gcs"/"gs"
for Google (never "gcp"); the same latent mismatch existed for Azure ("az"
vs the accepted "azure"). The provider→storage_type map already emitted the
right values, so mirrors were fine — only the stored provider string was
wrong.

Rename the DataProvider values to what the backend accepts: Azure "az"→
"azure", GCP→GCS "gcp"→"gcs". Member GCP→GCS, schema/type Gcp*→Gcs*. Auth
type stays `gcp_workload_identity` (WIF is a GCP-platform feature, not
storage). Provider labels spelled out in the form.

Legacy rows: reads bypass Zod, so `normalizeConnection` in the
data-connections DynamoDB client remaps "az"→"azure" / "gcp"→"gcs" on
fetchById/listAll. Marked ponytail; drop after backfill.

The now-redundant provider→storage_type translation is left in place here
and removed in the follow-up that drops ProductMirror.storage_type.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Nothing branched on `storage_type`: the data proxy keys off the
connection's `details.provider`, and the only source.coop consumer was a
display label. With provider values now equal to the backend vocabulary
(previous commit), the provider→storage_type maps in createProduct /
addProductMirror are pure identity — so remove the field and both maps.

- Drop `storage_type` from ProductMirrorSchema; delete both
  STORAGE_TYPE_BY_PROVIDER maps (mirror no longer stores it).
- Mirror "Type" label now reads the provider from connectionInfo (sourced
  from the connection's details.provider on the edit page).
- No migration: ProductMirrorSchema is a plain z.object, so existing
  records still carrying storage_type parse fine (unknown key stripped).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
source-cooperative Ready Ready Preview, Comment Jul 29, 2026 4:59am

Request Review

@claude

claude Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Claude finished @alukach's task in 1m 7s —— View job


Review of PR #456

  • Gather context (diff, changed files)
  • Review diff for correctness/security/best-practice issues
  • Post findings

✅ No blocking issues — safe to merge.

  • The diff cleanly removes storage_type everywhere it was written/read/tested, and DataConnnectionDetailsSchema is a provider-discriminated union, so c.details.provider in src/app/(app)/edit/product/[account_id]/[product_id]/data-connections/page.tsx:59 is valid for all three provider variants (S3/Azure/GCS) — no type gap.
  • Minor (non-blocking) behavioral note: ProductMirrorsManager.tsx:237 now derives the "Type" label from connectionInfo[mirror.connection_id]?.provider, whereas before it was denormalized onto the mirror itself. If a mirror's underlying connection is later deleted (filtered out via .filter((c) => c != null) in page.tsx:47), the "Type" field will silently render blank rather than showing a hidden Field like the adjacent "Bucket" field does (ProductMirrorsManager.tsx:240, guarded by connectionInfo[mirror.connection_id] &&). This is an accepted tradeoff of the intentional de-denormalization described in the PR body, not a regression introduced carelessly — flagging only for awareness, not requesting a change.
  • Test/schema/fixture updates are consistent (product-mirrors.test.ts, products.test.ts, product.test.ts), and leftover storage_type keys in fixtures/products.json / scripts/load-dynamodb-exports.ts are harmless since ProductMirrorSchema is a plain z.object that strips unknown keys, as noted in the PR description.

Note: I was unable to run tsc/jest/lint myself in this sandboxed environment (command execution required approval that wasn't available), so I relied on static review of the diff; the PR description states these were already run clean.

alukach and others added 2 commits July 22, 2026 15:10
The azure-data-connection fixture still carried the pre-rename provider
value; AzureDataConnectionSchema now requires "azure", and utils.mock.ts
eagerly parses this fixture at module load, so every test importing it (and
local dev seeding via init-local.ts) threw. Caught in CI review.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
alukach and others added 2 commits July 22, 2026 15:28
Replace the runtime normalizeConnection read-shim (LEGACY_PROVIDER_ALIASES)
with a one-time migration script that converts persisted provider values
"az"->"azure" / "gcp"->"gcs". Keeps the DB read path free of legacy-value
handling; the conversion is done once at deploy instead of on every read.

- Remove normalizeConnection + its test; fetchById/listAll return rows as-is.
- Add scripts/migrate-provider-values.ts, matching the existing migration
  convention (positional table arg, DynamoDB scan + guarded UpdateCommand,
  progress logging). Dry-run by default; --apply to write. Re-runnable
  (canonical rows are skipped).

Run the migration (dry-run, then --apply) before deploying the value rename.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
# Conflicts:
#	src/lib/clients/database/data-connections.ts
#	src/types/data-connection.ts
alukach added a commit that referenced this pull request Jul 22, 2026
#455)

## Problem
Creating a GCP data connection persisted `details.provider: "gcp"`, but
the data proxy (data.source.coop) reads `details.provider` directly and
only accepts `"gcs"`/`"gs"` for Google — never `"gcp"`. The same latent
mismatch existed for Azure (`"az"` vs the accepted `"azure"`). The
`provider→storage_type` map already emitted the right values, so mirrors
were fine — **only the stored provider string was wrong**.

## Change — rename `DataProvider` values to what the backend accepts
```
enum DataProvider { S3 = "s3", Azure = "azure" /* was "az" */, GCS = "gcs" /* was GCP="gcp" */ }
```
- Member `GCP`→`GCS`, schema/type `Gcp*`→`Gcs*`. Auth type stays
`gcp_workload_identity` (WIF is a GCP-*platform* feature, not storage).
Provider labels spelled out in the form.
- **Maps kept** — the now-redundant `provider→storage_type` translation
is left in place here and removed in the stacked follow-up (#456).

## Migration (legacy `az`/`gcp` rows)
A one-time script — `scripts/migrate-provider-values.ts` — converts
persisted `details.provider` values (`"az"→"azure"`, `"gcp"→"gcs"`),
matching the repo's existing migration convention (positional table arg,
DynamoDB scan + guarded `UpdateCommand`, progress logging). **Dry-run by
default; `--apply` to write.** Re-runnable (canonical rows are skipped).
Run it (dry-run, then `--apply`) at/before deploy:
```
npx tsx scripts/migrate-provider-values.ts sc-prod-data-connections          # preview
npx tsx scripts/migrate-provider-values.ts sc-prod-data-connections --apply   # write
```
(Earlier revisions used a runtime read-shim; replaced with this script
so the DB read path carries no legacy-value handling.)

## Backend compatibility (verified against data.source.coop)
**S3** unchanged. **Azure** accepts both `"az"` and `"azure"` →
compatible during rollout. **GCS**: old `"gcp"` never worked (hit the
error arm); `"gcs"` is accepted. Pairs with data.source.coop#191
(enables the GCS backend).

## Verification
`tsc` clean · `jest` affected suites green · lint clean · fixture
`provider` fixed (`az`→`azure`) so module-load parsing passes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Base automatically changed from align-provider-values to main July 22, 2026 22:32
…-type

# Conflicts:
#	src/lib/actions/product-mirrors.test.ts
#	src/lib/actions/product-mirrors.ts
#	src/lib/actions/products.ts
#	src/types/data-connection.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant