diff --git a/.dockerignore b/.dockerignore index 4c62cfa..ac56bfd 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,8 +1,15 @@ +shared/node_modules +shared/.output + +lyx-ui/node_modules +lyx-ui/.nuxt +lyx-ui/.output + +dashboard/node_modules +dashboard/.nuxt +dashboard/.output +dashboard/explains +dashboard/tests +dashboard/.env +dashboard/winston-*.ndjson -# Consumer -**/node_modules -**/ecosystem.config.cjs -**/ecosystem.config.example.cjs -**/dist -**/.nuxt -**/.env \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 39bc474..2099ce1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,6 +3,7 @@ FROM node:21-alpine as base FROM base as build RUN npm i -g pnpm +RUN npm i -g pm2 # COPY --link dashboard/package.json dashboard/pnpm-lock.yaml ./ # RUN npm install --production=false @@ -15,14 +16,15 @@ COPY --link consumer ./consumer COPY --link producer ./producer COPY --link shared ./shared -WORKDIR /home/app/dashboard +WORKDIR /home/app/producer RUN pnpm install WORKDIR /home/app/consumer RUN pnpm install -WORKDIR /home/app/producer +WORKDIR /home/app/dashboard RUN pnpm install +RUN pnpm run dev # CMD [ "node", "/home/app/.output/server/index.mjs" ] \ No newline at end of file diff --git a/dashboard/Dockerfile b/dashboard/Dockerfile new file mode 100644 index 0000000..009bd20 --- /dev/null +++ b/dashboard/Dockerfile @@ -0,0 +1,49 @@ +# Start with a minimal Node.js base image +FROM node:21-alpine AS base + +# Create a distinct build environment +FROM base AS build + +# Install pnpm globally with caching to avoid reinstalling if nothing has changed +RUN npm i -g pnpm + +# Set the working directory +WORKDIR /home/app + +# Copy only package-related files to leverage caching +COPY --link ./dashboard/package.json ./dashboard/pnpm-lock.yaml ./dashboard/ +COPY --link ./lyx-ui/package.json ./lyx-ui/pnpm-lock.yaml ./lyx-ui/ +COPY --link ./shared/package.json ./shared/pnpm-lock.yaml ./shared/ + +# Install dependencies for each package +WORKDIR /home/app/lyx-ui +RUN pnpm install --frozen-lockfile + +# WORKDIR /home/app/shared +# RUN pnpm install --frozen-lockfile + +WORKDIR /home/app/dashboard +RUN pnpm install --frozen-lockfile + +# Now copy the rest of the source files +WORKDIR /home/app + +COPY --link ./dashboard ./dashboard +COPY --link ./lyx-ui ./lyx-ui +COPY --link ./shared ./shared + +# Build the dashboard +WORKDIR /home/app/dashboard +RUN pnpm run build + +# Use a smaller base image for the final production build +FROM node:21-alpine AS production + +# Set the working directory for the production container +WORKDIR /home/app + +# Copy the built application from the build stage +COPY --from=build /home/app/dashboard/.output /home/app/.output + +# Start the application +CMD ["node", "/home/app/.output/server/index.mjs"] \ No newline at end of file diff --git a/dashboard/package.json b/dashboard/package.json index 3da59db..42285aa 100644 --- a/dashboard/package.json +++ b/dashboard/package.json @@ -10,7 +10,8 @@ "postinstall": "nuxt prepare", "test": "vitest", "docker-build": "docker build -t litlyx-dashboard -f Dockerfile ../", - "docker-inspect": "docker run -it litlyx-dashboard sh" + "docker-inspect": "docker run -it litlyx-dashboard sh", + "docker-run": "docker run -p 3000:3000 --name litlyx-dashboard litlyx-dashboard" }, "dependencies": { "@getbrevo/brevo": "^2.2.0", diff --git a/dashboard/server/api/v1/events.post.ts b/dashboard/server/api/v1/events.post.ts index e580d37..2ee7d36 100644 --- a/dashboard/server/api/v1/events.post.ts +++ b/dashboard/server/api/v1/events.post.ts @@ -1,9 +1,12 @@ import { checkApiKey, checkAuthorization, eventsListApi } from '~/server/services/ApiService'; +import { useCors } from '~/server/utils/useCors'; export default defineEventHandler(async event => { + useCors(event); + const { rows, from, to, limit } = await readBody(event); const token = checkAuthorization(event); diff --git a/dashboard/server/api/v1/events.ts b/dashboard/server/api/v1/events.ts index defd321..833ec2a 100644 --- a/dashboard/server/api/v1/events.ts +++ b/dashboard/server/api/v1/events.ts @@ -1,9 +1,12 @@ import { checkApiKey, checkAuthorization, eventsListApi, } from '~/server/services/ApiService'; +import { useCors } from '~/server/utils/useCors'; export default defineEventHandler(async event => { + useCors(event); + const { row, from, to, limit } = getQuery(event); const token = checkAuthorization(event); diff --git a/dashboard/server/api/v1/visits.post.ts b/dashboard/server/api/v1/visits.post.ts index 509832d..9415a99 100644 --- a/dashboard/server/api/v1/visits.post.ts +++ b/dashboard/server/api/v1/visits.post.ts @@ -1,10 +1,13 @@ import { checkApiKey, checkAuthorization } from '~/server/services/ApiService'; import { visitsListApi } from '../../services/ApiService'; +import { useCors } from '~/server/utils/useCors'; export default defineEventHandler(async event => { + useCors(event); + const { rows, from, to, limit } = await readBody(event); const token = checkAuthorization(event); diff --git a/dashboard/server/api/v1/visits.ts b/dashboard/server/api/v1/visits.ts index 309370c..307cfa1 100644 --- a/dashboard/server/api/v1/visits.ts +++ b/dashboard/server/api/v1/visits.ts @@ -2,9 +2,12 @@ import { ApiSettingsModel } from '@schema/ApiSettingsSchema'; import { VisitModel } from '@schema/metrics/VisitSchema'; import { checkApiKey, checkAuthorization, visitsListApi } from '~/server/services/ApiService'; +import { useCors } from '~/server/utils/useCors'; export default defineEventHandler(async event => { + useCors(event); + const { row, from, to, limit } = getQuery(event); const token = checkAuthorization(event); diff --git a/dashboard/server/utils/useCors.ts b/dashboard/server/utils/useCors.ts new file mode 100644 index 0000000..b8bcc38 --- /dev/null +++ b/dashboard/server/utils/useCors.ts @@ -0,0 +1,10 @@ + + +import type { H3Event, EventHandlerRequest } from 'h3'; + + +export function useCors(event: H3Event) { + setResponseHeader(event, 'Access-Control-Allow-Origin', '*'); + setResponseHeader(event, 'Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE'); + setResponseHeader(event, 'Access-Control-Allow-Headers', 'Content-Type, Authorization'); +} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 961b8d6..c49b83d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,53 +4,60 @@ services: environment: MONGO_INITDB_ROOT_USERNAME: litlyx MONGO_INITDB_ROOT_PASSWORD: litlyx - ports: - - 27017:27017 + + # Uncomment to expose database + + # ports: + # - 27017:27017 + volumes: - mongo-data:/data/db cache: image: redis:alpine restart: always - ports: - - "6379:6379" + + # Uncomment to expose redis + + # ports: + # - "6379:6379" + command: redis-server --save 20 1 --loglevel warning --requirepass litlyx - producer: - image: litlyx-producer - restart: always - ports: - - "3099:3099" - environment: - PORT: "3099" - REDIS_URL: "redis://cache" - REDIS_USERNAME: "default" - REDIS_PASSWORD: "litlyx" - STREAM_NAME: "lib-events" - build: - dockerfile: ./producer/Dockerfile + # producer: + # image: litlyx-producer + # restart: always + # ports: + # - "3099:3099" + # environment: + # PORT: "3099" + # REDIS_URL: "redis://cache" + # REDIS_USERNAME: "default" + # REDIS_PASSWORD: "litlyx" + # STREAM_NAME: "lib-events" + # build: + # dockerfile: ./producer/Dockerfile + # broker: + # image: litlyx-consumer + # restart: always + # ports: + # - "3999:3999" + # environment: - broker: - image: litlyx-consumer - restart: always - ports: - - "3999:3999" - environment: + # # Optional - Used to send welcome and quota emails - # Optional - Used to send welcome and quota emails + # # NUXT_EMAIL_SERVICE: "Brevo" + # # NUXT_BREVO_API_KEY: "" - # NUXT_EMAIL_SERVICE: "Brevo" - # NUXT_BREVO_API_KEY: "" - - PORT: "3999" - MONGO_CONNECTION_STRING: "mongodb://litlyx:litlyx@mongo:27017/SimpleMetrics?readPreference=primaryPreferred&authSource=admin" - REDIS_URL: "redis://cache" - REDIS_USERNAME: "default" - REDIS_PASSWORD: "litlyx" - STREAM_NAME: "lib-events" - build: - dockerfile: ./broker/Dockerfile + # PORT: "3999" + # MONGO_CONNECTION_STRING: "mongodb://litlyx:litlyx@mongo:27017/SimpleMetrics?readPreference=primaryPreferred&authSource=admin" + # REDIS_URL: "redis://cache" + # REDIS_USERNAME: "default" + # REDIS_PASSWORD: "litlyx" + # STREAM_NAME: "lib-events" + # build: + # dockerfile: ./broker/Dockerfile dashboard: image: litlyx-dashboard @@ -65,8 +72,7 @@ services: NUXT_REDIS_USERNAME: "default" NUXT_REDIS_PASSWORD: "litlyx" - - # Optional - Used to use Lit, the AI analyst + # Optional - Used for Lit, the AI analyst # NUXT_AI_ORG: 'OPEN_AI_ORGANIZATION' # NUXT_AI_PROJECT: 'OPEN_AI_PROJECT' @@ -80,14 +86,13 @@ services: NUXT_AUTH_JWT_SECRET: "litlyx_jwt_secret" - # Optional - Used to register / login via google # NUXT_GOOGLE_AUTH_CLIENT_ID: "" # NUXT_GOOGLE_AUTH_CLIENT_SECRET: "" # NO_AUTH or GOOGLE - + NUXT_PUBLIC_AUTH_MODE: 'NO_AUTH' # Default user created in NO_AUTH mode @@ -101,7 +106,6 @@ services: # NUXT_STRIPE_SECRET_TEST: "" # NUXT_STRIPE_WH_SECRET_TEST: "" - # Optional - Stripe secret - Used to change plans of the projects # NUXT_STRIPE_SECRET: ""