Skip to content

refactor(api): sets → src/api modules (Effort 1)#58

Merged
chiptus merged 2 commits into
mainfrom
claude/effort1-sets
Jun 25, 2026
Merged

refactor(api): sets → src/api modules (Effort 1)#58
chiptus merged 2 commits into
mainfrom
claude/effort1-sets

Conversation

@chiptus

@chiptus chiptus commented Jun 25, 2026

Copy link
Copy Markdown
Owner

Mechanical move of the sets feature from src/hooks/queries/sets to src/api/sets, adding queryOptions factories for the set query hooks. No behavior change. Part of #52.

Manual verification

  • In an edition, open the Artists and Schedule tabs — sets render and filter as before.
  • Open a Set details page and cast a vote — voting + set info still work.
  • In admin, open Sets management: create, edit, add/remove artist, delete a set — all succeed.
  • pnpm run lint && pnpm test && pnpm run build all pass.

Generated by Claude Code

@vercel

vercel Bot commented Jun 25, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
upline Ready Ready Preview, Comment Jun 25, 2026 3:08am

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Refactor sets feature into src/api/sets with shared types/keys and queryOptions
✨ Enhancement 🕐 20-40 Minutes

Grey Divider

Description

• Move sets data-access hooks under src/api/sets and update imports across UI
• Centralize FestivalSet/Stage types and React Query keys in src/api/sets/types
• Add queryOptions factories for sets queries to standardize query construction
Diagram

graph TD
  UI["Pages & components"] --> Hooks["src/api/sets hooks"] --> RQ["React Query"] --> SB["Supabase client"] --> DB[("Postgres")]
  Types["sets/types.ts"] --> Hooks --> RQ --> SB --> DB
  UI --> Types
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Add a src/api/sets/index.ts barrel for public exports
  • ➕ Prevents many deep imports (e.g., '@/api/sets/useSetsByEdition') and eases future reshuffles
  • ➕ Lets you explicitly define the supported public surface (types, keys, hooks)
  • ➖ Slight indirection; can hide unused exports if not curated
  • ➖ Requires follow-up refactor across imports to standardize usage
2. Keep query key factory in a dedicated queryKeys module per domain
  • ➕ Avoids coupling domain types and cache keys in one file
  • ➕ Makes keys reusable even when types move (or in non-TS contexts)
  • ➖ Adds another file and slightly more import churn
  • ➖ May be over-structure for a small domain

Recommendation: The current approach (centralizing FestivalSet/Stage and setsKeys in src/api/sets/types.ts and adding queryOptions factories) is a good, low-risk step toward a cleaner API layer. If import churn continues across domains, consider adding a small barrel (index.ts) to stabilize the public import paths and reduce future mechanical changes.

Files changed (30) +81 / -68

Enhancement (3) +28 / -36
useSetBySlug.tsAdd setBySlugQuery() queryOptions factory and reuse in hook +10/-5

Add setBySlugQuery() queryOptions factory and reuse in hook

• Introduces a queryOptions factory (setBySlugQuery) that encapsulates queryKey/queryFn for fetching a set by slug, and updates the hook to spread those options into useQuery. Also migrates FestivalSet/setsKeys imports to the shared types module.

src/api/sets/useSetBySlug.ts

useSets.tsExtract setsQuery() queryOptions factory and centralize types/keys +8/-26

Extract setsQuery() queryOptions factory and centralize types/keys

• Moves FestivalSet/Stage/setsKeys definitions out to src/api/sets/types and adds setsQuery() returning queryOptions for the sets list. useSetsQuery now delegates to useQuery(setsQuery()) for consistency.

src/api/sets/useSets.ts

useSetsByEdition.tsAdd setsByEditionQuery() queryOptions factory and reuse in hook +10/-5

Add setsByEditionQuery() queryOptions factory and reuse in hook

• Adds a setsByEditionQuery factory to standardize queryKey/queryFn construction, then updates the hook to spread it into useQuery. Also switches FestivalSet/setsKeys imports to src/api/sets/types.

src/api/sets/useSetsByEdition.ts

Refactor (27) +53 / -32
types.tsAdd shared sets types and React Query key factory +21/-0

Add shared sets types and React Query key factory

• Introduces FestivalSet and Stage types sourced from Supabase table rows and adds a centralized setsKeys query-key factory. This becomes the shared import point for both sets hooks and consumers that need the set type or keys.

src/api/sets/types.ts

useAddArtistToSet.tsRepoint cache key import to sets/types +1/-1

Repoint cache key import to sets/types

• Updates the mutation to import setsKeys from the new types module. Behavior is unchanged; this is part of centralizing keys/types.

src/api/sets/useAddArtistToSet.ts

useCreateSet.tsUse shared FestivalSet/setsKeys from sets/types +1/-1

