Compare commits

..

13 Commits

Author SHA1 Message Date
dcb466f53b chore: fix husky
Some checks failed
Monorepo Pipeline / 🧪 Quality Assurance (push) Failing after 1m3s
Monorepo Pipeline / 🚀 Release (push) Has been skipped
Monorepo Pipeline / 🐳 Build Directus (Base) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Gatekeeper (Product) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Build-Base (push) Has been skipped
Monorepo Pipeline / 🐳 Build Production Runtime (push) Has been skipped
2026-02-09 23:44:34 +01:00
14089766ea feat: infra cms
Some checks failed
Monorepo Pipeline / 🧪 Quality Assurance (push) Failing after 1m5s
Monorepo Pipeline / 🚀 Release (push) Has been skipped
Monorepo Pipeline / 🐳 Build Directus (Base) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Gatekeeper (Product) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Build-Base (push) Has been skipped
Monorepo Pipeline / 🐳 Build Production Runtime (push) Has been skipped
2026-02-09 23:33:45 +01:00
6ecabe4a04 chore: sync lock file
Some checks failed
Monorepo Pipeline / 🧪 Quality Assurance (push) Failing after 9s
Monorepo Pipeline / 🚀 Release (push) Has been skipped
Monorepo Pipeline / 🐳 Build Directus (Base) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Gatekeeper (Product) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Build-Base (push) Has been skipped
Monorepo Pipeline / 🐳 Build Production Runtime (push) Has been skipped
2026-02-09 23:26:38 +01:00
b205220bde fix: cli compatibility with nextjs 16
Some checks failed
Monorepo Pipeline / 🧪 Quality Assurance (push) Failing after 14s
Monorepo Pipeline / 🚀 Release (push) Has been skipped
Monorepo Pipeline / 🐳 Build Directus (Base) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Gatekeeper (Product) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Build-Base (push) Has been skipped
Monorepo Pipeline / 🐳 Build Production Runtime (push) Has been skipped
2026-02-09 23:15:50 +01:00
3d5a802c6e chore: release packages
Some checks failed
Monorepo Pipeline / 🧪 Quality Assurance (push) Failing after 1m42s
Monorepo Pipeline / 🚀 Release (push) Has been skipped
Monorepo Pipeline / 🐳 Build Directus (Base) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Gatekeeper (Product) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Build-Base (push) Has been skipped
Monorepo Pipeline / 🐳 Build Production Runtime (push) Has been skipped
2026-02-09 23:05:15 +01:00
b5d1272f85 fix: customer manager
Some checks failed
Monorepo Pipeline / 🧪 Quality Assurance (push) Failing after 2m15s
Monorepo Pipeline / 🚀 Release (push) Has been skipped
Monorepo Pipeline / 🐳 Build Directus (Base) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Gatekeeper (Product) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Build-Base (push) Has been skipped
Monorepo Pipeline / 🐳 Build Production Runtime (push) Has been skipped
2026-02-09 23:04:21 +01:00
e152fb8171 fix: sync versions 2026-02-09 22:50:28 +01:00
d7cec1fa0e fix: docker images
All checks were successful
Monorepo Pipeline / 🧪 Quality Assurance (push) Successful in 4m4s
Monorepo Pipeline / 🐳 Build Directus (Base) (push) Successful in 29s
Monorepo Pipeline / 🚀 Release (push) Successful in 3m44s
Monorepo Pipeline / 🐳 Build Build-Base (push) Successful in 4m40s
Monorepo Pipeline / 🐳 Build Production Runtime (push) Successful in 17s
Monorepo Pipeline / 🐳 Build Gatekeeper (Product) (push) Successful in 7m15s
2026-02-09 22:37:19 +01:00
67c2af958a fix: docker images
Some checks failed
Monorepo Pipeline / 🧪 Quality Assurance (push) Successful in 4m1s
Monorepo Pipeline / 🐳 Build Directus (Base) (push) Successful in 33s
Monorepo Pipeline / 🐳 Build Gatekeeper (Product) (push) Failing after 21s
Monorepo Pipeline / 🐳 Build Build-Base (push) Failing after 45s
Monorepo Pipeline / 🐳 Build Production Runtime (push) Successful in 27s
Monorepo Pipeline / 🚀 Release (push) Successful in 3m43s
2026-02-09 22:26:16 +01:00
015e295370 fix: pipeline 2026-02-09 22:21:22 +01:00
c9952bfd1d fix: pipeline
Some checks failed
Monorepo Pipeline / 🧪 Quality Assurance (push) Successful in 6m14s
Monorepo Pipeline / 🚀 Release (push) Has been skipped
Monorepo Pipeline / 🐳 Build Directus (Base) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Gatekeeper (Product) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Production Runtime (push) Has been skipped
Monorepo Pipeline / 🐳 Build Build-Base (push) Has been cancelled
2026-02-09 22:16:07 +01:00
f9aaf3712e fix: pipeline
Some checks failed
Monorepo Pipeline / 🧪 Quality Assurance (push) Failing after 7m22s
Monorepo Pipeline / 🚀 Release (push) Has been skipped
Monorepo Pipeline / 🐳 Build Directus (Base) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Gatekeeper (Product) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Build-Base (push) Has been skipped
Monorepo Pipeline / 🐳 Build Production Runtime (push) Has been skipped
2026-02-09 22:02:58 +01:00
d2bbfe3b40 fix: pipeline 2026-02-09 21:58:04 +01:00
38 changed files with 1212 additions and 2375 deletions

View File

@@ -1,5 +0,0 @@
---
"@mintel/mail": minor
---
Initial release of the branded email system package.

View File

@@ -1,7 +1,7 @@
node_modules node_modules
.next .next
.git .git
.npmrc # .npmrc is allowed as it contains the registry template
dist dist
build build
out out

View File

@@ -2,6 +2,8 @@ name: Monorepo Pipeline
on: on:
push: push:
branches:
- '**'
tags: tags:
- 'v*' - 'v*'
@@ -15,6 +17,8 @@ jobs:
runs-on: docker runs-on: docker
container: container:
image: catthehacker/ubuntu:act-latest image: catthehacker/ubuntu:act-latest
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
@@ -28,12 +32,13 @@ jobs:
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node_version: 20 node_version: 20
cache: 'pnpm'
- name: Install dependencies - name: Install dependencies
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - name: 🏷️ Sync Versions (if Tagged)
if: startsWith(github.ref, 'refs/tags/v')
run: pnpm sync-versions
- name: Lint - name: Lint
run: pnpm lint run: pnpm lint
@@ -69,7 +74,6 @@ jobs:
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node_version: 20 node_version: 20
cache: 'pnpm'
- name: Install dependencies - name: Install dependencies
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
@@ -77,7 +81,6 @@ jobs:
- name: 🏷️ Release Packages (Tag-Driven) - name: 🏷️ Release Packages (Tag-Driven)
run: | run: |
echo "🏷️ Tag detected [${{ github.ref_name }}], performing sync release..." echo "🏷️ Tag detected [${{ github.ref_name }}], performing sync release..."
pnpm sync-versions
pnpm release:tag pnpm release:tag
build-images: build-images:

13
.husky/pre-push Executable file
View File

@@ -0,0 +1,13 @@
# Check if we are pushing a tag
if echo "$*" | grep -q "refs/tags/v"; then
echo "🏷️ Tag detected in push, syncing versions..."
pnpm sync-versions
# Stage the changed package.json files
git add "package.json" "packages/*/package.json" "apps/*/package.json"
# Amend the tag if it's on the current commit, but this is complex in pre-push.
# Better: Just warn the user that they might need to update the tag if package.json changed.
echo "⚠️ package.json files updated to match tag. Please ensure these changes are part of your tag/commit."
fi

View File

@@ -1,6 +1,6 @@
{ {
"name": "sample-website", "name": "sample-website",
"version": "0.1.1", "version": "1.6.0",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
@@ -11,12 +11,6 @@
"lint": "next lint", "lint": "next lint",
"typecheck": "tsc --noEmit", "typecheck": "tsc --noEmit",
"test": "vitest run --passWithNoTests", "test": "vitest run --passWithNoTests",
"cms:bootstrap": "mintel directus bootstrap",
"cms:push:testing": "mintel directus sync push testing",
"cms:pull:testing": "mintel directus sync pull testing",
"cms:push:staging": "mintel directus sync push staging",
"cms:pull:staging": "mintel directus sync pull staging",
"cms:push:prod": "mintel directus sync push production",
"cms:pull:prod": "mintel directus sync pull production", "cms:pull:prod": "mintel directus sync pull production",
"pagespeed:test": "mintel pagespeed" "pagespeed:test": "mintel pagespeed"
}, },
@@ -24,8 +18,8 @@
"@mintel/next-utils": "workspace:*", "@mintel/next-utils": "workspace:*",
"@mintel/observability": "workspace:*", "@mintel/observability": "workspace:*",
"@mintel/next-observability": "workspace:*", "@mintel/next-observability": "workspace:*",
"@sentry/nextjs": "^8.55.0", "@sentry/nextjs": "10.38.0",
"next": "15.1.6", "next": "16.1.6",
"next-intl": "^4.8.2", "next-intl": "^4.8.2",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0" "react-dom": "^19.0.0"

