Files
publisher-dashboard/CLAUDE.md
igm f9f1dc7403
Some checks failed
CI / ci (push) Has been cancelled
Merge branch 'test-coverage'
2026-01-12 15:08:49 +08:00

3.1 KiB

Claude Code Notes

Running Tests

Use bun run test:cov to run all tests with coverage. This runs both unit tests and e2e tests that require a database connection.

  • bun run test:cov - Run all tests with coverage (preferred)
  • bun run test:unit:cov - Run only unit tests with coverage (no database required)

Database Scripts

Use the wrapper scripts instead of running dbmate directly:

  • ./scripts/db-dump - Dump schema without random \restrict tokens
  • ./scripts/db-migrate - Run migrations and dump clean schema

PostgreSQL 17.6+ adds random \restrict/\unrestrict lines to pg_dump output (CVE-2025-8714 fix), causing schema.sql to show as changed on every dump. These scripts strip those lines.

Development Server

Before starting the dev server, check if it's already running:

  • Use lsof -i :6827 or check for existing background tasks
  • The dev server runs on port 6827 (may fall back to 6828 if port is in use)
  • Start with bun run --cwd apps/publisher-dashboard dev or devenv up

Pull Requests

This repo uses Gitea (git.rev.iq) with the tea CLI for pull requests:

  • Use the /gitea skill when creating PRs
  • tea 0.10.1 is pinned in nix/tea.nix (0.11.x has TTY bugs)
  • Always specify -r igm/publisher-dashboard flag (SSH remote auto-detection doesn't work)

sed Syntax (GNU coreutils)

This project uses GNU coreutils via devenv, so use standard GNU sed syntax:

  • In-place edit: sed -i 's/old/new/g' file
  • Use | as delimiter when patterns contain /: sed -i 's|old/path|new/path|g' file
  • For multiple files: for f in *.txt; do sed -i 's/old/new/g' "$f"; done
  • Do NOT use BSD sed syntax (sed -i '') - we have GNU sed available

SvelteKit resolve() Usage

Use resolve() from $app/paths for type-safe navigation. The patterns are:

Static routes - use resolve() directly

href={resolve("/auth/login")}
href={resolve("/dashboard")}

Dynamic routes - use two-argument form

href={resolve("/dashboard/[slug]", { slug: orgSlug })}
href={resolve("/account/org-invites/[inviteId]", { inviteId: String(invite.id) })}

Login redirects - use gotoLogin helper

For redirecting to login with a return URL, use the helper from $lib/utils/navigation:

import { gotoLogin } from "$lib/utils/navigation";

gotoLogin(page.url.pathname);

This helper uses resolve() internally and handles the query string correctly.

Navigation arrays - use as const with route patterns

For type-safe navigation arrays, define routes as literal strings with as const:

const navItems = [
  { route: "/dashboard/[slug]/settings", icon: Settings, label: "General" },
  { route: "/dashboard/[slug]/settings/members", icon: Users, label: "Members" },
] as const;

Then use resolve with params:

{#each navItems as item (item.route)}
  <a href={resolve(item.route, { slug })}>
{/each}

Runtime strings - skip resolve, use eslint-disable

When paths are fully dynamic (e.g., server-provided redirects), skip resolve:

// eslint-disable-next-line svelte/no-navigation-without-resolve
goto(redirectUrl);