From 9a1ec4e8a594e155c9bbb4e004a93906375720f1 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Tue, 31 Mar 2026 13:42:31 +1300 Subject: [PATCH] (docs): rewrite CLAUDE.md with comprehensive project conventions --- CLAUDE.md | 155 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 129 insertions(+), 26 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index c5c61cac0..e5ec7d524 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,33 +1,45 @@ # Appwrite Console -SvelteKit web dashboard for Appwrite. Manages projects, databases, functions, auth, storage, messaging, and sites. +SvelteKit web dashboard for Appwrite. Manages projects, databases, functions, auth, storage, messaging, and sites. Static SPA (no SSR) served behind Nginx at `/console`. ## Commands +All commands use **bun** (not pnpm/npm). + | Command | Purpose | |---------|---------| -| `pnpm dev` | Start dev server (port 3000) | -| `pnpm build` | Production build (`bun run build.js`) | -| `pnpm check` | `svelte-kit sync && svelte-check` | -| `pnpm format` | Prettier write + cache | -| `pnpm lint` | Prettier check + ESLint | -| `pnpm test:unit` | Vitest (TZ=EST) | -| `pnpm test:unit-watch` | Vitest watch mode | -| `pnpm test:e2e` | Playwright | -| `pnpm clean` | Remove node_modules, .svelte-kit, reinstall | +| `bun dev` | Dev server (port 3000) | +| `bun run build` | Production build (custom `build.js` via Vite) | +| `bun check` | `svelte-kit sync && svelte-check` | +| `bun format` | Prettier write + cache | +| `bun run lint` | Prettier check + ESLint | +| `bun tests` | Unit + E2E | +| `bun test:unit` | Vitest (TZ=EST) | +| `bun test:unit-watch` | Vitest watch mode | +| `bun test:e2e` | Playwright | +| `bun run clean` | Remove node_modules, .svelte-kit, reinstall | + +**Always run `bun format` before committing.** + +## CI checks (`.github/workflows/tests.yml`) + +Runs on PRs: `bun audit` -> `bun check` -> `bun run lint` -> `bun test:unit` -> `bun run build`. Uses frozen lockfile. ## Stack -- **Framework:** SvelteKit 2 + Svelte 5, TypeScript, static adapter -- **Bundler:** Vite (rolldown-vite) +- **Framework:** SvelteKit 2 + **Svelte 5** (runes), TypeScript, `@sveltejs/adapter-static` +- **Bundler:** Vite 7 (overridden to `rolldown-vite`) - **Design system:** `@appwrite.io/pink-svelte`, `@appwrite.io/pink-icons-svelte` -- **UI primitives:** Melt UI (`@melt-ui/svelte`) -- **API client:** `@appwrite.io/console` SDK +- **UI primitives:** Melt UI (`@melt-ui/svelte` with preprocessor) +- **API client:** `@appwrite.io/console` SDK (pinned to GitHub commit) - **Code editing:** CodeMirror 6 -- **Charts:** ECharts +- **Charts:** ECharts 5 +- **3D:** Three.js via Threlte - **Payments:** Stripe -- **Testing:** Vitest + @testing-library/svelte (unit), Playwright (e2e) +- **AI:** Vercel AI SDK (`@ai-sdk/svelte`) +- **Testing:** Vitest + @testing-library/svelte (unit), Playwright (E2E) - **Error tracking:** Sentry (`@sentry/sveltekit`) +- **Analytics:** Plausible + custom Growth endpoint ## Architecture @@ -49,26 +61,60 @@ Each route can have: - `store.ts` — route-scoped state - Feature components colocated alongside (e.g. `table.svelte`, `create.svelte`) +### Path aliases + +| Alias | Path | +|-------|------| +| `$lib` | `src/lib` (SvelteKit built-in) | +| `$routes` | `src/routes` | +| `$themes` | `src/themes` | +| `$database` | `src/routes/(console)/project-[region]-[project]/databases/database-[database]` | + ### Library (`src/lib/`) | Directory | Contents | |-----------|----------| -| `components/` | Feature components (billing, permissions, filters, etc.) | +| `components/` | Feature components (billing, permissions, filters, etc.) — barrel-exported via `index.ts` | | `elements/forms/` | Form inputs (text, email, phone, OTP, file, geometry, etc.) | | `elements/table/` | Table components | -| `layout/` | Shell, Container, Wizard, Breadcrumbs, Navigation | +| `layout/` | Shell, Container, Wizard, Breadcrumbs, Navigation — barrel-exported via `index.ts` | | `stores/` | Svelte stores for global state | | `helpers/` | Utilities (array, date, object, numbers, string, validation) | | `sdk/` | Custom SDK extensions (billing, usage, sources) | | `actions/` | Svelte actions and analytics tracking | -| `charts/` | Chart visualization components | +| `charts/` | Chart visualization components — barrel-exported via `index.ts` | | `commandCenter/` | Command palette | | `profiles/` | CSS profiles and theming | | `mock/` | Mock data for development | +### Imports + +Components use **barrel exports** — always import from the directory `index.ts`: +```typescript +import { Card, Modal, Steps } from '$lib/components'; +import { Shell, Container } from '$lib/layout'; +``` + +### Svelte 5 runes + +The codebase uses **Svelte 5 runes exclusively** — no legacy `export let` or `$:` syntax. + +```svelte + +``` + ### SDK usage (`src/lib/stores/sdk.ts`) -Three client instances: `clientConsole` (console API), `clientProject` (project API, admin mode), `clientRealtime` (realtime subscriptions). Region-aware endpoints with subdomain support (fra., nyc., syd., sfo., sgp., tor.). +Three client instances: `clientConsole` (console API), `clientProject` (project API, admin mode), `clientRealtime` (realtime subscriptions). Region-aware endpoints with subdomain routing (fra., nyc., syd., sfo., sgp., tor.). ```typescript import { sdk } from '$lib/stores/sdk'; @@ -83,7 +129,27 @@ await sdk.forConsoleIn(region).projects.get({ projectId }); await sdk.forProject(region, projectId).tablesDB.listTables(); ``` -### Data loading pattern +**Console SDK services:** Account, Avatars, Functions, Health, Locale, Projects, Teams, Users, Migrations, Console, Assistant, Sources, Sites, Domains, Storage, Realtime, Organizations + +**Project SDK services:** Account, Avatars, Backups, Functions, Health, Locale, Messaging, Project, Storage, Tokens, Teams, Users, VCS, Proxy, Migrations, Sites, TablesDB, DocumentsDB, Compute, VectorsDB, Webhooks, Console + +### Database types (feat-dedicated-db) + +The databases feature unifies four database backends behind a polymorph API (`$database/(entity)/helpers/sdk.ts`): + +| Type | Entity | Field | Record | Index types | +|------|--------|-------|--------|-------------| +| `tablesdb` | table | column | row | `TablesDBIndexType` | +| `documentsdb` | collection | attribute | document | `DocumentsDBIndexType` | +| `vectorsdb` | collection | attribute | document | `VectorsDBIndexType` | +| `dedicateddb` | table | column | row | managed externally | + +- `useDatabaseSdk()` returns a unified interface regardless of backing type +- `useTerminology()` returns singular/plural names for the current database type +- DedicatedDB uses the `Compute` service (not Appwrite schema APIs) — creates always-on PostgreSQL/MySQL instances via `compute.createDatabase()` with `Backend.Edge` +- `DatabaseType` union: `'legacy' | 'tablesdb' | 'documentsdb' | 'vectorsdb' | 'dedicateddb'` + +### Data loading Load functions declare dependencies for cache invalidation via `depends()`: ```typescript @@ -92,15 +158,31 @@ export const load: LayoutLoad = async ({ depends, parent, params }) => { return { database: await sdk.forProject(...).tablesDB.get(...) }; }; ``` -Invalidate with `await invalidate(Dependencies.DATABASE)` after mutations. +Invalidate with `await invalidate(Dependencies.DATABASE)` after mutations. Dependency keys are defined in `src/lib/constants.ts` as the `Dependencies` enum. ### State management -Stores in `src/lib/stores/` — writable, derived, and "conservative" (selective update) patterns. Key stores: `app`, `user`, `organization`, `projects`, `billing`, `wizard`, `notifications`, `sdk`. Stores often derive from SvelteKit's `page` store for route-aware state. +Stores in `src/lib/stores/` — writable, derived, and "conservative" (selective update via `createConservative()` from `$lib/helpers/stores`) patterns. Key stores: `app`, `user`, `organization`, `projects`, `billing`, `wizard`, `notifications`, `sdk`. Stores often derive from SvelteKit's `page` store for route-aware state. + +### Wizard pattern (`$lib/stores/wizard`) + +Modal wizard flow: `wizard.start(Component, media?, step?, props?)` to open, `wizard.hide()` to close. Supports `setInterceptor()` for async pre-step validation, `finalAction()` for completion, and `setNextDisabled()` for flow control. + +### Notifications (`$lib/stores/notifications`) + +```typescript +import { addNotification } from '$lib/stores/notifications'; +addNotification({ type: 'error', message: error.message }); +``` +Types: `'success' | 'error' | 'info' | 'warning'`. Auto-dismisses after 6s by default. Max 5 visible. + +### Analytics (`$lib/actions/analytics`) + +Plausible + custom Growth endpoint. Track events via `trackEvent(Click.* | Submit.*, data)` and errors via `trackError(exception, Submit.*)`. Respects `navigator.doNotTrack`. ### Theming -Four theme variants: `light`, `dark`, `light-cloud`, `dark-cloud` (JSON files in `src/themes/`). Resolved based on `isCloud` flag and user preference. +Four theme variants in `src/themes/`: `light`, `dark`, `light-cloud`, `dark-cloud`. Resolved based on `isCloud` flag and user preference. ### Modes (`src/lib/system.ts`) @@ -108,11 +190,32 @@ Two modes: `cloud` and `self-hosted`, set via `PUBLIC_CONSOLE_MODE` env var. Gat ## Code style -- **Formatting:** Prettier — 4 spaces, single quotes, no trailing commas, 100 char width, bracket same line -- **Always run `pnpm format` before committing** — the project uses `prettier --cache` +- **Formatter:** Prettier — 4 spaces, single quotes, no trailing commas, 100 char width, bracket same line +- **Svelte 5 runes only** — use `$props()`, `$state()`, `$derived()`, `$effect()`, `$bindable()`. Never `export let` or `$:` - Types from `@appwrite.io/console` SDK (`Models`, `Query`, enums) — don't redefine what the SDK provides - Error handling: try/catch with `addNotification()` for user-facing errors, `trackError()` for analytics - Queries use the SDK's `Query` builder: `Query.equal()`, `Query.limit()`, `Query.offset()`, etc. +- Mark tech debt with `@todo` annotations, never `@fixme` +- Don't add new dependencies without consulting the team + +## Environment variables + +Set via `.env` (copy `.env.example`). All prefixed with `PUBLIC_` for SvelteKit: + +| Variable | Default | Purpose | +|----------|---------|---------| +| `PUBLIC_CONSOLE_MODE` | `self-hosted` | `cloud` or `self-hosted` | +| `PUBLIC_APPWRITE_ENDPOINT` | `http://localhost/v1` | API endpoint | +| `PUBLIC_APPWRITE_MULTI_REGION` | `false` | Multi-region support | +| `PUBLIC_STRIPE_KEY` | — | Stripe public key (cloud only) | +| `PUBLIC_GROWTH_ENDPOINT` | — | Analytics endpoint | +| `PUBLIC_CONSOLE_FEATURE_FLAGS` | — | Feature flags | +| `PUBLIC_CONSOLE_EMAIL_VERIFICATION` | `false` | Require email verification | +| `PUBLIC_CONSOLE_MOCK_AI_SUGGESTIONS` | `true` | Mock AI in dev | + +## Branch naming + +`TYPE-ISSUE_ID-DESCRIPTION` (e.g. `feat-548-add-backup-ui`). Types: feat, fix, doc, cicd, refactor. ## Cross-repo context