Use shared FestivalSet/setsKeys from sets/types

• Switches imports to pull FestivalSet and setsKeys from src/api/sets/types. This aligns create-set cache invalidation and typing with the new shared module.

src/api/sets/useCreateSet.ts

useDeleteSet.tsRepoint cache key import to sets/types +1/-1

Repoint cache key import to sets/types

• Updates delete-set mutation to import setsKeys from the shared types module, keeping cache invalidation consistent after the refactor.

src/api/sets/useDeleteSet.ts

useRemoveArtistFromSet.tsRepoint cache key import to sets/types +1/-1

Repoint cache key import to sets/types

• Updates remove-artist mutation to use setsKeys from src/api/sets/types. No functional changes beyond import consolidation.

src/api/sets/useRemoveArtistFromSet.ts

useUpdateSet.tsRepoint cache key import to sets/types +1/-1

Repoint cache key import to sets/types

• Updates update-set mutation to import setsKeys from the shared types module. This maintains consistent cache invalidation after the refactor.

src/api/sets/useUpdateSet.ts

ReviewStage.tsxUpdate setsKeys import to new API location +1/-1

Update setsKeys import to new API location

• Replaces the previous setsKeys import from hooks/queries with the new src/api/sets/types module. This keeps schedule import cache interactions aligned with the refactor.

src/components/Admin/ScheduleImport/ReviewStage.tsx

useVote.tsUpdate setsKeys import for vote invalidation +1/-1

Update setsKeys import for vote invalidation

• Updates voting mutation to import setsKeys from src/api/sets/types, ensuring set-related cache updates still target the correct query keys.

src/hooks/queries/voting/useVote.ts

useScheduleData.tsSwitch FestivalSet type import to src/api/sets/types +1/-1

Switch FestivalSet type import to src/api/sets/types

• Repoints the FestivalSet type import used in schedule data shaping to the new shared types module. No runtime behavior changes.

src/hooks/useScheduleData.ts

useVoteCount.tsSwitch FestivalSet type import to src/api/sets/types +1/-1

Switch FestivalSet type import to src/api/sets/types

• Updates the FestivalSet type import to the new src/api/sets/types module to match the sets refactor.

src/hooks/useVoteCount.ts

ArtistsTab.tsxUse sets-by-edition query from src/api/sets +1/-1

Use sets-by-edition query from src/api/sets

• Updates Artists tab to import useSetsByEditionQuery from src/api/sets/useSetsByEdition instead of the old hooks path. Intended to be a behavior-preserving module move.

src/pages/EditionView/tabs/ArtistsTab/ArtistsTab.tsx

FestivalSetContext.tsxSwitch FestivalSet context typing to new module +1/-1

Switch FestivalSet context typing to new module

• Repoints FestivalSet type import for the Artists tab context to src/api/sets/types. No runtime logic changes.

src/pages/EditionView/tabs/ArtistsTab/FestivalSetContext.tsx

SetsPanel.tsxSwitch FestivalSet type import to new module +1/-1

Switch FestivalSet type import to new module

• Updates SetsPanel typing to import FestivalSet from src/api/sets/types after the sets refactor.

src/pages/EditionView/tabs/ArtistsTab/SetsPanel.tsx

useSetFiltering.tsSwitch FestivalSet type import used in filtering +1/-1

Switch FestivalSet type import used in filtering

• Repoints FestivalSet type import to src/api/sets/types for the set filtering hook used on the Artists tab.

src/pages/EditionView/tabs/ArtistsTab/useSetFiltering.ts

Timeline.tsxUse sets-by-edition query from src/api/sets in timeline +1/-1

Use sets-by-edition query from src/api/sets in timeline

• Updates the schedule timeline to import the sets-by-edition query hook from src/api/sets, keeping schedule rendering wired to the refactored module.

src/pages/EditionView/tabs/ScheduleTab/horizontal/Timeline.tsx

ListSchedule.tsxUse sets-by-edition query from src/api/sets in list view +1/-1

Use sets-by-edition query from src/api/sets in list view

• Switches the schedule list view to use the sets-by-edition query hook from src/api/sets rather than the old hooks location.

src/pages/EditionView/tabs/ScheduleTab/list/ListSchedule.tsx

SetExploreCard.tsxSwitch FestivalSet type import for explore card +1/-1

Switch FestivalSet type import for explore card

• Updates the explore card component to import FestivalSet from src/api/sets/types.

src/pages/ExploreSetPage/SetExploreCard.tsx

CardStackContainer.tsxSwitch FestivalSet type import for explore stack container +1/-1

Switch FestivalSet type import for explore stack container

• Repoints FestivalSet typing used by the card stack container to src/api/sets/types to match the new sets module layout.

