Skip to content

Commit c389fa1

Browse files
committed
dns-prefetch, update docker file, removed unauthorized console error
1 parent 2da06e5 commit c389fa1

File tree

15 files changed

+296
-84
lines changed

15 files changed

+296
-84
lines changed

Backend/.dockerignore

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,34 @@
1-
# Node modules (don’t copy your host’s node_modules)
2-
node_modules
3-
npm-debug.log
1+
# Include any files or directories that you don't want to be copied to your
2+
# container here (e.g., local build artifacts, temporary files, etc.).
3+
#
4+
# For more help, visit the .dockerignore file reference guide at
5+
# https://docs.docker.com/go/build-context-dockerignore/
46

5-
# Environment variables
6-
.env
7-
.env.local
8-
.env.test
9-
.env.production
10-
11-
# Logs
12-
logs
13-
*.log
14-
15-
# OS / Editor junk
16-
.DS_Store
17-
.vscode
18-
.idea
19-
20-
# Git
21-
.git
22-
.gitignore
23-
24-
# Docker itself
25-
Dockerfile
26-
.dockerignore
7+
**/.classpath
8+
**/.dockerignore
9+
**/.env
10+
**/.git
11+
**/.gitignore
12+
**/.project
13+
**/.settings
14+
**/.toolstarget
15+
**/.vs
16+
**/.vscode
17+
**/.next
18+
**/.cache
19+
**/*.*proj.user
20+
**/*.dbmdl
21+
**/*.jfm
22+
**/charts
23+
**/docker-compose*
24+
**/compose.y*ml
25+
**/Dockerfile*
26+
**/node_modules
27+
**/npm-debug.log
28+
**/obj
29+
**/secrets.dev.yaml
30+
**/values.dev.yaml
31+
**/build
32+
**/dist
33+
LICENSE
34+
README.md

Backend/Dockerfile

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,76 @@
1-
FROM node:20-alpine AS base
1+
# syntax=docker/dockerfile:1
22

3-
WORKDIR /app
3+
# Comments are provided throughout this file to help you get started.
4+
# If you need more help, visit the Dockerfile reference guide at
5+
# https://docs.docker.com/go/dockerfile-reference/
46

5-
RUN npm i -g pnpm
7+
# Want to help us make this template better? Share your feedback here: https://forms.gle/ybq9Krt8jtBL3iCk7
68

7-
COPY package*.json pnpm-lock.yaml* ./
9+
ARG NODE_VERSION=22.18.0
10+
ARG PNPM_VERSION=10.11.0
811

9-
RUN pnpm install
12+
################################################################################
13+
# Use node image for base image for all stages.
14+
FROM node:${NODE_VERSION}-alpine as base
1015

16+
# Set working directory for all build stages.
17+
WORKDIR /usr/src/app
18+
19+
# Install pnpm.
20+
RUN --mount=type=cache,target=/root/.npm \
21+
npm install -g pnpm@${PNPM_VERSION}
22+
23+
################################################################################
24+
# Create a stage for installing production dependecies.
25+
FROM base as deps
26+
27+
# Download dependencies as a separate step to take advantage of Docker's caching.
28+
# Leverage a cache mount to /root/.local/share/pnpm/store to speed up subsequent builds.
29+
# Leverage bind mounts to package.json and pnpm-lock.yaml to avoid having to copy them
30+
# into this layer.
31+
RUN --mount=type=bind,source=package.json,target=package.json \
32+
--mount=type=bind,source=pnpm-lock.yaml,target=pnpm-lock.yaml \
33+
--mount=type=cache,target=/root/.local/share/pnpm/store \
34+
pnpm install --prod --frozen-lockfile
35+
36+
################################################################################
37+
# Create a stage for building the application.
38+
FROM deps as build
39+
40+
# Download additional development dependencies before building, as some projects require
41+
# "devDependencies" to be installed to build. If you don't need this, remove this step.
42+
RUN --mount=type=bind,source=package.json,target=package.json \
43+
--mount=type=bind,source=pnpm-lock.yaml,target=pnpm-lock.yaml \
44+
--mount=type=cache,target=/root/.local/share/pnpm/store \
45+
pnpm install --frozen-lockfile
46+
47+
# Copy the rest of the source files into the image.
1148
COPY . .
49+
# Run the build script.
50+
RUN pnpm run build
51+
52+
################################################################################
53+
# Create a new stage to run the application with minimal runtime dependencies
54+
# where the necessary files are copied from the build stage.
55+
FROM base as final
56+
57+
# Use production node environment by default.
58+
ENV NODE_ENV production
59+
60+
# Run the application as a non-root user.
61+
USER node
62+
63+
# Copy package.json so that package manager commands can be used.
64+
COPY package.json .
65+
66+
# Copy the production dependencies from the deps stage and also
67+
# the built application from the build stage into the image.
68+
COPY --from=deps /usr/src/app/node_modules ./node_modules
69+
COPY --from=build /usr/src/app/dist ./dist
1270

