diff --git a/.github/workflows/deploy-postgres-dev.yml b/.github/workflows/deploy-postgres-dev.yml index 784d2ae..1ba1ca2 100644 --- a/.github/workflows/deploy-postgres-dev.yml +++ b/.github/workflows/deploy-postgres-dev.yml @@ -30,9 +30,6 @@ jobs: kubectl config set-context runner-context --cluster=microk8s --user=runner --namespace="$NAMESPACE" kubectl config use-context runner-context - - name: Apply DEV secrets - run: kubectl apply -f db/k8s/secrets/ - - name: Deploy DEV Postgres run: kubectl apply -f db/k8s/postgres/postgres-dev-stripe-to-invoice.yaml @@ -67,11 +64,30 @@ jobs: - name: Load DEV DB creds run: | - export POSTGRES_USER=$(kubectl get secret postgres-secret -o jsonpath='{.data.POSTGRES_USER}' | base64 -d) - export POSTGRES_PASSWORD=$(kubectl get secret postgres-secret -o jsonpath='{.data.POSTGRES_PASSWORD}' | base64 -d) + DB_NAMESPACE=dev + SECRET_NAME=postgres-secret + + POSTGRES_USER=$(kubectl get secret $SECRET_NAME \ + --namespace $DB_NAMESPACE \ + -o jsonpath='{.data.POSTGRES_USER}' | base64 -d) + + POSTGRES_PASSWORD=$(kubectl get secret $SECRET_NAME \ + --namespace $DB_NAMESPACE \ + -o jsonpath='{.data.POSTGRES_PASSWORD}' | base64 -d) + + POSTGRES_DB=$(kubectl get secret $SECRET_NAME \ + --namespace $DB_NAMESPACE \ + -o jsonpath='{.data.POSTGRES_DB}' | base64 -d) + + POSTGRES_HOST=postgres-dev.stripe-invoice-dev.svc.cluster.local + POSTGRES_PORT=5432 + + DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}?sslmode=disable" echo "POSTGRES_USER=$POSTGRES_USER" >> $GITHUB_ENV echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> $GITHUB_ENV + echo "POSTGRES_DB=$POSTGRES_DB" >> $GITHUB_ENV + echo "DATABASE_URL=$DATABASE_URL" >> $GITHUB_ENV - name: Run Atlas migrations (DEV) run: | diff --git a/.github/workflows/juntekim.yml b/.github/workflows/juntekim.yml index 632b2f2..cdea3c0 100644 --- a/.github/workflows/juntekim.yml +++ b/.github/workflows/juntekim.yml @@ -8,7 +8,7 @@ on: - "**" jobs: - Push-to-docker-hub: + Push-to-juntekim-to-docker-hub: runs-on: ubuntu-22.04 steps: diff --git a/.github/workflows/stripe-to-invoice.yml b/.github/workflows/stripe-to-invoice.yml new file mode 100644 index 0000000..3cd01c0 --- /dev/null +++ b/.github/workflows/stripe-to-invoice.yml @@ -0,0 +1,81 @@ +# name: Build & Deploy stripe-to-invoice + +# on: +# push: +# branches: +# - main +# - feature/** +# - release/** +# tags: +# - "*" + +# jobs: +# build: +# runs-on: ubuntu-22.04 +# steps: +# - uses: actions/checkout@v4 + +# - name: Inject slug variables +# uses: rlespinasse/github-slug-action@v4 + +# - name: Login to Docker Hub +# uses: docker/login-action@v3 +# with: +# username: ${{ secrets.DOCKER_HUB_USERNAME }} +# password: ${{ secrets.DOCKER_HUB_TOKEN }} + +# - name: Build image +# run: | +# docker build \ +# -f stripe_to_invoice/deployment/Dockerfile \ +# -t docker.io/kimjunte/stripe_to_invoice:$GITHUB_REF_SLUG \ +# . + +# - name: Push image +# run: | +# docker push docker.io/kimjunte/stripe_to_invoice:$GITHUB_REF_SLUG + +# deploy: +# runs-on: mealcraft-runners +# needs: build + +# steps: +# - uses: actions/checkout@v4 + +# - name: Install kubectl +# run: | +# sudo apt-get update +# sudo apt-get install -y curl ca-certificates gettext +# curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" +# sudo install -m 0755 kubectl /usr/local/bin/kubectl + +# - name: Configure kubeconfig +# run: | +# KUBE_HOST="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT" +# SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) +# CA_CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt +# NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace) + +# kubectl config set-cluster microk8s --server="$KUBE_HOST" --certificate-authority="$CA_CERT" +# kubectl config set-credentials runner --token="$SA_TOKEN" +# kubectl config set-context runner-context --cluster=microk8s --user=runner --namespace="$NAMESPACE" +# kubectl config use-context runner-context + +# - name: Inject slug variables +# uses: rlespinasse/github-slug-action@v4 + +# - name: Set environment +# run: | +# if [[ "$GITHUB_REF" == refs/heads/release/* || "$GITHUB_REF" == refs/tags/* ]]; then +# echo "NAMESPACE=default" >> $GITHUB_ENV +# echo "DB_ENV=prod" >> $GITHUB_ENV +# else +# echo "NAMESPACE=dev" >> $GITHUB_ENV +# echo "DB_ENV=dev" >> $GITHUB_ENV +# fi + +# - name: Deploy +# run: | +# export IMAGE="docker.io/kimjunte/stripe_to_invoice:$GITHUB_REF_SLUG" +# export NAMESPACE DB_ENV +# envsubst < stripe_to_invoice/deployment/deployment.yaml | kubectl apply -f - diff --git a/.vscode/settings.json b/.vscode/settings.json index 0004f17..fc7cd3e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,10 +24,10 @@ }, // Terminal copy/paste via Ctrl+Shift+C / Ctrl+Shift+V - "terminal.integrated.copyOnSelection": false, +/* "terminal.integrated.copyOnSelection": false, "terminal.integrated.commandsToSkipShell": [ "workbench.action.terminal.copySelection", "workbench.action.terminal.paste" - ], + ], */ } \ No newline at end of file diff --git a/db/atlas/atlas.hcl b/db/atlas/atlas.hcl index a2c53d8..1ea6f2b 100644 --- a/db/atlas/atlas.hcl +++ b/db/atlas/atlas.hcl @@ -1,5 +1,5 @@ env "stripe_invoice_dev" { - url = "postgres://${getenv("POSTGRES_USER")}:${getenv("POSTGRES_PASSWORD")}@postgres-dev.default.svc.cluster.local:5432/stripe_invoice?sslmode=disable" + url = "postgres://${getenv("POSTGRES_USER")}:${getenv("POSTGRES_PASSWORD")}@postgres-dev.dev.svc.cluster.local:5432/stripe_invoice?sslmode=disable" migration { dir = "file://./db/atlas/stripe_invoice/migrations" diff --git a/db/k8s/postgres/postgres-dev-stripe-to-invoice.yaml b/db/k8s/postgres/postgres-dev-stripe-to-invoice.yaml index 6402bc9..3016ae1 100644 --- a/db/k8s/postgres/postgres-dev-stripe-to-invoice.yaml +++ b/db/k8s/postgres/postgres-dev-stripe-to-invoice.yaml @@ -4,7 +4,7 @@ apiVersion: v1 kind: PersistentVolume metadata: - name: postgres-pv + name: postgres-dev-pv spec: capacity: storage: 20Gi @@ -13,7 +13,7 @@ spec: persistentVolumeReclaimPolicy: Retain storageClassName: local-storage hostPath: - path: /home/kimjunte/k8s_storage/postgres/stripe_invoice + path: /home/kimjunte/k8s_storage/postgres/stripe_invoice_dev --- # -------------------------------------------------- @@ -23,7 +23,7 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: name: postgres-pvc - namespace: default + namespace: dev spec: accessModes: - ReadWriteOnce @@ -40,7 +40,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: postgres - namespace: default + namespace: dev spec: replicas: 1 selector: @@ -62,16 +62,6 @@ spec: volumeMounts: - name: postgres-data mountPath: /var/lib/postgresql/data - readinessProbe: - tcpSocket: - port: 5432 - initialDelaySeconds: 10 - periodSeconds: 5 - livenessProbe: - tcpSocket: - port: 5432 - initialDelaySeconds: 30 - periodSeconds: 10 volumes: - name: postgres-data persistentVolumeClaim: @@ -85,7 +75,7 @@ apiVersion: v1 kind: Service metadata: name: postgres-dev - namespace: default + namespace: dev spec: type: ClusterIP selector: @@ -95,13 +85,16 @@ spec: targetPort: 5432 --- +# -------------------------------------------------- +# Secret +# -------------------------------------------------- apiVersion: v1 kind: Secret metadata: name: postgres-secret - namespace: default + namespace: dev type: Opaque stringData: POSTGRES_USER: postgres POSTGRES_PASSWORD: averysecretpasswordPersonAppleWinter938 - POSTGRES_DB: stripe_invoice \ No newline at end of file + POSTGRES_DB: stripe_invoice diff --git a/db/k8s/secrets/postgres-secret-dev.yaml b/db/k8s/secrets/postgres-secret-dev.yaml deleted file mode 100644 index 2dbdaf3..0000000 --- a/db/k8s/secrets/postgres-secret-dev.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# Github runners/workers needs access to secret to set env variable for various things ---- -apiVersion: v1 -kind: Secret -metadata: - name: postgres-secret - namespace: arc-systems -type: Opaque -stringData: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: averysecretpasswordPersonAppleWinter938 - POSTGRES_DB: stripe_invoice - ---- -apiVersion: v1 -kind: Secret -metadata: - name: postgres-prod-secret - namespace: arc-systems -type: Opaque -stringData: - POSTGRES_USER: stripe_invoice_prod - POSTGRES_PASSWORD: productionPassword1142M@ke!tH@rd2Br3akWith$ymb0ls - POSTGRES_DB: stripe_invoice_prod diff --git a/mist_infra/scripts/backup_k8s_storage_to_s3.sh b/mist_infra/scripts/backup_k8s_storage_to_s3.sh index e667643..ec620ab 100644 --- a/mist_infra/scripts/backup_k8s_storage_to_s3.sh +++ b/mist_infra/scripts/backup_k8s_storage_to_s3.sh @@ -14,7 +14,6 @@ fi # ================================================== # GLOBAL CONFIG # ================================================== -NAMESPACE="default" K8S_STORAGE_ROOT="/k8s_storage" BACKUP_ROOT="/tmp/k8s-backups" DATE="$(date -u +%Y-%m-%d_%H-%M-%S)" @@ -33,8 +32,9 @@ TAR_EXCLUDES=( case "$ENVIRONMENT" in dev) PG_SECRET_NAME="postgres-secret" - PG_POD_SELECTOR="app=postgres" + PG_POD_SELECTOR="app=postgres-dev" S3_PREFIX="dev" + NAMESPACE="dev" ;; prod) if [[ "${I_UNDERSTAND_THIS_IS_PROD:-}" != "true" ]]; then @@ -46,6 +46,7 @@ case "$ENVIRONMENT" in PG_SECRET_NAME="postgres-prod-secret" PG_POD_SELECTOR="app=postgres-prod" S3_PREFIX="prod" + NAMESPACE="default" ;; *) echo "❌ Invalid ENVIRONMENT: $ENVIRONMENT (must be dev or prod)" diff --git a/stripe_to_invoice/app/connect/stripe/page.tsx b/stripe_to_invoice/app/connect/stripe/page.tsx new file mode 100644 index 0000000..cbce634 --- /dev/null +++ b/stripe_to_invoice/app/connect/stripe/page.tsx @@ -0,0 +1,77 @@ +// app/connect/stripe/page.tsx +// +// STEP 2 — Connect Stripe +// Purpose: +// - Explain why Stripe access is needed +// - Provide a single, clear action +// - Feel safe, boring, and familiar (Zapier-style) + +import { cookies } from "next/headers"; +import { redirect } from "next/navigation"; + +export default async function ConnectStripePage() { + const cookieStore = await cookies(); + const session = cookieStore.get("session"); + + // Safety: if not logged in, bounce to login + if (!session) { + redirect("/login"); + } + + return ( +
+ {/* -------------------------------------------------- + Header + -------------------------------------------------- */} +
+