src/pages/ExploreSetPage/components/CardStackContainer.tsx

VotingSection.tsxSwitch FestivalSet type import for explore voting section +1/-1

Switch FestivalSet type import for explore voting section

• Updates the explore voting section to use FestivalSet from src/api/sets/types for consistent typing after the refactor.

src/pages/ExploreSetPage/components/VotingSection.tsx

useExplorableSets.tsxUse sets-by-edition query from src/api/sets in explore hook +1/-1

Use sets-by-edition query from src/api/sets in explore hook

• Switches useExplorableSets to import useSetsByEditionQuery from src/api/sets, preserving behavior while moving to the new API module.

src/pages/ExploreSetPage/useExplorableSets.tsx

SetDetails.tsxUse set-by-slug query from src/api/sets +1/-1

Use set-by-slug query from src/api/sets

• Updates SetDetails page to import useSetBySlugQuery from src/api/sets/useSetBySlug. Maintains the same data flow while aligning with the new module structure.

src/pages/SetDetails.tsx

MultiArtistSetInfoCard.tsxSwitch FestivalSet type import for multi-artist info card +1/-1

Switch FestivalSet type import for multi-artist info card

• Repoints FestivalSet typing used by the multi-artist info card to src/api/sets/types.

src/pages/SetDetails/MultiArtistSetInfoCard.tsx

SetInfoCard.tsxSwitch FestivalSet type import for set info card +1/-1

Switch FestivalSet type import for set info card

• Updates the set info card to use FestivalSet from src/api/sets/types, reflecting the refactor without changing runtime behavior.

src/pages/SetDetails/SetInfoCard.tsx

SetVotingButtons.tsxSwitch FestivalSet type import for voting buttons +1/-1

Switch FestivalSet type import for voting buttons

• Repoints FestivalSet type usage in set voting buttons to src/api/sets/types to match the new sets API module layout.

src/pages/SetDetails/SetVotingButtons.tsx

SetFormDialog.tsxMove admin set mutations to src/api/sets +5/-5

Move admin set mutations to src/api/sets

• Updates the admin set form to import FestivalSet and all set mutations (create/update/add/remove artist) from src/api/sets. This aligns admin CRUD operations with the new sets API module.

src/pages/admin/festivals/SetFormDialog.tsx

SetManagement.tsxUse sets API hooks/types in admin management page +3/-3

Use sets API hooks/types in admin management page

• Switches the sets management page to import FestivalSet, useSetsByEditionQuery, and useDeleteSetMutation from src/api/sets. Keeps admin list + delete functionality wired to the refactored modules.

src/pages/admin/festivals/SetsManagement/SetManagement.tsx

SetsTable.tsxSwitch FestivalSet type import for admin table +1/-1

Switch FestivalSet type import for admin table

• Updates the admin sets table component to import FestivalSet from src/api/sets/types after the refactor.

src/pages/admin/festivals/SetsTable.tsx

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 109 rules
✅ Skills: 4 invoked
  supabase
  supabase-postgres-best-practices
  tdd
  improve-codebase-architecture

Grey Divider


Remediation recommended

1. API depends on hooks 🐞 Bug ⚙ Maintainability
Description
src/api/sets/types.ts imports Artist from src/hooks/queries/artists/useArtists.ts, coupling
the API layer back to the hooks layer and making future refactors (e.g., moving artists into
src/api) more brittle. Keeping API types derived from Database (or a dedicated
src/api/artists/types.ts) avoids cross-layer dependencies and reduces risk of future import
cycles.
Code

src/api/sets/types.ts[R1-6]

