diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml
deleted file mode 100644
index 904ccb6..0000000
--- a/.github/workflows/changelog.yml
+++ /dev/null
@@ -1,101 +0,0 @@
-name: "Changelog"
-
-on:
- push:
- branches:
- - main
- paths:
- - 'apps/**'
- - 'packages/**'
- pull_request:
- paths:
- - 'apps/**'
- - 'packages/**'
-
-permissions:
- contents: write
- packages: write
- pull-requests: write
-
-jobs:
- changelog:
- name: Changelog
- if: github.event_name != 'pull_request'
- runs-on: ubuntu-24.04
-
- outputs:
- skipped: ${{ steps.changelog.outputs.skipped }}
- tag: ${{ steps.changelog.outputs.tag }}
- clean_changelog: ${{ steps.changelog.outputs.clean_changelog }}
- version: ${{ steps.changelog.outputs.version }}
-
- env:
- PR_BRANCH: release-ci-${{ github.run_id }}
-
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Create Branch
- run: |
- git checkout -b ${{ env.PR_BRANCH }} || git checkout ${{ env.PR_BRANCH }}
-
- - name: Create Changelog
- uses: TriPSs/conventional-changelog-action@v6
- id: changelog
- with:
- github-token: ${{ github.token }}
- git-user-name: "github-actions[bot]"
- git-user-email: "github-actions[bot]@users.noreply.github.com"
- git-branch: ${{ env.PR_BRANCH }}
- skip-git-pull: true
- output-file: CHANGELOG.md
- create-summary: true
-
- - name: Create Changelog PR
- if: steps.changelog.outputs.skipped == 'false'
- run: |
- gh pr create --base main --head ${{ env.PR_BRANCH }} --title 'chore(release): ${{ steps.changelog.outputs.tag }} [skip-ci]' --body "${{ steps.changelog.outputs.clean_changelog }}"
- env:
- GH_TOKEN: ${{ github.token }}
-
- - name: Approve Changelog PR
- if: steps.changelog.outputs.skipped == 'false'
- run: |
- gh pr review --approve ${{ env.PR_BRANCH }}
- env:
- GH_TOKEN: ${{ secrets.GH_TOKEN_ANDREJ }}
-
- - name: Merge Changelog PR
- if: steps.changelog.outputs.skipped == 'false'
- run: |
- gh pr merge --squash --auto --delete-branch ${{ env.PR_BRANCH }}
- env:
- GH_TOKEN: ${{ secrets.GH_TOKEN_ANDREJ }}
-
- release:
- name: Release
- needs: changelog
- if: github.event_name != 'pull_request' && needs.changelog.outputs.skipped == 'false'
- runs-on: ubuntu-24.04
-
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Create Release
- uses: softprops/action-gh-release@v2
- with:
- token: ${{ secrets.GH_TOKEN_ANDREJ }}
- tag_name: ${{ needs.changelog.outputs.tag }}
- prerelease: false
- draft: false
- files: bin/*
- generate_release_notes: true
- name: ${{ needs.changelog.outputs.tag }}
- body: |
-
- 🤖 Autogenerated Conventional Changelog
- ${{ needs.changelog.outputs.clean_changelog }}
-
\ No newline at end of file
diff --git a/apps/api/Dockerfile b/apps/api/Dockerfile
index 36cd439..de088a1 100644
--- a/apps/api/Dockerfile
+++ b/apps/api/Dockerfile
@@ -1,4 +1,4 @@
-FROM --platform=$BUILDPLATFORM node:lts-slim AS base
+FROM --platform=$BUILDPLATFORM node:22-slim AS base
WORKDIR /app
COPY package.json .
diff --git a/apps/web/.env.production b/apps/web/.env.production
new file mode 100644
index 0000000..4bf50f4
--- /dev/null
+++ b/apps/web/.env.production
@@ -0,0 +1 @@
+VITE_API_URL=KANEO_API_URL
\ No newline at end of file
diff --git a/apps/web/Dockerfile b/apps/web/Dockerfile
index 4f39503..6df1b0b 100644
--- a/apps/web/Dockerfile
+++ b/apps/web/Dockerfile
@@ -1,4 +1,4 @@
-FROM node:20-alpine AS builder
+FROM node:22-alpine AS builder
RUN npm install -g bun
@@ -26,6 +26,9 @@ COPY --from=builder /app/apps/web/dist /usr/share/nginx/html
COPY apps/web/nginx.conf /etc/nginx/conf.d/default.conf
+COPY apps/web/env.sh /docker-entrypoint.d/env.sh
+RUN chmod +x /docker-entrypoint.d/env.sh
+
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
\ No newline at end of file
diff --git a/apps/web/env.sh b/apps/web/env.sh
new file mode 100644
index 0000000..4ebbd3c
--- /dev/null
+++ b/apps/web/env.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+for i in $(env | grep KANEO_)
+do
+ key=$(echo $i | cut -d '=' -f 1)
+ value=$(echo $i | cut -d '=' -f 2-)
+ echo $key=$value
+
+ find /usr/share/nginx/html -type f \( -name '*.js' -o -name '*.css' \) -exec sed -i "s|${key}|${value}|g" '{}' +
+done
\ No newline at end of file
diff --git a/apps/web/index.html b/apps/web/index.html
index 7bd8c80..413099d 100644
--- a/apps/web/index.html
+++ b/apps/web/index.html
@@ -5,6 +5,15 @@
+
Kaneo
diff --git a/apps/web/src/routes/__root.tsx b/apps/web/src/routes/__root.tsx
index 8ab9152..a34581c 100644
--- a/apps/web/src/routes/__root.tsx
+++ b/apps/web/src/routes/__root.tsx
@@ -1,20 +1,40 @@
+import TanStackRouterDevtools from "@/tanstack/router";
import type { LoggedInUser } from "@/types/user";
import type { QueryClient } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
-import { Outlet, createRootRouteWithContext } from "@tanstack/react-router";
-import { TanStackRouterDevtools } from "@tanstack/router-devtools";
+import {
+ Outlet,
+ createRootRouteWithContext,
+ redirect,
+} from "@tanstack/react-router";
export const Route = createRootRouteWithContext<{
queryClient: QueryClient;
user: LoggedInUser | null | undefined;
}>()({
component: RootComponent,
+ async beforeLoad({ context: { user }, location }) {
+ const isRouteUnprotected = location.pathname.includes("auth");
+ const isOnDashboard = location.pathname.includes("dashboard");
+
+ if (user === null && !isRouteUnprotected) {
+ throw redirect({
+ to: "/auth/sign-in",
+ });
+ }
+
+ if (user && !isOnDashboard) {
+ throw redirect({
+ to: "/dashboard",
+ });
+ }
+ },
});
function RootComponent() {
return (
<>
-
+
diff --git a/apps/web/src/tanstack/router.tsx b/apps/web/src/tanstack/router.tsx
new file mode 100644
index 0000000..05df440
--- /dev/null
+++ b/apps/web/src/tanstack/router.tsx
@@ -0,0 +1,12 @@
+import React from "react";
+
+const TanStackRouterDevtools =
+ process.env.NODE_ENV === "production"
+ ? () => null
+ : React.lazy(() =>
+ import("@tanstack/router-devtools").then((res) => ({
+ default: res.TanStackRouterDevtools,
+ })),
+ );
+
+export default TanStackRouterDevtools;
diff --git a/compose.yml b/compose.yml
index ed91b44..dfea5d4 100644
--- a/compose.yml
+++ b/compose.yml
@@ -1,20 +1,49 @@
-version: '3.8'
-
services:
- api:
- image: ghcr.io/kaneo-app/api:latest
- environment:
- - JWT_ACCESS=jwt_secret_goes_here
+ traefik:
+ image: "traefik:v3.3"
+ container_name: "traefik"
+ command:
+ - "--providers.docker=true"
+ - "--entryPoints.web.address=:80"
+ - "--entryPoints.websecure.address=:443"
ports:
- - "1337:1337"
+ - "80:80"
+ - "443:443"
+
+ networks:
+ - traefik-net
volumes:
- - .:/app
+ - "/var/run/docker.sock:/var/run/docker.sock:ro"
+
+ backend:
+ image: ghcr.io/kaneo-app/api:latest
+ labels:
+ - "traefik.enable=true"
+ - "traefik.http.routers.backend.rule=Host(`demo-api.kaneo.app`)"
+ - "traefik.http.routers.backend.entrypoints=web"
+ environment:
+ JWT_ACCESS: "change_me"
+ networks:
+ - traefik-net
restart: unless-stopped
- web:
- image: ghcr.io/kaneo-app/web:latest
- ports:
- - "80:80"
+ frontend:
+ build:
+ context: .
+ dockerfile: ./apps/web/Dockerfile
+ container_name: "kaneo-web"
+ environment:
+ KANEO_API_URL: "change_me"
+ labels:
+ - "traefik.enable=true"
+ - "traefik.http.routers.frontend.rule=Host(`demo.kaneo.app`)"
+ - "traefik.http.routers.frontend.entrypoints=web"
depends_on:
- - api
- restart: unless-stopped
\ No newline at end of file
+ - backend
+ restart: unless-stopped
+ networks:
+ - traefik-net
+
+networks:
+ traefik-net:
+ driver: bridge
\ No newline at end of file