feat: fix alot of issues

This commit is contained in:
2026-10-08 00:25:30 +02:00
parent 8b1e38cb4d
commit e5580767a5
35 changed files with 127 additions and 615 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
# KoolTab Remote Tab Control
# KoolTap Remote Tab Control
DATABASE_URL="file:./dev.db"
JWT_SECRET="dev-jwt-secret-change-in-production"
+1 -1
View File
@@ -1,4 +1,4 @@
# Production environment variables for KoolTab
# Production environment variables for KoolTap
# Copy to .env and fill in your values
# PostgreSQL
+3 -3
View File
@@ -17,10 +17,10 @@ COPY packages/shared packages/shared
COPY apps/api apps/api
COPY apps/dashboard apps/dashboard
RUN pnpm --filter @kooltab/shared run build
RUN pnpm --filter @kooltap/shared run build
RUN cd apps/api && npx prisma generate
RUN pnpm --filter @kooltab/api run build
RUN pnpm --filter @kooltab/dashboard run build
RUN pnpm --filter @kooltap/api run build
RUN pnpm --filter @kooltap/dashboard run build
# ---- Production API image ----
FROM node:20-alpine AS api
+1 -1
View File
@@ -1,4 +1,4 @@
# KoolTab Remote Tab Control
# KoolTap Remote Tab Control
A production-quality remote tab control system for venues. Allows bar staff to manage and close tabs remotely from a web dashboard, with commands delivered to bar terminals via a sync API.
+3 -3
View File
@@ -1,5 +1,5 @@
{
"name": "@kooltab/api",
"name": "@kooltap/api",
"version": "1.0.0",
"private": true,
"scripts": {
@@ -19,7 +19,7 @@
"clean": "rimraf dist"
},
"dependencies": {
"@kooltab/shared": "workspace:*",
"@kooltap/shared": "workspace:*",
"@nestjs/common": "^10.3.0",
"@nestjs/core": "^10.3.0",
"@nestjs/jwt": "^10.2.0",
@@ -70,7 +70,7 @@
"coverageDirectory": "../coverage",
"testEnvironment": "node",
"moduleNameMapper": {
"^@kooltab/shared$": "<rootDir>/../../packages/shared/src"
"^@kooltap/shared$": "<rootDir>/../../packages/shared/src"
}
}
}
+2 -2
View File
@@ -21,9 +21,9 @@ async function main() {
const venueId = uuidv4();
await prisma.venue.create({
data: { id: venueId, name: 'KoolTab Demo Bar' },
data: { id: venueId, name: 'KoolTap Demo Bar' },
});
console.log(`Created venue: KoolTab Demo Bar (${venueId})`);
console.log(`Created venue: KoolTap Demo Bar (${venueId})`);
const adminHash = await bcrypt.hash('Admin123!', 10);
await prisma.clientUser.create({
+2 -2
View File
@@ -23,9 +23,9 @@ async function main() {
// Create venue
const venueId = uuidv4();
await prisma.venue.create({
data: { id: venueId, name: 'KoolTab Demo Bar' },
data: { id: venueId, name: 'KoolTap Demo Bar' },
});
console.log(`Created venue: KoolTab Demo Bar (${venueId})`);
console.log(`Created venue: KoolTap Demo Bar (${venueId})`);
// Create admin user
const adminHash = await bcrypt.hash('Admin123!', 10);
+2 -2
View File
@@ -10,7 +10,7 @@ const ADMIN_EMAIL = process.env.SETUP_ADMIN_EMAIL || process.argv[3] || 'admin@e
const ADMIN_PASSWORD = process.env.SETUP_ADMIN_PASSWORD || process.argv[4] || 'admin123';
async function main() {
console.log('=== KoolTab Production Setup ===\n');
console.log('=== KoolTap Production Setup ===\n');
// Wipe everything
await prisma.auditLog.deleteMany();
@@ -49,7 +49,7 @@ async function main() {
console.log(` Admin: ${ADMIN_EMAIL}`);
console.log(` Password: ${ADMIN_PASSWORD}`);
console.log('\nSave the Venue ID — the Flutter app needs it to find your venue.');
console.log('Login at https://kooltab.com with the admin credentials above.');
console.log('Login at https://kooltap.com with the admin credentials above.');
await prisma.$disconnect();
}
+1 -1
View File
@@ -5,7 +5,7 @@ import * as crypto from 'crypto';
import { v4 as uuidv4 } from 'uuid';
import { PrismaService } from '../prisma/prisma.service';
import { AuditService } from '../audit/audit.service';
import { TOKEN_EXPIRY_DAYS, TOKEN_BYTE_LENGTH, TOKEN_PREFIX_LENGTH } from '@kooltab/shared';
import { TOKEN_EXPIRY_DAYS, TOKEN_BYTE_LENGTH, TOKEN_PREFIX_LENGTH } from '@kooltap/shared';
@Injectable()
export class AuthService {
+1 -1
View File
@@ -8,7 +8,7 @@ import { v4 as uuidv4 } from 'uuid';
import { PrismaService } from '../prisma/prisma.service';
import { AuditService } from '../audit/audit.service';
import { CreateCommandDto } from './dto/create-command.dto';
import { COMMAND_EXPIRY_HOURS, DEVICE_OFFLINE_THRESHOLD_MS } from '@kooltab/shared';
import { COMMAND_EXPIRY_HOURS, DEVICE_OFFLINE_THRESHOLD_MS } from '@kooltap/shared';
@Injectable()
export class CommandsService {
+1 -1
View File
@@ -40,7 +40,7 @@ async function bootstrap() {
app.useGlobalInterceptors(new LoggingInterceptor());
const config = new DocumentBuilder()
.setTitle('KoolTab Remote Tab Control API')
.setTitle('KoolTap Remote Tab Control API')
.setDescription('API for managing remote tab control in venues')
.setVersion('1.0')
.addBearerAuth()
+3 -3
View File
@@ -21,7 +21,7 @@ export class RemindersService {
constructor(private prisma: PrismaService) {
this.resendApiKey = process.env.RESEND_API_KEY || '';
this.fromEmail = process.env.RESEND_FROM_EMAIL || 'KoolTab <onboarding@resend.dev>';
this.fromEmail = process.env.RESEND_FROM_EMAIL || 'KoolTap <onboarding@resend.dev>';
}
async listCandidates(venueId: string) {
@@ -182,9 +182,9 @@ export class RemindersService {
body: JSON.stringify({
from: this.fromEmail,
to: tab.email,
subject: `Test email from KoolTab`,
subject: `Test email from KoolTap`,
html: `<p>Hi ${escapeHtml(tab.customerName)},</p>
<p>This is a test email from KoolTab to verify that email reminders are working correctly.</p>
<p>This is a test email from KoolTap to verify that email reminders are working correctly.</p>
<p>If you received this, the email configuration is working!</p>
<hr>
<p style="color: #888; font-size: 12px;">This is a test — no action needed.</p>`,
+1 -1
View File
@@ -5,7 +5,7 @@ import { AppModule } from '../src/app.module';
import { PrismaService } from '../src/prisma/prisma.service';
import { HttpExceptionFilter } from '../src/common/filters/http-exception.filter';
describe('KoolTab API (e2e)', () => {
describe('KoolTap API (e2e)', () => {
let app: INestApplication;
let prisma: PrismaService;
+2 -2
View File
@@ -1,5 +1,5 @@
{
"name": "@kooltab/dashboard",
"name": "@kooltap/dashboard",
"version": "1.0.0",
"private": true,
"scripts": {
@@ -11,7 +11,7 @@
"clean": "echo 'clean'"
},
"dependencies": {
"@kooltab/shared": "workspace:*",
"@kooltap/shared": "workspace:*",
"@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
+2 -2
View File
@@ -84,7 +84,7 @@ export default function DashboardLayout({
<button onClick={() => setSidebarOpen(!sidebarOpen)} className="p-2">
{sidebarOpen ? <X className="h-5 w-5" /> : <Menu className="h-5 w-5" />}
</button>
<span className="font-semibold">KoolTab</span>
<span className="font-semibold">KoolTap</span>
<div className="w-9" />
</div>
@@ -105,7 +105,7 @@ export default function DashboardLayout({
>
<div className="flex flex-col h-full">
<div className="p-6 border-b">
<h2 className="text-xl font-bold">KoolTab</h2>
<h2 className="text-xl font-bold">KoolTap</h2>
{venue && (
<p className="text-sm text-muted-foreground mt-1">{venue.name}</p>
)}
+1 -1
View File
@@ -6,7 +6,7 @@ import { Providers } from './providers';
const inter = Inter({ subsets: ['latin'] });
export const metadata: Metadata = {
title: 'KoolTab - Remote Tab Control',
title: 'KoolTap - Remote Tab Control',
description: 'Manage tabs remotely across your venue',
};
+1 -1
View File
@@ -35,7 +35,7 @@ export default function LoginPage() {
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-slate-100 to-slate-200 p-4">
<Card className="w-full max-w-md">
<CardHeader className="space-y-1 text-center">
<CardTitle className="text-2xl font-bold">KoolTab</CardTitle>
<CardTitle className="text-2xl font-bold">KoolTap</CardTitle>
<CardDescription>Remote Tab Control Dashboard</CardDescription>
</CardHeader>
<CardContent>
+2 -2
View File
@@ -335,13 +335,13 @@ export function LanguageProvider({ children }: { children: ReactNode }) {
const [lang, setLangState] = useState<Lang>('en');
useEffect(() => {
const stored = localStorage.getItem('kooltab-lang') as Lang | null;
const stored = localStorage.getItem('kooltap-lang') as Lang | null;
if (stored === 'en' || stored === 'nl') setLangState(stored);
}, []);
function setLang(l: Lang) {
setLangState(l);
localStorage.setItem('kooltab-lang', l);
localStorage.setItem('kooltap-lang', l);
}
function t(key: string, params?: Record<string, string | number>): string {
+1 -1
View File
@@ -22,7 +22,7 @@
"@/*": [
"./src/*"
],
"@kooltab/shared": [
"@kooltap/shared": [
"../../packages/shared/src"
]
},
File diff suppressed because one or more lines are too long
+46
View File
@@ -0,0 +1,46 @@
# Coolify deployment (Docker Compose build pack).
# Postgres runs as a separate Coolify database resource so it gets scheduled backups;
# set DATABASE_URL to its internal connection URL. Domains are assigned in the Coolify UI:
# api -> https://api.example.com:3001
# dashboard -> https://dashboard.example.com:3000
services:
api:
build:
context: .
dockerfile: Dockerfile
target: api
environment:
DATABASE_URL: ${DATABASE_URL}
JWT_SECRET: ${SERVICE_BASE64_64_JWT}
PORT: 3001
CORS_ORIGIN: ${DASHBOARD_URL}
RESEND_API_KEY: ${RESEND_API_KEY:-}
RESEND_FROM_EMAIL: ${RESEND_FROM_EMAIL:-KoolTap <onboarding@resend.dev>}
# Coolify's proxy is one hop; use 2 if Cloudflare proxying is also enabled
TRUST_PROXY: ${TRUST_PROXY:-1}
healthcheck:
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3001/api/v1/health"]
interval: 15s
timeout: 5s
retries: 5
# Migrations run before the server starts
start_period: 60s
restart: unless-stopped
dashboard:
build:
context: .
dockerfile: Dockerfile
target: dashboard
args:
NEXT_PUBLIC_API_URL: ${API_URL}/api/v1
healthcheck:
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/"]
interval: 15s
timeout: 5s
retries: 5
start_period: 30s
depends_on:
api:
condition: service_healthy
restart: unless-stopped
+9 -9
View File
@@ -4,18 +4,18 @@ services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: kooltab
POSTGRES_USER: kooltab
POSTGRES_DB: kooltap
POSTGRES_USER: kooltap
POSTGRES_PASSWORD: ${DB_PASSWORD:-changeme}
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U kooltab"]
test: ["CMD-SHELL", "pg_isready -U kooltap"]
interval: 5s
timeout: 5s
retries: 5
networks:
- kooltab-net
- kooltap-net
api:
build:
@@ -25,13 +25,13 @@ services:
ports:
- "${API_PORT:-3001}:3001"
environment:
DATABASE_URL: "postgresql://kooltab:${DB_PASSWORD:-changeme}@postgres:5432/kooltab"
DATABASE_URL: "postgresql://kooltap:${DB_PASSWORD:-changeme}@postgres:5432/kooltap"
JWT_SECRET: "${JWT_SECRET}"
JWT_REFRESH_SECRET: "${JWT_REFRESH_SECRET}"
PORT: 3001
CORS_ORIGIN: "${DASHBOARD_URL:-http://localhost:3000}"
RESEND_API_KEY: "${RESEND_API_KEY:-}"
RESEND_FROM_EMAIL: "${RESEND_FROM_EMAIL:-KoolTab <onboarding@resend.dev>}"
RESEND_FROM_EMAIL: "${RESEND_FROM_EMAIL:-KoolTap <onboarding@resend.dev>}"
# The API sits behind a reverse proxy: trust one hop of X-Forwarded-For for per-client rate limiting
TRUST_PROXY: "${TRUST_PROXY:-1}"
depends_on:
@@ -39,7 +39,7 @@ services:
condition: service_healthy
restart: unless-stopped
networks:
- kooltab-net
- kooltap-net
- scoobydoo
dashboard:
@@ -55,14 +55,14 @@ services:
- api
restart: unless-stopped
networks:
- kooltab-net
- kooltap-net
- scoobydoo
volumes:
pgdata:
networks:
kooltab-net:
kooltap-net:
driver: bridge
scoobydoo:
external: true
+3 -3
View File
@@ -17,7 +17,7 @@ services:
volumes:
- api-data:/app/prisma
networks:
- kooltab-net
- kooltap-net
dashboard:
build:
@@ -31,11 +31,11 @@ services:
depends_on:
- api
networks:
- kooltab-net
- kooltap-net
volumes:
api-data:
networks:
kooltab-net:
kooltap-net:
driver: bridge
+2 -2
View File
@@ -1,8 +1,8 @@
# KoolTab Architecture
# KoolTap Architecture
## Overview
KoolTab is a modular monolith designed for remote tab control in venues.
KoolTap is a modular monolith designed for remote tab control in venues.
## Components
+9 -9
View File
@@ -1,9 +1,9 @@
## KoolTab Flutter App — Remote Backoffice Integration (Improved Pairing Flow)
## KoolTap Flutter App — Remote Backoffice Integration (Improved Pairing Flow)
You are implementing the device-side integration for the KoolTab remote tab control system. The Flutter app (bar POS terminal) needs to register with a remote backend, sync open tabs, and process remote close-tab commands.
You are implementing the device-side integration for the KoolTap remote tab control system. The Flutter app (bar POS terminal) needs to register with a remote backend, sync open tabs, and process remote close-tab commands.
### Project Location
`C:\Users\bram\StudioProjects\kooltab2`
`C:\Users\bram\StudioProjects\kooltap`
### Architecture Overview
- State management: `provider` (ChangeNotifier pattern)
@@ -22,7 +22,7 @@ You are implementing the device-side integration for the KoolTab remote tab cont
### Pairing Flow (improved)
Instead of typing a UUID venueId, the flow is:
1. Tablet calls `GET https://api.kooltab.com/api/v1/venues/` (public, no auth)
1. Tablet calls `GET https://api.kooltap.com/api/v1/venues/` (public, no auth)
2. Gets list of `[{id, name}]` — admin picks venue from a dropdown
3. Admin enters device name (e.g. "Bar terminal 1")
4. Admin enters the 6-character registration code (generated from dashboard)
@@ -44,7 +44,7 @@ Do NOT rewrite these files, just modify as needed:
#### 1. Update Server URL
In `lib/utils/app_config.dart`:
```dart
const kRemoteServerUrl = 'https://api.kooltab.com/api/v1/';
const kRemoteServerUrl = 'https://api.kooltap.com/api/v1/';
```
#### 2. Add Venue Model
@@ -91,7 +91,7 @@ Create `lib/views/registration_view.dart` — a full-screen registration flow wi
**Step 3 — Success screen:**
- Success animation/message
- "Start using KoolTab" button → navigates to main bar screen and triggers sync
- "Start using KoolTap" button → navigates to main bar screen and triggers sync
#### 6. Wire Registration into Navigation
In `lib/app/app_bootstrap.dart`:
@@ -120,13 +120,13 @@ In the **Settings screen** (`lib/views/settings_view.dart`) or **Admin screen**:
**Venues list:**
```
GET https://api.kooltab.com/api/v1/venues/
Response: [{"id": "uuid", "name": "KoolTab Demo Bar"}, ...]
GET https://api.kooltap.com/api/v1/venues/
Response: [{"id": "uuid", "name": "KoolTap Demo Bar"}, ...]
```
**Device registration:**
```
POST https://api.kooltab.com/api/v1/devices/register
POST https://api.kooltap.com/api/v1/devices/register
{
"venueId": "uuid-from-venue-list",
"name": "Bar terminal 1",
+1 -1
View File
@@ -1,4 +1,4 @@
## KoolTab Flutter App — Planned Tab Sync
## KoolTap Flutter App — Planned Tab Sync
Add support for **planned tab names** that are synced from the server. The server now returns a `plannedTabNames` list in the sync response. The app should create open tabs for any planned names that don't already have an open tab.
+1 -1
View File
@@ -9,7 +9,7 @@
```bash
# Clone the repository
git clone <repo>
cd kooltab
cd kooltap_backoffice
# Install dependencies
pnpm install
+5 -5
View File
@@ -1,4 +1,4 @@
# KoolTab Production Deployment
# KoolTap Production Deployment
## Option A: Docker (recommended)
@@ -60,15 +60,15 @@ api.yourdomain.com {
Create database and user:
```sql
CREATE DATABASE kooltab;
CREATE USER kooltab WITH PASSWORD 'your-password';
GRANT ALL PRIVILEGES ON DATABASE kooltab TO kooltab;
CREATE DATABASE kooltap;
CREATE USER kooltap WITH PASSWORD 'your-password';
GRANT ALL PRIVILEGES ON DATABASE kooltap TO kooltap;
```
### 2. Configure environment
```env
DATABASE_URL="postgresql://kooltab:your-password@localhost:5432/kooltab"
DATABASE_URL="postgresql://kooltap:your-password@localhost:5432/kooltap"
JWT_SECRET="<random-64-char-string>"
JWT_REFRESH_SECRET="<random-64-char-string>"
PORT=3001
-534
View File
@@ -1,534 +0,0 @@
{
"name": "kooltab",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "kooltab",
"devDependencies": {
"tsx": "^4.23.15"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz",
"integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz",
"integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz",
"integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz",
"integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz",
"integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz",
"integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz",
"integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz",
"integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz",
"integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz",
"integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz",
"integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz",
"integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz",
"integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz",
"integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz",
"integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz",
"integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz",
"integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz",
"integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz",
"integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz",
"integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz",
"integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openharmony-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz",
"integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openharmony"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz",
"integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz",
"integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz",
"integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz",
"integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/esbuild": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz",
"integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.28.2",
"@esbuild/android-arm": "0.28.2",
"@esbuild/android-arm64": "0.28.2",
"@esbuild/android-x64": "0.28.2",
"@esbuild/darwin-arm64": "0.28.2",
"@esbuild/darwin-x64": "0.28.2",
"@esbuild/freebsd-arm64": "0.28.2",
"@esbuild/freebsd-x64": "0.28.2",
"@esbuild/linux-arm": "0.28.2",
"@esbuild/linux-arm64": "0.28.2",
"@esbuild/linux-ia32": "0.28.2",
"@esbuild/linux-loong64": "0.28.2",
"@esbuild/linux-mips64el": "0.28.2",
"@esbuild/linux-ppc64": "0.28.2",
"@esbuild/linux-riscv64": "0.28.2",
"@esbuild/linux-s390x": "0.28.2",
"@esbuild/linux-x64": "0.28.2",
"@esbuild/netbsd-arm64": "0.28.2",
"@esbuild/netbsd-x64": "0.28.2",
"@esbuild/openbsd-arm64": "0.28.2",
"@esbuild/openbsd-x64": "0.28.2",
"@esbuild/openharmony-arm64": "0.28.2",
"@esbuild/sunos-x64": "0.28.2",
"@esbuild/win32-arm64": "0.28.2",
"@esbuild/win32-ia32": "0.28.2",
"@esbuild/win32-x64": "0.28.2"
}
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/tsx": {
"version": "4.23.15",
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.15.tgz",
"integrity": "sha512-Yiex1Ovn8z2xPpOWckIiysV1SSyRMY9BkLF++q0yKiDxCqRhosKfMg3janKkiLBwZ5c/YryloKwGZcrEmtwxKw==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "~0.28.0"
},
"bin": {
"tsx": "dist/cli.mjs"
},
"engines": {
"node": ">=18.0.0"
},
"optionalDependencies": {
"fsevents": "~2.3.3"
}
}
}
}
+7 -7
View File
@@ -1,5 +1,5 @@
{
"name": "kooltab",
"name": "kooltap",
"private": true,
"scripts": {
"install:all": "pnpm install",
@@ -8,12 +8,12 @@
"lint": "pnpm -r run lint",
"typecheck": "pnpm -r run typecheck",
"test": "pnpm -r run test",
"test:e2e": "pnpm --filter @kooltab/api run test:e2e",
"db:generate": "pnpm --filter @kooltab/api run db:generate",
"db:migrate": "pnpm --filter @kooltab/api run db:migrate",
"db:seed": "pnpm --filter @kooltab/api run db:seed",
"db:reset": "pnpm --filter @kooltab/api run db:reset",
"api:docs": "pnpm --filter @kooltab/api run start:dev",
"test:e2e": "pnpm --filter @kooltap/api run test:e2e",
"db:generate": "pnpm --filter @kooltap/api run db:generate",
"db:migrate": "pnpm --filter @kooltap/api run db:migrate",
"db:seed": "pnpm --filter @kooltap/api run db:seed",
"db:reset": "pnpm --filter @kooltap/api run db:reset",
"api:docs": "pnpm --filter @kooltap/api run start:dev",
"clean": "pnpm -r run clean"
},
"engines": {
+1 -1
View File
@@ -1,5 +1,5 @@
{
"name": "@kooltab/shared",
"name": "@kooltap/shared",
"version": "1.0.0",
"main": "dist/index.js",
"types": "src/index.ts",
+2 -2
View File
@@ -14,7 +14,7 @@ importers:
apps/api:
dependencies:
'@kooltab/shared':
'@kooltap/shared':
specifier: workspace:*
version: link:../../packages/shared
'@nestjs/common':
@@ -129,7 +129,7 @@ importers:
apps/dashboard:
dependencies:
'@kooltab/shared':
'@kooltap/shared':
specifier: workspace:*
version: link:../../packages/shared
'@radix-ui/react-alert-dialog':
+3 -3
View File
@@ -1,5 +1,5 @@
#!/bin/sh
# KoolTab Production Deploy
# KoolTap Production Deploy
# Usage: ./scripts/deploy.sh "My Venue" admin@myvenue.com password
VENUE_NAME="${1:-${SETUP_VENUE_NAME}}"
@@ -12,7 +12,7 @@ if [ -z "$VENUE_NAME" ] || [ -z "$ADMIN_EMAIL" ] || [ -z "$ADMIN_PASSWORD" ]; th
exit 1
fi
echo "=== Deploying KoolTab ==="
echo "=== Deploying KoolTap ==="
echo " Venue: $VENUE_NAME"
echo " Admin: $ADMIN_EMAIL"
echo ""
@@ -39,5 +39,5 @@ docker compose -f docker-compose.prod.yml exec api sh -c "
echo ""
echo "=== Done ==="
echo " Dashboard: https://kooltab.com"
echo " Dashboard: https://kooltap.com"
echo " Login: $ADMIN_EMAIL / $ADMIN_PASSWORD"
+3 -3
View File
@@ -1,5 +1,5 @@
/**
* KoolTab Interactive Device Simulator
* KoolTap Interactive Device Simulator
*
* An interactive CLI that simulates a Flutter bar terminal device.
* Keeps running until you press Q.
@@ -214,7 +214,7 @@ async function setVenueAndCode() {
function printHelp() {
console.log(`
╔══════════════════════════════════════════╗
║ KoolTab Device Simulator ║
║ KoolTap Device Simulator ║
╠══════════════════════════════════════════╣
║ P — Pair / register device ║
║ T — Add tab (uses planned customers) ║
@@ -230,7 +230,7 @@ function printHelp() {
async function main() {
console.clear();
console.log('╔══════════════════════════════════════╗');
console.log('║ KoolTab Device Simulator ║');
console.log('║ KoolTap Device Simulator ║');
console.log('╚══════════════════════════════════════╝');
// Prompt for venue / code on first run
+3 -3
View File
@@ -1,5 +1,5 @@
#!/bin/sh
# KoolTab Production Setup
# KoolTap Production Setup
# Usage: ./scripts/setup.sh "My Venue" admin@myvenue.com mypassword
#
# Or with env vars:
@@ -15,7 +15,7 @@ if [ -z "$VENUE_NAME" ] || [ -z "$ADMIN_EMAIL" ] || [ -z "$ADMIN_PASSWORD" ]; th
exit 1
fi
echo "=== KoolTab Production Setup ==="
echo "=== KoolTap Production Setup ==="
echo ""
echo " Venue: $VENUE_NAME"
echo " Admin: $ADMIN_EMAIL"
@@ -37,4 +37,4 @@ SETUP_VENUE_NAME="$VENUE_NAME" SETUP_ADMIN_EMAIL="$ADMIN_EMAIL" SETUP_ADMIN_PASS
node prisma/setup.js || { echo "FAILED"; exit 1; }
echo ""
echo "Setup complete. Login at https://kooltab.com"
echo "Setup complete. Login at https://kooltap.com"