+import type { Database } from "@/integrations/supabase/types";
+import type { Artist } from "@/hooks/queries/artists/useArtists";
+
+export type FestivalSet = Database["public"]["Tables"]["sets"]["Row"] & {
+  artists: Artist[];
+  votes: { vote_type: number; user_id: string }[];
Evidence
The sets API types module directly imports a type from a hooks-layer file, which establishes an
unwanted cross-layer dependency (API → hooks). The imported Artist type is defined in the hooks
module, confirming the coupling.

src/api/sets/types.ts[1-6]
src/hooks/queries/artists/useArtists.ts[1-8]
docs/adr/0001-api-modules.md[1-17]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`src/api/sets/types.ts` imports `Artist` from a hooks/query module (`src/hooks/queries/artists/useArtists.ts`). This creates an API→hooks dependency that makes the layer separation fragile and increases refactor risk.

## Issue Context
The API layer is being feature-sliced under `src/api/`, and `types.ts` is intended to be a small, reusable definition module. Depending on a hook module for a type undermines that direction.

## Fix Focus Areas
- src/api/sets/types.ts[1-8]

## Suggested fix
- Replace the `Artist` import with a local type derived from `Database["public"]["Tables"]["artists"]["Row"]` plus the extra nested fields needed (`artist_music_genres`, optional `soundcloud_followers`).
 - Example:
   - `export type SetArtist = Database["public"]["Tables"]["artists"]["Row"] & { artist_music_genres: { music_genre_id: string }[] | null; soundcloud_followers?: number }`
   - Then use `SetArtist[]` in `FestivalSet`.
- Alternatively (preferred long-term): create `src/api/artists/types.ts` exporting the shared `Artist` type and import from there.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

2. Non-type FestivalSet imports 🐞 Bug ⚙ Maintainability
Description
Multiple files import FestivalSet via a normal value import from @/api/sets/types even though
FestivalSet is a type-only export, which reduces tooling robustness and obscures intent. Since
src/api/sets/types.ts also exports runtime values (setsKeys), using `import type { FestivalSet }
...` in type-only consumers avoids accidentally retaining runtime imports under different TS
transforms and makes dependency intent explicit.
Code

src/pages/SetDetails/SetInfoCard.tsx[12]

+import { FestivalSet } from "@/api/sets/types";
Evidence
FestivalSet is type-only (export type) while types.ts also exports a runtime constant
(setsKeys). Several consumers import FestivalSet using a non-type import, and the project uses
isolatedModules, where explicit type-only imports are a safer/clearer pattern.

src/api/sets/types.ts[4-13]
src/pages/SetDetails/SetInfoCard.tsx[8-23]
tsconfig.app.json[9-16]
src/hooks/useVoteCount.ts[1-5]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`FestivalSet` is exported as `export type` from `src/api/sets/types.ts`, but many call sites import it as a normal value import. This is less robust across TS transforms and makes it less obvious the import is type-only.

## Issue Context
The project is using `isolatedModules`, and `src/api/sets/types.ts` also contains runtime exports (`setsKeys`). Explicit type-only imports help keep module boundaries clear and avoid accidentally retaining runtime imports in certain build pipelines.

## Fix Focus Areas
- src/pages/SetDetails/SetInfoCard.tsx[8-23]
- src/hooks/useVoteCount.ts[1-5]
- src/pages/EditionView/tabs/ArtistsTab/FestivalSetContext.tsx[1-6]
- src/pages/admin/festivals/SetFormDialog.tsx[1-10]

## Suggested fix
- In files where `FestivalSet` is only used in type positions, change:
 - `import { FestivalSet } from "@/api/sets/types";`
 to:
 - `import type { FestivalSet } from "@/api/sets/types";`
- If any file needs both `setsKeys` (runtime) and `FestivalSet` (type), split imports:
 - `import { setsKeys } from "@/api/sets/types";`
 - `import type { FestivalSet } from "@/api/sets/types";`

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

chiptus commented Jun 25, 2026

Copy link
Copy Markdown
Owner Author

Triage of Qodo's two findings — both Maintainability, neither a behavior/correctness bug, so #58 stays a pure mechanical move:

1. src/api/sets/types.ts imports Artist from the hooks layer — pre-existing, resolves with the artists slice.
On main, FestivalSet lived in src/hooks/queries/sets/useSets.ts and already imported Artist from ../artists/useArtists. This PR moved that type verbatim into src/api/sets/types.ts, which re-labels the existing import as an api→hooks edge — it isn't new coupling. It becomes api→api (smell gone) when artists moves to src/api/artists in a later restructure slice (per #52's order); that slice repoints this import as a normal consumer update. Introducing a divergent local SetArtist type now would only create drift against the canonical Artist until then, so deferring.

2. import type { FestivalSet } — optional, intentionally consistent with the codebase.
tsconfig.app.json sets isolatedModules but not verbatimModuleSyntax, so value-importing a type compiles fine (build is green) and TS elides it on emit. The repo imports types as values throughout; the move preserved that style. Converting only sets' consumers to import type would make them inconsistent with everything else — out of scope for a mechanical move, and flagged Optional by the review.

No changes here.


Generated by Claude Code

Mechanical move of the sets feature from src/hooks/queries/sets to src/api/sets.
Added queryOptions factories for the set query hooks. No behavior change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K513rsQz6Lg1HbbfYiafrE
Comment thread src/api/sets/useSets.ts Outdated
useSetsQuery (fetch all sets, unscoped) had no call sites — every consumer
uses the edition-scoped useSetsByEditionQuery. The file was already orphaned
on main; removing it rather than carrying dead code into src/api.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K513rsQz6Lg1HbbfYiafrE
@chiptus chiptus merged commit 3766f28 into main Jun 25, 2026
10 checks passed
@chiptus chiptus deleted the claude/effort1-sets branch June 25, 2026 03:14
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.

2 participants