|
1 | | -# Appwrite Console - Copilot Instructions |
| 1 | +# Appwrite Console |
| 2 | + |
| 3 | +SvelteKit web dashboard for Appwrite. Manages projects, databases, functions, auth, storage, messaging, and sites. Static SPA (no SSR) served behind Nginx at `/console`. |
| 4 | + |
| 5 | +## Commands |
| 6 | + |
| 7 | +All commands use **bun** (not pnpm/npm). Use `bun run <script>` consistently — `bun run build` is required to avoid invoking bun's built-in bundler. |
| 8 | + |
| 9 | +| Command | Purpose | |
| 10 | +| ------------------------- | --------------------------------------------- | |
| 11 | +| `bun run dev` | Dev server (port 3000) | |
| 12 | +| `bun run build` | Production build (custom `build.js` via Vite) | |
| 13 | +| `bun run check` | `svelte-kit sync && svelte-check` | |
| 14 | +| `bun run format` | Prettier write + cache | |
| 15 | +| `bun run lint` | Prettier check + ESLint | |
| 16 | +| `bun run tests` | Unit + E2E | |
| 17 | +| `bun run test:unit` | Vitest (TZ=EST) | |
| 18 | +| `bun run test:unit-watch` | Vitest watch mode | |
| 19 | +| `bun run test:e2e` | Playwright | |
| 20 | +| `bun run clean` | Remove node_modules, .svelte-kit, reinstall | |
| 21 | + |
| 22 | +**Always run before committing:** `bun run format && bun run check && bun run lint && bun run tests && bun run build` |
| 23 | + |
| 24 | +## CI checks (`.github/workflows/tests.yml`) |
| 25 | + |
| 26 | +`bun audit --audit-level high` -> `bun check` -> `bun lint` -> `bun test:unit` -> `bun run build`. Uses frozen lockfile. |
| 27 | + |
| 28 | +## Stack |
| 29 | + |
| 30 | +- **Framework:** SvelteKit 2 + Svelte 5, TypeScript (strict: false), `@sveltejs/adapter-static` |
| 31 | +- **Bundler:** Vite 7 (overridden to `rolldown-vite`) |
| 32 | +- **Design system:** `@appwrite.io/pink-svelte`, `@appwrite.io/pink-icons-svelte` |
| 33 | +- **UI primitives:** Melt UI (`@melt-ui/svelte` with preprocessor) |
| 34 | +- **API client:** `@appwrite.io/console` SDK (pinned to GitHub commit) |
| 35 | +- **Code editing:** CodeMirror 6 |
| 36 | +- **Charts:** ECharts 5 |
| 37 | +- **3D:** Three.js via Threlte |
| 38 | +- **Payments:** Stripe |
| 39 | +- **AI:** Vercel AI SDK (`@ai-sdk/svelte`) |
| 40 | +- **Testing:** Vitest + @testing-library/svelte (unit), Playwright (E2E) |
| 41 | +- **Error tracking:** Sentry (`@sentry/sveltekit`) |
| 42 | +- **Analytics:** Plausible + custom Growth endpoint |
| 43 | + |
| 44 | +## Architecture |
| 45 | + |
| 46 | +### Route structure (`src/routes/`) |
| 47 | + |
| 48 | +SvelteKit file-based routing with layout groups: |
| 49 | + |
| 50 | +- `(public)/` -- unauthenticated routes: `(guest)/` (login, register), auth (OAuth, magic URL), invite, recover, card, functions/sites deploy, hackathon, templates |
| 51 | +- `(console)/` -- authenticated console (projects, orgs, account, onboarding) |
| 52 | +- `(authenticated)/` -- post-login flows (MFA, Git authorization) |
| 53 | + |
| 54 | +Dynamic segments: `project-[region]-[project]`, `organization-[organization]` |
| 55 | + |
| 56 | +### Route file conventions |
| 57 | + |
| 58 | +Each route can have: |
| 59 | + |
| 60 | +- `+page.svelte` -- page component |
| 61 | +- `+page.ts` -- client-side load function |
| 62 | +- `+layout.svelte` / `+layout.ts` -- layout wrappers |
| 63 | +- `store.ts` -- route-scoped state |
| 64 | +- Feature components colocated alongside (e.g. `table.svelte`, `create.svelte`) |
| 65 | + |
| 66 | +### Path aliases |
| 67 | + |
| 68 | +| Alias | Path | |
| 69 | +| ----------- | ------------------------------------------------------------------------------- | |
| 70 | +| `$lib` | `src/lib` (SvelteKit built-in) | |
| 71 | +| `$routes` | `src/routes` | |
| 72 | +| `$themes` | `src/themes` | |
| 73 | +| `$database` | `src/routes/(console)/project-[region]-[project]/databases/database-[database]` | |
| 74 | + |
| 75 | +### Library (`src/lib/`) |
| 76 | + |
| 77 | +| Directory | Contents | |
| 78 | +| ----------------- | ------------------------------------------------------------------------------------------ | |
| 79 | +| `components/` | Feature components (billing, permissions, filters, etc.) -- barrel-exported via `index.ts` | |
| 80 | +| `elements/forms/` | Form inputs (text, email, phone, OTP, file, geometry, etc.) | |
| 81 | +| `elements/table/` | Table components | |
| 82 | +| `layout/` | Shell, Container, Wizard, Breadcrumbs, Navigation -- barrel-exported via `index.ts` | |
| 83 | +| `stores/` | Svelte stores for global state | |
| 84 | +| `helpers/` | Utilities (array, date, object, numbers, string, validation) | |
| 85 | +| `sdk/` | Custom SDK extensions (billing, usage, sources) | |
| 86 | +| `actions/` | Svelte actions and analytics tracking | |
| 87 | +| `charts/` | Chart visualization components -- barrel-exported via `index.ts` | |
| 88 | +| `commandCenter/` | Command palette | |
| 89 | +| `images/` | SVG assets (logos, illustrations, empty states) | |
| 90 | +| `data/` | Static data (testimonials) | |
| 91 | +| `profiles/` | CSS profiles and theming | |
| 92 | +| `mock/` | Mock data for development | |
| 93 | + |
| 94 | +### Imports |
| 95 | + |
| 96 | +Components use **barrel exports** -- always import from the directory `index.ts`: |
| 97 | + |
| 98 | +```typescript |
| 99 | +import { Card, Modal, Steps } from '$lib/components'; |
| 100 | +import { Shell, Container } from '$lib/layout'; |
| 101 | +import { InputText, Button, Form } from '$lib/elements/forms'; |
| 102 | +``` |
| 103 | + |
| 104 | +### Svelte 5 migration (in progress) |
2 | 105 |
|
3 | | -## Repository Overview |
| 106 | +~500 files still use legacy Svelte 4 syntax, ~240 migrated to runes. **When touching a file, migrate it to runes if practical.** Don't mix syntaxes within a single component. |
4 | 107 |
|
5 | | -Appwrite Console is the web-based GUI for the Appwrite backend-as-a-service platform. Single-page application built with |
6 | | -**Svelte 5 + SvelteKit 2**, **TypeScript** (not strict mode), **Vite 7**, tested with **Vitest + Playwright**. Package |
7 | | -manager/runtime: **Bun** (Node 20+ optional for tooling). ~1500 files with extensive component-based architecture. |
| 108 | +Legacy (Svelte 4): |
8 | 109 |
|
9 | | -## Critical Build & Test Commands |
| 110 | +```svelte |
| 111 | +<script lang="ts"> |
| 112 | + export let items: Item[] = []; |
| 113 | + export let disabled = false; |
| 114 | + $: count = items.length; |
| 115 | +</script> |
| 116 | +``` |
10 | 117 |
|
11 | | -### Setup (REQUIRED before any commands) |
| 118 | +Runes (Svelte 5 -- preferred for new and modified code): |
12 | 119 |
|
13 | | -1. **Install Bun**: |
14 | | - - Linux & macOS: `curl -fsSL https://bun.sh/install | bash` |
15 | | - - Windows: `powershell -c "irm bun.sh/install.ps1 | iex"` |
16 | | -2. **Create .env**: `cp .env.example .env` (configure `PUBLIC_APPWRITE_ENDPOINT` and `PUBLIC_CONSOLE_MODE`) |
17 | | -3. **Configure network access** (if using GitHub Actions or restricted environments): |
18 | | - - Ensure firewall/proxy allows access to: `pkg.pr.new`, `pkg.vc`, `registry.npmjs.org` |
19 | | - - These domains are required for dependencies: `@appwrite.io/console`, `@appwrite.io/pink-icons-svelte`, |
20 | | - `@appwrite.io/pink-svelte` |
21 | | - - In GitHub Actions: Ensure Bun is installed and registry access is configured |
22 | | - - If network errors persist, check proxy settings: `npm config get proxy` and `npm config get https-proxy` |
23 | | -4. **Install dependencies**: `bun install --frozen-lockfile` (if pkg.pr.new/pkg.vc fail due to network restrictions, |
24 | | - installation may still succeed with cached versions) |
| 120 | +```svelte |
| 121 | +<script lang="ts"> |
| 122 | + // $bindable() enables two-way binding so parent components can mutate items directly |
| 123 | + let { items = $bindable(), disabled = false }: Props = $props(); |
| 124 | + let selected = $state<string | null>(null); |
| 125 | + const count = $derived(items.length); |
| 126 | + const filtered = $derived.by(() => items.filter((i) => i.active)); |
| 127 | +
|
| 128 | + $effect(() => { |
| 129 | + console.log('selected changed:', selected); |
| 130 | + }); |
| 131 | +</script> |
| 132 | +``` |
25 | 133 |
|
26 | | -### Development Commands |
| 134 | +### SDK usage (`src/lib/stores/sdk.ts`) |
27 | 135 |
|
28 | | -**Standard workflow**: `check` → `lint` → `test` → `build` (before committing) |
| 136 | +Four client instances: `clientConsole` (console API), `scopedConsoleClient` (region-scoped console API, used by `forConsoleIn()`), `clientProject` (project API, admin mode), `clientRealtime` (realtime subscriptions). Region-aware endpoints with subdomain routing (fra., nyc., syd., sfo., sgp., tor.). |
29 | 137 |
|
30 | | -- `bun run check` - TypeScript/Svelte validation (~30-60s) |
31 | | -- `bun run lint` - ESLint check (~10-20s) |
32 | | -- `bun run format` - Auto-fix Prettier formatting |
33 | | -- `bun run test` - Vitest unit tests with TZ=EST (~10-30s) |
34 | | -- `bun run build` - Production build via build.js (~60-120s) |
35 | | -- `bun run dev` - Dev server on port 3000 |
36 | | -- `bun run preview` - Preview build on port 4173 |
37 | | -- `bun run e2e` - Playwright tests (needs `bunx playwright install --with-deps chromium` first, ~120s+) |
| 138 | +```typescript |
| 139 | +import { sdk } from '$lib/stores/sdk'; |
38 | 140 |
|
39 | | -**CI Pipeline** (`.github/workflows/tests.yml`): audit → install → check → lint → test → build |
| 141 | +// Console-level operations |
| 142 | +await sdk.forConsole.account.get(); |
40 | 143 |
|
41 | | -## Project Structure |
| 144 | +// Region-scoped console operations |
| 145 | +await sdk.forConsoleIn(region).projects.get({ projectId }); |
42 | 146 |
|
| 147 | +// Project-level operations (admin mode) |
| 148 | +await sdk.forProject(region, projectId).tablesDB.listTables(); |
43 | 149 | ``` |
44 | | -src/ |
45 | | -├── lib/ # Reusable logic ($lib alias) |
46 | | -│ ├── components/ # Feature components (billing, domains, permissions, etc.) |
47 | | -│ ├── elements/ # Basic UI elements |
48 | | -│ ├── helpers/ # Utility functions (array, date, string, etc.) |
49 | | -│ ├── stores/ # Svelte stores for state |
50 | | -│ ├── sdk/ # Appwrite SDK wrappers |
51 | | -│ └── constants.ts, flags.ts, system.ts |
52 | | -├── routes/ |
53 | | -│ ├── (console)/ # Auth-required routes |
54 | | -│ │ ├── organization-[organization]/ |
55 | | -│ │ └── project-[region]-[project]/ # databases, functions, messaging, storage |
56 | | -│ └── (public)/ # Public routes (login, register, auth callbacks) |
57 | | -├── themes/ # Theme definitions ($themes alias) |
58 | | -└── app.html, hooks.{client,server}.ts, service-worker.ts |
| 150 | + |
| 151 | +### Database types (feat-dedicated-db) |
| 152 | + |
| 153 | +The databases feature unifies multiple database backends behind a polymorph API (`$database/(entity)/helpers/sdk.ts`): |
| 154 | + |
| 155 | +| Type | Entity | Field | Record | Status | |
| 156 | +| ------------- | ---------- | --------- | -------- | ------------------------ | |
| 157 | +| `tablesdb` | table | column | row | Implemented | |
| 158 | +| `documentsdb` | collection | attribute | document | Implemented | |
| 159 | +| `vectorsdb` | -- | -- | -- | Not yet implemented | |
| 160 | +| `dedicateddb` | table | column | row | Cross-repo (cloud/edge) | |
| 161 | + |
| 162 | +- `useDatabaseSdk()` returns a unified interface regardless of backing type |
| 163 | +- `useTerminology()` returns singular/plural names for the current database type |
| 164 | + |
| 165 | +### Data loading |
| 166 | + |
| 167 | +Load functions declare dependencies for cache invalidation via `depends()`: |
| 168 | + |
| 169 | +```typescript |
| 170 | +export const load: LayoutLoad = async ({ depends, parent, params }) => { |
| 171 | + depends(Dependencies.DATABASE); |
| 172 | + return { database: await sdk.forProject(...).tablesDB.get(...) }; |
| 173 | +}; |
59 | 174 | ``` |
60 | 175 |
|
61 | | -**SvelteKit conventions**: `+page.svelte` (component), `+page.ts` (data loader), `+layout.svelte` (wrapper), |
62 | | -`+error.svelte` (errors). Groups like `(console)` organize routes without affecting URLs. Dynamic params: `[param]`. |
63 | | - |
64 | | -## Key Configuration |
65 | | - |
66 | | -**svelte.config.js**: Adapter = static SPA (fallback: index.html), base path `/console`, aliases: `$lib`, `$routes`, |
67 | | -`$themes` |
68 | | -**vite.config.ts**: Dev port 3000 |
69 | | -**tsconfig.json**: Extends `.svelte-kit/tsconfig.json`, **NOT strict mode** (`strict: false`) |
70 | | -**eslint.config.js**: Flat config (ESLint 9+), many rules disabled (see TODOs) |
71 | | -**.prettierrc**: 4 spaces, single quotes, 100 char width, no trailing commas |
72 | | - |
73 | | -## Testing |
74 | | - |
75 | | -**Unit (Bun test)**: Tests in `src/lib/helpers/*.test.ts`, run with `TZ=EST` (timezone matters). Setup mocks SvelteKit ( |
76 | | -`$app/*`) in `bun-test-setup.ts` via `bunfig.toml`. |
77 | | -**E2E (Playwright)**: Tests in `e2e/journeys/*.spec.ts`, needs build+preview on port 4173, retries 3x, timeout 120s, |
78 | | -Chromium only. |
79 | | - |
80 | | -## Common Pitfalls |
81 | | - |
82 | | -1. **Blank page in dev**: Disable ad blockers if seeing "Failed to fetch dynamically imported module" (known SvelteKit |
83 | | - issue) |
84 | | -2. **Network errors on install**: |
85 | | - - pkg.pr.new/pkg.vc deps may fail due to firewall/proxy restrictions |
86 | | - - Check access: `curl -I https://pkg.pr.new` and `curl -I https://pkg.vc` |
87 | | - - Configure proxy if needed: `npm config set proxy http://proxy:port` and |
88 | | - `npm config set https-proxy http://proxy:port` |
89 | | - - GitHub Actions: Ensure runner has internet access and Bun is installed |
90 | | - - Local dev: Often safe to continue with cached versions if network fails |
91 | | -3. **OOM on build**: Set `NODE_OPTIONS=--max_old_space_size=8192` (like Dockerfile does) |
92 | | -4. **Test failures**: Always use `bun run test` (sets TZ=EST), not `bun test` directly |
93 | | -5. **TS errors not showing**: Run `bun run check` explicitly (dev server doesn't always surface them) |
94 | | -6. **Format vs lint conflicts**: Run `bun run format` before `bun run lint` |
95 | | -7. **E2E timeouts**: Wait 120s for preview server startup, tests auto-retry 3x |
96 | | -8. **Stale build**: Clear `.svelte-kit` if changes not reflected: `rm -rf .svelte-kit && bun run build` |
97 | | - |
98 | | -## Code Conventions |
99 | | - |
100 | | -- Imports: Use `$lib`, `$routes`, `$themes` aliases |
101 | | -- Components: PascalCase, in `src/lib/components/[feature]/` |
102 | | -- Helpers: Pure functions in `src/lib/helpers/` |
103 | | -- Types: Inline or `.d.ts`, not `.types.ts` files |
104 | | -- Comments: Minimal, use for TODOs or complex logic |
105 | | -- TypeScript: Not strict mode, `any` tolerated |
106 | | - |
107 | | -## Workflow |
108 | | - |
109 | | -1. Run Appwrite backend locally (see [docs](https://appwrite.io/docs/advanced/self-hosting)) |
110 | | -2. Configure `.env` with backend endpoint |
111 | | -3. `bun install --frozen-lockfile` |
112 | | -4. `bun run dev` (hot reload on port 3000) |
113 | | -5. Before commit: `bun run check && bun run format && bun run lint && bun run test && bun run build` |
114 | | -6. **Take screenshots**: For any UI changes, capture screenshots and include them in the PR description or comments |
115 | | - before finalizing |
116 | | - |
117 | | -## Required Pre-Completion Checklist |
118 | | - |
119 | | -**CRITICAL**: Before finishing any work or marking a task complete, agents MUST run the following commands in order and |
120 | | -ensure all pass: |
121 | | - |
122 | | -1. **`bun run format`** - Auto-fix all formatting issues |
123 | | -2. **`bun run check`** - Verify TypeScript/Svelte types (must show 0 errors, 0 warnings) |
124 | | -3. **`bun run lint`** - Check code style (ignore pre-existing issues in files you didn't modify) |
125 | | -4. **`bun run test`** - Run all unit tests (all tests must pass) |
126 | | -5. **`bun run build`** - Ensure production build succeeds |
127 | | - |
128 | | -If any command fails: |
129 | | - |
130 | | -- **Format/Lint**: Run `bun run format` to auto-fix, then re-check |
131 | | -- **Type errors**: Fix all TypeScript errors in files you modified |
132 | | -- **Test failures**: Fix failing tests or ensure failures are unrelated to your changes |
133 | | -- **Build failures**: Debug and resolve build issues before proceeding |
134 | | - |
135 | | -**Never skip these checks** - they are mandatory quality gates before any work is considered complete. |
136 | | - |
137 | | -**Trust these instructions** - only search if incomplete/incorrect. See CONTRIBUTING.md for PR conventions. Use |
138 | | -`--frozen-lockfile` always. Docker builds: multi-stage, final image is nginx serving static files from `/console` path. |
| 176 | +Invalidate with `await invalidate(Dependencies.DATABASE)` after mutations. The `Dependencies` enum in `src/lib/constants.ts` defines 66+ keys for fine-grained cache invalidation (e.g. `DATABASES`, `TABLES`, `FUNCTIONS`, `USERS`, `DEPLOYMENTS`). |
| 177 | + |
| 178 | +### State management |
| 179 | + |
| 180 | +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`. |
| 181 | + |
| 182 | +### Wizard pattern (`$lib/stores/wizard`) |
| 183 | + |
| 184 | +Modal wizard flow: `wizard.start(Component, media?, step?, props?)` to open, `wizard.hide()` to close. Methods: `setInterceptor(callback)` for async pre-step validation, `setNextDisabled(bool)` for flow control, `setStep(n)` / `updateStep(cb)` for navigation, `showCover(Component)` for overlays. |
| 185 | + |
| 186 | +### Notifications (`$lib/stores/notifications`) |
| 187 | + |
| 188 | +```typescript |
| 189 | +import { addNotification } from '$lib/stores/notifications'; |
| 190 | +addNotification({ type: 'error', message: error.message }); |
| 191 | +``` |
| 192 | + |
| 193 | +Types: `'success' | 'error' | 'info' | 'warning'`. Auto-dismisses after 6s. Max 5 visible. |
| 194 | + |
| 195 | +### Analytics (`$lib/actions/analytics`) |
| 196 | + |
| 197 | +Plausible + custom Growth endpoint. Track events via `trackEvent(Click.* | Submit.*, data)` and errors via `trackError(exception, Submit.*)`. Respects `navigator.doNotTrack`. |
| 198 | + |
| 199 | +### Theming and modes |
| 200 | + |
| 201 | +Four theme variants in `src/themes/`: `light`, `dark`, `light-cloud`, `dark-cloud`. Resolved based on `isCloud` flag and user preference. Two modes (`src/lib/system.ts`): `cloud` and `self-hosted`, set via `PUBLIC_CONSOLE_MODE` env var. Gate features using `isCloud` (for cloud-only) or `isSelfHosted` (for self-hosted-only). |
| 202 | + |
| 203 | +## Code style |
| 204 | + |
| 205 | +- **Formatter:** Prettier -- 4 spaces, single quotes, no trailing commas, 100 char width, bracket same line |
| 206 | +- **Prefer Svelte 5 runes** in new and modified code (`$props()`, `$state()`, `$derived()`, `$effect()`) |
| 207 | +- Types from `@appwrite.io/console` SDK (`Models`, `Query`, enums) -- don't redefine what the SDK provides |
| 208 | +- Error handling: try/catch with `addNotification()` for user-facing errors, `trackError()` for analytics |
| 209 | +- Queries use the SDK's `Query` builder: `Query.equal()`, `Query.limit()`, `Query.offset()`, etc. |
| 210 | +- Mark tech debt with `@todo` annotations, never `@fixme` |
| 211 | +- Don't add new dependencies without consulting the team |
| 212 | + |
| 213 | +## Environment variables |
| 214 | + |
| 215 | +Set via `.env` (copy `.env.example`). All prefixed with `PUBLIC_` for SvelteKit: |
| 216 | + |
| 217 | +| Variable | Default | Purpose | |
| 218 | +| ------------------------------------ | --------------------- | ------------------------------ | |
| 219 | +| `PUBLIC_CONSOLE_MODE` | `self-hosted` | `cloud` or `self-hosted` | |
| 220 | +| `PUBLIC_APPWRITE_ENDPOINT` | `http://localhost/v1` | API endpoint | |
| 221 | +| `PUBLIC_APPWRITE_MULTI_REGION` | `false` | Multi-region support | |
| 222 | +| `PUBLIC_STRIPE_KEY` | -- | Stripe public key (cloud only) | |
| 223 | +| `PUBLIC_GROWTH_ENDPOINT` | -- | Analytics endpoint | |
| 224 | +| `PUBLIC_CONSOLE_FEATURE_FLAGS` | -- | Feature flags | |
| 225 | +| `PUBLIC_CONSOLE_EMAIL_VERIFICATION` | `false` | Require email verification | |
| 226 | +| `PUBLIC_CONSOLE_MOCK_AI_SUGGESTIONS` | `true` | Mock AI in dev | |
| 227 | + |
| 228 | +## Common pitfalls |
| 229 | + |
| 230 | +- **Blank page in dev:** Disable ad blockers if seeing "Failed to fetch dynamically imported module" |
| 231 | +- **OOM on build:** Set `NODE_OPTIONS=--max_old_space_size=8192` |
| 232 | +- **Test failures:** Always use `bun run tests` (runs test:unit with TZ=EST, plus test:e2e), not `bun test` directly |
| 233 | +- **TS errors not showing:** Run `bun run check` explicitly (dev server doesn't always surface them) |
| 234 | +- **Format vs lint conflicts:** Run `bun run format` before `bun run lint` |
| 235 | +- **Stale build:** Clear `.svelte-kit` if changes not reflected: `rm -rf .svelte-kit && bun run build` |
| 236 | + |
| 237 | +## Branch naming |
| 238 | + |
| 239 | +`TYPE-ISSUE_ID-DESCRIPTION` (e.g. `feat-548-add-backup-ui`). Types: feat, fix, doc, cicd, refactor. |
| 240 | + |
| 241 | +## Cross-repo context |
| 242 | + |
| 243 | +The `feat-dedicated-db` feature spans cloud, edge, and console. When modifying API contracts or response models, check the other repos for breaking changes. |
0 commit comments