TCG Pocket Collection Tracker Deck Building Architecture: How Validation Rules Are Applied
The TCG Pocket Collection Tracker implements deck building as a layered frontend architecture using React, Zod schema validation, and Supabase, enforcing game rules through client-side validation in DeckBuilder.tsx and business logic utilities in utils.ts before persisting to PostgreSQL.
The deck building feature in the TCG Pocket Collection Tracker enables users to construct, validate, and share Pokémon TCG Pocket decks while ensuring compliance with game rules. This React-based application combines type-safe form handling with real-time collection integration to validate deck composition before persistence.
Frontend Architecture Overview
The deck building system resides entirely in the frontend React application, organized into distinct layers that separate UI concerns from business logic and data persistence. This architecture ensures type safety through TypeScript and Zod schemas while maintaining responsive user experiences via React Query.
Core Components and File Structure
DeckBuilder.tsx – UI and Form Validation
Located at frontend/src/pages/decks/DeckBuilder.tsx, this component serves as the primary interface for deck construction. It integrates react-hook-form with Zod validation to enforce structural constraints before submission.
The Zod schema defined at lines 92-99 declares:
const formSchema = z.object({
id: z.number().optional(),
is_public: z.boolean(),
name: z.string().min(4), // name must be at least 4 characters
energy: z.array(z.enum(energies)).min(1), // at least one energy type
cards: z.array(z.number()).length(20), // exactly 20 card IDs
})
utils.ts – Business Logic and Card Counting
The frontend/src/pages/decks/utils.ts file contains pure functions for deck analysis. The getDeckCardCounts function calculates how many copies of each card exist in the current deck, while getMissingCardsCount determines whether the user owns sufficient copies based on their collection data.
React Query Hooks – Data Management
Located in frontend/src/services/decks/useDeck.ts, these hooks encapsulate asynchronous operations. useUpdateDeck prepares the deck payload (including the current user's email) and triggers the Supabase service layer. useDeleteDeck, useLikeDeck, and related hooks handle additional deck operations while managing query cache invalidation.
Supabase Service Layer – Backend Integration
The frontend/src/services/decks/deckService.ts file implements the CRUD interface with Supabase. Functions like getDeck, updateDeck, and deleteDeck perform upsert operations on the decks and public_decks tables, merging private and public deck data as needed.
How Deck Validation Rules Are Applied
Client-Side Schema Validation
The Zod schema in DeckBuilder.tsx enforces four critical rules before any network request occurs:
- Deck name: Minimum 4 characters
- Energy types: At least one energy type must be selected
- Card count: Exactly 20 card IDs must be present
- Type safety: All fields are strictly typed via TypeScript and Zod
React Hook Form's zodResolver prevents form submission until these constraints pass, providing immediate user feedback.
UI-Enforced Card Copy Limits
The interface enforces the game rule of maximum 2 copies per card through interactive elements. In DeckBuilder.tsx, the add button disables when a card's count reaches 2, as implemented in the card list render loop (lines 19-21) and the CardsTable render callback (lines 24-26).
Missing Card Warnings
Before saving, the application checks collection ownership via getMissingCardsCount in utils.ts. This function compares deck requirements against the user's actual card inventory, displaying warnings when the deck includes cards the user does not own or lacks sufficient copies of.
Server-Side Persistence Validation
While the primary validation occurs client-side, the service layer in deckService.ts ensures data integrity during the upsert operation. The useUpdateDeck hook (in useDeck.ts) attaches the authenticated user's email to the payload, ensuring deck ownership is verified before the Supabase upsert modifies the decks table.
Summary
- The deck building architecture resides entirely in the frontend React application, utilizing TypeScript for type safety.
- Zod schemas in
DeckBuilder.tsxenforce structural validation (name length, energy requirements, exactly 20 cards) before submission. - Business logic utilities in
utils.tscalculate card counts and verify collection ownership against game rules (max 2 copies per card). - React Query hooks in
useDeck.tsmanage asynchronous operations and cache invalidation, while deckService.ts handles Supabase CRUD operations. - Validation occurs in multiple layers: client-side schema validation, UI-enforced copy limits, missing card warnings, and server-side persistence checks.
Frequently Asked Questions
How does the TCG Pocket Collection Tracker enforce the 20-card deck limit?
The application enforces the 20-card limit through a Zod schema in DeckBuilder.tsx that requires exactly 20 card IDs: cards: z.array(z.number()).length(20). React Hook Form prevents submission until this constraint is satisfied, and the UI disables the save button when the deck size is incorrect.
What prevents users from adding more than two copies of the same card to a deck?
The UI enforces the two-copy limit through disabled state logic in DeckBuilder.tsx. When rendering the card list and table components, the add button checks the current count for each card and disables the button when the count reaches 2, preventing users from exceeding the game rule maximum.
Where is deck data stored in the TCG Pocket Collection Tracker?
Deck data persists in Supabase PostgreSQL tables including decks and public_decks. The deckService.ts file in frontend/src/services/decks/ implements the CRUD interface, performing upsert operations that merge private and public deck data while attaching user authentication via the React Query hooks in useDeck.ts.
How does the deck builder warn users about cards they don't own?
Before saving, the getMissingCardsCount function in frontend/src/pages/decks/utils.ts compares the deck's card requirements against the user's collection data. It calculates how many copies the user is missing and displays a warning indicator next to cards that exceed the user's owned quantity, allowing players to identify incomplete decks before publication.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →