feat: fix alot of issues
This commit is contained in:
+1
-1
@@ -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
@@ -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
@@ -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,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.
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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({
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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>`,
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -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',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
@@ -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
@@ -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
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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,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.
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
Generated
-534
@@ -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
@@ -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,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",
|
||||||
|
|||||||
Generated
+2
-2
@@ -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
@@ -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"
|
||||||
@@ -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
@@ -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"
|
||||||
Reference in New Issue
Block a user