Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
{
"label": "dev",
"type": "shell",
"command": "./node_modules/.bin/dotenv -e .dev.env -e .public.env -e .secret.env -- 'turbo run dev --filter=${input:project}-frontend --filter=${input:project}-backend'"
"command": "./node_modules/.bin/dotenv -e .dev.env -e .secret.env -e .public.env -- 'turbo run dev --filter=${input:project}-frontend --filter=${input:project}-backend'",
},
{
"label": "serve",
"type": "shell",
"command": "./node_modules/.bin/dotenv -e .public.env -e .secret.env -- 'turbo run serve --filter=${input:project}-frontend --filter=${input:project}-backend'"
"command": "./node_modules/.bin/dotenv -e .secret.env -e .public.env -- 'turbo run serve --filter=${input:project}-frontend --filter=${input:project}-backend'"
},
{
"label": "deploy",
Expand All @@ -42,7 +42,7 @@
"id": "project",
"description": "Full Stack Projects worth running",
"type": "pickString",
"options": ["template", "test"]
"options": ["template", "test", "playoff-schedule"]
},
{
"id": "workspace",
Expand Down
5 changes: 5 additions & 0 deletions apps/playoff-schedule/backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM node:20-alpine
WORKDIR /usr/src/app
COPY ./dist /usr/src/app
EXPOSE 4590
CMD ["node","bundle.js"]
37 changes: 37 additions & 0 deletions apps/playoff-schedule/backend/build.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// בס"ד
import { build, context } from "esbuild";
import { spawn } from "child_process";

const isDev = process.env.NODE_ENV === "DEV";

const bundlePath = "dist/bundle.js";

const buildSettings = {
entryPoints: ["src/main.ts"],
outfile: "dist/bundle.js",
bundle: true,
plugins: [],
minify: true,
platform: "node",
target: ["ES2022"],
format: "cjs",
external: ["@repo/config-env"],
} satisfies Parameters<typeof build>[0];

const buildDev = async () =>
context(buildSettings)
.then(async (ctx) => ctx.watch())
.then(() => {
console.log("Starting nodemon to manage execution of bundle.js");
spawn(
"nodemon",
[bundlePath, "--watch", bundlePath, "--ext", "js", "--exec", "node"],
{ stdio: "inherit", shell: true }
);
});

const buildedProject = isDev ? buildDev() : build(buildSettings);

buildedProject.catch((error: unknown) => {
console.warn(error);
});
11 changes: 11 additions & 0 deletions apps/playoff-schedule/backend/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
services:
backend:
build:
context: .
dockerfile: Dockerfile

env_file:
- ../../../.public.env
- ../../../.secret.env
ports:
- "${BACKEND_PORT}:4590" # Maps host:${FRONTEND_PORT} to container:4590
20 changes: 20 additions & 0 deletions apps/playoff-schedule/backend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "playoff-schedule-backend",
"version": "1.0.0",
"description": "Backend for the application",
"main": "index.js",
"scripts": {
"test": "echo Backend Test Succeeded && exit 0",
"build": "tsx build.ts",
"serve": "node dist/bundle.js",
"dev": "tsx build.ts"
},
"author": "",
"license": "ISC",
"dependencies": {
"process": "^0.11.10"
},
"devDependencies": {
"@types/node": "^24.8.1"
}
}
65 changes: 65 additions & 0 deletions apps/playoff-schedule/backend/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// בס"ד
import express from "express";
import { apiRouter } from "./routes";
import cors from "cors";
import dotenv from "dotenv";
import { StatusCodes } from "http-status-codes";
dotenv.config();

const app = express();
app.use(
cors({
origin: "*",
})
);
app.use("/api/v1", apiRouter);

const defaultPort = 4590;
const port = process.env.BACKEND_PORT ?? defaultPort;

app.use(express.json({ limit: "10mb" }));
app.use(express.urlencoded({ limit: "10mb", extended: true }));

const apiKey: string | undefined = process.env.TBA_API_KEY;
if (apiKey === undefined) {
throw new Error("TBA_API_KEY is not defined.");
}

