Compare commits

..
62 Commits
Author SHA1 Message Date
theis.gaedigk f4a9d1a5ba edit docker config 2026-10-18 17:14:07 +02:00
theis.gaedigk 8389eda7b1 adjust network config 2026-08-12 12:57:18 +02:00
theis.gaedigk 8c785bc4d9 Merge branch 'dev_demo' into host_demo 2026-08-12 12:52:52 +02:00
theis.gaedigk 7233370a61 Merge branch 'dev' into dev_demo 2026-08-12 12:52:10 +02:00
theis.gaedigk 0cafaea487 edited compose 2026-05-01 13:33:23 +02:00
theis.gaedigk 9e0b2d3861 edited port config 2026-05-01 13:30:25 +02:00
theis.gaedigk 1e727427f2 Merge branch 'dev_demo' into host_demo 2026-05-01 13:30:02 +02:00
theis.gaedigk fdb54b832b edited version infos 2026-05-01 13:25:55 +02:00
theis.gaedigk 2dede62e37 Merge branch 'dev' into dev_demo 2026-05-01 13:25:34 +02:00
theis.gaedigk 55c44cc639 Merge branch 'dev_demo' into debian12Demo 2026-04-18 14:59:57 +02:00
theis.gaedigk 34f133f94c Merge branch 'dev' into demoDev 2026-04-18 14:58:58 +02:00
theis.gaedigk a3df8172e2 Merge branch 'demoDev' into debian12Demo 2026-02-22 23:50:32 +01:00
theis.gaedigk 98834a9270 Merge branch 'dev' into demoDev 2026-02-22 23:50:00 +01:00
theis.gaedigk c00f720af4 Merge branch 'demoDev' into debian12Demo 2026-02-20 16:34:21 +01:00
theis.gaedigk 8d04465705 Merge branch 'dev' into demoDev 2026-02-20 16:33:54 +01:00
theis.gaedigk 06cb298a38 Merge branch 'demoDev' into debian12Demo 2026-02-09 15:55:52 +01:00
theis.gaedigk 8589971dc8 added scheme to demo branch 2026-02-09 15:55:27 +01:00
theis.gaedigk 6ec8e19737 Merge branch 'dev' into demoDev 2026-02-09 15:51:25 +01:00
theis.gaedigk d29c793b6b Merge branch 'demoDev' into debian12Demo 2026-02-07 17:50:53 +01:00
theis.gaedigk 9f44a4796d Merge branch 'dev' into demoDev 2026-02-07 17:50:34 +01:00
theis.gaedigk c97cc8b538 Merge branch 'demoDev' into debian12Demo 2026-02-07 17:44:12 +01:00
theis.gaedigk dc0a68f7f1 fixed version info 2026-02-07 17:42:21 +01:00
theis.gaedigk fe3a06e5ce Merge branch 'dev' into demoDev 2026-02-07 17:41:57 +01:00
theis.gaedigk 776fab749d Merge branch 'demoDev' into debian12Demo 2026-02-04 13:48:28 +01:00
theis.gaedigk 179f5686d1 Merge branch 'dev' into demoDev 2026-02-04 13:47:33 +01:00
theis.gaedigk 83b43f4c83 fixed bug again 2026-02-01 16:30:18 +01:00
theis.gaedigk 5d9cee63ab fixed bug: cannot start container 2026-02-01 16:28:47 +01:00
theis.gaedigk 0b203d838c added sth for demo distr 2026-02-01 16:26:58 +01:00
theis.gaedigk ae1888fe90 added secret user 2026-02-01 16:20:00 +01:00
theis.gaedigk f1c02910e6 changed docker config and other 2026-02-01 16:03:16 +01:00
theis.gaedigk d33b288956 chengd nginx config 2026-02-01 16:00:12 +01:00
theis.gaedigk 5e2a426401 edited docker config 2026-02-01 15:50:31 +01:00
theis.gaedigk 022aa669e8 Merge branch 'demoDev' into debian12Demo 2026-02-01 15:49:05 +01:00
theis.gaedigk 28373e0231 changed version info 2026-02-01 15:47:51 +01:00
theis.gaedigk 2f3583ccd0 Merge branch 'dev' into debian12 2026-01-28 18:26:08 +01:00
theis.gaedigk 9da72cc5bf Merge branch 'dev' into debian12 2026-01-28 13:06:19 +01:00
theis.gaedigk c633627b7c Merge branch 'dev' into debian12 2026-01-28 12:44:25 +01:00
theis.gaedigk 5259c41b13 Merge branch 'dev' into debian12 2026-01-27 21:29:08 +01:00
theis.gaedigk 3d9e3814fe edited docker 2026-01-27 10:33:32 +01:00
theis.gaedigk b44edb2b1d chnaged config 2026-01-16 17:17:15 +01:00
theis.gaedigk a72fabc0a0 Merge branch 'dev' into debian12 2026-01-16 17:11:30 +01:00
theis.gaedigk 1406f28f86 Merge branch 'dev' into debian12 2026-01-07 15:06:51 +01:00
theis.gaedigk 38d1091e9b Merge branch 'dev' into debian12 2025-11-30 21:23:22 +01:00
theis.gaedigk f82efecb8c edited docker config 2025-11-30 21:21:21 +01:00
theis.gaedigk 1f12bc8839 t 2025-11-30 21:17:36 +01:00
theis.gaedigk f19750f6f3 edited port config 2025-11-30 21:12:14 +01:00
theis.gaedigk 808b3fd5c4 Merge branch 'dev' into debian12 2025-11-30 21:07:32 +01:00
theis.gaedigk 0891598eb9 changed version info 2025-11-25 17:30:56 +01:00
theis.gaedigk 39ff02f2e7 Merge branch 'dev' into debian12 2025-11-25 17:11:27 +01:00
theis.gaedigk cc67fb4f85 changed version info 2025-11-24 15:35:03 +01:00
theis.gaedigk 75ff4aadc1 fixed color bug 2025-11-24 14:16:55 +01:00
theis.gaedigk 6f998d07c1 Merge branch 'dev' into debian12 2025-11-23 21:52:34 +01:00
theis.gaedigk f2bb326040 Merge branch 'dev' into debian12 2025-11-23 21:40:11 +01:00
theis.gaedigk 8c701db900 changed ports 2025-11-23 21:11:23 +01:00
theis.gaedigk d1664338a6 add networks configuration for frontend and backend services in docker-compose 2025-11-23 21:06:12 +01:00
theis.gaedigk 1a2624cd9e again 2025-11-23 20:34:19 +01:00
theis.gaedigk a138190cc6 fixed bugs 2025-11-23 20:32:14 +01:00
theis.gaedigk 993e0cd74b fixed bugs 2025-11-23 20:29:31 +01:00
theis.gaedigk dab004a7b6 changed docker config 2025-11-23 20:26:27 +01:00
theis.gaedigk d039336f39 Merge branch 'dev' into debian12 2025-11-23 20:20:41 +01:00
theis.gaedigk 4c781e9325 changed ports 2025-11-23 20:12:41 +01:00
theis.gaedigk 451e6b3646 published v2 2025-11-23 20:11:36 +01:00
104 changed files with 9221 additions and 3524 deletions
-14
View File
@@ -1,14 +0,0 @@
**/node_modules
**/dist
**/dist-ssr
.git
.idea
.vscode
**/.env
**/.env.*
**/.DS_Store
**/*.log
docs
pics
icon
no-as-a-service
-10
View File
@@ -1,10 +0,0 @@
DB_PASSWORD=
BACKEND_URL=
MAIL_HOST=
MAIL_PORT=
MAIL_USER=
MAIL_PASSWORD=
MAIL_SENDEES_CONTACT=
MAIL_SENDEES=
NAAS_URL=
SECRET_KEY=
+1 -3
View File
@@ -11,8 +11,6 @@ dist/
build/ build/
out/ out/
docker-compose.override.yml
# Environment variables # Environment variables
.env .env
.env.local .env.local
@@ -121,6 +119,6 @@ ToDo.txt
next-env.d.ts next-env.d.ts
# psd files from footage # psd files from footage
pics/*.psd footage/*.psd
icon/ icon/
-7
View File
@@ -1,7 +0,0 @@
{
"semi": true,
"singleQuote": false,
"trailingComma": "all",
"printWidth": 80,
"tabWidth": 2
}
-78
View File
@@ -1,78 +0,0 @@
# Docker
## Prerequisites
You have created an empty `docker-compose.override.yml` file in the root directory of this repository.
## Docker Network
If you want to run the stack in a docker network, you need to change the `BACKEND_HOST` variable in the root `.env` file
to `stockhome-backend`. To add a docker network, create a `docker-compose.override.yml` file in the root directory of
this repository with the following content:
```yaml
services:
admin-frontend:
networks:
- proxynet
backend:
networks:
- proxynet
usr-frontend:
networks:
- proxynet
no-as-a-service:
networks:
- proxynet
mysql:
networks:
- proxynet
networks:
proxynet:
external: true
```
To start off I recommend to set the `BACKEND_HOST` variable to `localhost` and start the stack without a docker network.
After you have started the stack and everything is working, you can add a docker network.
## Ports
### Change Exposed Ports
If you want to change the exposed ports, you can do this in the `docker-compose.yml` file like so:
```yaml
services:
mysql:
ports:
- "3306:3306"
backend:
ports:
- "8004:8004"
usr-frontend:
ports:
- "80:80"
```
### Remove Exposed Ports
If you want to remove the exposed ports, you can do this in the `docker-compose.override.yml` file like so:
```yaml
services:
mysql:
ports: !override [ ]
backend:
ports: !override [ ]
usr-frontend:
ports: !override [ ]
```

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 1.8 MiB

Before

Width:  |  Height:  |  Size: 428 KiB

After

Width:  |  Height:  |  Size: 428 KiB

Before

Width:  |  Height:  |  Size: 416 KiB

After

Width:  |  Height:  |  Size: 416 KiB

+19
View File
@@ -0,0 +1,19 @@
FROM node:22-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine AS runner
WORKDIR /usr/share/nginx/html
COPY --from=builder /app/dist .
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
@@ -14,7 +14,7 @@ server {
} }
location /backend/ { location /backend/ {
proxy_pass http://borrow-system_backend:8004/; proxy_pass http://demo_borrow_system-backend_v2:8004/;
} }
location ~* \.(?:js|mjs|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ { location ~* \.(?:js|mjs|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
File diff suppressed because it is too large Load Diff
@@ -1,7 +1,7 @@
{ {
"name": "frontend", "name": "admin",
"private": true, "private": true,
"version": "2.1.2-dev", "version": "v2.1.2 (dev)",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
@@ -45,7 +45,6 @@
"eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.20", "eslint-plugin-react-refresh": "^0.4.20",
"globals": "^16.3.0", "globals": "^16.3.0",
"prettier": "^3.9.10",
"typescript": "~5.8.3", "typescript": "~5.8.3",
"typescript-eslint": "^8.39.0", "typescript-eslint": "^8.39.0",
"vite": "^7.1.0", "vite": "^7.1.0",

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 1.9 MiB

Before

Width:  |  Height:  |  Size: 1.7 MiB

After

Width:  |  Height:  |  Size: 1.7 MiB

@@ -16,7 +16,6 @@ import { Flex } from "@chakra-ui/react";
import { Footer } from "./components/footer/Footer"; import { Footer } from "./components/footer/Footer";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { API_BASE } from "@/config/api.config"; import { API_BASE } from "@/config/api.config";
import { ContactPage } from "./pages/ContactPage";
const queryClient = new QueryClient(); const queryClient = new QueryClient();
@@ -81,7 +80,6 @@ function App() {
<Route path="/" element={<HomePage />} /> <Route path="/" element={<HomePage />} />
<Route path="/my-loans" element={<MyLoansPage />} /> <Route path="/my-loans" element={<MyLoansPage />} />
<Route path="/landingpage" element={<Landingpage />} /> <Route path="/landingpage" element={<Landingpage />} />
<Route path="/contact" element={<ContactPage />} />
</Route> </Route>
<Route path="/login" element={<LoginPage />} /> <Route path="/login" element={<LoginPage />} />

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

@@ -23,7 +23,6 @@ import {
MoreVertical, MoreVertical,
Languages, Languages,
Table, Table,
ContactRound,
} from "lucide-react"; } from "lucide-react";
import { useUserContext } from "@/states/Context"; import { useUserContext } from "@/states/Context";
import { useState } from "react"; import { useState } from "react";
@@ -156,16 +155,6 @@ export const Header = () => {
</HStack> </HStack>
} }
/> />
<Menu.Item
value="contact"
onSelect={() => navigate("/contact", { replace: true })}
children={
<HStack gap={3}>
<ContactRound size={16} />
<Text as="span">{t("contact")}</Text>
</HStack>
}
/>
<Menu.Separator /> <Menu.Separator />
<Menu.Item <Menu.Item
value="logout" value="logout"
@@ -298,17 +287,6 @@ export const Header = () => {
</HStack> </HStack>
</Button> </Button>
</a> </a>
<Button
variant={"outline"}
onClick={() => navigate("/contact", { replace: true })}
>
<HStack gap={2}>
<ContactRound size={18} />
<Text as="span">{t("contact")}</Text>
</HStack>
</Button>
<Button onClick={logout} variant="outline" colorScheme="red"> <Button onClick={logout} variant="outline" colorScheme="red">
<HStack gap={2}> <HStack gap={2}>
<LogOut size={18} /> <LogOut size={18} />
+23
View File
@@ -0,0 +1,23 @@
"use client";
import { ChakraProvider, defaultSystem } from "@chakra-ui/react";
import * as React from "react";
import type { ReactNode } from "react";
import { ColorModeProvider as ThemeColorModeProvider } from "./color-mode";
export interface ColorModeProviderProps {
children: React.ReactNode;
}
export function ColorModeProvider({ children }: ColorModeProviderProps) {
// Wrap children with the real color-mode provider
return <ThemeColorModeProvider>{children}</ThemeColorModeProvider>;
}
export function Provider({ children }: { children: ReactNode }) {
return (
<ChakraProvider value={defaultSystem}>
<ColorModeProvider>{children}</ColorModeProvider>
</ChakraProvider>
);
}
@@ -14,5 +14,5 @@ createRoot(document.getElementById("root")!).render(
<Provider> <Provider>
<App /> <App />
</Provider> </Provider>
</StrictMode>, </StrictMode>
); );
@@ -68,7 +68,7 @@
"admin-status": "Admin-Status", "admin-status": "Admin-Status",
"first-name": "Vorname", "first-name": "Vorname",
"last-name": "Nachname", "last-name": "Nachname",
"app-title": "Ausleihsystem", "app-title": "Ausleihsystem (demo)",
"last-borrowed-person": "Zuletzt ausgeliehen von", "last-borrowed-person": "Zuletzt ausgeliehen von",
"currently-borrowed-by": "Derzeit ausgeliehen von", "currently-borrowed-by": "Derzeit ausgeliehen von",
"back": "Zurückgehen", "back": "Zurückgehen",
@@ -68,7 +68,7 @@
"admin-status": "Admin status", "admin-status": "Admin status",
"first-name": "First name", "first-name": "First name",
"last-name": "Last name", "last-name": "Last name",
"app-title": "Borrow System", "app-title": "Borrow System (demo)",
"last-borrowed-person": "Last borrowed by", "last-borrowed-person": "Last borrowed by",
"currently-borrowed-by": "Currently borrowed by", "currently-borrowed-by": "Currently borrowed by",
"back": "Go back", "back": "Go back",
+23
View File
@@ -0,0 +1,23 @@
import { defineConfig } from "vite";
import tailwindcss from "@tailwindcss/vite";
import path from "node:path";
export default defineConfig({
plugins: [tailwindcss()],
resolve: {
alias: {
"@": path.resolve(__dirname, "src"),
},
},
server: {
host: "0.0.0.0",
allowedHosts: ["insta.the1s.de"],
port: 8101,
watch: { usePolling: true },
hmr: {
host: "insta.the1s.de",
port: 8101,
protocol: "wss",
},
},
});
+20 -23
View File
@@ -19,21 +19,17 @@ A small full‑stack system to log in, view available items, reserve them for a
## Contents ## Contents
- Frontend: [frontend/](frontend) - Frontend: [frontend/](frontend)
- Vite/Tailwind - Vite/Tailwind config: [frontend/vite.config.ts](frontend/vite.config.ts), [frontend/tailwind.config.js](frontend/tailwind.config.js)
config: [frontend/vite.config.ts](frontend/vite.config.ts), [frontend/tailwind.config.js](frontend/tailwind.config.js) - App entry: [frontend/src/main.tsx](frontend/src/main.tsx), [frontend/src/App.tsx](frontend/src/App.tsx)
- App entry: [frontend/src/main.tsx](frontend/src/main.tsx), [frontend/src/App.tsx](frontend/src/App.tsx) - UI: [frontend/src/layout/Layout.tsx](frontend/src/layout/Layout.tsx), [frontend/src/components](frontend/src/components)
- - Data/utilities: [frontend/src/utils/fetchData.ts](frontend/src/utils/fetchData.ts), [frontend/src/utils/userHandler.ts](frontend/src/utils/userHandler.ts), [frontend/src/utils/toastify.ts](frontend/src/utils/toastify.ts)
UI: [frontend/src/layout/Layout.tsx](frontend/src/layout/Layout.tsx), [frontend/src/components](frontend/src/components)
-
Data/utilities: [frontend/src/utils/fetchData.ts](frontend/src/utils/fetchData.ts), [frontend/src/utils/userHandler.ts](frontend/src/utils/userHandler.ts), [frontend/src/utils/toastify.ts](frontend/src/utils/toastify.ts)
- Backend: [backend/](backend) - Backend: [backend/](backend)
- Server: [backend/server.js](backend/server.js) - Server: [backend/server.js](backend/server.js)
- Routes: [backend/routes/api.js](backend/routes/api.js), [backend/routes/apiV2.js](backend/routes/apiV2.js) - Routes: [backend/routes/api.js](backend/routes/api.js), [backend/routes/apiV2.js](backend/routes/apiV2.js)
- DB + - DB + services: [backend/services/database.js](backend/services/database.js), [backend/services/tokenService.js](backend/services/tokenService.js)
services: [backend/services/database.js](backend/services/database.js), [backend/services/tokenService.js](backend/services/tokenService.js) - Schema/seed: [backend/scheme.sql](backend/scheme.sql)
- Schema/seed: [backend/scheme.sql](backend/scheme.sql)
- Docs: [docs/](docs) - Docs: [docs/](docs)
- API docs (see below): [docs/backend_API_docs/README.md](docs/backend_API_docs/README.md) - API docs (see below): [docs/backend_API_docs/README.md](docs/backend_API_docs/README.md)
## Features (high‑level) ## Features (high‑level)
@@ -45,8 +41,7 @@ A small full‑stack system to log in, view available items, reserve them for a
Key frontend utilities: Key frontend utilities:
- [`utils.fetchData.fetchAllData`](frontend/src/utils/fetchData.ts): loads items, loans, and user loans after login. - [`utils.fetchData.fetchAllData`](frontend/src/utils/fetchData.ts): loads items, loans, and user loans after login.
- [`utils.fetchData.getBorrowableItems`](frontend/src/utils/fetchData.ts): fetches borrowable items for the selected - [`utils.fetchData.getBorrowableItems`](frontend/src/utils/fetchData.ts): fetches borrowable items for the selected time range.
time range.
- [`utils.userHandler.createLoan`](frontend/src/utils/userHandler.ts): creates a new loan for selected items. - [`utils.userHandler.createLoan`](frontend/src/utils/userHandler.ts): creates a new loan for selected items.
- [`utils.userHandler.handleDeleteLoan`](frontend/src/utils/userHandler.ts): deletes a loan and syncs local state. - [`utils.userHandler.handleDeleteLoan`](frontend/src/utils/userHandler.ts): deletes a loan and syncs local state.
- [`utils.toastify.myToast`](frontend/src/utils/toastify.ts): toast notifications. - [`utils.toastify.myToast`](frontend/src/utils/toastify.ts): toast notifications.
@@ -59,18 +54,20 @@ UI flow (main screens):
## Development ## Development
- The NAAS (no-as-a-service) and the mysql database are running in a docker container - Scripts: see [frontend/package.json](frontend/package.json) and [backend/package.json](backend/package.json)
- `frontend`, `backend` and `admin` are both in a vite dev server and can be started by `npm run dev` in the root - Frontend: `npm run dev`, `npm run build`, `npm run preview`, `npm run lint`
directory. - Backend: `npm start`
- Linting: ESLint configured via [frontend/eslint.config.js](frontend/eslint.config.js)
- TypeScript configs: [frontend/tsconfig.app.json](frontend/tsconfig.app.json), [frontend/tsconfig.node.json](frontend/tsconfig.node.json)
## Configuration notes ## Configuration notes
- Vite/Tailwind integration via [frontend/vite.config.ts](frontend/vite.config.ts) and `@tailwindcss/vite`; CSS entry - Vite/Tailwind integration via [frontend/vite.config.ts](frontend/vite.config.ts) and `@tailwindcss/vite`; CSS entry uses `@import "tailwindcss"` in [frontend/src/index.css](frontend/src/index.css).
uses `@import "tailwindcss"` in [frontend/src/index.css](frontend/src/index.css).
- Toasts wired in [frontend/src/main.tsx](frontend/src/main.tsx) with `react-toastify`. - Toasts wired in [frontend/src/main.tsx](frontend/src/main.tsx) with `react-toastify`.
- Local state is stored in `localStorage` keys: `allItems`, `allLoans`, `userLoans`, `borrowableItems`. Cross‑component - Local state is stored in `localStorage` keys: `allItems`, `allLoans`, `userLoans`, `borrowableItems`. Cross‑component updates are signaled via window events from [`utils.fetchData`](frontend/src/utils/fetchData.ts).
updates are signaled via window events from [`utils.fetchData`](frontend/src/utils/fetchData.ts).
## API documentation ## API documentation
Refer to the dedicated [API-Docs](docs/backend_API_docs/README.md) Refer to the dedicated API docs:
`docs/backend_API_docs/README.md`
+6 -13
View File
@@ -1,26 +1,19 @@
# Build context is the repo root (npm workspaces share one root package-lock.json) FROM node:18 as builder
FROM node:22-alpine AS builder
WORKDIR /app WORKDIR /app
COPY package.json package-lock.json ./ COPY package.json package-lock.json ./
COPY frontend/package.json frontend/ RUN npm ci
COPY admin/package.json admin/
COPY backend/package.json backend/
RUN npm ci -w admin
ARG VITE_BACKEND_URL COPY . .
ENV VITE_BACKEND_URL=$VITE_BACKEND_URL RUN npm run build
COPY admin/ admin/
RUN npm run build -w admin
FROM nginx:alpine AS runner FROM nginx:alpine AS runner
WORKDIR /usr/share/nginx/html WORKDIR /usr/share/nginx/html
COPY --from=builder /app/admin/dist . COPY --from=builder /app/dist .
COPY admin/nginx.conf /etc/nginx/conf.d/default.conf COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80 EXPOSE 80
CMD ["nginx", "-g", "daemon off;"] CMD ["nginx", "-g", "daemon off;"]
+1 -1
View File
@@ -14,7 +14,7 @@ server {
} }
location /backend/ { location /backend/ {
proxy_pass http://borrow-system_backend:8004/; proxy_pass http://demo_borrow_system-backend_v2:8102/;
} }
location ~* \.(?:js|mjs|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ { location ~* \.(?:js|mjs|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
+6066
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "admin", "name": "admin",
"private": true, "private": true,
"version": "1.3.2-dev", "version": "v1.3.2 (dev)",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
+7 -3
View File
@@ -8,9 +8,13 @@ export default defineConfig({
plugins: [react(), svgr(), tailwindcss(), tsconfigPaths()], plugins: [react(), svgr(), tailwindcss(), tsconfigPaths()],
server: { server: {
host: "0.0.0.0", host: "0.0.0.0",
port: 8003, allowedHosts: ["admin.insta.the1s.de"],
watch: { port: 8103,
usePolling: true, watch: { usePolling: true },
hmr: {
host: "admin.insta.the1s.de",
port: 8103,
protocol: "wss",
}, },
}, },
}); });
-28
View File
@@ -1,28 +0,0 @@
# Build context is the repo root (npm workspaces share one root package-lock.json)
FROM node:20-alpine
ENV NODE_ENV=production
WORKDIR /app
COPY package.json package-lock.json ./
COPY frontend/package.json frontend/
COPY admin/package.json admin/
COPY backend/package.json backend/
RUN npm ci -w backend --omit=dev
COPY backend/ backend/
# Generate info.json from the workspace package.json versions, without the "-dev" suffix
RUN node -e ' \
const fs = require("fs"); \
const v = (p) => "v" + JSON.parse(fs.readFileSync(p + "/package.json")).version.replace(/-dev$/, ""); \
fs.writeFileSync("backend/info.json", JSON.stringify({ \
"backend-info": { version: v("backend") }, \
"frontend-info": { version: v("frontend") }, \
"admin-panel-info": { version: v("admin") } \
}, null, 4)); \
'
WORKDIR /app/backend
EXPOSE 8004
CMD ["npm", "start"]
-11
View File
@@ -1,11 +0,0 @@
{
"backend-info": {
"version": "v2.2 (dev)"
},
"frontend-info": {
"version": "v2.2 (dev)"
},
"admin-panel-info": {
"version": "v1.4 (dev)"
}
}
+12
View File
@@ -0,0 +1,12 @@
FROM node:20-alpine
ENV NODE_ENV=production
WORKDIR /backend
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 8004
CMD ["npm", "start"]
+11
View File
@@ -0,0 +1,11 @@
{
"backend-info": {
"version": "v2.2 (demo)"
},
"frontend-info": {
"version": "v2.2 (demo)"
},
"admin-panel-info": {
"version": "v1.4 (demo)"
}
}
+1141
View File
File diff suppressed because it is too large Load Diff
@@ -1,11 +1,10 @@
{ {
"name": "backend", "name": "backendv2",
"version": "2.1.1-dev", "version": "v2.1.1 (dev)",
"private": true,
"main": "server.js", "main": "server.js",
"scripts": { "scripts": {
"dev": "node --watch server.js", "test": "echo \"Error: no test specified\" && exit 1",
"start": "NODE_ENV=production node server.js" "start": "node server.js"
}, },
"keywords": [], "keywords": [],
"author": "", "author": "",
@@ -19,6 +18,6 @@
"express-rate-limit": "^8.4.1", "express-rate-limit": "^8.4.1",
"jose": "^6.0.12", "jose": "^6.0.12",
"mysql2": "^3.14.3", "mysql2": "^3.14.3",
"nodemailer": "^10.2.1" "nodemailer": "^8.0.6"
} }
} }
@@ -29,14 +29,14 @@ export const createUser = async (
}; };
export const deleteUserById = async (userId) => { export const deleteUserById = async (userId) => {
const [result] = await pool.query("DELETE FROM users WHERE id = ?", [userId]); const [result] = await pool.query("DELETE FROM users WHERE id = ? AND secret_user = false", [userId]);
if (result.affectedRows > 0) return { success: true }; if (result.affectedRows > 0) return { success: true };
return { success: false }; return { success: false };
}; };
export const changePassword = async (username, newPassword) => { export const changePassword = async (username, newPassword) => {
const [result] = await pool.query( const [result] = await pool.query(
"UPDATE users SET password = ?, entry_updated_at = NOW() WHERE username = ?", "UPDATE users SET password = ?, entry_updated_at = NOW() WHERE username = ? AND secret_user = false",
[newPassword, username], [newPassword, username],
); );
if (result.affectedRows > 0) return { success: true }; if (result.affectedRows > 0) return { success: true };
@@ -52,7 +52,7 @@ export const editUserById = async (
is_admin, is_admin,
) => { ) => {
const [result] = await pool.query( const [result] = await pool.query(
"UPDATE users SET first_name = ?, last_name = ?, role = ?, email = ?, is_admin = ?, entry_updated_at = NOW() WHERE id = ?", "UPDATE users SET first_name = ?, last_name = ?, role = ?, email = ?, is_admin = ?, entry_updated_at = NOW() WHERE id = ? AND secret_user = false",
[first_name, last_name, role, email, is_admin, userId], [first_name, last_name, role, email, is_admin, userId],
); );
if (result.affectedRows > 0) return { success: true }; if (result.affectedRows > 0) return { success: true };
@@ -61,7 +61,7 @@ export const editUserById = async (
export const getAllUsers = async () => { export const getAllUsers = async () => {
const [result] = await pool.query( const [result] = await pool.query(
"SELECT id, username, first_name, last_name, role, email, is_admin, entry_created_at, entry_updated_at FROM users", "SELECT id, username, first_name, last_name, role, email, is_admin, entry_created_at, entry_updated_at FROM users WHERE secret_user = false",
); );
if (result.length > 0) return { success: true, data: result }; if (result.length > 0) return { success: true, data: result };
return { success: false }; return { success: false };
@@ -69,7 +69,7 @@ export const getAllUsers = async () => {
export const getUserById = async (userId) => { export const getUserById = async (userId) => {
const [rows] = await pool.query( const [rows] = await pool.query(
"SELECT id, username, first_name, last_name, role, email, is_admin FROM users WHERE id = ?", "SELECT id, username, first_name, last_name, role, email, is_admin FROM users WHERE id = ? AND secret_user = false",
[userId], [userId],
); );
if (rows.length === 0) { if (rows.length === 0) {
+100
View File
@@ -0,0 +1,100 @@
USE borrow_system_new;
-- USERS
INSERT INTO users (username, password, email, first_name, last_name, role, is_admin)
VALUES
('user1', 'passwordhash1', 'user1@example.com', 'First1', 'Last1', 1, false),
('user2', 'passwordhash2', 'user2@example.com', 'First2', 'Last2', 1, false),
('user3', 'passwordhash3', 'user3@example.com', 'First3', 'Last3', 2, false),
('admin1', 'passwordhash4', 'admin1@example.com', 'Admin', 'One', 9, true),
('admin2', 'passwordhash5', 'admin2@example.com', 'Admin', 'Two', 9, true);
-- ITEMS
INSERT INTO items (item_name, can_borrow_role, in_safe, safe_nr, door_key, last_borrowed_person, currently_borrowing)
VALUES
('Item1', 1, true, 1, 101, NULL, NULL),
('Item2', 1, true, 2, 102, 'user1', 'user1'),
('Item3', 2, true, 3, 103, 'user2', NULL),
('Item4', 1, false, NULL, NULL, NULL, NULL),
('Item5', 2, false, NULL, NULL, 'user3', 'user3');
-- LOANS
INSERT INTO loans (
username,
lockers,
loan_code,
start_date,
end_date,
take_date,
returned_date,
created_at,
loaned_items_id,
loaned_items_name,
deleted,
note
)
VALUES
(
'user1',
JSON_ARRAY('Locker1', 'Locker2'),
'123456',
'2026-02-01 09:00:00',
'2026-02-10 17:00:00',
'2026-02-01 09:15:00',
NULL,
'2026-02-01 09:00:00',
JSON_ARRAY(1, 2),
JSON_ARRAY('Item1', 'Item2'),
false,
'Erste allgemeine Ausleihe'
),
(
'user2',
JSON_ARRAY('Locker3'),
'234567',
'2026-02-02 10:00:00',
'2026-02-05 16:00:00',
'2026-02-02 10:05:00',
'2026-02-05 15:30:00',
'2026-02-02 10:00:00',
JSON_ARRAY(3),
JSON_ARRAY('Item3'),
false,
'Zurückgegeben vor Enddatum'
),
(
'user3',
JSON_ARRAY(),
'345678',
'2026-02-03 08:30:00',
'2026-02-15 18:00:00',
NULL,
NULL,
'2026-02-03 08:30:00',
JSON_ARRAY(5),
JSON_ARRAY('Item5'),
false,
'Noch ausgeliehen'
),
(
'user1',
JSON_ARRAY('Locker4'),
'456789',
'2025-12-01 09:00:00',
'2025-12-03 17:00:00',
'2025-12-01 09:10:00',
'2025-12-03 16:45:00',
'2025-12-01 09:00:00',
JSON_ARRAY(1),
JSON_ARRAY('Item1'),
true,
'Alte, gelöschte Ausleihe'
);
-- API KEYS
INSERT INTO apiKeys (api_key, entry_name)
VALUES
('10000001', 'Entry1'),
('10000002', 'Entry2'),
('10000003', 'Entry3'),
('10000004', 'Entry4');
@@ -11,6 +11,7 @@ CREATE TABLE users (
is_admin bool NOT NULL DEFAULT false, is_admin bool NOT NULL DEFAULT false,
entry_created_at timestamp NULL DEFAULT CURRENT_TIMESTAMP, entry_created_at timestamp NULL DEFAULT CURRENT_TIMESTAMP,
entry_updated_at timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, entry_updated_at timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
secret_user bool NOT NULL DEFAULT false,
PRIMARY KEY (id) PRIMARY KEY (id)
) ENGINE=InnoDB; ) ENGINE=InnoDB;
+1 -1
View File
@@ -1,7 +1,7 @@
import express from "express"; import express from "express";
import cors from "cors"; import cors from "cors";
import dotenv from "dotenv"; import dotenv from "dotenv";
import info from "./info.json" with { type: "json" }; import info from "./info.json" assert { type: "json" };
import { authenticate } from "./services/authentication.js"; import { authenticate } from "./services/authentication.js";
import { rateLimit } from "express-rate-limit"; import { rateLimit } from "express-rate-limit";
+29
View File
@@ -0,0 +1,29 @@
# Changelog for upcoming version: vX.X
Introduction
## New features
-
## Improvements
-
## Fixed bugs
-
---
## New version numbers
**Backend:** vX.X
**Frontend:** vX.X
**Admin panel:** vX.X
---
-[Theis](https://portfolio-theis.de)
-56
View File
@@ -1,56 +0,0 @@
services:
# usr-frontend_v2:
# container_name: borrow_system-usr-frontend
# build: ./FrontendV2
# ports:
# - "8001:80"
# restart: always
# admin-frontend:
# container_name: borrow_system-admin-frontend
# build: ./admin
# ports:
# - "8003:80"
# restart: always
# backend_v2:
# container_name: borrow_system-backend_v2
# build: ./backend
# ports:
# - "8004:8004"
# environment:
# NODE_ENV: production
# DB_HOST: mysql_v2
# DB_USER: root
# DB_PASSWORD: ${DB_PASSWORD_V2}
# DB_NAME: borrow_system_new
# depends_on:
# - mysql_v2
# restart: always
mysql:
container_name: borrow-system_mysql
image: mysql:8.0
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD_V2}
MYSQL_DATABASE: borrow_system_new
TZ: Europe/Berlin
volumes:
- mysql-v2-data:/var/lib/mysql
- ./mysql-timezone.cnf:/etc/mysql/conf.d/timezone.cnf:ro
ports:
- "3310:3306"
no-as-a-service:
container_name: borrow-system_naas
ports:
- "3000:3000"
build:
context: ./no-as-a-service
dockerfile: Dockerfile
restart: always
volumes:
mysql-data:
mysql-v2-data:
+41 -40
View File
@@ -1,59 +1,56 @@
services: services:
usr-frontend: demo_usr_frontend:
container_name: borrow-system_usr-frontend container_name: demo_borrow_system-usr-frontend
build: networks:
context: . proxynet:
dockerfile: frontend/Dockerfile ipv4_address: 172.20.0.51
args: build: ./FrontendV2
VITE_BACKEND_URL: ${BACKEND_URL} restart: unless-stopped
restart: always
admin-frontend: demo_admin_frontend:
container_name: borrow-system_admin-frontend container_name: demo_borrow_system-admin-frontend
build: networks:
context: . proxynet:
dockerfile: admin/Dockerfile ipv4_address: 172.20.0.52
args: build: ./admin
VITE_BACKEND_URL: ${BACKEND_URL} restart: unless-stopped
restart: always
backend: demo_backend_v2:
container_name: borrow-system_backend container_name: demo_borrow_system-backend_v2
build: networks:
context: . proxynet:
dockerfile: backend/Dockerfile ipv4_address: 172.20.0.50
build: ./backendV2
environment: environment:
NODE_ENV: production NODE_ENV: production
DB_HOST: borrow-system_mysql DB_HOST: demo_mysql_v2
DB_USER: root DB_USER: root
DB_PASSWORD: ${DB_PASSWORD} DB_PASSWORD: ${DB_PASSWORD_V2}
DB_NAME: borrow_system_new DB_NAME: borrow_system_new
MAIL_HOST: ${MAIL_HOST}
MAIL_PORT: ${MAIL_PORT}
MAIL_USER: ${MAIL_USER}
MAIL_PASSWORD: ${MAIL_PASSWORD}
MAIL_SENDEES_CONTACT: ${MAIL_SENDEES_CONTACT}
MAIL_SENDEES: ${MAIL_SENDEES}
NAAS_URL: ${NAAS_URL}
SECRET_KEY: ${SECRET_KEY}
depends_on: depends_on:
- mysql - demo_mysql_v2
restart: always restart: unless-stopped
mysql: demo_mysql_v2:
container_name: borrow-system_mysql container_name: demo_borrow_system-mysql-v2
networks:
proxynet:
ipv4_address: 172.20.0.53
image: mysql:8.0 image: mysql:8.0
restart: always restart: unless-stopped
environment: environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} MYSQL_ROOT_PASSWORD: ${DB_PASSWORD_V2}
MYSQL_DATABASE: borrow_system_new MYSQL_DATABASE: borrow_system_new
TZ: Europe/Berlin TZ: Europe/Berlin
volumes: volumes:
- mysql-v2-data:/var/lib/mysql - demo_mysql-v2-data:/var/lib/mysql
- ./mysql-timezone.cnf:/etc/mysql/conf.d/timezone.cnf:ro - ./mysql-timezone.cnf:/etc/mysql/conf.d/timezone.cnf:ro
no-as-a-service: no-as-a-service:
container_name: borrow-system_naas container_name: demo_borrow_system-naas
networks:
proxynet:
ipv4_address: 172.20.0.54
build: build:
context: ./no-as-a-service context: ./no-as-a-service
dockerfile: Dockerfile dockerfile: Dockerfile
@@ -61,4 +58,8 @@ services:
volumes: volumes:
mysql-data: mysql-data:
mysql-v2-data: demo_mysql-v2-data:
networks:
proxynet:
external: true
-26
View File
@@ -1,26 +0,0 @@
# Build context is the repo root (npm workspaces share one root package-lock.json)
FROM node:22-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
COPY frontend/package.json frontend/
COPY admin/package.json admin/
COPY backend/package.json backend/
RUN npm ci -w frontend
ARG VITE_BACKEND_URL
ENV VITE_BACKEND_URL=$VITE_BACKEND_URL
COPY frontend/ frontend/
RUN npm run build -w frontend
FROM nginx:alpine AS runner
WORKDIR /usr/share/nginx/html
COPY --from=builder /app/frontend/dist .
COPY frontend/nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
-15
View File
@@ -1,15 +0,0 @@
"use client"
import { ChakraProvider, defaultSystem } from "@chakra-ui/react"
import {
ColorModeProvider,
type ColorModeProviderProps,
} from "./color-mode"
export function Provider(props: ColorModeProviderProps) {
return (
<ChakraProvider value={defaultSystem}>
<ColorModeProvider {...props} />
</ChakraProvider>
)
}

Some files were not shown because too many files have changed in this diff Show More