+ Connect Stripe +

+ +

+ We need read-only access to your Stripe account so we can + detect successful payments and automatically reconcile + invoices in Xero. +

+
+ + {/* -------------------------------------------------- + What will happen + -------------------------------------------------- */} +
+

+ What happens next +

+ + +
+ + {/* -------------------------------------------------- + Trust / reassurance + -------------------------------------------------- */} +
+

+ We never see your passwords. +
+ Access can be revoked at any time from Stripe. +

+
+ + {/* -------------------------------------------------- + Primary action + -------------------------------------------------- */} +
+ + Connect Stripe → + +
+
+ ); +} diff --git a/stripe_to_invoice/app/page.tsx b/stripe_to_invoice/app/page.tsx index 0d1db2d..3c95830 100644 --- a/stripe_to_invoice/app/page.tsx +++ b/stripe_to_invoice/app/page.tsx @@ -7,7 +7,18 @@ // // Everything else lives elsewhere. -export default function Home() { +import { cookies } from "next/headers"; +import { redirect } from "next/navigation"; + +export default async function Home() { + const cookieStore = await cookies(); + const session = cookieStore.get("session"); + + // ✅ If already logged in, go straight to app + if (session) { + redirect("/app"); + } + return (
@@ -58,5 +69,5 @@ export default function Home() {
- ) + ); } diff --git a/stripe_to_invoice/deployment/Dockerfile b/stripe_to_invoice/deployment/Dockerfile new file mode 100644 index 0000000..80123e3 --- /dev/null +++ b/stripe_to_invoice/deployment/Dockerfile @@ -0,0 +1,37 @@ +# ---------- base ---------- +FROM node:20-alpine AS base +ENV NODE_ENV=production +WORKDIR /app/stripe_to_invoice + +# ---------- deps ---------- +FROM base AS deps +RUN apk add --no-cache libc6-compat +COPY stripe_to_invoice/package.json stripe_to_invoice/package-lock.json ./ +RUN npm ci + +# ---------- builder ---------- +FROM base AS builder +WORKDIR /app/stripe_to_invoice # 🔥 THIS WAS MISSING +COPY --from=deps /app/stripe_to_invoice/node_modules ./node_modules +COPY stripe_to_invoice . +ENV NEXT_TELEMETRY_DISABLED=1 +RUN node -e "require('typescript')" +RUN npm run build + +# ---------- runner ---------- +FROM node:20-alpine AS runner +WORKDIR /app + +RUN addgroup -g 1001 nodejs \ + && adduser -u 1001 -G nodejs -s /bin/sh -D nextjs + +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 + +COPY --from=builder /app/stripe_to_invoice/public ./public +COPY --from=builder /app/stripe_to_invoice/.next/standalone ./ +COPY --from=builder /app/stripe_to_invoice/.next/static ./.next/static + +USER nextjs +EXPOSE 3000 +CMD ["node", "server.js"] diff --git a/stripe_to_invoice/deployment/TODO.md b/stripe_to_invoice/deployment/TODO.md new file mode 100644 index 0000000..78c9611 --- /dev/null +++ b/stripe_to_invoice/deployment/TODO.md @@ -0,0 +1,170 @@ +# kind: Deployment +# apiVersion: apps/v1 +# metadata: +# namespace: ${NAMESPACE} +# name: portfolio-page +# labels: +# app: portfolio-page +# spec: +# replicas: 1 +# selector: +# matchLabels: +# app: portfolio-page +# template: +# metadata: +# labels: +# app: portfolio-page +# spec: +# containers: +# - name: portfolio-page +# image: kimjunte/portfolio_page:$GITHUB_REF_SLUG +# imagePullPolicy: Always +# ports: +# - name: portfolioport +# containerPort: 3000 +# imagePullSecrets: +# - name: registrypullsecret +# # This is a file I used to push juntekim.com as deployment while keeping a different namespace for prod and staging + +# --- +# apiVersion: v1 +# kind: Service +# metadata: +# name: portfolio-page +# namespace: ${NAMESPACE} +# spec: +# ports: +# - protocol: TCP +# name: portfolioport +# port: 80 +# targetPort: 3000 +# selector: +# app: portfolio-page +# --- +# apiVersion: traefik.io/v1alpha1 +# kind: IngressRoute +# metadata: +# name: juntekim-portfolio-page +# namespace: ${NAMESPACE} +# spec: +# entryPoints: +# - websecure +# routes: +# - match: "Host(`${HOSTNAME}`) || Host(`www.${HOSTNAME}`)" +# kind: Rule +# services: +# - name: portfolio-page +# port: 80 +# passHostHeader: false +# tls: +# certResolver: myresolver +# domains: +# - main: ${HOSTNAME} +# for the beta version lets use stripe-to-invoice-dev.juntekim.com for now and deploy things on feature and main branch +# only once it goes to production from a release branch we'll make this go to the same name space as production database which default as well - however the postgres data +# will be postgres-prod, with different password and user name + +# the workflow for the deployment the portfolio page looks as follows including pushing to the docker registry +# +# name: Build juntekim.com + +# on: +# push: +# tags: +# - "*" +# branches: +# - "**" + +# jobs: +# Push-to-docker-hub: +# runs-on: ubuntu-22.04 + +# steps: +# - uses: actions/checkout@v3 + +# - name: Inject slug/short variables +# uses: rlespinasse/github-slug-action@v4 + +# - name: Login to Docker Hub +# uses: docker/login-action@v3 +# with: +# username: ${{ secrets.DOCKER_HUB_USERNAME }} +# password: ${{ secrets.DOCKER_HUB_TOKEN }} + +# - name: Build Docker Image +# run: | +# docker build \ +# -f juntekim_frontend/deployment/Dockerfile \ +# -t docker.io/kimjunte/portfolio_page:$GITHUB_REF_SLUG \ +# juntekim_frontend + +# - name: Push to Docker Hub +# run: | +# docker push docker.io/kimjunte/portfolio_page:$GITHUB_REF_SLUG + + +# run-on-k8s: +# runs-on: mealcraft-runners # <-- your ARC scale set label +# needs: Push-to-docker-hub +# steps: +# - uses: actions/checkout@v4 + +# # Install kubectl inside containerMode's default Ubuntu +# - name: Install kubectl +# run: | +# sudo apt-get update +# sudo apt-get install -y curl ca-certificates +# curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" +# sudo install -m 0755 kubectl /usr/local/bin/kubectl + +# - name: Install envsubst +# run: | +# sudo apt-get update +# sudo apt-get install -y gettext # <---- envsubst lives here + +# # Configure kubeconfig from ARC's service account +# - name: Configure kubeconfig +# run: | +# KUBE_HOST="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT" +# SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) +# CA_CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt +# NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace) + +# kubectl config set-cluster microk8s --server="$KUBE_HOST" --certificate-authority="$CA_CERT" +# kubectl config set-credentials runner --token="$SA_TOKEN" +# kubectl config set-context runner-context --cluster=microk8s --user=runner --namespace="$NAMESPACE" +# kubectl config use-context runner-context + +# - name: Inject slug variables +# uses: rlespinasse/github-slug-action@v4 + +# - name: Set namespace +# id: ns +# run: | +# if [[ $GITHUB_REF == refs/tags/* ]]; then +# echo "NAMESPACE=default" >> $GITHUB_ENV +# else +# echo "NAMESPACE=staging" >> $GITHUB_ENV +# fi + +# - name: Set hostname +# run: | +# if [ "$NAMESPACE" = "staging" ]; then +# echo "HOSTNAME=staging.juntekim.com" >> $GITHUB_ENV +# else +# echo "HOSTNAME=juntekim.com" >> $GITHUB_ENV +# fi + +# - name: Deploy to Kubernetes +# run: | +# export IMAGE="docker.io/kimjunte/portfolio_page:$GITHUB_REF_SLUG" +# export NAMESPACE HOSTNAME + +# envsubst < juntekim_frontend/deployment/deployment.yml | kubectl apply -f - +# envsubst < juntekim_frontend/deployment/service.yml | kubectl apply -f - +# envsubst < juntekim_frontend/deployment/ingressroute.yml | kubectl apply -f - + +# 1) First make me a Dockerfile for the nextjs app that i have under stripe_to_invoice that is produciton ready +# 2) make me a depoloyment file which i'll have under stripe_to_invoice/deployment/deployment.yaml +# 3) Make me the github workflow to run this in feature/* or main ( in dev) and releases in prod ( which just uses a different database) + diff --git a/stripe_to_invoice/deployment/deployment.yaml b/stripe_to_invoice/deployment/deployment.yaml new file mode 100644 index 0000000..3544346 --- /dev/null +++ b/stripe_to_invoice/deployment/deployment.yaml @@ -0,0 +1,78 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: stripe-to-invoice + namespace: ${NAMESPACE} + labels: + app: stripe-to-invoice +spec: + replicas: 1 + selector: + matchLabels: + app: stripe-to-invoice + template: + metadata: + labels: + app: stripe-to-invoice + spec: + containers: + - name: stripe-to-invoice + image: ${IMAGE} + imagePullPolicy: Always + ports: + - name: http + containerPort: 3000 + env: + - name: NODE_ENV + value: "production" + + # ---- Database ---- + - name: DATABASE_URL + valueFrom: + secretKeyRef: + name: postgres-${DB_ENV} + key: DATABASE_URL + + # ---- Stripe ---- + - name: STRIPE_SECRET_KEY + valueFrom: + secretKeyRef: + name: stripe-secrets + key: STRIPE_SECRET_KEY + + imagePullSecrets: + - name: registrypullsecret + +--- +apiVersion: v1 +kind: Service +metadata: + name: stripe-to-invoice + namespace: ${NAMESPACE} +spec: + selector: + app: stripe-to-invoice + ports: + - name: http + protocol: TCP + port: 80 + targetPort: 3000 + +--- +apiVersion: traefik.io/v1alpha1 +kind: IngressRoute +metadata: + name: stripe-to-invoice + namespace: ${NAMESPACE} +spec: + entryPoints: + - websecure + routes: + - match: Host(`${HOSTNAME}`) + kind: Rule + services: + - name: stripe-to-invoice + port: 80 + passHostHeader: true + tls: + certResolver: myresolver diff --git a/stripe_to_invoice/next.config.ts b/stripe_to_invoice/next.config.ts index e9ffa30..8843504 100644 --- a/stripe_to_invoice/next.config.ts +++ b/stripe_to_invoice/next.config.ts @@ -1,7 +1,10 @@ import type { NextConfig } from "next"; -const nextConfig: NextConfig = { - /* config options here */ +const nextConfig = { + output: 'standalone', + experimental: { + turbo: false, // disables Turbopack in prod builds + }, }; -export default nextConfig; +export default nextConfig; \ No newline at end of file diff --git a/stripe_to_invoice/package-lock.json b/stripe_to_invoice/package-lock.json index 29887ca..42d776c 100644 --- a/stripe_to_invoice/package-lock.json +++ b/stripe_to_invoice/package-lock.json @@ -9,29 +9,29 @@ "version": "0.1.0", "dependencies": { "@aws-sdk/client-ses": "^3.958.0", + "@tailwindcss/postcss": "^4", "drizzle-orm": "^0.45.1", "next": "16.0.10", "pg": "^8.16.3", "react": "19.2.1", - "react-dom": "19.2.1" + "react-dom": "19.2.1", + "tailwindcss": "^4", + "typescript": "^5.5.0" }, "devDependencies": { - "@tailwindcss/postcss": "^4", "@types/node": "^20", + "@types/pg": "^8.16.0", "@types/react": "^19", "@types/react-dom": "^19", "drizzle-kit": "^0.31.8", "eslint": "^9", - "eslint-config-next": "16.0.10", - "tailwindcss": "^4", - "typescript": "^5" + "eslint-config-next": "16.0.10" } }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -944,7 +944,6 @@ "version": "1.7.1", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -966,7 +965,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -2517,7 +2515,6 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -2528,7 +2525,6 @@ "version": "2.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -2539,7 +2535,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -2549,14 +2544,12 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -2567,7 +2560,6 @@ "version": "0.2.12", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -3382,7 +3374,6 @@ "version": "4.1.18", "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz", "integrity": "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/remapping": "^2.3.4", @@ -3398,7 +3389,6 @@ "version": "4.1.18", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.18.tgz", "integrity": "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==", - "dev": true, "license": "MIT", "engines": { "node": ">= 10" @@ -3425,7 +3415,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3442,7 +3431,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3459,7 +3447,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3476,7 +3463,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3493,7 +3479,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3510,7 +3495,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3527,7 +3511,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3544,7 +3527,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3561,7 +3543,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3586,7 +3567,6 @@ "cpu": [ "wasm32" ], - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -3608,7 +3588,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3625,7 +3604,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3639,7 +3617,6 @@ "version": "4.1.18", "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.18.tgz", "integrity": "sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==", - "dev": true, "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", @@ -3653,7 +3630,6 @@ "version": "0.10.1", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -3685,12 +3661,24 @@ "version": "20.19.26", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.26.tgz", "integrity": "sha512-0l6cjgF0XnihUpndDhk+nyD3exio3iKaYROSgvh/qSevPXax3L8p5DBRFjbvalnwatGgHEQn2R88y2fA3g4irg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" } }, + "node_modules/@types/pg": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.16.0.tgz", + "integrity": "sha512-RmhMd/wD+CF8Dfo+cVIy3RR5cl8CyfXQ0tGgW6XBL8L4LM/UTEbNXYRbLwU6w+CgrKBNbrQWt4FUtTfaU5jSYQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, "node_modules/@types/react": { "version": "19.2.7", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", @@ -4908,7 +4896,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=8" @@ -5101,7 +5088,6 @@ "version": "5.18.4", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz", "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==", - "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -6140,7 +6126,6 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, "license": "ISC" }, "node_modules/has-bigints": { @@ -6757,7 +6742,6 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", - "dev": true, "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" @@ -6894,7 +6878,6 @@ "version": "1.30.2", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", - "dev": true, "license": "MPL-2.0", "dependencies": { "detect-libc": "^2.0.3" @@ -6927,7 +6910,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -6948,7 +6930,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -6969,7 +6950,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -6990,7 +6970,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7011,7 +6990,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7032,7 +7010,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7053,7 +7030,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7074,7 +7050,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7095,7 +7070,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7116,7 +7090,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7137,7 +7110,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7201,7 +7173,6 @@ "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" @@ -7752,7 +7723,6 @@ "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, "funding": [ { "type": "opencollective", @@ -8555,14 +8525,12 @@ "version": "4.1.18", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==", - "dev": true, "license": "MIT" }, "node_modules/tapable": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -8773,7 +8741,6 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -8830,7 +8797,7 @@ "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/unrs-resolver": { diff --git a/stripe_to_invoice/package.json b/stripe_to_invoice/package.json index 57530a8..522978c 100644 --- a/stripe_to_invoice/package.json +++ b/stripe_to_invoice/package.json @@ -10,21 +10,22 @@ }, "dependencies": { "@aws-sdk/client-ses": "^3.958.0", + "@tailwindcss/postcss": "^4", "drizzle-orm": "^0.45.1", "next": "16.0.10", "pg": "^8.16.3", "react": "19.2.1", - "react-dom": "19.2.1" + "react-dom": "19.2.1", + "tailwindcss": "^4", + "typescript": "^5.5.0" }, "devDependencies": { - "@tailwindcss/postcss": "^4", "@types/node": "^20", + "@types/pg": "^8.16.0", "@types/react": "^19", "@types/react-dom": "^19", "drizzle-kit": "^0.31.8", "eslint": "^9", - "eslint-config-next": "16.0.10", - "tailwindcss": "^4", - "typescript": "^5" + "eslint-config-next": "16.0.10" } } diff --git a/stripe_to_invoice/postcss.config.js b/stripe_to_invoice/postcss.config.js new file mode 100644 index 0000000..106d2f8 --- /dev/null +++ b/stripe_to_invoice/postcss.config.js @@ -0,0 +1,5 @@ +module.exports = { + plugins: { + '@tailwindcss/postcss': {}, + }, +}; \ No newline at end of file diff --git a/stripe_to_invoice/postcss.config.mjs b/stripe_to_invoice/postcss.config.mjs deleted file mode 100644 index 61e3684..0000000 --- a/stripe_to_invoice/postcss.config.mjs +++ /dev/null @@ -1,7 +0,0 @@ -const config = { - plugins: { - "@tailwindcss/postcss": {}, - }, -}; - -export default config;