Skip to content

feat: add shared card platform validation and diff utilities#63

Open
SdSarthak wants to merge 2 commits into
Dev-Card:mainfrom
SdSarthak:feat/card-validation-diff
Open

feat: add shared card platform validation and diff utilities#63
SdSarthak wants to merge 2 commits into
Dev-Card:mainfrom
SdSarthak:feat/card-validation-diff

Conversation

@SdSarthak
Copy link
Copy Markdown

Summary

Implements the context-card diffing and validation layer described in the product doc (section 4.5), living in packages/shared so both web and mobile clients can use it.

New: packages/shared/src/cards.ts

validateCardPlatforms(platforms: string[]): CardValidationResult

  • All platform IDs must exist in PLATFORMS
  • No duplicate IDs
  • Maximum 10 platforms per card
  • Returns { valid: boolean, errors: string[] }

diffCardPlatforms(oldCard: string[], newCard: string[]): CardDiffResult

  • Pure, order-insensitive diff
  • Returns { added: string[], removed: string[], unchanged: string[] }

Both are exported from packages/shared/src/index.ts.

Tests: packages/shared/src/__tests__/cards.test.ts

16 vitest unit tests covering:

  • Empty arrays
  • All-invalid platforms
  • Duplicate platforms
  • Max (>10) exceeded, exactly 10 boundary
  • Multiple simultaneous errors
  • All diff cases (added, removed, unchanged, both changed, empty old, empty new, both empty, order-insensitive)

Backend: apps/backend/src/routes/cards.ts

Updated POST / (create card) and PUT /:id (update card) to:

  1. Resolve the provided linkIds to their platform fields via Prisma
  2. Call validateCardPlatforms(platformIds) from shared
  3. Return 400 { error: 'Invalid card platforms', details: [...] } on failure

Package changes

Added vitest ^2.0.0 and "test": "vitest run" to packages/shared/package.json.

Closes #31

Test plan

  • pnpm --filter @devcard/shared test — all 16 tests pass
  • Create a card with >10 links → 400 with validation error
  • Create a card with an unknown/duplicate platform → 400
  • Valid card creation continues to work correctly
  • pnpm -r typecheck passes

- Add packages/shared/src/cards.ts with:
  - validateCardPlatforms(platforms): checks all IDs exist in PLATFORMS,
    no duplicates, max 10 per card; returns { valid, errors }
  - diffCardPlatforms(oldCard, newCard): pure diff returning { added, removed, unchanged }
  - CardValidationResult and CardDiffResult types
- Export from packages/shared/src/index.ts
- Add comprehensive vitest unit tests in packages/shared/src/__tests__/cards.test.ts
  covering: empty arrays, unknown platforms, duplicates, max exceeded,
  boundary (exactly 10), multiple errors, and all diff cases
- Add vitest as devDependency and "test" script to shared package.json
- Update apps/backend/src/routes/cards.ts to import validateCardPlatforms and
  call it on both POST / (create) and PUT /:id (update) after resolving
  PlatformLink records to their platform IDs, returning 400 with structured
  errors on failure

Closes Dev-Card#31
Copilot AI review requested due to automatic review settings May 10, 2026 18:15
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a shared cards utility module in @devcard/shared to validate card platform selections and compute platform diffs, then integrates the shared validator into backend card create/update routes.

Changes:

  • Introduces validateCardPlatforms and diffCardPlatforms in packages/shared/src/cards.ts and exports them from packages/shared/src/index.ts.
  • Adds Vitest unit tests for the new shared utilities and wires up a test script for the shared package.
  • Updates backend POST / and PUT /:id card routes to validate requested platforms via the shared validator after resolving linkIds to platform IDs.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
packages/shared/src/index.ts Exports new shared card utilities.
packages/shared/src/cards.ts Adds platform validation + platform diff utilities.
packages/shared/src/tests/cards.test.ts Adds Vitest coverage for the new shared utilities.
packages/shared/package.json Adds Vitest dependency and a shared-package test script.
apps/backend/src/routes/cards.ts Uses shared platform validation when creating/updating card links.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/shared/src/cards.ts Outdated

const seen = new Set<string>();
for (const id of platforms) {
if (!PLATFORMS[id]) {
Comment thread packages/shared/src/cards.ts Outdated
Comment on lines +63 to +65
const added = newCard.filter((id) => !oldSet.has(id));
const removed = oldCard.filter((id) => !newSet.has(id));
const unchanged = oldCard.filter((id) => newSet.has(id));
Comment on lines +42 to +53
// Validate platform IDs via shared utility
if (parsed.data.linkIds.length > 0) {
const links = await app.prisma.platformLink.findMany({
where: { id: { in: parsed.data.linkIds }, userId },
select: { platform: true },
});
const platformIds = links.map((l) => l.platform);
const validation = validateCardPlatforms(platformIds);
if (!validation.valid) {
return reply.status(400).send({ error: 'Invalid card platforms', details: validation.errors });
}
}
Comment on lines +115 to +126
// Validate updated platform set via shared utility
if (parsed.data.linkIds.length > 0) {
const links = await app.prisma.platformLink.findMany({
where: { id: { in: parsed.data.linkIds }, userId },
select: { platform: true },
});
const platformIds = links.map((l) => l.platform);
const validation = validateCardPlatforms(platformIds);
if (!validation.valid) {
return reply.status(400).send({ error: 'Invalid card platforms', details: validation.errors });
}
}
Comment on lines +53 to +57
it('returns all platform IDs listed in PLATFORMS as valid', () => {
const known = ['github', 'linkedin', 'twitter', 'gitlab', 'devfolio', 'npm'];
const result = validateCardPlatforms(known);
expect(result.valid).toBe(true);
});
@SdSarthak
Copy link
Copy Markdown
Author

Thanks for the review — all three fixed in the follow-up commit:

  • validateCardPlatforms now uses Object.prototype.hasOwnProperty.call(PLATFORMS, id) to guard against inherited property keys.
  • diffCardPlatforms now operates over Set spreads so duplicates in either input are deduplicated before diffing.
  • Both the create (POST /) and update (PUT /:id) card routes now reject requests where links.length !== new Set(linkIds).size, ensuring all supplied link IDs exist and belong to the requesting user before proceeding.

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.

shared: build a context-card diffing utility and validation layer

2 participants