Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
b44e631
refactor(db): use modern drizzle object connection syntax for Turso
AndersonDesign1 Jun 11, 2026
5e38977
chore: ignore plans and mcps directories
AndersonDesign1 Jun 20, 2026
58cf3d6
fix(auth): prevent self-assigned admin role at signup
AndersonDesign1 Jun 20, 2026
d72a3cd
fix(db): stop seeding demo data from request handlers
AndersonDesign1 Jun 20, 2026
5578f08
chore(lint): restore green lint gate
AndersonDesign1 Jun 20, 2026
14cab9e
perf(db): add indexes on hot foreign-key columns
AndersonDesign1 Jun 20, 2026
b05912d
test(db): characterize access control and invite lifecycle
AndersonDesign1 Jun 20, 2026
d479415
chore(deps): update compatible dependencies
AndersonDesign1 Jun 21, 2026
5774c95
ci: add quality workflow for lint, typecheck, test, and build
AndersonDesign1 Jun 21, 2026
60431e2
fix: require BETTER_AUTH_SECRET in production and normalize milestone…
AndersonDesign1 Jun 21, 2026
d05e550
docs: add CLAUDE.md for agent onboarding
AndersonDesign1 Jun 21, 2026
5f30fe5
docs(adr): multi-tenancy direction decision memo
AndersonDesign1 Jun 21, 2026
33f7576
docs(adr): colleague-invite complete-or-remove decision memo
AndersonDesign1 Jun 21, 2026
ae2c5fc
refactor(db): extract invites domain into src/db/invites.ts
AndersonDesign1 Jun 21, 2026
94aff17
fix(ci/db): pin Bun version, migration FK, and client link validation
AndersonDesign1 Jun 21, 2026
f17ca51
fix(invites): defer colleague invite email until admin approval
AndersonDesign1 Jun 21, 2026
5ce3922
fix(security): scope admin access to active organization
AndersonDesign1 Jun 21, 2026
44a59ad
fix(security): scope project PATCH/DELETE to active organization
AndersonDesign1 Jun 21, 2026
297126d
fix(security): scope all admin mutations to active organization
AndersonDesign1 Jun 21, 2026
f606ae2
fix(invites): address Greptile review findings
AndersonDesign1 Jun 22, 2026
066043d
fix(review): address PR #21 review comments
AndersonDesign1 Jun 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Quality

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
push:
branches: [main]

permissions:
contents: read

concurrency:
group: quality-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
quality:
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.3.12
- run: bun install --frozen-lockfile
- run: bun run lint
- run: bun run typecheck
- run: bun run test
- run: bun run build
# Advisory only: bun audit reports dev-tooling CVEs with no production fix yet.
- run: bun audit || true
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ count.txt
__unconfig*
todos.json
local.db
react-doctor-report.json
react-doctor-report.json
plans/
mcps/
77 changes: 77 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# CLAUDE.md

Guidance for AI agents and new contributors working in this repo. For product
intent see `PRD.md`, for roadmap/status see `phases.md`, and for the latest
hardening audit see `docs/audits/production-readiness-audit.md`.

## What this is

Clientra — a deliberately lightweight client/project management app for
freelancers and small agencies. An **admin** (the operator) manages clients and
projects; external **clients** get a read-mostly portal.

**Non-goals (do not build these):** enterprise CRM workflows, marketing/sales
pipelines, complex automation, and billing/invoicing/payments. Keep changes
lightweight and in line with `PRD.md`.

## Stack

TanStack Start (React 19) · Drizzle ORM + Turso (libSQL/SQLite) · Better Auth ·
Zod · Bun · Vitest · Biome + Ultracite · Tailwind v4 + shadcn/ui.

## Commands

- `bun dev` — dev server (port 3000)
- `bun run test` — Vitest
- `bun run lint` — Biome (via Ultracite)
- `bun run typecheck` — `tsc --noEmit`
- `bun run build` — Vite build
- `bun run db:studio` — Drizzle Studio
- `bun run db:sync` — push schema + seed (local/dev)

Before opening a PR, all of `lint`, `typecheck`, `test`, and `build` must pass.

## Layout

- `src/routes/**` — pages; `src/routes/api/**` — server route handlers.
- `src/server/http/route-utils.ts` — request guards: `requireSessionRequest`,
`requireMutationSessionRequest`, `requireAdminMutationRequest`,
`requireSameOrigin`, plus JSON/error helpers. Use these; don't hand-roll auth.
- `src/db/records.ts` — the data-access layer (large; being split by domain).
- `src/db/schema.ts` — Drizzle schema; migrations live in `drizzle/` and are
generated with `drizzle-kit generate`.
- `src/auth/**` — Better Auth config (`better-auth.ts`), roles (`roles.ts`),
session helpers (`session.server.ts`).
- `src/lib/api.ts` — client-side fetch + React Query hooks (large; being split).
- `src/__tests__/**` — tests. DB-backed tests apply `drizzle/*.sql` to a temp
`file:` libSQL database — see `records-collaboration.test.ts` for the pattern.

## Conventions

- **Auth on every mutating route**: same-origin + session (+ role/ownership)
checks via the guards in `route-utils.ts`. Client-reachable routes that touch a
project/file/note must call `canAccessProject` (in `records.ts`).
- **Validate input with Zod** via `parseJsonBody(request, schema)` before use.
- **Roles**: `ROLES.ADMIN` / `ROLES.CLIENT` from `src/auth/roles.ts` — never
hardcode the strings. The `role` field is server-controlled (not settable at
signup).
- **Error handling**: return the typed helpers from `route-utils.ts`
(`unauthorizedError`, `forbiddenError`, `notFoundError`, …), not ad-hoc responses.
- Match the surrounding file's style; run `bun run fix` (Ultracite) to auto-format.

## Known debt / gotchas

- `src/db/records.ts` and `src/lib/api.ts` are oversized and being split by domain
(see `plans/`). Prefer adding to the right domain seam over growing them.
- `src/components/evilcharts/**` is vendored chart code and is excluded from
linting — don't hand-fix lint there.
- Seeding (`seedIfEmpty`) is for local/dev only — enforced by a non-local DB
guard; it must not run from request handlers or against production Turso.
- Multi-tenancy (Better Auth `organization` plugin + `organizationId` columns) is
partially wired — confirm scoping before relying on it.

## Where to look first

- A bug in data access → `src/db/records.ts` + the matching `src/__tests__/` file.
- An auth/access question → `src/auth/` + `src/server/http/route-utils.ts`.
- A page/data-flow question → the route in `src/routes/` + `src/lib/api.ts`.
6 changes: 6 additions & 0 deletions biome.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,11 @@
"ultracite/biome/core",
"ultracite/biome/react",
"ultracite/biome/vitest"
],
"overrides": [
{
"includes": ["src/components/evilcharts/**"],
"linter": { "enabled": false }
}
]
}
Loading
Loading