├── .gitattributes ├── packages ├── trpc │ ├── src │ │ ├── utils │ │ │ ├── index.ts │ │ │ └── send-email-helper.ts │ │ ├── schema │ │ │ ├── base.ts │ │ │ ├── README.md │ │ │ └── index.ts │ │ ├── procedures │ │ │ ├── admin-view.ts │ │ │ ├── matches │ │ │ │ ├── delete-match.ts │ │ │ │ └── create-match.ts │ │ │ ├── onboarding │ │ │ │ └── verify-email-code.ts │ │ │ ├── user.ts │ │ │ ├── get-project.ts │ │ │ ├── get-pnr-and-admins.ts │ │ │ ├── mediamaker-matches.ts │ │ │ ├── project │ │ │ │ └── song-request-submission.ts │ │ │ └── comments │ │ │ │ └── upsertComment.ts │ │ ├── types.ts │ │ ├── handler.ts │ │ ├── middleware │ │ │ ├── not-authenticated.ts │ │ │ └── authenticated.ts │ │ ├── internal │ │ │ ├── context.ts │ │ │ ├── query-client-factory.ts │ │ │ ├── prisma-abstraction.ts │ │ │ └── init.ts │ │ └── server.ts │ ├── eslint.config.js │ ├── tsconfig.json │ └── package.json ├── hooks │ ├── src │ │ ├── index.ts │ │ └── useAuthenticatedUser.ts │ ├── eslint.config.js │ ├── tsconfig.json │ └── package.json ├── ui │ ├── declarations.d.ts │ ├── shad │ │ ├── index.ts │ │ ├── label.tsx │ │ ├── textarea.tsx │ │ ├── separator.tsx │ │ ├── input.tsx │ │ ├── checkbox.tsx │ │ ├── switch.tsx │ │ ├── badge.tsx │ │ ├── X.tsx │ │ ├── tooltip.tsx │ │ ├── popover.tsx │ │ └── radio-group.tsx │ ├── eslint.config.js │ ├── tsconfig.json │ ├── tailwind.config.ts │ ├── components.json │ └── svg │ │ └── CheckIcon.tsx ├── components │ ├── src │ │ ├── landing-pages │ │ │ ├── AdminLanding.tsx │ │ │ ├── ModeratorLanding.tsx │ │ │ └── components │ │ │ │ ├── EmptyMessage.tsx │ │ │ │ └── Header.tsx │ │ ├── oldStuff │ │ │ ├── submit │ │ │ │ ├── index.tsx │ │ │ │ └── project │ │ │ │ │ ├── sections │ │ │ │ │ ├── FinalProjectDetails.tsx │ │ │ │ │ └── ProjectOverview.tsx │ │ │ │ │ └── common.tsx │ │ │ ├── projects │ │ │ │ ├── MediamakerOverview.tsx │ │ │ │ └── MediamakerProjects.tsx │ │ │ ├── form │ │ │ │ ├── index.tsx │ │ │ │ ├── types.ts │ │ │ │ ├── GoodDogTextarea.tsx │ │ │ │ └── GoodDogMultiSelect.tsx │ │ │ ├── loading │ │ │ │ └── Spinner.tsx │ │ │ ├── registration │ │ │ │ ├── index.tsx │ │ │ │ ├── inputs │ │ │ │ │ ├── RegistrationCheckbox.tsx │ │ │ │ │ └── RegistrationInput.tsx │ │ │ │ └── onboarding │ │ │ │ │ └── PNROnboardingInput.tsx │ │ │ ├── matching │ │ │ │ └── InfoIcon.tsx │ │ │ ├── CheckerColumn.tsx │ │ │ └── MediaMusicianAbout.tsx │ │ ├── GrayPlaceholder.tsx │ │ ├── base │ │ │ ├── NotificationBadge.tsx │ │ │ ├── SearchBar.tsx │ │ │ ├── DictionaryWord.tsx │ │ │ ├── Card.tsx │ │ │ ├── Modal.tsx │ │ │ ├── ProfileDropdown.tsx │ │ │ └── Checkbox.tsx │ │ ├── music │ │ │ ├── MusicDashboard.tsx │ │ │ └── components │ │ │ │ ├── MusicNote.tsx │ │ │ │ ├── SongRequestInformation.tsx │ │ │ │ ├── Matches.tsx │ │ │ │ └── Popup.tsx │ │ ├── user-onboarding │ │ │ ├── widgets │ │ │ │ ├── UserOnboardingWidgetContainer.tsx │ │ │ │ ├── components │ │ │ │ │ └── PasswordRequirements.tsx │ │ │ │ ├── reset-password-widget │ │ │ │ │ └── ResetPasswordWidget.tsx │ │ │ │ └── forgot-password-widget │ │ │ │ │ └── ForgotPasswordWidget.tsx │ │ │ ├── SectionRow.tsx │ │ │ ├── UserOnboarding.tsx │ │ │ ├── MediaMakerSection.tsx │ │ │ └── MusicianSection.tsx │ │ ├── svg │ │ │ ├── Search.tsx │ │ │ ├── TrashIcon.tsx │ │ │ ├── CloseX.tsx │ │ │ ├── status-icons │ │ │ │ ├── ClockFull.tsx │ │ │ │ ├── Check.tsx │ │ │ │ └── Hourglass.tsx │ │ │ ├── homepage │ │ │ │ └── Check.tsx │ │ │ ├── MusicNote.tsx │ │ │ ├── MusicNoteIcon.tsx │ │ │ ├── PencilIcon.tsx │ │ │ └── People.tsx │ │ ├── motion │ │ │ └── GrowOnScroll.tsx │ │ ├── rhf-base │ │ │ ├── RHFTextArea.tsx │ │ │ ├── RHFRadioGroup.tsx │ │ │ ├── RHFTextInput.tsx │ │ │ └── RFHMultiselectDropdown.tsx │ │ ├── PageContainer.tsx │ │ ├── meda-maker-matching │ │ │ ├── components │ │ │ │ ├── MatchesSection.tsx │ │ │ │ └── ListOfMatches.tsx │ │ │ └── MediaMakerMatchingDashboard.tsx │ │ ├── PermissionsLayoutWrapper.tsx │ │ ├── Nav.tsx │ │ └── project │ │ │ └── components │ │ │ └── SongRequest.tsx │ ├── eslint.config.js │ ├── utils │ │ ├── allCapsListFormatter.ts │ │ └── getStatusHelper.ts │ ├── tsconfig.json │ ├── tailwind.config.ts │ └── package.json ├── auth │ ├── src │ │ ├── permissions │ │ │ ├── index.ts │ │ │ └── resources.ts │ │ ├── password.ts │ │ └── cookies.ts │ ├── eslint.config.js │ ├── tsconfig.json │ └── package.json ├── db │ ├── prisma │ │ └── migrations │ │ │ ├── 20241025232323_name_required │ │ │ └── migration.sql │ │ │ ├── 20251023032950_affiliation_is_optional │ │ │ └── migration.sql │ │ │ ├── migration_lock.toml │ │ │ ├── 20250925235150_added_is_submitter_in_contrib_table │ │ │ └── migration.sql │ │ │ ├── 20251110032804_genre_enums │ │ │ └── migration.sql │ │ │ ├── 20250920203043_remove_email_confirmed_column │ │ │ └── migration.sql │ │ │ ├── 20251109181338_remove_referral │ │ │ └── migration.sql │ │ │ ├── 20241016233845_first_migration │ │ │ └── migration.sql │ │ │ ├── 20251123021548_add_song_request_titles │ │ │ └── migration.sql │ │ │ ├── 20251111183252_reformat_genres │ │ │ └── migration.sql │ │ │ ├── 20250202214637_add_phone_number │ │ │ └── migration.sql │ │ │ ├── 20241108002053_email_verification_code │ │ │ └── migration.sql │ │ │ ├── 20241031000211_new_user_fields │ │ │ └── migration.sql │ │ │ ├── 20250314225857_unlicensed-music │ │ │ └── migration.sql │ │ │ ├── 20250226222351_moderator_invites │ │ │ └── migration.sql │ │ │ ├── 20241121004111_password_reset_request │ │ │ └── migration.sql │ │ │ ├── 20250223072034_fix_project_owner_id │ │ │ └── migration.sql │ │ │ ├── 20241124210934_renamed_initiator_id │ │ │ └── migration.sql │ │ │ ├── 20250119220136_added_referral_source │ │ │ └── migration.sql │ │ │ ├── 20241111161425_sign_up_flow_reqs │ │ │ └── migration.sql │ │ │ ├── 20250921190345_added_contributor_table_and_supporting_enums │ │ │ └── migration.sql │ │ │ ├── 20251005222343_changed_music_sub_id_name_in_contribs │ │ │ └── migration.sql │ │ │ ├── 20251107140820_changed_contrib_name_and_genres │ │ │ └── migration.sql │ │ │ ├── 20241002232629_user_and_session_schemas │ │ │ └── migration.sql │ │ │ ├── 20251115215703_update_project_submissions │ │ │ └── migration.sql │ │ │ ├── 20250227231837_project_fixes │ │ │ └── migration.sql │ │ │ ├── 20241023232921_added_uuid │ │ │ └── migration.sql │ │ │ ├── 20251002181054_refactor_match_comments_to_comments │ │ │ └── migration.sql │ │ │ ├── 20250920182635_remove_unlicensed_music │ │ │ └── migration.sql │ │ │ └── 20251005222327_rename_matches_table │ │ │ └── migration.sql │ ├── eslint.config.js │ ├── tsconfig.json │ ├── src │ │ └── index.ts │ └── package.json ├── email │ ├── eslint.config.js │ ├── src │ │ └── index.ts │ ├── tsconfig.json │ └── package.json └── env │ ├── src │ └── env.ts │ ├── eslint.config.js │ ├── tsconfig.json │ └── package.json ├── bun.lockb ├── apps └── web │ ├── postcss.config.cjs │ ├── app │ ├── forbidden.tsx │ ├── api │ │ └── trpc │ │ │ └── [trpc] │ │ │ └── route.ts │ ├── (pages) │ │ ├── song │ │ │ └── [id] │ │ │ │ ├── layout.tsx │ │ │ │ └── page.tsx │ │ ├── project │ │ │ ├── layout.tsx │ │ │ └── [id] │ │ │ │ ├── add-song-request │ │ │ │ └── page.tsx │ │ │ │ └── page.tsx │ │ ├── music-submission │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ │ ├── song-request │ │ │ ├── layout.tsx │ │ │ └── [id] │ │ │ │ └── page.tsx │ │ ├── project-submission │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ │ ├── profile │ │ │ └── page.tsx │ │ ├── login │ │ │ └── page.tsx │ │ ├── signup │ │ │ ├── page.tsx │ │ │ ├── musician │ │ │ │ └── page.tsx │ │ │ └── media-maker │ │ │ │ └── page.tsx │ │ ├── forgot-password │ │ │ └── page.tsx │ │ ├── reset-password │ │ │ └── page.tsx │ │ └── page.tsx │ ├── not-found.tsx │ ├── error.tsx │ ├── loading.tsx │ ├── layout.tsx │ └── ClientWrapper.tsx │ ├── public │ ├── images │ │ ├── sandbox.png │ │ ├── profHeadshot.png │ │ ├── mediaMakerAbout.png │ │ ├── musicianAbout.png │ │ ├── pianoStockImage.png │ │ ├── greenLineRecords.png │ │ └── mainLandingImage.webp │ ├── bg-assets │ │ └── green-rectangle-cut.svg │ └── icons │ │ ├── Project_Leaf.svg │ │ └── back_button.svg │ ├── next-env.d.ts │ ├── eslint.config.js │ ├── next.config.ts │ ├── tailwind.config.ts │ ├── tsconfig.json │ └── package.json ├── bunfig.toml ├── tests ├── happydom.ts ├── frontend │ ├── util.tsx │ └── signin.test.tsx ├── tsconfig.json ├── mocks │ ├── MockNextCache.ts │ ├── util.ts │ ├── MockEmailService.ts │ └── MockNextNavigation.ts ├── eslint.config.js ├── testing-library.ts ├── runtime.ts ├── package.json └── api │ └── email-service.test.ts ├── tooling ├── typescript │ ├── package.json │ ├── internal-package.json │ └── base.json ├── tailwind │ ├── eslint.config.js │ ├── native.ts │ ├── tsconfig.json │ ├── web.ts │ ├── README.md │ └── package.json ├── eslint │ ├── tsconfig.json │ ├── nextjs.js │ ├── react.js │ └── package.json └── prettier │ ├── tsconfig.json │ ├── package.json │ └── index.js ├── .vscode ├── extensions.json ├── launch.json └── settings.json ├── turbo └── generators │ └── templates │ ├── eslint.config.js.hbs │ ├── tsconfig.json.hbs │ └── package.json.hbs ├── .github ├── actions │ └── setup-bun │ │ └── action.yml ├── workflows │ ├── apply-migrations.yml │ ├── static-checks.yml │ ├── check-migrations.yml │ └── bun-tests.yml ├── scripts │ └── verify_db_empty.sh └── pull_request_template.md ├── compose.yml ├── .gitignore └── .env.example /.gitattributes: -------------------------------------------------------------------------------- 1 | *.lockb binary diff=lockb -------------------------------------------------------------------------------- /packages/trpc/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./send-email-helper"; 2 | -------------------------------------------------------------------------------- /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandboxnu/good-dog-licensing/main/bun.lockb -------------------------------------------------------------------------------- /packages/hooks/src/index.ts: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | export * from "./useAuthenticatedUser"; 4 | -------------------------------------------------------------------------------- /apps/web/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /apps/web/app/forbidden.tsx: -------------------------------------------------------------------------------- 1 | export default function Forbidden() { 2 | return
Forbidden
; 3 | } 4 | -------------------------------------------------------------------------------- /bunfig.toml: -------------------------------------------------------------------------------- 1 | [test] 2 | preload = ["./tests/runtime.ts", "./tests/happydom.ts", "./tests/testing-library.ts"] 3 | -------------------------------------------------------------------------------- /packages/ui/declarations.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.svg" { 2 | const content: string; 3 | export default content; 4 | } 5 | -------------------------------------------------------------------------------- /packages/components/src/landing-pages/AdminLanding.tsx: -------------------------------------------------------------------------------- 1 | export default function AdminLanding() { 2 | return <>; 3 | } 4 | -------------------------------------------------------------------------------- /tests/happydom.ts: -------------------------------------------------------------------------------- 1 | import { GlobalRegistrator } from "@happy-dom/global-registrator"; 2 | 3 | GlobalRegistrator.register(); 4 | -------------------------------------------------------------------------------- /apps/web/public/images/sandbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandboxnu/good-dog-licensing/main/apps/web/public/images/sandbox.png -------------------------------------------------------------------------------- /packages/auth/src/permissions/index.ts: -------------------------------------------------------------------------------- 1 | export type { GoodDogPermissionsFactory } from "./factory"; 2 | export * from "./resources"; 3 | -------------------------------------------------------------------------------- /apps/web/public/images/profHeadshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandboxnu/good-dog-licensing/main/apps/web/public/images/profHeadshot.png -------------------------------------------------------------------------------- /packages/db/prisma/migrations/20241025232323_name_required/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "User" ALTER COLUMN "name" SET NOT NULL; -------------------------------------------------------------------------------- /apps/web/public/images/mediaMakerAbout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandboxnu/good-dog-licensing/main/apps/web/public/images/mediaMakerAbout.png -------------------------------------------------------------------------------- /apps/web/public/images/musicianAbout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandboxnu/good-dog-licensing/main/apps/web/public/images/musicianAbout.png -------------------------------------------------------------------------------- /apps/web/public/images/pianoStockImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandboxnu/good-dog-licensing/main/apps/web/public/images/pianoStockImage.png -------------------------------------------------------------------------------- /packages/components/src/oldStuff/submit/index.tsx: -------------------------------------------------------------------------------- 1 | export * from "./project/ProjectSubmissionForm"; 2 | export * from "./MusicSubmissionForm"; 3 | -------------------------------------------------------------------------------- /apps/web/public/images/greenLineRecords.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandboxnu/good-dog-licensing/main/apps/web/public/images/greenLineRecords.png -------------------------------------------------------------------------------- /apps/web/public/images/mainLandingImage.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandboxnu/good-dog-licensing/main/apps/web/public/images/mainLandingImage.webp -------------------------------------------------------------------------------- /apps/web/app/api/trpc/[trpc]/route.ts: -------------------------------------------------------------------------------- 1 | import NextApiHandler from "@good-dog/trpc/next"; 2 | 3 | export { NextApiHandler as GET, NextApiHandler as POST }; 4 | -------------------------------------------------------------------------------- /packages/components/src/GrayPlaceholder.tsx: -------------------------------------------------------------------------------- 1 | export default function GrayPlaceholder() { 2 | return
; 3 | } 4 | -------------------------------------------------------------------------------- /packages/components/src/landing-pages/ModeratorLanding.tsx: -------------------------------------------------------------------------------- 1 | export default function ModeratorLanding() { 2 | return

Moderator landing page!

; 3 | } 4 | -------------------------------------------------------------------------------- /tooling/typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@good-dog/typescript", 3 | "private": true, 4 | "version": "0.1.0", 5 | "files": [ 6 | "*.json" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /packages/components/src/oldStuff/projects/MediamakerOverview.tsx: -------------------------------------------------------------------------------- 1 | export default function MediamakerOverview() { 2 | return
PLACEHOLDER
; 3 | } 4 | -------------------------------------------------------------------------------- /packages/db/prisma/migrations/20251023032950_affiliation_is_optional/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "MusicContributor" ALTER COLUMN "affiliation" DROP NOT NULL; 3 | -------------------------------------------------------------------------------- /packages/db/prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (e.g., Git) 3 | provider = "postgresql" -------------------------------------------------------------------------------- /packages/db/prisma/migrations/20250925235150_added_is_submitter_in_contrib_table/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "MusicContributor" ADD COLUMN "isSubmitter" BOOLEAN NOT NULL DEFAULT false; 3 | -------------------------------------------------------------------------------- /packages/ui/shad/index.ts: -------------------------------------------------------------------------------- 1 | import { cx } from "class-variance-authority"; 2 | import { twMerge } from "tailwind-merge"; 3 | 4 | const cn = (...inputs: Parameters) => twMerge(cx(inputs)); 5 | 6 | export { cn }; 7 | -------------------------------------------------------------------------------- /tooling/tailwind/eslint.config.js: -------------------------------------------------------------------------------- 1 | // FIXME: This kinda stinks... 2 | /// 3 | 4 | import baseConfig from "@good-dog/eslint/base"; 5 | 6 | export default [...baseConfig]; 7 | -------------------------------------------------------------------------------- /packages/db/prisma/migrations/20251110032804_genre_enums/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateEnum 2 | CREATE TYPE "Genre" AS ENUM ('ROCK', 'POP', 'HIP_HOP', 'JAZZ', 'CLASSICAL', 'ELECTRONIC', 'COUNTRY', 'REGGAE', 'BLUES', 'FOLK', 'OTHER'); 3 | -------------------------------------------------------------------------------- /packages/auth/eslint.config.js: -------------------------------------------------------------------------------- 1 | import baseConfig from "@good-dog/eslint/base"; 2 | 3 | /** @type {import('typescript-eslint').Config} */ 4 | export default [ 5 | { 6 | ignores: [], 7 | }, 8 | ...baseConfig, 9 | ]; 10 | -------------------------------------------------------------------------------- /packages/db/eslint.config.js: -------------------------------------------------------------------------------- 1 | import baseConfig from "@good-dog/eslint/base"; 2 | 3 | /** @type {import('typescript-eslint').Config} */ 4 | export default [ 5 | { 6 | ignores: [], 7 | }, 8 | ...baseConfig, 9 | ]; 10 | -------------------------------------------------------------------------------- /tooling/tailwind/native.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | 3 | import base from "./base"; 4 | 5 | export default { 6 | content: base.content, 7 | presets: [base], 8 | theme: {}, 9 | } satisfies Config; 10 | -------------------------------------------------------------------------------- /packages/email/eslint.config.js: -------------------------------------------------------------------------------- 1 | import baseConfig from "@good-dog/eslint/base"; 2 | 3 | /** @type {import('typescript-eslint').Config} */ 4 | export default [ 5 | { 6 | ignores: [], 7 | }, 8 | ...baseConfig, 9 | ]; 10 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "dbaeumer.vscode-eslint", 4 | "esbenp.prettier-vscode", 5 | "yoavbls.pretty-ts-errors", 6 | "bradlc.vscode-tailwindcss", 7 | "Prisma.prisma" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /apps/web/public/bg-assets/green-rectangle-cut.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/components/src/oldStuff/form/index.tsx: -------------------------------------------------------------------------------- 1 | export * from "./GoodDogInput"; 2 | export * from "./GoodDogTextarea"; 3 | export * from "./GoodDogDatePicker"; 4 | export * from "./GoodDogSingleSelect"; 5 | export * from "./GoodDogMultiSelect"; 6 | -------------------------------------------------------------------------------- /apps/web/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. 6 | -------------------------------------------------------------------------------- /tooling/eslint/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@good-dog/typescript/base.json", 3 | "compilerOptions": { 4 | "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json" 5 | }, 6 | "include": ["."], 7 | "exclude": ["node_modules"] 8 | } 9 | -------------------------------------------------------------------------------- /tooling/prettier/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@good-dog/typescript/base.json", 3 | "compilerOptions": { 4 | "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json" 5 | }, 6 | "include": ["."], 7 | "exclude": ["node_modules"] 8 | } 9 | -------------------------------------------------------------------------------- /tooling/tailwind/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@good-dog/typescript/base.json", 3 | "compilerOptions": { 4 | "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json" 5 | }, 6 | "include": ["."], 7 | "exclude": ["node_modules"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/db/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@good-dog/typescript/base.json", 3 | "compilerOptions": { 4 | "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json" 5 | }, 6 | "include": ["*.ts", "src"], 7 | "exclude": ["node_modules"] 8 | } 9 | -------------------------------------------------------------------------------- /apps/web/public/icons/Project_Leaf.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /tests/frontend/util.tsx: -------------------------------------------------------------------------------- 1 | import { render } from "@testing-library/react"; 2 | 3 | import { TRPCProvider } from "@good-dog/trpc/client"; 4 | 5 | export const renderWithShell = (ui: React.ReactElement) => { 6 | return render({ui}); 7 | }; 8 | -------------------------------------------------------------------------------- /apps/web/app/(pages)/song/[id]/layout.tsx: -------------------------------------------------------------------------------- 1 | import { musicianOnlyPermissions } from "@good-dog/auth/permissions"; 2 | import { layoutWithPermissions } from "@good-dog/components/PermissionsLayoutWrapper"; 3 | 4 | export default layoutWithPermissions(musicianOnlyPermissions); 5 | -------------------------------------------------------------------------------- /apps/web/app/(pages)/project/layout.tsx: -------------------------------------------------------------------------------- 1 | import { mediaMakerOnlyPermissions } from "@good-dog/auth/permissions"; 2 | import { layoutWithPermissions } from "@good-dog/components/PermissionsLayoutWrapper"; 3 | 4 | export default layoutWithPermissions(mediaMakerOnlyPermissions); 5 | -------------------------------------------------------------------------------- /packages/trpc/src/schema/base.ts: -------------------------------------------------------------------------------- 1 | import z from "zod"; 2 | 3 | export const zRequiredString = z 4 | .string({ error: "This is required" }) 5 | .min(1, { error: "This is required" }); 6 | 7 | export const zRequiredEmail = z.email({ error: "Please enter a valid email" }); 8 | -------------------------------------------------------------------------------- /apps/web/app/(pages)/music-submission/layout.tsx: -------------------------------------------------------------------------------- 1 | import { musicianOnlyPermissions } from "@good-dog/auth/permissions"; 2 | import { layoutWithPermissions } from "@good-dog/components/PermissionsLayoutWrapper"; 3 | 4 | export default layoutWithPermissions(musicianOnlyPermissions); 5 | -------------------------------------------------------------------------------- /apps/web/app/(pages)/song-request/layout.tsx: -------------------------------------------------------------------------------- 1 | import { mediaMakerOnlyPermissions } from "@good-dog/auth/permissions"; 2 | import { layoutWithPermissions } from "@good-dog/components/PermissionsLayoutWrapper"; 3 | 4 | export default layoutWithPermissions(mediaMakerOnlyPermissions); 5 | -------------------------------------------------------------------------------- /packages/env/src/env.ts: -------------------------------------------------------------------------------- 1 | export const env = { 2 | NODE_ENV: process.env.NODE_ENV, 3 | RESEND_API_KEY: process.env.RESEND_API_KEY, 4 | GOOD_DOG_FROM_EMAIL: process.env.GOOD_DOG_FROM_EMAIL, 5 | VERCEL_ENV: process.env.VERCEL_ENV, 6 | VERCEL_URL: process.env.VERCEL_URL, 7 | }; 8 | -------------------------------------------------------------------------------- /apps/web/app/(pages)/project-submission/layout.tsx: -------------------------------------------------------------------------------- 1 | import { mediaMakerOnlyPermissions } from "@good-dog/auth/permissions"; 2 | import { layoutWithPermissions } from "@good-dog/components/PermissionsLayoutWrapper"; 3 | 4 | export default layoutWithPermissions(mediaMakerOnlyPermissions); 5 | -------------------------------------------------------------------------------- /tooling/tailwind/web.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | import animate from "tailwindcss-animate"; 3 | 4 | import base from "./base"; 5 | 6 | export default { 7 | content: base.content, 8 | presets: [base], 9 | plugins: [animate], 10 | } satisfies Config; 11 | -------------------------------------------------------------------------------- /packages/email/src/index.ts: -------------------------------------------------------------------------------- 1 | import { env } from "@good-dog/env"; 2 | 3 | import { EmailService } from "./service"; 4 | 5 | export const emailService = new EmailService(env.RESEND_API_KEY); 6 | 7 | export type { EmailMessage } from "./service"; 8 | export { EmailService } from "./service"; 9 | -------------------------------------------------------------------------------- /packages/env/eslint.config.js: -------------------------------------------------------------------------------- 1 | import baseConfig from "@good-dog/eslint/base"; 2 | 3 | /** @type {import('typescript-eslint').Config} */ 4 | 5 | export default [ 6 | ...baseConfig, 7 | { 8 | rules: { 9 | "no-restricted-properties": "off", 10 | }, 11 | }, 12 | ]; 13 | -------------------------------------------------------------------------------- /apps/web/app/not-found.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | 3 | export default function NotFound() { 4 | return ( 5 |
6 |

