PackagesServer Package

Server Packages

Backend services and data layer: @uwdsc/db, @uwdsc/core, and @uwdsc/admin.

Overview

The packages/server/ directory contains three sub-packages. There is no Prisma; data access uses postgres.js (via @uwdsc/db) and Supabase for auth and storage.

Sub-packages:

  • @uwdsc/db β€” Database connection, Supabase clients, BaseRepository, migrations
  • @uwdsc/core β€” Shared services and repositories used by web and admin apps
  • @uwdsc/admin β€” Admin-only services (e.g. member management for admin dashboard)

Structure

packages/server/
β”œβ”€β”€ db/              # @uwdsc/db
β”‚   └── src/
β”‚       β”œβ”€β”€ config/       # connection, supabase, baseRepository
β”‚       └── migrations/   # db-migrate SQL files
β”œβ”€β”€ core/            # @uwdsc/core
β”‚   └── src/
β”‚       β”œβ”€β”€ services/     # Auth, Profile, Application, File, Resume, Team
β”‚       β”œβ”€β”€ repositories/ # Data access (extend BaseRepository)
β”‚       └── ...
└── admin/           # @uwdsc/admin
    └── src/              # Admin-specific services (e.g. profileService for members)

@uwdsc/db

Purpose: Database connection, Supabase clients, base repository, migrations.

Exports:

  • @uwdsc/db/connection β€” Postgres sql (postgres.js)
  • @uwdsc/db/supabase β€” createSupabaseBrowserClient, createSupabaseServerClient, createSupabaseMiddlewareClient
  • @uwdsc/db/baseRepository β€” BaseRepository (abstract class with protected this.sql)

Tech: postgres.js (Supabase Transaction Pooler), Supabase JS/SSR, db-migrate. Run migrations from root: pnpm migrate, pnpm migrate:down, pnpm migrate:create <name>.

@uwdsc/core

Purpose: Shared services and repositories used by web and admin apps.

Exports: Service classes and singleton instances: profileService, applicationService, teamService. AuthService and ResumeService require a Supabase client and are created per-request in each app’s lib/services.ts via createAuthService() / createResumeService().

import { profileService, applicationService, teamService } from "@uwdsc/core";
import { AuthService, ResumeService } from "@uwdsc/core";

Contents:

  • Services: AuthService, ProfileService, ApplicationService, FileService, ResumeService, TeamService
  • Repositories: Extend BaseRepository from @uwdsc/db/baseRepository; use this.sql for queries
  • Dependencies: @uwdsc/db, @uwdsc/common

@uwdsc/admin

Purpose: Admin-only services (e.g. profile/member listing and updates for the admin dashboard).

Exports: Admin-specific profileService (and related) for member management.

import { profileService } from "@uwdsc/admin";

Used by: apps/admin API routes only. Dependencies: @uwdsc/core, @uwdsc/db, @uwdsc/common.

Usage

In API Routes (web or admin)

// apps/web/app/api/profile/route.ts
import { profileService } from "@uwdsc/core";
 
export async function GET() {
  const profile = await profileService.getProfileByUserId(user.id);
  return NextResponse.json(profile);
}
// apps/admin/app/api/members/route.ts
import { profileService } from "@uwdsc/admin";
 
export async function GET() {
  const members = await profileService.listMembers();
  return NextResponse.json(members);
}

Auth and resume (per-request)

Create Supabase-backed services in the app:

// apps/web/lib/services.ts
import { createSupabaseServerClient } from "@uwdsc/db";
import { AuthService, ResumeService } from "@uwdsc/core";
 
export async function createAuthService() {
  const supabase = await createSupabaseServerClient();
  return new AuthService(supabase);
}
 
export async function createResumeService() {
  const supabase = await createSupabaseServerClient();
  return new ResumeService(supabase);
}

Repository layer

Repositories extend BaseRepository and use this.sql (postgres.js):

import { BaseRepository } from "@uwdsc/db/baseRepository";
 
export class ProfileRepository extends BaseRepository {
  async findByUserId(userId: string) {
    const rows = await this.sql`SELECT * FROM profiles WHERE id = ${userId}`;
    return rows[0] ?? null;
  }
}

Database migrations

Migrations live in packages/server/db. From repo root:

  • pnpm migrate β€” apply
  • pnpm migrate:down β€” rollback last
  • pnpm migrate:create <name> β€” create new migration
  • pnpm migrate:check β€” status

Best practices

Do

  • Use services from @uwdsc/core or @uwdsc/admin in API routes
  • Use singletons (profileService, applicationService, teamService) where the service is stateless
  • Create AuthService/ResumeService per-request via lib/services.ts
  • Extend BaseRepository from @uwdsc/db/baseRepository for new repositories
  • Use ApiResponse from @uwdsc/common/utils in API routes when applicable

Don’t

  • Import server packages in React components β€” use client API functions from lib/api/
  • Put business logic in API routes or repositories
  • Access the database directly from API routes
  • Assume Prisma β€” the project uses postgres.js and Supabase

Next steps