13-
RUN npm run build
1471

72+
# Expose the port that the application listens on.
1573
EXPOSE 3000
1674

17-
CMD ["npm", "start"]
75+
# Run the application.
76+
CMD ["node", "dist/app.js"]

Backend/src/controllers/user.controllers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ export const handleGoogleCallBack = async (req: Request, res: Response, next: Ne
237237
maxAge: 24 * 60 * 60 * 1000
238238
});
239239

240-
res.redirect(`${process.env.CLIENT_URL}/`);
240+
res.redirect(`${process.env.CLIENT_URL}/dashboard`);
241241
} catch (error) {
242242
next(new InternalServerError("Error while creating account with Google."));
243243
}

Backend/src/middlewares/auth.middlewares.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,43 @@ export function restrictUserLogin(req: Request, res: Response, next: NextFunctio
4040
res.status(401).json({ message: "Authentication failed" });
4141
return;
4242
}
43+
}
44+
export function softRestrictUserLogin(req: Request, res: Response, next: NextFunction): void {
45+
let token = req.cookies?.token;
46+
47+
if (!token && typeof req.headers.authorization === "string") {
48+
const authHeader = req.headers.authorization;
49+
if (authHeader.startsWith("Bearer ")) {
50+
token = authHeader.split(" ")[1];
51+
}
52+
}
53+
54+
if (!token) {
55+
res.status(200).json({
56+
authorized: false,
57+
message: "Please login again or create a new account."
58+
});
59+
return;
60+
}
61+
62+
try {
63+
const verifiedUser = verifyToken(token);
64+
if (!verifiedUser) {
65+
res.status(200).json({
66+
authorized: false,
67+
message: "Invalid or expired token"
68+
});
69+
return;
70+
}
71+
72+
req.jwtUser = verifiedUser;
73+
next();
74+
} catch (err) {
75+
console.error("Auth error:", err);
76+
res.status(200).json({
77+
authorized: false,
78+
message: "Authentication failed"
79+
});
80+
return;
81+
}
4382
}

Backend/src/routes/user.routes.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import express from "express";
22
import passport from "passport";
33
import { Request, Response } from "express";
44
import { handleUserLogin, handleUserRegister, handleChangeUserDetails, handleForgotPassword, handleUserLogout, handleUserDetails, handleGoogleCallBack, handleResetPassword, handleUserVerification, handleOtpResend } from "../controllers/user.controllers";
5-
import { restrictUserLogin } from "../middlewares/auth.middlewares";
5+
import { restrictUserLogin, softRestrictUserLogin } from "../middlewares/auth.middlewares";
66
import { changeUserDetailsSchema, forgotPasswordSchema, loginSchema, registerSchema, resetPasswordSchema, verifyUserIdSchema, verifyUserSchema } from "../schemas/user.schema";
77
import { validate } from "../middlewares/validate.middlewares";
88
const router = express.Router();
@@ -23,7 +23,7 @@ router.get('/auth/google/callback',
2323
passport.authenticate('google', { session: false }), handleGoogleCallBack);
2424

2525
router.get('/logout', handleUserLogout);
26-
router.get('/details', restrictUserLogin, handleUserDetails);
26+
router.get('/details', softRestrictUserLogin, handleUserDetails);
2727

2828
router.post('/login', validate(loginSchema), handleUserLogin);
2929
router.post('/register',validate(registerSchema) , handleUserRegister);

Frontend/index.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
<meta charset="UTF-8" />
66
<link rel="icon" href="/logo.webp" type="image/webp">
77
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
8+
<link rel="dns-prefetch" href="https://request.cronjon.site" />
9+
<link rel="preconnect" href="https://request.cronjon.site" crossorigin />
810
<title>CronJob Scheduler</title>
911
</head>
1012

Frontend/src/components/common/Header.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export default function Header({ sidebarOpen, setSidebarOpen }: Props) {
3434
dispatch(logout());
3535
dispatch(clearJobs());
3636
navigate("/login");
37-
}).catch(err => console.error(err))
37+
}).catch(err => console.error(err));
3838