View File

View File

@@ -1,17 +1,18 @@
services: services:
app: app:
build: build:
context: . context: ./apps/sample-website
dockerfile: Dockerfile dockerfile: Dockerfile
args: args:
NEXT_PUBLIC_BASE_URL: ${NEXT_PUBLIC_BASE_URL:-http://localhost:3000} NEXT_PUBLIC_BASE_URL: ${NEXT_PUBLIC_BASE_URL:-http://localhost:3000}
NEXT_PUBLIC_UMAMI_WEBSITE_ID: ${NEXT_PUBLIC_UMAMI_WEBSITE_ID} NEXT_PUBLIC_UMAMI_WEBSITE_ID: ${NEXT_PUBLIC_UMAMI_WEBSITE_ID}
NEXT_PUBLIC_UMAMI_SCRIPT_URL: ${NEXT_PUBLIC_UMAMI_SCRIPT_URL} NEXT_PUBLIC_UMAMI_SCRIPT_URL: ${NEXT_PUBLIC_UMAMI_SCRIPT_URL}
NEXT_PUBLIC_TARGET: ${TARGET:-development} NEXT_PUBLIC_TARGET: ${TARGET:-development}
DIRECTUS_URL: ${DIRECTUS_URL:-http://directus:8055}
restart: always restart: always
networks: networks:
- infra - infra
environment:
- DIRECTUS_URL=${DIRECTUS_URL:-http://directus:8055}
env_file: env_file:
- .env - .env
ports: ports:
@@ -46,6 +47,7 @@ services:
volumes: volumes:
- ./directus/uploads:/directus/uploads - ./directus/uploads:/directus/uploads
- ./directus/extensions:/directus/extensions - ./directus/extensions:/directus/extensions
- ./directus/schema:/directus/schema
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.sample-website-directus.rule=Host(`${DIRECTUS_HOST:-cms.sample-website.localhost}`)" - "traefik.http.routers.sample-website-directus.rule=Host(`${DIRECTUS_HOST:-cms.sample-website.localhost}`)"

View File

@@ -10,6 +10,11 @@
"changeset": "changeset", "changeset": "changeset",
"version-packages": "changeset version", "version-packages": "changeset version",
"sync-versions": "tsx scripts/sync-versions.ts", "sync-versions": "tsx scripts/sync-versions.ts",
"cms:push:infra": "./scripts/sync-directus.sh push infra",
"cms:pull:infra": "./scripts/sync-directus.sh pull infra",
"cms:schema:snapshot": "./scripts/cms-snapshot.sh",
"cms:schema:apply": "./scripts/cms-apply.sh",
"dev:infra": "docker-compose up -d directus directus-db",
"release": "pnpm build && changeset publish", "release": "pnpm build && changeset publish",
"release:tag": "pnpm build && pnpm -r publish --no-git-checks --access public", "release:tag": "pnpm build && pnpm -r publish --no-git-checks --access public",
"prepare": "husky" "prepare": "husky"
@@ -27,7 +32,7 @@
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.2", "@vitejs/plugin-react": "^5.1.2",
"eslint": "^9.39.2", "eslint": "^9.39.2",
"eslint-plugin-next": "^0.0.0", "@next/eslint-plugin-next": "16.1.6",
"eslint-plugin-react": "^7.37.5", "eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-hooks": "^7.0.1",
"happy-dom": "^20.4.0", "happy-dom": "^20.4.0",
@@ -45,5 +50,6 @@
"pino": "^10.3.1", "pino": "^10.3.1",
"pino-pretty": "^13.1.3", "pino-pretty": "^13.1.3",
"require-in-the-middle": "^8.0.1" "require-in-the-middle": "^8.0.1"
} },
"version": "1.6.0"
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/cli", "name": "@mintel/cli",
"version": "1.0.1", "version": "1.6.0",
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",
"registry": "https://npm.infra.mintel.me" "registry": "https://npm.infra.mintel.me"

View File

@@ -231,7 +231,7 @@ program
"pagespeed:test": "mintel pagespeed", "pagespeed:test": "mintel pagespeed",
}, },
dependencies: { dependencies: {
next: "15.1.6", next: "16.1.6",
react: "^19.0.0", react: "^19.0.0",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
"@mintel/next-utils": "workspace:*", "@mintel/next-utils": "workspace:*",

View File

@@ -1,11 +1,11 @@
{ {
"name": "@mintel/cms-infra", "name": "@mintel/cms-infra",
"version": "1.0.0", "version": "1.6.0",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
"up": "docker compose up -d", "up": "docker compose up -d",
"down": "docker compose down", "down": "docker compose down",
"logs": "docker compose logs -f" "logs": "docker compose logs -f"
} }
} }

