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

12 KiB

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:

curl -fsSL https://bun.sh/install | bash

Common Commands:

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:

{
  "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:

bun add hono@^4.10.8

Routing Pattern:

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:

// 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:

bun add -D postcss@^8.5.6 tailwindcss@^4.1.18 autoprefixer@^10.4.23

Configuration Files:

postcss.config.js:

export default {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
};

tailwind.config.js:

export default {
  content: [
    './frontend/**/*.html',
    './frontend/**/*.js',
  ],
  theme: {
    extend: {
      colors: {
        // Add custom colors if needed
      },
    },
  },
  plugins: [],
};

Build Command:

bun run build:css

CSS Input (input.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:

<!-- ✅ 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):

{
  "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:

// ✅ 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:

bun add ioredis

Usage:

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:

bun add pocketbase@^0.26.5

Frontend Usage (auth.js):

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:

bun add dotenv@^17.2.3

Usage (Backend):

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:

# .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:

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:

bun build --target bun --outdir dist backend/server.ts

Output:

dist/
  server.ts  (bundled, optimized)

Deployment:

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:

{
  "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:

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

.eslintrc.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.