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" DATABASE_URL="file:./dev.db"
JWT_SECRET="dev-jwt-secret-change-in-production" 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 # Copy to .env and fill in your values
# PostgreSQL # PostgreSQL
+3 -3
View File
@@ -17,10 +17,10 @@ COPY packages/shared packages/shared
COPY apps/api apps/api COPY apps/api apps/api
COPY apps/dashboard apps/dashboard 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 cd apps/api && npx prisma generate
RUN pnpm --filter @kooltab/api run build RUN pnpm --filter @kooltap/api run build
RUN pnpm --filter @kooltab/dashboard run build RUN pnpm --filter @kooltap/dashboard run build
# ---- Production API image ---- # ---- Production API image ----
FROM node:20-alpine AS api 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. 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", "version": "1.0.0",
"private": true, "private": true,
"scripts": { "scripts": {
@@ -19,7 +19,7 @@
"clean": "rimraf dist" "clean": "rimraf dist"
}, },
"dependencies": { "dependencies": {
"@kooltab/shared": "workspace:*", "@kooltap/shared": "workspace:*",
"@nestjs/common": "^10.3.0", "@nestjs/common": "^10.3.0",
"@nestjs/core": "^10.3.0", "@nestjs/core": "^10.3.0",
"@nestjs/jwt": "^10.2.0", "@nestjs/jwt": "^10.2.0",
@@ -70,7 +70,7 @@
"coverageDirectory": "../coverage", "coverageDirectory": "../coverage",
"testEnvironment": "node", "testEnvironment": "node",
"moduleNameMapper": { "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(); const venueId = uuidv4();
await prisma.venue.create({ 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); const adminHash = await bcrypt.hash('Admin123!', 10);
await prisma.clientUser.create({ await prisma.clientUser.create({
+2 -2
View File
@@ -23,9 +23,9 @@ async function main() {
// Create venue // Create venue
const venueId = uuidv4(); const venueId = uuidv4();
await prisma.venue.create({ 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 // Create admin user
const adminHash = await bcrypt.hash('Admin123!', 10); 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'; const ADMIN_PASSWORD = process.env.SETUP_ADMIN_PASSWORD || process.argv[4] || 'admin123';
async function main() { async function main() {
console.log('=== KoolTab Production Setup ===\n'); console.log('=== KoolTap Production Setup ===\n');
// Wipe everything // Wipe everything
await prisma.auditLog.deleteMany(); await prisma.auditLog.deleteMany();
@@ -49,7 +49,7 @@ async function main() {
console.log(` Admin: ${ADMIN_EMAIL}`); console.log(` Admin: ${ADMIN_EMAIL}`);
console.log(` Password: ${ADMIN_PASSWORD}`); console.log(` Password: ${ADMIN_PASSWORD}`);
console.log('\nSave the Venue ID — the Flutter app needs it to find your venue.'); 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(); await prisma.$disconnect();
} }
+1 -1
View File
@@ -5,7 +5,7 @@ import * as crypto from 'crypto';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { PrismaService } from '../prisma/prisma.service'; import { PrismaService } from '../prisma/prisma.service';
import { AuditService } from '../audit/audit.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() @Injectable()
export class AuthService { export class AuthService {
+1 -1
View File
@@ -8,7 +8,7 @@ import { v4 as uuidv4 } from 'uuid';
import { PrismaService } from '../prisma/prisma.service'; import { PrismaService } from '../prisma/prisma.service';
import { AuditService } from '../audit/audit.service'; import { AuditService } from '../audit/audit.service';
import { CreateCommandDto } from './dto/create-command.dto'; 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() @Injectable()
export class CommandsService { export class CommandsService {
+1 -1
View File
@@ -40,7 +40,7 @@ async function bootstrap() {
app.useGlobalInterceptors(new LoggingInterceptor()); app.useGlobalInterceptors(new LoggingInterceptor());
const config = new DocumentBuilder() 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') .setDescription('API for managing remote tab control in venues')
.setVersion('1.0') .setVersion('1.0')
.addBearerAuth() .addBearerAuth()
+3 -3
View File
@@ -21,7 +21,7 @@ export class RemindersService {
constructor(private prisma: PrismaService) { constructor(private prisma: PrismaService) {
this.resendApiKey = process.env.RESEND_API_KEY || ''; 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) { async listCandidates(venueId: string) {
@@ -182,9 +182,9 @@ export class RemindersService {
body: JSON.stringify({ body: JSON.stringify({
from: this.fromEmail, from: this.fromEmail,
to: tab.email, to: tab.email,
subject: `Test email from KoolTab`, subject: `Test email from KoolTap`,
html: `<p>Hi ${escapeHtml(tab.customerName)},</p> 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> <p>If you received this, the email configuration is working!</p>
<hr> <hr>
<p style="color: #888; font-size: 12px;">This is a test — no action needed.</p>`, <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 { PrismaService } from '../src/prisma/prisma.service';
import { HttpExceptionFilter } from '../src/common/filters/http-exception.filter'; import { HttpExceptionFilter } from '../src/common/filters/http-exception.filter';
describe('KoolTab API (e2e)', () => { describe('KoolTap API (e2e)', () => {
let app: INestApplication; let app: INestApplication;
let prisma: PrismaService; let prisma: PrismaService;
+2 -2
View File
@@ -1,5 +1,5 @@
{ {
"name": "@kooltab/dashboard", "name": "@kooltap/dashboard",
"version": "1.0.0", "version": "1.0.0",
"private": true, "private": true,
"scripts": { "scripts": {
@@ -11,7 +11,7 @@
"clean": "echo 'clean'" "clean": "echo 'clean'"
}, },
"dependencies": { "dependencies": {
"@kooltab/shared": "workspace:*", "@kooltap/shared": "workspace:*",
"@radix-ui/react-alert-dialog": "^1.0.5", "@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6", "@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"> <button onClick={() => setSidebarOpen(!sidebarOpen)} className="p-2">
{sidebarOpen ? <X className="h-5 w-5" /> : <Menu className="h-5 w-5" />} {sidebarOpen ? <X className="h-5 w-5" /> : <Menu className="h-5 w-5" />}
</button> </button>
<span className="font-semibold">KoolTab</span> <span className="font-semibold">KoolTap</span>
<div className="w-9" /> <div className="w-9" />
</div> </div>
@@ -105,7 +105,7 @@ export default function DashboardLayout({
> >
<div className="flex flex-col h-full"> <div className="flex flex-col h-full">
<div className="p-6 border-b"> <div className="p-6 border-b">
<h2 className="text-xl font-bold">KoolTab</h2> <h2 className="text-xl font-bold">KoolTap</h2>
{venue && ( {venue && (
<p className="text-sm text-muted-foreground mt-1">{venue.name}</p> <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'] }); const inter = Inter({ subsets: ['latin'] });
export const metadata: Metadata = { export const metadata: Metadata = {
title: 'KoolTab - Remote Tab Control', title: 'KoolTap - Remote Tab Control',
description: 'Manage tabs remotely across your venue', 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"> <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"> <Card className="w-full max-w-md">
<CardHeader className="space-y-1 text-center"> <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> <CardDescription>Remote Tab Control Dashboard</CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
+2 -2
View File
@@ -335,13 +335,13 @@ export function LanguageProvider({ children }: { children: ReactNode }) {
const [lang, setLangState] = useState<Lang>('en'); const [lang, setLangState] = useState<Lang>('en');
useEffect(() => { 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); if (stored === 'en' || stored === 'nl') setLangState(stored);
}, []); }, []);
function setLang(l: Lang) { function setLang(l: Lang) {
setLangState(l); setLangState(l);
localStorage.setItem('kooltab-lang', l); localStorage.setItem('kooltap-lang', l);
} }
function t(key: string, params?: Record<string, string | number>): string { function t(key: string, params?: Record<string, string | number>): string {
+1 -1
View File
@@ -22,7 +22,7 @@
"@/*": [ "@/*": [
"./src/*" "./src/*"
], ],
"@kooltab/shared": [ "@kooltap/shared": [
"../../packages/shared/src" "../../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: postgres:
image: postgres:16-alpine image: postgres:16-alpine
environment: environment:
POSTGRES_DB: kooltab POSTGRES_DB: kooltap
POSTGRES_USER: kooltab POSTGRES_USER: kooltap
POSTGRES_PASSWORD: ${DB_PASSWORD:-changeme} POSTGRES_PASSWORD: ${DB_PASSWORD:-changeme}
volumes: volumes:
- pgdata:/var/lib/postgresql/data - pgdata:/var/lib/postgresql/data
healthcheck: healthcheck:
test: ["CMD-SHELL", "pg_isready -U kooltab"] test: ["CMD-SHELL", "pg_isready -U kooltap"]
interval: 5s interval: 5s
timeout: 5s timeout: 5s
retries: 5 retries: 5
networks: networks:
- kooltab-net - kooltap-net
api: api:
build: build:
@@ -25,13 +25,13 @@ services:
ports: ports:
- "${API_PORT:-3001}:3001" - "${API_PORT:-3001}:3001"
environment: 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_SECRET: "${JWT_SECRET}"
JWT_REFRESH_SECRET: "${JWT_REFRESH_SECRET}" JWT_REFRESH_SECRET: "${JWT_REFRESH_SECRET}"
PORT: 3001 PORT: 3001
CORS_ORIGIN: "${DASHBOARD_URL:-http://localhost:3000}" CORS_ORIGIN: "${DASHBOARD_URL:-http://localhost:3000}"
RESEND_API_KEY: "${RESEND_API_KEY:-}" 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 # The API sits behind a reverse proxy: trust one hop of X-Forwarded-For for per-client rate limiting
TRUST_PROXY: "${TRUST_PROXY:-1}" TRUST_PROXY: "${TRUST_PROXY:-1}"
depends_on: depends_on:
@@ -39,7 +39,7 @@ services:
condition: service_healthy condition: service_healthy
restart: unless-stopped restart: unless-stopped
networks: networks:
- kooltab-net - kooltap-net
- scoobydoo - scoobydoo
dashboard: dashboard:
@@ -55,14 +55,14 @@ services:
- api - api
restart: unless-stopped restart: unless-stopped
networks: networks:
- kooltab-net - kooltap-net
- scoobydoo - scoobydoo
volumes: volumes:
pgdata: pgdata:
networks: networks:
kooltab-net: kooltap-net:
driver: bridge driver: bridge
scoobydoo: scoobydoo:
external: true external: true
+3 -3
View File
@@ -17,7 +17,7 @@ services:
volumes: volumes:
- api-data:/app/prisma - api-data:/app/prisma
networks: networks:
- kooltab-net - kooltap-net
dashboard: dashboard:
build: build:
@@ -31,11 +31,11 @@ services:
depends_on: depends_on:
- api - api
networks: networks:
- kooltab-net - kooltap-net
volumes: volumes:
api-data: api-data:
networks: networks:
kooltab-net: kooltap-net:
driver: bridge driver: bridge
+2 -2
View File
@@ -1,8 +1,8 @@
# KoolTab Architecture # KoolTap Architecture
## Overview ## 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 ## 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 ### Project Location
`C:\Users\bram\StudioProjects\kooltab2` `C:\Users\bram\StudioProjects\kooltap`
### Architecture Overview ### Architecture Overview
- State management: `provider` (ChangeNotifier pattern) - 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) ### Pairing Flow (improved)
Instead of typing a UUID venueId, the flow is: 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 2. Gets list of `[{id, name}]` — admin picks venue from a dropdown
3. Admin enters device name (e.g. "Bar terminal 1") 3. Admin enters device name (e.g. "Bar terminal 1")
4. Admin enters the 6-character registration code (generated from dashboard) 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 #### 1. Update Server URL
In `lib/utils/app_config.dart`: In `lib/utils/app_config.dart`:
```dart ```dart
const kRemoteServerUrl = 'https://api.kooltab.com/api/v1/'; const kRemoteServerUrl = 'https://api.kooltap.com/api/v1/';
``` ```
#### 2. Add Venue Model #### 2. Add Venue Model
@@ -91,7 +91,7 @@ Create `lib/views/registration_view.dart` — a full-screen registration flow wi
**Step 3 — Success screen:** **Step 3 — Success screen:**
- Success animation/message - 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 #### 6. Wire Registration into Navigation
In `lib/app/app_bootstrap.dart`: In `lib/app/app_bootstrap.dart`:
@@ -120,13 +120,13 @@ In the **Settings screen** (`lib/views/settings_view.dart`) or **Admin screen**:
**Venues list:** **Venues list:**
``` ```
GET https://api.kooltab.com/api/v1/venues/ GET https://api.kooltap.com/api/v1/venues/
Response: [{"id": "uuid", "name": "KoolTab Demo Bar"}, ...] Response: [{"id": "uuid", "name": "KoolTap Demo Bar"}, ...]
``` ```
**Device registration:** **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", "venueId": "uuid-from-venue-list",
"name": "Bar terminal 1", "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. 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 ```bash
# Clone the repository # Clone the repository
git clone <repo> git clone <repo>
cd kooltab cd kooltap_backoffice
# Install dependencies # Install dependencies
pnpm install pnpm install
+5 -5
View File
@@ -1,4 +1,4 @@
# KoolTab Production Deployment # KoolTap Production Deployment
## Option A: Docker (recommended) ## Option A: Docker (recommended)
@@ -60,15 +60,15 @@ api.yourdomain.com {
Create database and user: Create database and user:
```sql ```sql
CREATE DATABASE kooltab; CREATE DATABASE kooltap;
CREATE USER kooltab WITH PASSWORD 'your-password'; CREATE USER kooltap WITH PASSWORD 'your-password';
GRANT ALL PRIVILEGES ON DATABASE kooltab TO kooltab; GRANT ALL PRIVILEGES ON DATABASE kooltap TO kooltap;
``` ```
### 2. Configure environment ### 2. Configure environment
```env ```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_SECRET="<random-64-char-string>"
JWT_REFRESH_SECRET="<random-64-char-string>" JWT_REFRESH_SECRET="<random-64-char-string>"
PORT=3001 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, "private": true,
"scripts": { "scripts": {
"install:all": "pnpm install", "install:all": "pnpm install",
@@ -8,12 +8,12 @@
"lint": "pnpm -r run lint", "lint": "pnpm -r run lint",
"typecheck": "pnpm -r run typecheck", "typecheck": "pnpm -r run typecheck",
"test": "pnpm -r run test", "test": "pnpm -r run test",
"test:e2e": "pnpm --filter @kooltab/api run test:e2e", "test:e2e": "pnpm --filter @kooltap/api run test:e2e",
"db:generate": "pnpm --filter @kooltab/api run db:generate", "db:generate": "pnpm --filter @kooltap/api run db:generate",
"db:migrate": "pnpm --filter @kooltab/api run db:migrate", "db:migrate": "pnpm --filter @kooltap/api run db:migrate",
"db:seed": "pnpm --filter @kooltab/api run db:seed", "db:seed": "pnpm --filter @kooltap/api run db:seed",
"db:reset": "pnpm --filter @kooltab/api run db:reset", "db:reset": "pnpm --filter @kooltap/api run db:reset",
"api:docs": "pnpm --filter @kooltab/api run start:dev", "api:docs": "pnpm --filter @kooltap/api run start:dev",
"clean": "pnpm -r run clean" "clean": "pnpm -r run clean"
}, },
"engines": { "engines": {
+1 -1
View File
@@ -1,5 +1,5 @@
{ {
"name": "@kooltab/shared", "name": "@kooltap/shared",
"version": "1.0.0", "version": "1.0.0",
"main": "dist/index.js", "main": "dist/index.js",
"types": "src/index.ts", "types": "src/index.ts",
+2 -2
View File
@@ -14,7 +14,7 @@ importers:
apps/api: apps/api:
dependencies: dependencies:
'@kooltab/shared': '@kooltap/shared':
specifier: workspace:* specifier: workspace:*
version: link:../../packages/shared version: link:../../packages/shared
'@nestjs/common': '@nestjs/common':
@@ -129,7 +129,7 @@ importers:
apps/dashboard: apps/dashboard:
dependencies: dependencies:
'@kooltab/shared': '@kooltap/shared':
specifier: workspace:* specifier: workspace:*
version: link:../../packages/shared version: link:../../packages/shared
'@radix-ui/react-alert-dialog': '@radix-ui/react-alert-dialog':
+3 -3
View File
@@ -1,5 +1,5 @@
#!/bin/sh #!/bin/sh
# KoolTab Production Deploy # KoolTap Production Deploy
# Usage: ./scripts/deploy.sh "My Venue" admin@myvenue.com password # Usage: ./scripts/deploy.sh "My Venue" admin@myvenue.com password
VENUE_NAME="${1:-${SETUP_VENUE_NAME}}" VENUE_NAME="${1:-${SETUP_VENUE_NAME}}"
@@ -12,7 +12,7 @@ if [ -z "$VENUE_NAME" ] || [ -z "$ADMIN_EMAIL" ] || [ -z "$ADMIN_PASSWORD" ]; th
exit 1 exit 1
fi fi
echo "=== Deploying KoolTab ===" echo "=== Deploying KoolTap ==="
echo " Venue: $VENUE_NAME" echo " Venue: $VENUE_NAME"
echo " Admin: $ADMIN_EMAIL" echo " Admin: $ADMIN_EMAIL"
echo "" echo ""
@@ -39,5 +39,5 @@ docker compose -f docker-compose.prod.yml exec api sh -c "
echo "" echo ""
echo "=== Done ===" echo "=== Done ==="
echo " Dashboard: https://kooltab.com" echo " Dashboard: https://kooltap.com"
echo " Login: $ADMIN_EMAIL / $ADMIN_PASSWORD" 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. * An interactive CLI that simulates a Flutter bar terminal device.
* Keeps running until you press Q. * Keeps running until you press Q.
@@ -214,7 +214,7 @@ async function setVenueAndCode() {
function printHelp() { function printHelp() {
console.log(` console.log(`
╔══════════════════════════════════════════╗ ╔══════════════════════════════════════════╗
║ KoolTab Device Simulator ║ ║ KoolTap Device Simulator ║
╠══════════════════════════════════════════╣ ╠══════════════════════════════════════════╣
║ P — Pair / register device ║ ║ P — Pair / register device ║
║ T — Add tab (uses planned customers) ║ ║ T — Add tab (uses planned customers) ║
@@ -230,7 +230,7 @@ function printHelp() {
async function main() { async function main() {
console.clear(); console.clear();
console.log('╔══════════════════════════════════════╗'); console.log('╔══════════════════════════════════════╗');
console.log('║ KoolTab Device Simulator ║'); console.log('║ KoolTap Device Simulator ║');
console.log('╚══════════════════════════════════════╝'); console.log('╚══════════════════════════════════════╝');
// Prompt for venue / code on first run // Prompt for venue / code on first run
+3 -3
View File
@@ -1,5 +1,5 @@
#!/bin/sh #!/bin/sh
# KoolTab Production Setup # KoolTap Production Setup
# Usage: ./scripts/setup.sh "My Venue" admin@myvenue.com mypassword # Usage: ./scripts/setup.sh "My Venue" admin@myvenue.com mypassword
# #
# Or with env vars: # Or with env vars:
@@ -15,7 +15,7 @@ if [ -z "$VENUE_NAME" ] || [ -z "$ADMIN_EMAIL" ] || [ -z "$ADMIN_PASSWORD" ]; th
exit 1 exit 1
fi fi
echo "=== KoolTab Production Setup ===" echo "=== KoolTap Production Setup ==="
echo "" echo ""
echo " Venue: $VENUE_NAME" echo " Venue: $VENUE_NAME"
echo " Admin: $ADMIN_EMAIL" 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; } node prisma/setup.js || { echo "FAILED"; exit 1; }
echo "" echo ""
echo "Setup complete. Login at https://kooltab.com" echo "Setup complete. Login at https://kooltap.com"