馃 distributed transcription service
thistle.dunkirk.sh
1# Thistle - Project Guidelines
2
3This is a Bun-based transcription service using the [Bun fullstack pattern](https://bun.com/docs/bundler/fullstack) for routing and bundled HTML.
4
5## Project Info
6
7- Name: Thistle
8- Purpose: Transcription service
9- Runtime: Bun (NOT Node.js)
10- Language: TypeScript with strict mode
11- Frontend: Vanilla HTML/CSS/JS with lightweight helpers on top of web components
12
13## Design System
14
15ALWAYS use the project's CSS variables for colors:
16
17```css
18:root {
19 /* Color palette */
20 --gunmetal: #2d3142ff; /* dark blue-gray */
21 --paynes-gray: #4f5d75ff; /* medium blue-gray */
22 --silver: #bfc0c0ff; /* light gray */
23 --white: #ffffffff; /* white */
24 --coral: #ef8354ff; /* warm orange */
25
26 /* Semantic color assignments */
27 --text: var(--gunmetal);
28 --background: var(--white);
29 --primary: var(--paynes-gray);
30 --secondary: var(--silver);
31 --accent: var(--coral);
32}
33```
34
35**Color usage:**
36- NEVER hardcode colors like `#4f46e5`, `white`, `red`, etc.
37- Always use semantic variables (`var(--primary)`, `var(--background)`, `var(--accent)`, etc.) or named color variables (`var(--gunmetal)`, `var(--coral)`, etc.)
38
39**Dimensions:**
40- Use `rem` for all sizes, spacing, and widths (not `px`)
41- Base font size is 16px (1rem = 16px)
42- Common values: `0.5rem` (8px), `1rem` (16px), `2rem` (32px), `3rem` (48px)
43- Max widths: `48rem` (768px) for content, `56rem` (896px) for forms/data
44- Spacing scale: `0.25rem`, `0.5rem`, `0.75rem`, `1rem`, `1.5rem`, `2rem`, `3rem`
45
46## NO FRAMEWORKS
47
48NEVER use React, Vue, Svelte, or any heavy framework.
49
50This project prioritizes:
51- Speed: Minimal JavaScript, fast load times
52- Small bundle sizes: Keep bundles tiny
53- Native web platform: Use web standards (Web Components, native DOM APIs)
54- Simplicity: Vanilla HTML, CSS, and JavaScript
55
56Allowed lightweight helpers:
57- Lit (~8-10KB gzipped) for reactive web components
58- Native Web Components
59- Plain JavaScript/TypeScript
60
61Explicitly forbidden:
62- React, React DOM
63- Vue
64- Svelte
65- Angular
66- Any framework with a virtual DOM or large runtime
67
68## Commands
69
70```bash
71# Install dependencies
72bun install
73
74# Development server with hot reload
75bun dev
76
77# Run tests
78bun test
79
80# Build files
81bun build <file.html|file.ts|file.css>
82```
83
84Development workflow: `bun dev` runs the server with hot module reloading. Changes to TypeScript, HTML, or CSS files automatically reload.
85
86**IMPORTANT**: NEVER run `bun dev` yourself - the user always has it running already.
87
88## Bun Usage
89
90Default to using Bun instead of Node.js.
91
92- Use `bun <file>` instead of `node <file>` or `ts-node <file>`
93- Use `bun test` instead of `jest` or `vitest`
94- Use `bun build <file>` instead of `webpack` or `esbuild`
95- Use `bun install` instead of `npm install` or `yarn install` or `pnpm install`
96- Use `bun run <script>` instead of `npm run <script>` or `yarn run <script>`
97- Bun automatically loads .env, so don't use dotenv
98
99## Bun APIs
100
101Use Bun's built-in APIs instead of npm packages:
102
103- `Bun.serve()` supports WebSockets, HTTPS, and routes. Don't use `express`.
104- `bun:sqlite` for SQLite. Don't use `better-sqlite3`.
105- `Bun.redis` for Redis. Don't use `ioredis`.
106- `Bun.sql` for Postgres. Don't use `pg` or `postgres.js`.
107- `WebSocket` is built-in. Don't use `ws`.
108- Prefer `Bun.file` over `node:fs`'s readFile/writeFile
109- `Bun.$\`ls\`` instead of execa
110
111## Server Setup
112
113Use `Bun.serve()` with the routes pattern:
114
115```ts
116import index from "./index.html"
117
118Bun.serve({
119 routes: {
120 "/": index,
121 "/api/users/:id": {
122 GET: (req) => {
123 return new Response(JSON.stringify({ id: req.params.id }));
124 },
125 },
126 },
127 // optional websocket support
128 websocket: {
129 open: (ws) => {
130 ws.send("Hello, world!");
131 },
132 message: (ws, message) => {
133 ws.send(message);
134 },
135 close: (ws) => {
136 // handle close
137 }
138 },
139 development: {
140 hmr: true,
141 console: true,
142 }
143})
144```
145
146## Frontend Pattern
147
148Don't use Vite or any build tools. Use HTML imports with `Bun.serve()`.
149
150HTML files can directly import `.ts` or `.js` files:
151
152```html
153<!DOCTYPE html>
154<html lang="en">
155
156<head>
157 <meta charset="UTF-8">
158 <meta name="viewport" content="width=device-width, initial-scale=1.0">
159 <title>Page Title - Thistle</title>
160 <link rel="icon"
161 href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='0.9em' font-size='90'>馃</text></svg>">
162 <link rel="stylesheet" href="../styles/main.css">
163</head>
164
165<body>
166 <auth-component></auth-component>
167
168 <main>
169 <h1>Page Title</h1>
170 <my-component></my-component>
171 </main>
172
173 <script type="module" src="../components/auth.ts"></script>
174 <script type="module" src="../components/my-component.ts"></script>
175</body>
176
177</html>
178```
179
180**Standard HTML template:**
181- Always include the `<auth-component>` element for consistent login/logout UI
182- Always include the thistle emoji favicon
183- Always include proper meta tags (charset, viewport)
184- Structure: auth component, then main content, then scripts
185- Import `auth.ts` on every page for authentication UI
186
187Bun's bundler will transpile and bundle automatically. `<link>` tags pointing to stylesheets work with Bun's CSS bundler.
188
189Frontend TypeScript (vanilla or with Lit web components):
190
191```ts
192import { LitElement, html, css } from 'lit';
193import { customElement, property } from 'lit/decorators.js';
194
195// Define a Lit web component
196@customElement('my-component')
197export class MyComponent extends LitElement {
198 @property({ type: String }) name = 'World';
199
200 // Scoped styles using css tagged template
201 static styles = css`
202 :host {
203 display: block;
204 padding: 1rem;
205 }
206 .greeting {
207 color: blue;
208 }
209 `;
210
211 // Render using html tagged template
212 render() {
213 return html`
214 <div class="greeting">
215 Hello, ${this.name}!
216 </div>
217 `;
218 }
219}
220
221// Or use plain DOM manipulation for simple interactions
222document.querySelector('h1')?.addEventListener('click', () => {
223 console.log('Clicked!');
224});
225```
226
227**When to use Lit:**
228- Components with reactive properties (auto-updates when data changes)
229- Complex components needing scoped styles
230- Form controls with internal state
231- Components with lifecycle needs
232
233**When to skip Lit:**
234- Static content (use plain HTML)
235- Simple one-off interactions (use vanilla JS)
236- Anything without reactive state
237
238Lit provides:
239- `@customElement` decorator to register components
240- `@property` decorator for reactive properties
241- `html` tagged template for declarative rendering
242- `css` tagged template for scoped styles
243- Automatic re-rendering when properties change
244- Size: ~8-10KB minified+gzipped
245
246## Testing
247
248Use `bun test` to run tests.
249
250```ts
251import { test, expect } from "bun:test";
252
253test("hello world", () => {
254 expect(1).toBe(1);
255});
256```
257
258## TypeScript Configuration
259
260Strict mode is enabled with these settings:
261
262```json
263{
264 "strict": true,
265 "noFallthroughCasesInSwitch": true,
266 "noUncheckedIndexedAccess": true,
267 "noImplicitOverride": true
268}
269```
270
271Deliberately disabled:
272- `noUnusedLocals`: false
273- `noUnusedParameters`: false
274- `noPropertyAccessFromIndexSignature`: false
275
276Module system:
277- `moduleResolution`: "bundler"
278- `module`: "Preserve"
279- JSX: `preserve` (NOT react-jsx - we don't use React)
280- Allows importing `.ts` extensions directly
281
282## Frontend Technologies
283
284Core (always use):
285- Vanilla HTML, CSS, JavaScript/TypeScript
286- Native Web Components API
287- Native DOM APIs (querySelector, addEventListener, etc.)
288
289Lightweight helpers:
290- Lit (~8-10KB gzipped): For reactive web components with state management
291
292Bundle size philosophy:
293- Start with vanilla JS
294- Add helpers only when they significantly reduce complexity
295- Measure bundle size impact before adding any library
296- Target: Keep total JS bundle under 50KB
297
298## Project Structure
299
300Based on Bun fullstack pattern:
301- `src/index.ts`: Server imports HTML files as modules
302- `src/pages/`: HTML files (route entry points)
303- `src/components/`: Lit web components
304- `src/styles/`: CSS files
305- `public/`: Static assets (images, fonts, etc.)
306
307**File flow:**
3081. Server imports HTML: `import indexHTML from "./pages/index.html"`
3092. HTML imports components: `<script type="module" src="../components/counter.ts"></script>`
3103. HTML links styles: `<link rel="stylesheet" href="../styles/main.css">`
3114. Components self-register as custom elements
3125. Bun bundles everything automatically
313
314## File Organization
315
316- `src/index.ts`: Main server entry point with `Bun.serve()` routes
317- `src/pages/*.html`: Route entry points (imported as modules)
318- `src/components/*.ts`: Lit web components
319- `src/styles/*.css`: Stylesheets (linked from HTML)
320- `public/`: Static assets directory
321- Tests: `*.test.ts` files
322
323**Current structure example:**
324```
325src/
326 index.ts # Imports HTML, defines routes
327 pages/
328 index.html # Imports components via <script type="module">
329 components/
330 counter.ts # Lit component with @customElement
331 styles/
332 main.css # Linked from HTML with <link>
333```
334
335## Naming Conventions
336
337Follow TypeScript conventions:
338- PascalCase for components and classes
339- camelCase for functions and variables
340- kebab-case for file names
341
342## Development Workflow
343
3441. Make changes to `.ts`, `.html`, or `.css` files
3452. Bun's HMR automatically reloads changes
3463. Write tests in `*.test.ts` files
3474. Run `bun test` to verify
348
349## IDE Setup
350
351Biome LSP is configured in `crush.json` for linting and formatting support.
352
353## Common Tasks
354
355### Adding a new route
356Add to the `routes` object in `Bun.serve()` configuration
357
358### Adding a new page
359Create an HTML file, import it in the server, add to routes
360
361### Adding frontend functionality
362Import TS/JS files directly from HTML using `<script type="module" src="../components/my-component.ts"></script>`. Use Lit for reactive components or vanilla JS for simple interactions. Never React.
363
364### Adding WebSocket support
365Add `websocket` configuration to `Bun.serve()`
366
367## Important Notes
368
3691. No npm scripts needed: Bun is fast enough to run commands directly
3702. Private package: `package.json` has `"private": true`
3713. No build step for development: Hot reload handles everything
3724. Module type: Package uses `"type": "module"` (ESM)
3735. Bun types: Available via `@types/bun` (check `node_modules/bun-types/docs/**.md` for API docs)
374
375## Gotchas
376
3771. Don't use Node.js commands: Use `bun` instead of `node`, `npm`, `npx`, etc.
3782. Don't install Express/Vite/other tools: Bun has built-in equivalents
3793. NEVER EVER use React: This project is vanilla JS/TS with web components only. React is explicitly forbidden.
3804. Import .ts extensions: Bun allows importing `.ts` files directly
3815. No dotenv needed: Bun loads `.env` automatically
3826. HTML imports are special: They trigger Bun's bundler, don't treat them as static files
3837. Bundle size matters: Always consider the size impact before adding any library
384
385## Documentation Lookup
386
387Use Context7 MCP for looking up official documentation for libraries and frameworks.
388
389## Resources
390
391- [Bun Fullstack Documentation](https://bun.com/docs/bundler/fullstack)
392- [Lit Documentation](https://lit.dev/)
393- [Web Components MDN](https://developer.mozilla.org/en-US/docs/Web/Web_Components)
394- Bun API docs in `node_modules/bun-types/docs/**.md`
395
396## Future Additions
397
398As the codebase grows, document:
399- Database schema and migrations
400- API endpoint patterns
401- Authentication/authorization approach
402- Transcription service integration details
403- Deployment process
404- Environment variables needed