export const fetchData = async (url: string): Promise<unknown> => {
const response = await fetch(url, {
method: "GET",
headers: {
"X-TBA-Auth-Key": apiKey,
"Content-Type": "application/json",
},
mode: "cors",
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
};

app.get("/fetch", async (req, res) => {
try {
const encodedUrl = req.query.url;
if (!encodedUrl || typeof encodedUrl !== "string") {
res.status(StatusCodes.BAD_REQUEST).json({ error: "missing url param" });
return;
}
const fullUrl = decodeURIComponent(encodedUrl);

const data = await fetchData(fullUrl);
res.status(StatusCodes.OK).json(data);
} catch (error) {
console.error("Error in /fetch:", error);
res
.status(StatusCodes.INTERNAL_SERVER_ERROR)
.json({ error: "Failed to fetch data" });
}
});

app.listen(port, () => {
console.log(`Production server running at http://localhost:${port}`);
});
9 changes: 9 additions & 0 deletions apps/playoff-schedule/backend/src/routes/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// בס"ד
import { Router } from "express";
import { StatusCodes } from "http-status-codes";

export const apiRouter = Router();

apiRouter.get("/health", (req, res) => {
res.status(StatusCodes.OK).send({ message: "Healthy!" });
});
53 changes: 53 additions & 0 deletions apps/playoff-schedule/backend/src/routes/tba.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// בס"ד
import { Router } from "express";
import { StatusCodes } from "http-status-codes";

const tbaRouter = Router();

const getApiKey = (): string => {
const key = process.env.TBA_API_KEY;
if (!key) {
throw new Error("Missing TBA_API_KEY in environment variables");
}
return key;
};

export const fetchData = async (url: string): Promise<unknown> => {
const response = await fetch(url, {
method: "GET",
headers: {
"X-TBA-Auth-Key": getApiKey(),
"Content-Type": "application/json",
},
});

if (!response.ok) {
throw new Error(`HTTP error, status: ${response.status}`);
}

const data = await response.json();
return data;
};

tbaRouter.get("/fetch", async (req, res) => {
try {
const encodedUrl = req.query.url;

if (!encodedUrl || typeof encodedUrl !== "string") {
res.status(StatusCodes.BAD_REQUEST).json({ error: "missing url param" });
return;
}

const fullUrl = decodeURIComponent(encodedUrl);

const data = await fetchData(fullUrl);
res.status(StatusCodes.OK).json(data);
} catch (error) {
console.error("Error in /tba/fetch:", error);
res
.status(StatusCodes.INTERNAL_SERVER_ERROR)
.json({ error: "Failed to fetch data" });
}
});

export { tbaRouter };
2 changes: 2 additions & 0 deletions apps/playoff-schedule/backend/src/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// בס"ד
/// <reference types="vite/client" />
12 changes: 12 additions & 0 deletions apps/playoff-schedule/backend/turbo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"extends": [
"//"
],
"tasks": {
"build": {
"outputs": [
"dist/**"
]
}
}
}
7 changes: 7 additions & 0 deletions apps/playoff-schedule/frontend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM node:20-alpine
WORKDIR /app
COPY ./start.ts /app/start.ts
COPY ./dist /app/dist
EXPOSE 443
RUN ["npm","install","express"]
CMD ["npm","exec","--","tsx","start.ts"]
11 changes: 11 additions & 0 deletions apps/playoff-schedule/frontend/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
services:
frontend:
build:
context: .
dockerfile: Dockerfile

env_file:
- ../../../.public.env
- ../../../.secret.env
ports:
- "${FRONTEND_PORT}:443" # Maps host:${FRONTEND_PORT} to container:443
13 changes: 13 additions & 0 deletions apps/playoff-schedule/frontend/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="./src/assets/greenblitz.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>GreenBlitz 4590</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
32 changes: 32 additions & 0 deletions apps/playoff-schedule/frontend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "playoff-schedule-frontend",
"version": "1.0.0",
"description": "Frontend for the application",
"main": "index.js",
"scripts": {
"test": "echo Frontend Test Succeeded && exit 0",
"dev": "vite",
"build": "tsc -b && vite build",
"serve": "tsx start.ts",
"lint": "eslint .",
"preview": "vite preview"
},
"author": "",
"license": "ISC",
"dependencies": {
"react": "^19.1.1",
"react-dom": "^19.1.1",
"tailwindcss": "^4.1.16",
"@tailwindcss/vite": "^4.1.16"
},
"devDependencies": {
"@eslint/js": "^9.36.0",
"@types/node": "^24.6.0",
"@types/react": "^19.1.16",
"@types/react-dom": "^19.1.9",
"@vitejs/plugin-react": "^5.0.4",
"babel-plugin-react-compiler": "^19.1.0-rc.3",
"globals": "^16.4.0",
"vite": "^7.1.7"
}
}
Loading