Files
Job-Info/instructions/auth/TECH_STACK.md
T
2026-01-09 04:08:06 +00:00

579 lines
12 KiB
Markdown

# Tech Stack & Enforcement Rules
**Version:** 1.0
**Status:** PRODUCTION
**Last Updated:** January 2026
---
## Overview
This document enforces the specific versions and usage patterns for all technologies in Job Info. All developers must follow these rules to ensure consistency and compatibility.
---
## 1. Runtime & Build System
### Bun
**Version:** `latest` (1.0.0+)
**Rules:**
- ✅ Use `bun` for running TypeScript directly
- ✅ Use `bun install` to manage dependencies
- ✅ Use `bun run` for scripts
- ✅ Use `bun run build:css` for Tailwind compilation
- ❌ Do NOT use `npm` or `yarn`
- ❌ Do NOT use Node.js for production (Bun is faster, but ensure infrastructure supports it)
**Installation:**
```bash
curl -fsSL https://bun.sh/install | bash
```
**Common Commands:**
```bash
bun install # Install dependencies
bun add <package> # Add dependency
bun run <script> # Run npm script
bun --watch server.ts # Watch & reload
bun build --target bun # Build for production
```
**package.json Scripts:**
```json
{
"scripts": {
"dev": "bun --watch backend/server.ts",
"start": "bun run backend/server.ts",
"build:css": "tailwindcss -i input.css -o frontend/output.css --watch"
}
}
```
---
## 2. Web Framework
### Hono
**Version:** `^4.10.8` (pinned)
**Rules:**
- ✅ Use Hono for all backend routes
- ✅ Use typed context: `(c: Context)`
- ✅ Use middleware for auth, logging, CORS
- ✅ Return JSON responses with `c.json()`
- ❌ Do NOT mix Express or other frameworks
- ❌ Do NOT use un-typed `req` / `res`
**Installation:**
```bash
bun add hono@^4.10.8
```
**Routing Pattern:**
```typescript
import { Hono } from 'hono';
import { Context } from 'hono';
const app = new Hono();
// GET endpoint
app.get('/api/jobs', async (c: Context) => {
try {
const page = c.req.query('page') || '1';
const data = await fetchData();
return c.json({ items: data });
} catch (err) {
console.error('Error:', err);
return c.json({ error: 'Server error' }, 500);
}
});
// POST endpoint
app.post('/api/jobs', async (c: Context) => {
const body = await c.req.json();
// Process
return c.json({ success: true }, 201);
});
export default app;
```
**Middleware Pattern:**
```typescript
// Auth middleware
app.use('*', async (c, next) => {
const token = c.req.header('Authorization');
if (!token) return c.json({ error: 'Unauthorized' }, 401);
await next();
});
// CORS middleware
app.use('*', async (c, next) => {
c.header('Access-Control-Allow-Origin', '*');
await next();
});
```
---
## 3. CSS Framework
### PostCSS + Tailwind CSS
**Versions:**
- `postcss`: `^8.5.6` (pinned)
- `tailwindcss`: `^4.1.18` (pinned)
- `autoprefixer`: `^10.4.23` (devDependency)
**Installation:**
```bash
bun add -D postcss@^8.5.6 tailwindcss@^4.1.18 autoprefixer@^10.4.23
```
**Configuration Files:**
**postcss.config.js:**
```javascript
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
```
**tailwind.config.js:**
```javascript
export default {
content: [
'./frontend/**/*.html',
'./frontend/**/*.js',
],
theme: {
extend: {
colors: {
// Add custom colors if needed
},
},
},
plugins: [],
};
```
**Build Command:**
```bash
bun run build:css
```
**CSS Input (input.css):**
```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```
**Rules:**
- ✅ Use Tailwind utility classes: `bg-blue-600`, `px-4`, `rounded-lg`
- ✅ Use `@apply` for reusable component styles (if needed)
- ✅ Custom CSS in separate `.css` files (not inline styles)
- ❌ Do NOT use Bootstrap, Foundation, or other CSS frameworks
- ❌ Do NOT inline styles: `<div style="...">`
- ❌ Do NOT write CSS that conflicts with Tailwind
**Component Example:**
```html
<!-- ✅ CORRECT -->
<button class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">
Click Me
</button>
<!-- ❌ WRONG -->
<button style="background: blue; padding: 10px;">Click Me</button>
```
---
## 4. Runtime Type System
### TypeScript
**Version:** `^5` (peer dependency)
**Rules:**
- ✅ Use strict mode: `"strict": true` in tsconfig.json
- ✅ Type all function parameters
- ✅ Type all return values
- ✅ Use interfaces for objects
- ✅ Enable `noImplicitAny`
- ✅ Enable `strictNullChecks`
- ❌ Do NOT use `any` type
- ❌ Do NOT skip type annotations
**tsconfig.json (Backend):**
```json
{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"lib": ["ES2020"],
"moduleResolution": "node",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true
},
"include": ["backend/**/*.ts"],
"exclude": ["node_modules"]
}
```
**Example:**
```typescript
// ✅ CORRECT
interface Job {
id: string;
name: string;
number: number;
created_at: string;
}
function getJobNumber(job: Job): number {
return job.number;
}
async function fetchJob(id: string): Promise<Job | null> {
try {
const data = await fetch(`/api/jobs/${id}`);
if (!data.ok) return null;
return await data.json();
} catch (err) {
console.error('Error fetching job:', err);
return null;
}
}
// ❌ WRONG
function getJobNumber(job) { // No type
return job.number; // No return type
}
```
---
## 5. Caching & Session Management
### ioredis (Redis/Valkey Client)
**Version:** `^5.x` (add to dependencies)
**Installation:**
```bash
bun add ioredis
```
**Usage:**
```typescript
import Redis from 'ioredis';
const redis = new Redis({
host: process.env.REDIS_HOST || 'localhost',
port: Number(process.env.REDIS_PORT || 6379),
password: process.env.REDIS_PASSWORD,
retryStrategy(times) {
const delay = Math.min(times * 50, 2000);
return delay;
},
maxRetriesPerRequest: 3,
lazyConnect: true,
});
// Cache operations
export async function getCache(key: string): Promise<any | null> {
try {
const value = await redis.get(key);
if (!value) return null;
return JSON.parse(value);
} catch (err) {
console.error(`Cache get error for key "${key}":`, err);
return null;
}
}
export async function setCache(key: string, value: any, ttl: number = 300): Promise<boolean> {
try {
const serialized = JSON.stringify(value);
await redis.setex(key, ttl, serialized);
return true;
} catch (err) {
console.error(`Cache set error for key "${key}":`, err);
return false;
}
}
```
**Rules:**
- ✅ Use `setex` for automatic TTL expiration
- ✅ Check cache before fetching external data
- ✅ Log cache hits/misses for debugging
- ❌ Do NOT store secrets in cache
- ❌ Do NOT rely on cache for critical data (always have fallback)
---
## 6. Authentication & Backend Services
### PocketBase SDK
**Version:** `^0.26.5` (pinned)
**Installation:**
```bash
bun add pocketbase@^0.26.5
```
**Frontend Usage (auth.js):**
```javascript
const PocketBase = window.PocketBase;
const pb = new PocketBase('https://pocketbase.ccllc.pro');
// Login
const authData = await pb.collection('users')
.authWithPassword(email, password);
// Get token
const token = authData.token || pb.authStore.exportSession()?.token;
// Logout
pb.authStore.clear();
```
**Rules:**
- ✅ Single PocketBase instance
- ✅ Store token in localStorage
- ✅ Use token in all API requests
- ❌ Do NOT create multiple PocketBase instances
- ❌ Do NOT expose secrets in frontend
---
## 7. Dotenv Configuration
### dotenv
**Version:** `^17.2.3` (pinned)
**Installation:**
```bash
bun add dotenv@^17.2.3
```
**Usage (Backend):**
```typescript
import dotenv from 'dotenv';
dotenv.config();
const PORT = process.env.PORT || 3005;
const REDIS_HOST = process.env.REDIS_HOST || 'localhost';
const REDIS_PORT = Number(process.env.REDIS_PORT || 6379);
```
**Environment Variables:**
```bash
# .env (gitignored)
PORT=3005
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
POCKETBASE_URL=https://pocketbase.ccllc.pro
```
**Rules:**
- ✅ Load from `.env` file
- ✅ Provide sensible defaults for development
- ✅ Document required variables in `.env.example`
- ❌ Do NOT commit `.env` to git
- ❌ Do NOT hardcode secrets
---
## 8. Development Server
### Watch Mode
**Command:**
```bash
bun --watch backend/server.ts
```
**Features:**
- Auto-restart on file changes
- Clear cache on restart
- Logs all requests
**Usage:**
- Start with `bun run dev` in one terminal
- Start CSS watcher with `bun run build:css` in another
- Changes auto-refresh immediately
---
## 9. Production Build
### Bun Bundler
**Command:**
```bash
bun build --target bun --outdir dist backend/server.ts
```
**Output:**
```
dist/
server.ts (bundled, optimized)
```
**Deployment:**
```bash
bun run dist/server.ts
```
**Rules:**
- ✅ Build before deploying
- ✅ Test built version locally
- ✅ Deploy from `dist/` folder
- ❌ Do NOT deploy source TypeScript files
- ❌ Do NOT use development server in production
---
## 10. Dependency Management
### Package.json Structure
**Required:**
```json
{
"name": "job-info-pb",
"version": "1.0.0",
"type": "module",
"private": true,
"scripts": {
"dev": "bun --watch backend/server.ts",
"start": "bun run backend/server.ts",
"build:css": "tailwindcss -i input.css -o frontend/output.css --watch",
"build": "bun build --target bun --outdir dist backend/server.ts"
},
"dependencies": {
"dotenv": "^17.2.3",
"hono": "^4.10.8",
"ioredis": "^5.x",
"pocketbase": "^0.26.5"
},
"devDependencies": {
"@types/bun": "latest",
"autoprefixer": "^10.4.23",
"postcss": "^8.5.6",
"tailwindcss": "^4.1.18"
}
}
```
**Rules:**
- ✅ Pin versions for production stability
- ✅ Use `^` for compatible versions
- ✅ Regularly audit for security updates
- ❌ Do NOT use `*` or `latest` in production dependencies
- ❌ Do NOT add unnecessary dependencies
**Update Command:**
```bash
bun update # Check for updates
bun audit # Security audit
bun install --save-exact # Lock versions
```
---
## 11. Enforcement & Validation
### Code Review Checklist
Before committing, verify:
- [ ] Uses Hono for all routes (no Express)
- [ ] Uses Tailwind for all styles (no inline styles)
- [ ] All functions have TypeScript types
- [ ] No `any` type annotations
- [ ] All dependencies pinned in package.json
- [ ] Cache implemented for GET endpoints
- [ ] Errors logged to file and console
- [ ] No hardcoded secrets
- [ ] No console.log() in production code (use proper logging)
- [ ] Follows naming conventions from RULES.md
### ESLint Rules (Optional but Recommended)
**.eslintrc.json:**
```json
{
"parser": "@typescript-eslint/parser",
"extends": ["eslint:recommended"],
"rules": {
"no-console": ["warn", { "allow": ["error", "warn"] }],
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/explicit-function-return-types": "warn"
}
}
```
---
## 12. Troubleshooting
### Bun Issues
- **"Command not found"**: Add Bun to PATH
- **"Module not found"**: Run `bun install`
- **"Permission denied"**: Run `chmod +x` on files
### Hono Issues
- **Route not found**: Check route path spelling
- **Middleware not applied**: Order matters; add to top of file
### Tailwind Issues
- **Classes not applying**: Run `bun run build:css`
- **Cache issue**: Delete output.css and rebuild
### Redis Issues
- **Connection refused**: Ensure Redis/Valkey is running
- **Timeout**: Check credentials in .env
---
## Summary
| Technology | Version | Rule |
|-----------|---------|------|
| Bun | latest | Runtime & build tool |
| Hono | ^4.10.8 | All web routes |
| PostCSS | ^8.5.6 | CSS processing |
| Tailwind | ^4.1.18 | Utility CSS |
| TypeScript | ^5 | Strict typing required |
| ioredis | ^5.x | Cache client |
| PocketBase | ^0.26.5 | Auth backend |
| dotenv | ^17.2.3 | Config management |
**All new code must use these exact versions and patterns.**