3939
}
4040
return (

Frontend/src/components/routes/ProtectedRoute.tsx

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { useState, useEffect } from 'react';
22
import { Outlet, Navigate } from 'react-router-dom';
33
import { logout, setAuth } from '../../slices/authSlice';
44
import { useAppDispatch } from '../../hooks';
5-
import type { User } from '../../types';
65
import { Loader } from '../common';
76
import { clearJobs } from '../../slices/jobSlice';
87

@@ -17,21 +16,18 @@ export default function Layout() {
1716
credentials: 'include',
1817
})
1918
.then(async (res) => {
20-
21-
if (res.status === 401) {
22-
dispatch(logout());
23-
dispatch(clearJobs());
24-
setAuthorized(false);
25-
return null;
26-
}
27-
2819
const data = await res.json();
2920
if (!res.ok)
3021
throw new Error(data.message || "Something went wrong, Please try again later.");
3122
return data
3223
})
33-
.then((data: User | null) => {
34-
if (!data) return;
24+
.then(data => {
25+
if (data.authorized === false) {
26+
dispatch(logout());
27+
dispatch(clearJobs());
28+
setAuthorized(false);
29+
return null;
30+
}
3531

3632
setAuthorized(true);
3733

Frontend/src/pages/Dashboard.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export default function Dashboard() {
1717
disabled: 0,
1818
logs: 0
1919
});
20+
const user = useAppSelector(state => state.auth.user);
2021
const jobs = useAppSelector(state => state.jobs.jobs);
2122
const dispatch = useAppDispatch();
2223
const [isLoading, setIsLoading] = useState(true);
@@ -35,6 +36,7 @@ export default function Dashboard() {
3536

3637
useEffect(() => {
3738

39+
if (!user) return;
3840
if (jobs.length !== 0) return;
3941

4042
fetch(`${import.meta.env.VITE_BACKEND_URL}/api/jobs`, {
@@ -52,9 +54,10 @@ export default function Dashboard() {
5254

5355
dispatch(setJobs(data));
5456
}).catch(err => console.error(err));
55-
}, [dispatch, jobs.length])
57+
}, [dispatch, jobs.length, user])
5658

5759
useEffect(() => {
60+
if (!user) return;
5861
let intervalId: ReturnType<typeof setInterval> | undefined;
5962

6063
const fetchLogs = () => {
@@ -96,7 +99,7 @@ export default function Dashboard() {
9699
if (intervalId)
97100
clearInterval(intervalId);
98101
};
99-
}, [page]);
102+
}, [page, user]);
100103

101104
return (
102105
<>

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ A simple yet powerful cron job scheduler to automate recurring API requests (GET
1515
- ✨ Toggle jobs on/off without deleting them
1616
- 💻 Clean React + Tailwind
1717
- 🔐 JWT-based authentication
18+
- ⚡ Dedicated **Job Runner** for background execution
1819

1920
---
2021

@@ -35,6 +36,7 @@ A simple yet powerful cron job scheduler to automate recurring API requests (GET
3536
![Zod](https://img.shields.io/badge/Zod-7C3AED.svg?style=for-the-badge&logo=zod&logoColor=white)
3637
![Upstash](https://img.shields.io/badge/Qstash-10B981.svg?style=for-the-badge&logo=upstash&logoColor=white)
3738
![Pino](https://img.shields.io/badge/Pino-4B9E5F.svg?style=for-the-badge&logo=pino&logoColor=white)
39+
![Docker](https://img.shields.io/badge/Docker-2496ED.svg?style=for-the-badge&logo=docker&logoColor=white)
3840

3941
---
4042

@@ -79,6 +81,17 @@ pnpm install
7981
pnpm run dev
8082
```
8183

84+
### 4. Setup Job Runner
85+
> ⚡ Required for actual scheduling
86+
87+
```bash
88+
cd job-runner
89+
pnpm install
90+
cp .env.example .env
91+
# Make sure the MongoDB URI matches the backend
92+
pnpm run dev
93+
```
94+
8295
### 4. Setup Email Service (Optional)
8396
> ⚡ Only needed if you want to test/run email service.
8497

@@ -99,6 +112,7 @@ pnpm run dev
99112
CronJob-Scheduler/
100113
├── Backend/ # Server (Express + Agenda.js)
101114
├── Frontend/ # Client (React + Tailwind)
115+
├── job-runner/ # Background worker (Agenda.js)
102116
├── email-service/ # Email microservice (Express + Resend)
103117
├── README.md
104118
```

0 commit comments

Comments
 (0)