Not Found

7 |

Could not find requested resource

8 | Return Home 9 |
10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /tooling/typescript/internal-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "./base.json", 4 | "compilerOptions": { 5 | "declaration": true, 6 | "declarationMap": true, 7 | "noEmit": false, 8 | "emitDeclarationOnly": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /turbo/generators/templates/eslint.config.js.hbs: -------------------------------------------------------------------------------- 1 | import baseConfig from "@good-dog/eslint/base"; 2 | import reactConfig from "@good-dog/eslint/react"; 3 | 4 | /** @type {import('typescript-eslint').Config} */ 5 | export default [ 6 | { 7 | ignores: [], 8 | }, 9 | ...baseConfig, 10 | ]; 11 | -------------------------------------------------------------------------------- /packages/hooks/eslint.config.js: -------------------------------------------------------------------------------- 1 | import baseConfig from "@good-dog/eslint/base"; 2 | import reactConfig from "@good-dog/eslint/react"; 3 | 4 | /** @type {import('typescript-eslint').Config} */ 5 | export default [ 6 | { 7 | ignores: [], 8 | }, 9 | ...baseConfig, 10 | ...reactConfig, 11 | ]; 12 | -------------------------------------------------------------------------------- /packages/trpc/eslint.config.js: -------------------------------------------------------------------------------- 1 | import baseConfig from "@good-dog/eslint/base"; 2 | import reactConfig from "@good-dog/eslint/react"; 3 | 4 | /** @type {import('typescript-eslint').Config} */ 5 | export default [ 6 | { 7 | ignores: [], 8 | }, 9 | ...baseConfig, 10 | ...reactConfig, 11 | ]; 12 | -------------------------------------------------------------------------------- /packages/ui/eslint.config.js: -------------------------------------------------------------------------------- 1 | import baseConfig from "@good-dog/eslint/base"; 2 | import reactConfig from "@good-dog/eslint/react"; 3 | 4 | /** @type {import('typescript-eslint').Config} */ 5 | export default [ 6 | { 7 | ignores: [], 8 | }, 9 | ...baseConfig, 10 | ...reactConfig, 11 | ]; 12 | -------------------------------------------------------------------------------- /packages/components/eslint.config.js: -------------------------------------------------------------------------------- 1 | import baseConfig from "@good-dog/eslint/base"; 2 | import reactConfig from "@good-dog/eslint/react"; 3 | 4 | /** @type {import('typescript-eslint').Config} */ 5 | export default [ 6 | { 7 | ignores: [], 8 | }, 9 | ...baseConfig, 10 | ...reactConfig, 11 | ]; 12 | -------------------------------------------------------------------------------- /.github/actions/setup-bun/action.yml: -------------------------------------------------------------------------------- 1 | name: "Setup and install" 2 | description: "Setup and install Bun" 3 | 4 | runs: 5 | using: composite 6 | steps: 7 | - uses: oven-sh/setup-bun@v1 8 | with: 9 | bun-version: 1.1.27 10 | 11 | - shell: bash 12 | run: bun install --frozen-lockfile 13 | -------------------------------------------------------------------------------- /packages/auth/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@good-dog/typescript/base.json", 3 | "compilerOptions": { 4 | "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json", 5 | "lib": ["es2022"], 6 | "types": ["bun"] 7 | }, 8 | "include": ["*.ts", "src"], 9 | "exclude": ["node_modules"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/email/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@good-dog/typescript/base.json", 3 | "compilerOptions": { 4 | "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json", 5 | "lib": ["es2022"], 6 | "types": ["bun"] 7 | }, 8 | "include": ["*.ts", "src"], 9 | "exclude": ["node_modules"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/components/src/oldStuff/form/types.ts: -------------------------------------------------------------------------------- 1 | import type { FieldValues, Path } from "react-hook-form"; 2 | 3 | export interface GoodDogFieldBaseProps { 4 | name: Path; 5 | label: string; 6 | description?: React.ReactNode | string; 7 | required?: boolean; 8 | placeholder?: string; 9 | } 10 | -------------------------------------------------------------------------------- /packages/components/utils/allCapsListFormatter.ts: -------------------------------------------------------------------------------- 1 | export function formatAllCapsList(list: string[]): string { 2 | return list 3 | .map((word) => 4 | word 5 | .split("_") 6 | .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()) 7 | .join(" "), 8 | ) 9 | .join(", "); 10 | } 11 | -------------------------------------------------------------------------------- /packages/env/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@good-dog/typescript/base.json", 3 | "compilerOptions": { 4 | "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json", 5 | "lib": ["es2022"], 6 | "types": ["bun"], 7 | "allowJs": true 8 | }, 9 | "include": ["src"], 10 | "exclude": ["node_modules"] 11 | } 12 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Next.js", 6 | "type": "node-terminal", 7 | "request": "launch", 8 | "command": "bun dev", 9 | "cwd": "${workspaceFolder}/apps/web/", 10 | "skipFiles": ["/**"] 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /packages/db/prisma/migrations/20250920203043_remove_email_confirmed_column/migration.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Warnings: 3 | 4 | - You are about to drop the column `emailConfirmed` on the `EmailVerificationCode` table. All the data in the column will be lost. 5 | 6 | */ 7 | -- AlterTable 8 | ALTER TABLE "EmailVerificationCode" DROP COLUMN "emailConfirmed"; 9 | -------------------------------------------------------------------------------- /packages/db/prisma/migrations/20251109181338_remove_referral/migration.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Warnings: 3 | 4 | - You are about to drop the column `referral` on the `User` table. All the data in the column will be lost. 5 | 6 | */ 7 | -- AlterTable 8 | ALTER TABLE "User" DROP COLUMN "referral"; 9 | 10 | -- DropEnum 11 | DROP TYPE "ReferralSource"; 12 | -------------------------------------------------------------------------------- /packages/db/prisma/migrations/20241016233845_first_migration/migration.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Warnings: 3 | 4 | - You are about to drop the column `token` on the `Session` table. All the data in the column will be lost. 5 | 6 | */ 7 | -- DropIndex 8 | DROP INDEX "Session_token_key"; 9 | 10 | -- AlterTable 11 | ALTER TABLE "Session" DROP COLUMN "token"; 12 | -------------------------------------------------------------------------------- /packages/db/src/index.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from "@prisma/client"; 2 | 3 | export const prisma = new PrismaClient(); 4 | 5 | // Re-export prisma types and enums here if needed for other packages 6 | export { 7 | Role, 8 | MatchState, 9 | MusicAffiliation, 10 | MusicRole, 11 | Genre, 12 | ProjectType, 13 | } from "@prisma/client"; 14 | -------------------------------------------------------------------------------- /packages/db/prisma/migrations/20251123021548_add_song_request_titles/migration.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Warnings: 3 | 4 | - Added the required column `songRequestTitle` to the `SongRequest` table without a default value. This is not possible if the table is not empty. 5 | 6 | */ 7 | -- AlterTable 8 | ALTER TABLE "SongRequest" ADD COLUMN "songRequestTitle" TEXT NOT NULL; 9 | -------------------------------------------------------------------------------- /packages/hooks/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@good-dog/typescript/base.json", 3 | "compilerOptions": { 4 | "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json", 5 | "jsx": "preserve", 6 | "lib": ["es2022", "dom", "dom.iterable"], 7 | "types": ["bun"] 8 | }, 9 | "include": ["*.ts", "src"], 10 | "exclude": ["node_modules"] 11 | } 12 | -------------------------------------------------------------------------------- /tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@good-dog/typescript/base.json", 3 | "compilerOptions": { 4 | "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json", 5 | "lib": ["es2022", "dom"], 6 | "types": ["bun", "react/canary"], 7 | "jsx": "preserve" 8 | }, 9 | "include": ["**/*.tsx", "**/*.ts"], 10 | "exclude": ["node_modules"] 11 | } 12 | -------------------------------------------------------------------------------- /apps/web/app/(pages)/profile/page.tsx: -------------------------------------------------------------------------------- 1 | import PageContainer from "@good-dog/components/PageContainer"; 2 | import ProfileWidget from "@good-dog/components/user-onboarding/widgets/profile/ProfileWidget"; 3 | 4 | export default function Page() { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /packages/db/prisma/migrations/20251111183252_reformat_genres/migration.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Warnings: 3 | 4 | - The `genres` column on the `MusicSubmission` table would be dropped and recreated. This will lead to data loss if there is data in the column. 5 | 6 | */ 7 | -- AlterTable 8 | ALTER TABLE "MusicSubmission" DROP COLUMN "genres", 9 | ADD COLUMN "genres" "Genre"[]; 10 | -------------------------------------------------------------------------------- /packages/ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@good-dog/typescript/internal-package.json", 3 | "compilerOptions": { 4 | "lib": ["dom", "dom.iterable", "ES2022"], 5 | "jsx": "preserve", 6 | "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json" 7 | }, 8 | "include": ["*.ts", "*.tsx", "shad", "declarations.d.ts"], 9 | "exclude": ["node_modules"] 10 | } 11 | -------------------------------------------------------------------------------- /turbo/generators/templates/tsconfig.json.hbs: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@good-dog/typescript/base.json", 3 | "compilerOptions": { 4 | "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json", 5 | "jsx": "preserve", 6 | "lib": ["es2022", "dom", "dom.iterable"], 7 | "types": ["bun"] 8 | }, 9 | "include": ["*.ts", "src"], 10 | "exclude": ["node_modules"] 11 | } 12 | -------------------------------------------------------------------------------- /apps/web/eslint.config.js: -------------------------------------------------------------------------------- 1 | import baseConfig from "@good-dog/eslint/base"; 2 | import nextjsConfig from "@good-dog/eslint/nextjs"; 3 | import reactConfig from "@good-dog/eslint/react"; 4 | 5 | /** @type {import('typescript-eslint').Config} */ 6 | export default [ 7 | { 8 | ignores: [".next/**"], 9 | }, 10 | ...baseConfig, 11 | ...reactConfig, 12 | ...nextjsConfig, 13 | ]; 14 | -------------------------------------------------------------------------------- /packages/components/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@good-dog/typescript/base.json", 3 | "compilerOptions": { 4 | "lib": ["es2022", "dom", "dom.iterable"], 5 | "jsx": "preserve", 6 | "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json", 7 | "types": ["bun"] 8 | }, 9 | "include": ["*.ts", "src", "src/svg", "utils"], 10 | "exclude": ["node_modules"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/components/src/base/NotificationBadge.tsx: -------------------------------------------------------------------------------- 1 | export function NotificationBadge({ number }: { number: number }) { 2 | return ( 3 |
4 |
5 | {number} 6 |
7 |
8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /packages/trpc/src/schema/README.md: -------------------------------------------------------------------------------- 1 | # Schema 2 | 3 | This directory contains the schema definitions for the endpoints and frontend forms. These schemas should be shared between the backend and frontend to simplify validation 4 | 5 | Try to organize the schemas in a way that makes sense, and then export them in the [index.ts](./index.ts) file. This will allow you to import them easily in other files. 6 | -------------------------------------------------------------------------------- /apps/web/app/(pages)/login/page.tsx: -------------------------------------------------------------------------------- 1 | import PageContainer from "@good-dog/components/PageContainer"; 2 | import UserOnboarding from "@good-dog/components/user-onboarding/UserOnboarding"; 3 | 4 | export default function Page() { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /apps/web/app/(pages)/signup/page.tsx: -------------------------------------------------------------------------------- 1 | import PageContainer from "@good-dog/components/PageContainer"; 2 | import UserOnboarding from "@good-dog/components/user-onboarding/UserOnboarding"; 3 | 4 | export default function Page() { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /apps/web/app/(pages)/project-submission/page.tsx: -------------------------------------------------------------------------------- 1 | import PageContainer from "@good-dog/components/PageContainer"; 2 | import ProjectSubmissionWidget from "@good-dog/components/submit/project/ProjectSubmissionWidget"; 3 | 4 | export default function SubmissionForm() { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | postgres: 5 | image: postgres:15 6 | restart: always 7 | environment: 8 | POSTGRES_DB: "${POSTGRES_DATABASE}" 9 | POSTGRES_USER: "${POSTGRES_USER}" 10 | POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}" 11 | volumes: 12 | - ./volumes/postgres:/var/lib/postgresql/data 13 | ports: 14 | - "${POSTGRES_PORT}:5432" 15 | -------------------------------------------------------------------------------- /apps/web/app/(pages)/signup/musician/page.tsx: -------------------------------------------------------------------------------- 1 | import PageContainer from "@good-dog/components/PageContainer"; 2 | import UserOnboarding from "@good-dog/components/user-onboarding/UserOnboarding"; 3 | 4 | export default function Page() { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /apps/web/app/(pages)/forgot-password/page.tsx: -------------------------------------------------------------------------------- 1 | import PageContainer from "@good-dog/components/PageContainer"; 2 | import UserOnboarding from "@good-dog/components/user-onboarding/UserOnboarding"; 3 | 4 | export default function Page() { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /apps/web/app/(pages)/reset-password/page.tsx: -------------------------------------------------------------------------------- 1 | import PageContainer from "@good-dog/components/PageContainer"; 2 | import UserOnboarding from "@good-dog/components/user-onboarding/UserOnboarding"; 3 | 4 | export default function Page() { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /apps/web/app/(pages)/signup/media-maker/page.tsx: -------------------------------------------------------------------------------- 1 | import PageContainer from "@good-dog/components/PageContainer"; 2 | import UserOnboarding from "@good-dog/components/user-onboarding/UserOnboarding"; 3 | 4 | export default function Page() { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /packages/ui/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is not used for any compilation purpose, it is only used 3 | * for Tailwind Intellisense & Autocompletion in the source files 4 | */ 5 | import type { Config } from "tailwindcss"; 6 | 7 | import baseConfig from "@good-dog/tailwind/web"; 8 | 9 | export default { 10 | content: ["./shad/**/*.{ts,tsx}"], 11 | presets: [baseConfig], 12 | } satisfies Config; 13 | -------------------------------------------------------------------------------- /tests/mocks/MockNextCache.ts: -------------------------------------------------------------------------------- 1 | import { mock } from "bun:test"; 2 | 3 | // Mocks the next/cache module 4 | export class MockNextCache { 5 | async apply() { 6 | await mock.module("next/cache", () => this); 7 | } 8 | 9 | clear() { 10 | this.revalidatePath.mockClear(); 11 | } 12 | 13 | readonly revalidatePath = 14 | mock<(originalPath: string, type?: "layout" | "page") => void>(); 15 | } 16 | -------------------------------------------------------------------------------- /apps/web/next.config.ts: -------------------------------------------------------------------------------- 1 | import type { NextConfig } from "next"; 2 | 3 | import { env } from "@good-dog/env"; 4 | 5 | /** 6 | * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful 7 | * for Docker builds. 8 | */ 9 | env; 10 | 11 | const config: NextConfig = { 12 | experimental: { 13 | authInterrupts: true, 14 | }, 15 | }; 16 | 17 | export default config; 18 | -------------------------------------------------------------------------------- /packages/components/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is not used for any compilation purpose, it is only used 3 | * for Tailwind Intellisense & Autocompletion in the source files 4 | */ 5 | import type { Config } from "tailwindcss"; 6 | 7 | import baseConfig from "@good-dog/tailwind/web"; 8 | 9 | export default { 10 | content: ["./src/**/*.{ts,tsx}"], 11 | presets: [baseConfig], 12 | } satisfies Config; 13 | -------------------------------------------------------------------------------- /packages/trpc/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@good-dog/typescript/base.json", 3 | "compilerOptions": { 4 | "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json", 5 | "allowSyntheticDefaultImports": true, 6 | "jsx": "preserve", 7 | "lib": ["es2022", "dom", "dom.iterable"], 8 | "types": ["bun", "react/canary"] 9 | }, 10 | "include": ["*.ts", "src"], 11 | "exclude": ["node_modules"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/src/oldStuff/loading/Spinner.tsx: -------------------------------------------------------------------------------- 1 | export function Spinner({ className = "" }: { className?: string }) { 2 | return ( 3 |
7 | Loading... 8 |
9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /packages/ui/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "tailwind": { 5 | "config": "tailwind.config.js", 6 | "css": "app/globals.css", 7 | "baseColor": "slate", 8 | "cssVariables": true 9 | }, 10 | "rsc": false, 11 | "aliases": { 12 | "utils": "@good-dog/ui", 13 | "components": "@good-dog/ui", 14 | "ui": "@good-dog/ui" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /apps/web/app/(pages)/music-submission/page.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import PageContainer from "@good-dog/components/PageContainer"; 4 | import MusicSubmissionWidget from "@good-dog/components/submit/music/MusicSubmissionWidget"; 5 | 6 | export default function MusicSubmissionPage() { 7 | return ( 8 | 9 | 10 | 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /packages/trpc/src/schema/index.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | export const zPreProcessEmptyString = (schema: I) => 4 | z.preprocess((arg) => { 5 | if (typeof arg === "string" && arg === "") { 6 | return undefined; 7 | } else { 8 | return arg; 9 | } 10 | }, schema); 11 | 12 | // Re-export all the schemas from sub-files 13 | export * from "./auth"; 14 | export * from "./submit"; 15 | -------------------------------------------------------------------------------- /tests/eslint.config.js: -------------------------------------------------------------------------------- 1 | import baseConfig from "@good-dog/eslint/base"; 2 | import reactConfig from "@good-dog/eslint/react"; 3 | 4 | /** @type {import('typescript-eslint').Config} */ 5 | export default [ 6 | ...baseConfig, 7 | ...reactConfig, 8 | { 9 | ignores: [], 10 | rules: { 11 | "@typescript-eslint/no-non-null-assertion": "off", 12 | "@typescript-eslint/no-unsafe-assignment": "off", 13 | }, 14 | }, 15 | ]; 16 | -------------------------------------------------------------------------------- /packages/db/prisma/migrations/20250202214637_add_phone_number/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "User" ADD COLUMN "phoneNumber" TEXT NOT NULL DEFAULT ''; 3 | -- AlterTable remove default value 4 | ALTER TABLE "User" ALTER COLUMN "phoneNumber" DROP DEFAULT; 5 | 6 | -- AlterTable 7 | ALTER TABLE "_songWriters" ADD CONSTRAINT "_songWriters_AB_pkey" PRIMARY KEY ("A", "B"); 8 | 9 | -- DropIndex 10 | DROP INDEX "_songWriters_AB_unique"; 11 | -------------------------------------------------------------------------------- /packages/components/src/oldStuff/registration/index.tsx: -------------------------------------------------------------------------------- 1 | import ForgotPasswordForm from "./ForgotPassword"; 2 | import RegistrationPageLayout from "./RegistrationPageLayout"; 3 | import ResetPasswordForm from "./ResetPassword"; 4 | import SignInForm from "./SignInForm"; 5 | import SignUpForm from "./SignUpForm"; 6 | 7 | export { 8 | SignUpForm, 9 | SignInForm, 10 | ForgotPasswordForm, 11 | ResetPasswordForm, 12 | RegistrationPageLayout, 13 | }; 14 | -------------------------------------------------------------------------------- /packages/ui/shad/label.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import * as LabelPrimitive from "@radix-ui/react-label"; 3 | 4 | const Label = React.forwardRef< 5 | React.ElementRef, 6 | React.ComponentPropsWithoutRef 7 | >(({ className, ...props }, ref) => ( 8 | 9 | )); 10 | Label.displayName = LabelPrimitive.Root.displayName; 11 | 12 | export { Label }; 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | node_modules 3 | 4 | # Local env files 5 | .env 6 | .env.local 7 | .env.development.local 8 | .env.test.local 9 | .env.production.local 10 | 11 | # Testing 12 | coverage 13 | 14 | # Turbo 15 | .turbo 16 | 17 | # Vercel 18 | .vercel 19 | 20 | # Build Outputs 21 | .next/ 22 | out/ 23 | build 24 | dist 25 | 26 | # Debug 27 | npm-debug.log* 28 | yarn-debug.log* 29 | yarn-error.log* 30 | 31 | # Volumes 32 | volumes/* 33 | 34 | # Misc 35 | .DS_Store 36 | *.pem 37 | -------------------------------------------------------------------------------- /packages/db/prisma/migrations/20241108002053_email_verification_code/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateTable 2 | CREATE TABLE "EmailVerificationCode" ( 3 | "email" TEXT NOT NULL, 4 | "code" TEXT NOT NULL, 5 | "emailConfirmed" BOOLEAN NOT NULL DEFAULT false, 6 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, 7 | "updatedAt" TIMESTAMP(3) NOT NULL, 8 | "expiresAt" TIMESTAMP(3) NOT NULL, 9 | 10 | CONSTRAINT "EmailVerificationCode_pkey" PRIMARY KEY ("email") 11 | ); 12 | -------------------------------------------------------------------------------- /packages/components/src/music/MusicDashboard.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import MusicInformation from "./components/MusicInformation"; 4 | import MatchInformation from "./components/MatchInformation"; 5 | 6 | export default function MusicDashboard({ musicId }: { musicId: string }) { 7 | return ( 8 |
9 | 10 | 11 |
12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /packages/trpc/src/procedures/admin-view.ts: -------------------------------------------------------------------------------- 1 | import { adminPagePermissions } from "@good-dog/auth/permissions"; 2 | 3 | import { rolePermissionsProcedureBuilder } from "../middleware/role-check"; 4 | 5 | export const getAdminViewProcedure = rolePermissionsProcedureBuilder( 6 | adminPagePermissions, 7 | "read", 8 | ).query(async ({ ctx }) => { 9 | const [users] = await Promise.all([ 10 | ctx.prisma.user.findMany({ omit: { hashedPassword: true } }), 11 | ]); 12 | return { users }; 13 | }); 14 | -------------------------------------------------------------------------------- /packages/components/src/oldStuff/submit/project/sections/FinalProjectDetails.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React from "react"; 4 | 5 | import { ProjectSubmissionTextarea } from "../common"; 6 | 7 | export default function FinalProjectDetails() { 8 | return ( 9 | 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /packages/db/prisma/migrations/20241031000211_new_user_fields/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateEnum 2 | CREATE TYPE "Role" AS ENUM ('MUSICIAN', 'MEDIA_MAKER', 'ADMIN'); 3 | 4 | -- AlterTable 5 | ALTER TABLE "User" 6 | RENAME COLUMN "name" TO "firstName"; 7 | 8 | -- AlterTable 9 | ALTER TABLE "User" 10 | ADD COLUMN "lastName" TEXT NOT NULL DEFAULT '', 11 | ADD COLUMN "role" "Role" NOT NULL DEFAULT 'MEDIA_MAKER'; 12 | 13 | -- RemoveDefault 14 | ALTER TABLE "User" 15 | ALTER COLUMN "lastName" DROP DEFAULT, 16 | ALTER COLUMN "role" DROP DEFAULT; -------------------------------------------------------------------------------- /tests/mocks/util.ts: -------------------------------------------------------------------------------- 1 | import { 2 | deleteSessionCookieBuilder, 3 | getSessionCookieBuilder, 4 | setSessionCookieBuilder, 5 | } from "@good-dog/auth/cookies"; 6 | 7 | import type { MockNextCookies } from "./MockNextCookies"; 8 | 9 | export const createMockCookieService = (cookies: MockNextCookies) => { 10 | return { 11 | getSessionCookie: getSessionCookieBuilder(cookies), 12 | setSessionCookie: setSessionCookieBuilder(cookies), 13 | deleteSessionCookie: deleteSessionCookieBuilder(cookies), 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /packages/components/src/user-onboarding/widgets/UserOnboardingWidgetContainer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | interface UserOnboardingWidgetContainerProps { 4 | children: React.ReactNode; 5 | } 6 | 7 | export default function UserOnboardingWidgetContainer({ 8 | children, 9 | }: UserOnboardingWidgetContainerProps) { 10 | return ( 11 |
12 | {children} 13 |
14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /packages/db/prisma/migrations/20250314225857_unlicensed-music/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateTable 2 | CREATE TABLE "UnlicensedMusic" ( 3 | "musicId" TEXT NOT NULL, 4 | "songName" TEXT NOT NULL, 5 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, 6 | "updatedAt" TIMESTAMP(3) NOT NULL, 7 | "artist" TEXT NOT NULL, 8 | "songLink" TEXT NOT NULL, 9 | "genre" TEXT NOT NULL, 10 | "additionalInfo" TEXT NOT NULL DEFAULT '', 11 | 12 | CONSTRAINT "UnlicensedMusic_pkey" PRIMARY KEY ("musicId") 13 | ); 14 | -------------------------------------------------------------------------------- /.github/workflows/apply-migrations.yml: -------------------------------------------------------------------------------- 1 | name: Apply Database Migrations 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | migrate: 10 | runs-on: ubuntu-latest 11 | env: 12 | DATABASE_PRISMA_URL: ${{ secrets.DATABASE_PRISMA_URL }} 13 | 14 | steps: 15 | - name: Checkout code 16 | uses: actions/checkout@v4 17 | 18 | - uses: ./.github/actions/setup-bun 19 | 20 | - name: Apply Migrations 21 | run: bun prisma migrate deploy --schema=./packages/db/prisma/schema.prisma 22 | -------------------------------------------------------------------------------- /packages/auth/src/password.ts: -------------------------------------------------------------------------------- 1 | import bcrypt from "bcryptjs"; 2 | 3 | const SALT_ROUNDS = 10; // Number of salt rounds (higher is more secure, but slower) 4 | 5 | const hashPassword = async (password: string) => { 6 | const salt = await bcrypt.genSalt(SALT_ROUNDS); 7 | return await bcrypt.hash(password, salt); 8 | }; 9 | 10 | const comparePassword = async (password: string, hash: string) => { 11 | return await bcrypt.compare(password, hash); 12 | }; 13 | 14 | export const passwordService = { 15 | hashPassword, 16 | comparePassword, 17 | }; 18 | -------------------------------------------------------------------------------- /packages/ui/shad/textarea.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import { cn } from "@good-dog/ui"; 4 | 5 | export type TextareaProps = React.TextareaHTMLAttributes; 6 | 7 | const Textarea = React.forwardRef( 8 | ({ className, ...props }, ref) => { 9 | return ( 10 |