View File

@@ -1,29 +1,29 @@
{ {
"name": "customer-manager", "name": "customer-manager",
"description": "Custom High-Fidelity Customer & Company Management for Directus", "description": "Custom High-Fidelity Customer & Company Management for Directus",
"icon": "supervisor_account", "icon": "supervisor_account",
"version": "1.0.0", "version": "1.6.0",
"keywords": [ "keywords": [
"directus", "directus",
"directus-extension", "directus-extension",
"directus-extension-module" "directus-extension-module"
], ],
"files": [ "files": [
"dist" "dist"
], ],
"directus:extension": { "directus:extension": {
"type": "module", "type": "module",
"path": "index.js", "path": "index.js",
"source": "src/index.ts", "source": "src/index.ts",
"host": "*", "host": "*",
"name": "Customer Manager" "name": "Customer Manager"
}, },
"scripts": { "scripts": {
"build": "directus-extension build", "build": "directus-extension build",
"dev": "directus-extension build -w" "dev": "directus-extension build -w"
}, },
"devDependencies": { "devDependencies": {
"@directus/extensions-sdk": "11.0.2", "@directus/extensions-sdk": "11.0.2",
"vue": "^3.4.0" "vue": "^3.4.0"
} }
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/eslint-config", "name": "@mintel/eslint-config",
"version": "1.0.1", "version": "1.6.0",
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",
"registry": "https://npm.infra.mintel.me" "registry": "https://npm.infra.mintel.me"
@@ -20,8 +20,8 @@
"dependencies": { "dependencies": {
"@eslint/eslintrc": "^3.0.0", "@eslint/eslintrc": "^3.0.0",
"@eslint/js": "^9.39.2", "@eslint/js": "^9.39.2",
"@next/eslint-plugin-next": "15.1.6", "@next/eslint-plugin-next": "16.1.6",
"eslint-config-next": "15.1.6", "eslint-config-next": "16.1.6",
"eslint-plugin-react": "^7.37.5", "eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-hooks": "^7.0.1",
"typescript-eslint": "^8.54.0" "typescript-eslint": "^8.54.0"

View File

@@ -1,29 +1,29 @@
{ {
"name": "@mintel/extension-feedback-commander", "name": "@mintel/extension-feedback-commander",
"description": "Custom High-Fidelity Feedback Management Extension for Directus", "description": "Custom High-Fidelity Feedback Management Extension for Directus",
"icon": "view_kanban", "icon": "view_kanban",
"version": "1.0.0", "version": "1.6.0",
"keywords": [ "keywords": [
"directus", "directus",
"directus-extension", "directus-extension",
"directus-extension-module" "directus-extension-module"
], ],
"files": [ "files": [
"dist" "dist"
], ],
"directus:extension": { "directus:extension": {
"type": "module", "type": "module",
"path": "dist/index.js", "path": "dist/index.js",
"source": "src/index.ts", "source": "src/index.ts",
"host": "*", "host": "*",
"name": "Feedback Commander" "name": "Feedback Commander"
}, },
"scripts": { "scripts": {
"build": "directus-extension build", "build": "directus-extension build",
"dev": "directus-extension build -w" "dev": "directus-extension build -w"
}, },
"devDependencies": { "devDependencies": {
"@directus/extensions-sdk": "11.0.2", "@directus/extensions-sdk": "11.0.2",
"vue": "^3.4.0" "vue": "^3.4.0"
} }
} }

View File

@@ -1,20 +1,20 @@
{ {
"name": "@mintel/gatekeeper", "name": "@mintel/gatekeeper",
"version": "1.0.0", "version": "1.6.0",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"lint": "next lint", "lint": "eslint src/",
"test": "vitest run" "test": "vitest run"
}, },
"dependencies": { "dependencies": {
"@mintel/next-utils": "workspace:*", "@mintel/next-utils": "workspace:*",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"lucide-react": "^0.474.0", "lucide-react": "^0.474.0",
"next": "15.1.7", "next": "16.1.6",
"next-intl": "^4.8.2", "next-intl": "^4.8.2",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/husky-config", "name": "@mintel/husky-config",
"version": "1.0.0", "version": "1.6.0",
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",
"registry": "https://npm.infra.mintel.me" "registry": "https://npm.infra.mintel.me"

View File

@@ -19,7 +19,6 @@ COPY packages/cli/package.json ./packages/cli/package.json
COPY packages/observability/package.json ./packages/observability/package.json COPY packages/observability/package.json ./packages/observability/package.json
COPY packages/next-observability/package.json ./packages/next-observability/package.json COPY packages/next-observability/package.json ./packages/next-observability/package.json
COPY packages/husky-config/package.json ./packages/husky-config/package.json COPY packages/husky-config/package.json ./packages/husky-config/package.json
COPY packages/ui/package.json ./packages/ui/package.json
# Use a secret for NPM_TOKEN and a cache mount for the pnpm store # Use a secret for NPM_TOKEN and a cache mount for the pnpm store
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \ RUN --mount=type=cache,id=pnpm,target=/pnpm/store \

View File

@@ -5,15 +5,34 @@ WORKDIR /app
RUN corepack enable pnpm RUN corepack enable pnpm
# Step 2: Install dependencies # Step 2: Install dependencies
# We copy everything first because we have a .dockerignore ENV NPM_TOKEN=placeholder
# and we need the workspace structure for pnpm to work correctly # Copy manifest files specifically for better layer caching
COPY . . COPY pnpm-lock.yaml pnpm-workspace.yaml package.json .npmrc ./
# Copy package manifest files individually to preserve directory structure
COPY packages/cli/package.json ./packages/cli/
COPY packages/cms-infra/package.json ./packages/cms-infra/
COPY packages/customer-manager/package.json ./packages/customer-manager/
COPY packages/eslint-config/package.json ./packages/eslint-config/
COPY packages/feedback-commander/package.json ./packages/feedback-commander/
COPY packages/gatekeeper/package.json ./packages/gatekeeper/
COPY packages/husky-config/package.json ./packages/husky-config/
COPY packages/infra/package.json ./packages/infra/
COPY packages/mail/package.json ./packages/mail/
COPY packages/next-config/package.json ./packages/next-config/
COPY packages/next-feedback/package.json ./packages/next-feedback/
COPY packages/next-observability/package.json ./packages/next-observability/
COPY packages/next-utils/package.json ./packages/next-utils/
COPY packages/observability/package.json ./packages/observability/
COPY packages/tsconfig/package.json ./packages/tsconfig/
# packages/ui does not have a package.json
# Use a secret for NPM_TOKEN to authenticate with private registry # Use a secret for NPM_TOKEN and a standardized cache mount
RUN --mount=type=cache,target=/root/.local/share/pnpm/store/v3 \ RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
--mount=type=secret,id=NPM_TOKEN \ --mount=type=secret,id=NPM_TOKEN \
export NPM_TOKEN=$(cat /run/secrets/NPM_TOKEN) && \ export NPM_TOKEN=$(cat /run/secrets/NPM_TOKEN) && \
pnpm config set store-dir /pnpm/store && \
pnpm i --frozen-lockfile pnpm i --frozen-lockfile
# Step 3: Build shared packages # Step 3: Build shared packages
COPY . .
RUN pnpm --filter "./packages/*" -r build RUN pnpm --filter "./packages/*" -r build

View File

@@ -1,19 +1,22 @@
FROM node:20-alpine FROM node:20-alpine AS runner
RUN apk add --no-cache libc6-compat curl
# Install essential production utilities WORKDIR /app
RUN apk add --no-cache curl libc6-compat
# Set standard production environment
ENV NODE_ENV=production ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1 ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3000 ENV PORT=3000
ENV HOSTNAME="0.0.0.0" ENV HOSTNAME="0.0.0.0"
WORKDIR /app
# Create non-root user for security # Create non-root user for security
RUN addgroup --system --gid 1001 nodejs && \ RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs adduser --system --uid 1001 nextjs
# Expose the default Next.js port # Set correct permissions
RUN chown -R nextjs:nodejs /app
USER nextjs
EXPOSE 3000 EXPOSE 3000
CMD ["node", "server.js"]

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/infra", "name": "@mintel/infra",
"version": "1.0.1", "version": "1.6.0",
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",
"registry": "https://npm.infra.mintel.me" "registry": "https://npm.infra.mintel.me"

View File

@@ -0,0 +1,7 @@
# @mintel/mail
## 1.7.0
### Minor Changes
- 96ec2c7: Initial release of the branded email system package.

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/mail", "name": "@mintel/mail",
"version": "1.2.0", "version": "1.7.0",
"private": false, "private": false,
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",
@@ -38,6 +38,7 @@
"@mintel/tsconfig": "workspace:*", "@mintel/tsconfig": "workspace:*",
"@types/react": "^19.0.0", "@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0", "@types/react-dom": "^19.0.0",
"prettier": "^3.8.1",
"tsup": "^8.3.5", "tsup": "^8.3.5",
"typescript": "^5.0.0", "typescript": "^5.0.0",
"vitest": "^3.0.4" "vitest": "^3.0.4"

View File

@@ -0,0 +1,23 @@
import { defineConfig } from "vitest/config";
import path from "path";
export default defineConfig({
test: {
environment: "node",
alias: {
"prettier/plugins/html": path.resolve(
process.cwd(),
"../../node_modules/prettier/plugins/html.js",
),
"prettier/parser-html": path.resolve(
process.cwd(),
"../../node_modules/prettier/plugins/html.js",
),
},
server: {
deps: {
inline: [/@react-email/],
},
},
},
});

View File

@@ -1,5 +1,11 @@
# @mintel/next-config # @mintel/next-config
## 1.6.1
### Patch Changes
- Add `turbopack: {}` to support Next.js 16 default Turbopack behavior when a webpack config is present.
## 1.0.1 ## 1.0.1
### Patch Changes ### Patch Changes

View File

@@ -7,6 +7,7 @@ import path from "node:path";
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
export const baseNextConfig = { export const baseNextConfig = {
output: "standalone", output: "standalone",
turbopack: {},
images: { images: {
dangerouslyAllowSVG: true, dangerouslyAllowSVG: true,
contentDispositionType: "attachment", contentDispositionType: "attachment",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/next-config", "name": "@mintel/next-config",
"version": "1.0.1", "version": "1.6.0",
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",
"registry": "https://npm.infra.mintel.me" "registry": "https://npm.infra.mintel.me"
@@ -16,6 +16,7 @@
}, },
"dependencies": { "dependencies": {
"next-intl": "^4.8.2", "next-intl": "^4.8.2",
"@sentry/nextjs": "^8.0.0" "@sentry/nextjs": "^10.38.0",
"next": "16.1.6"
} }
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/next-feedback", "name": "@mintel/next-feedback",
"version": "1.0.0", "version": "1.6.0",
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",
"registry": "https://npm.infra.mintel.me" "registry": "https://npm.infra.mintel.me"
@@ -23,8 +23,7 @@
"scripts": { "scripts": {
"build": "tsup", "build": "tsup",
"dev": "tsup --watch", "dev": "tsup --watch",
"lint": "eslint src/", "lint": "eslint src/"
"test": "vitest run"
}, },
"dependencies": { "dependencies": {
"@directus/sdk": "^21.0.0", "@directus/sdk": "^21.0.0",
@@ -32,7 +31,7 @@
"framer-motion": "^11.5.4", "framer-motion": "^11.5.4",
"html2canvas": "^1.4.1", "html2canvas": "^1.4.1",
"lucide-react": "^0.441.0", "lucide-react": "^0.441.0",
"next": "15.1.7", "next": "16.1.6",
"tailwind-merge": "^2.5.2" "tailwind-merge": "^2.5.2"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/next-observability", "name": "@mintel/next-observability",
"version": "1.0.0", "version": "1.6.0",
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",
"registry": "https://npm.infra.mintel.me" "registry": "https://npm.infra.mintel.me"
@@ -28,8 +28,8 @@
}, },
"dependencies": { "dependencies": {
"@mintel/observability": "workspace:*", "@mintel/observability": "workspace:*",
"@sentry/nextjs": "^8.55.0", "@sentry/nextjs": "^10.38.0",
"next": "15.1.7" "next": "16.1.6"
}, },
"peerDependencies": { "peerDependencies": {
"react": "^18.0.0 || ^19.0.0", "react": "^18.0.0 || ^19.0.0",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/next-utils", "name": "@mintel/next-utils",
"version": "1.0.1", "version": "1.6.0",
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",
"registry": "https://npm.infra.mintel.me" "registry": "https://npm.infra.mintel.me"
@@ -16,7 +16,7 @@
}, },
"dependencies": { "dependencies": {
"@directus/sdk": "^21.0.0", "@directus/sdk": "^21.0.0",
"next": "15.1.7", "next": "16.1.6",
"next-intl": "^4.8.2", "next-intl": "^4.8.2",
"zod": "^3.0.0" "zod": "^3.0.0"
}, },

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/observability", "name": "@mintel/observability",
"version": "1.0.0", "version": "1.6.0",
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",
"registry": "https://npm.infra.mintel.me" "registry": "https://npm.infra.mintel.me"

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/tsconfig", "name": "@mintel/tsconfig",
"version": "1.0.1", "version": "1.6.0",
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",
"registry": "https://npm.infra.mintel.me" "registry": "https://npm.infra.mintel.me"

3029
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

50
scripts/cms-apply.sh Executable file
View File

@@ -0,0 +1,50 @@
#!/bin/bash
ENV=$1
REMOTE_HOST="root@infra.mintel.me"
REMOTE_DIR="/opt/infra/directus"
if [ -z "$ENV" ]; then
echo "Usage: ./scripts/cms-apply.sh [local|infra]"
exit 1
fi
case $ENV in
local)
CONTAINER=$(docker compose ps -q directus)
if [ -z "$CONTAINER" ]; then
echo "❌ Local directus container not found."
exit 1
fi
echo "🚀 Applying schema locally..."
docker exec "$CONTAINER" npx directus schema apply /directus/schema/snapshot.yaml --yes
;;
infra)
PROJECT_NAME="directus"
echo "📤 Uploading snapshot to $ENV..."
# Ensure remote directory exists
ssh "$REMOTE_HOST" "mkdir -p $REMOTE_DIR/directus/schema"
scp ./directus/schema/snapshot.yaml "$REMOTE_HOST:$REMOTE_DIR/directus/schema/snapshot.yaml"
echo "🔍 Detecting remote container..."
REMOTE_CONTAINER=$(ssh "$REMOTE_HOST" "cd $REMOTE_DIR && docker compose -p $PROJECT_NAME ps -q directus")
if [ -z "$REMOTE_CONTAINER" ]; then
echo "❌ Remote container for $ENV not found."
exit 1
fi
echo "🚀 Applying schema to $ENV..."
ssh "$REMOTE_HOST" "docker exec $REMOTE_CONTAINER npx directus schema apply /directus/schema/snapshot.yaml --yes"
echo "🔄 Restarting Directus to clear cache..."
ssh "$REMOTE_HOST" "cd $REMOTE_DIR && docker compose -p $PROJECT_NAME restart directus"
;;
*)
echo "❌ Invalid environment: $ENV. Only 'local' and 'infra' are supported."
exit 1
;;
esac
echo "✨ Schema apply complete!"

15
scripts/cms-snapshot.sh Executable file
View File

@@ -0,0 +1,15 @@
#!/bin/bash
# Detect local container
LOCAL_CONTAINER=$(docker compose ps -q directus)
if [ -z "$LOCAL_CONTAINER" ]; then
echo "❌ Local directus container not found. Is it running?"
exit 1
fi
echo "📸 Creating schema snapshot..."
# Note: we save it to the mounted volume path inside the container
docker exec "$LOCAL_CONTAINER" npx directus schema snapshot /directus/schema/snapshot.yaml
echo "✅ Snapshot saved to ./directus/schema/snapshot.yaml"

123
scripts/sync-directus.sh Executable file
View File

@@ -0,0 +1,123 @@
#!/bin/bash
# Configuration
REMOTE_HOST="root@infra.mintel.me"
REMOTE_DIR="/opt/infra/directus"
# DB Details (matching docker-compose defaults)
DB_USER="directus"
DB_NAME="directus"
ACTION=$1
ENV=$2
# Help
if [ -z "$ACTION" ] || [ -z "$ENV" ]; then
echo "Usage: ./scripts/sync-directus.sh [push|pull] [infra|testing|staging|production]"
echo ""
echo "Commands:"
echo " push Sync LOCAL data -> REMOTE"
echo " pull Sync REMOTE data -> LOCAL"
echo ""
echo "Environments:"
echo " infra (infra.mintel.me)"
exit 1
fi
# Map Environment
case $ENV in
infra)
PROJECT_NAME="directus"
;;
*)
echo "❌ Invalid environment: $ENV. Only 'infra' is currently configured for monorepo sync."
exit 1
;;
esac
# Detect local containers
echo "🔍 Detecting local database..."
LOCAL_DB_CONTAINER=$(docker compose ps -q directus-db)
if [ -z "$LOCAL_DB_CONTAINER" ]; then
echo "❌ Local directus-db container not found. Is it running? (npm run dev)"
exit 1
fi
if [ "$ACTION" == "push" ]; then
echo "🚀 Pushing Local Data to $ENV..."
# 1. DB Dump
echo "📦 Dumping local database..."
docker exec "$LOCAL_DB_CONTAINER" pg_dump -U "$DB_USER" --clean --if-exists --no-owner --no-privileges "$DB_NAME" > dump.sql
# 2. Upload Dump
echo "📤 Uploading dump to remote server..."
scp dump.sql "$REMOTE_HOST:$REMOTE_DIR/dump.sql"
# 3. Restore on Remote
echo "🔄 Restoring dump on $ENV..."
REMOTE_DB_CONTAINER=$(ssh "$REMOTE_HOST" "cd $REMOTE_DIR && docker compose -p $PROJECT_NAME ps -q directus-postgres")
if [ -z "$REMOTE_DB_CONTAINER" ]; then
echo "❌ Remote $ENV-db container not found!"
exit 1
fi
# Wipe remote DB clean before restore to avoid constraint errors
echo "🧹 Wiping remote database schema..."
ssh "$REMOTE_HOST" "docker exec $REMOTE_DB_CONTAINER psql -U $DB_USER $DB_NAME -c 'DROP SCHEMA public CASCADE; CREATE SCHEMA public;'"
echo "⚡ Restoring database..."
ssh "$REMOTE_HOST" "docker exec -i $REMOTE_DB_CONTAINER psql -U $DB_USER $DB_NAME < $REMOTE_DIR/dump.sql"
# 4. Sync Uploads
echo "📁 Syncing uploads (Local -> $ENV)..."
rsync -avz --progress ./directus/uploads/ "$REMOTE_HOST:$REMOTE_DIR/uploads/"
# Clean up
rm dump.sql
ssh "$REMOTE_HOST" "rm $REMOTE_DIR/dump.sql"
# 5. Restart Directus to trigger migrations and refresh schema cache
echo "🔄 Restarting remote Directus to apply migrations..."
ssh "$REMOTE_HOST" "cd $REMOTE_DIR && docker compose -p $PROJECT_NAME restart directus"
echo "✨ Push to $ENV complete!"
elif [ "$ACTION" == "pull" ]; then
echo "📥 Pulling $ENV Data to Local..."
# 1. DB Dump on Remote
echo "📦 Dumping remote database ($ENV)..."
REMOTE_DB_CONTAINER=$(ssh "$REMOTE_HOST" "cd $REMOTE_DIR && docker compose -p $PROJECT_NAME ps -q directus-postgres")
if [ -z "$REMOTE_DB_CONTAINER" ]; then
echo "❌ Remote $ENV-db container not found!"
exit 1
fi
ssh "$REMOTE_HOST" "docker exec $REMOTE_DB_CONTAINER pg_dump -U $DB_USER --clean --if-exists --no-owner --no-privileges $DB_NAME > $REMOTE_DIR/dump.sql"
# 2. Download Dump
echo "📥 Downloading dump..."
scp "$REMOTE_HOST:$REMOTE_DIR/dump.sql" dump.sql
# Wipe local DB clean before restore to avoid constraint errors
echo "🧹 Wiping local database schema..."
docker exec "$LOCAL_DB_CONTAINER" psql -U "$DB_USER" "$DB_NAME" -c 'DROP SCHEMA public CASCADE; CREATE SCHEMA public;'
echo "⚡ Restoring database locally..."
docker exec -i "$LOCAL_DB_CONTAINER" psql -U "$DB_USER" "$DB_NAME" < dump.sql
# 4. Sync Uploads
echo "📁 Syncing uploads ($ENV -> Local)..."
rsync -avz --progress "$REMOTE_HOST:$REMOTE_DIR/uploads/" ./directus/uploads/
# Clean up
rm dump.sql
ssh "$REMOTE_HOST" "rm $REMOTE_DIR/dump.sql"
echo "✨ Pull to Local complete!"
else
echo "Invalid action: $ACTION. Use push or pull."
exit 1
fi

View File

@@ -1,11 +1,45 @@
import * as fs from "fs"; import * as fs from "fs";
import * as path from "path"; import * as path from "path";
const tag = process.env.GITHUB_REF_NAME || process.env.TAG; import { execSync } from "child_process";
if (!tag || !tag.startsWith("v")) { /**
console.error("❌ No valid tag found (must start with v, e.g., v1.0.0)"); * Gets the current version tag from environment or git.
process.exit(1); */
function getVersionTag() {
// 1. Check CI environment variables
if (
process.env.GITHUB_REF_NAME &&
process.env.GITHUB_REF_NAME.startsWith("v")
) {
return process.env.GITHUB_REF_NAME;
}
if (process.env.TAG && process.env.TAG.startsWith("v")) {
return process.env.TAG;
}
// 2. Try to get it from local git
try {
const gitTag = execSync("git describe --tags --abbrev=0", {
encoding: "utf8",
}).trim();
if (gitTag && gitTag.startsWith("v")) {
return gitTag;
}
} catch (e) {
// Fallback or silence
}
return null;
}
const tag = getVersionTag();
if (!tag) {
console.log(
" No version tag found (starting with v). Skipping version sync.",
);
process.exit(0); // Exit gracefully if no tag is present
} }
const version = tag.replace(/^v/, ""); const version = tag.replace(/^v/, "");