Add cuisine subcategory filter, fix remap logic, and add OKE deployment manifests

- Add 파인다이닝/코스 cuisine type to 한식/일식/중식/양식 categories
- Change cuisine filter from flat list to grouped optgroup with subcategories
- Fix remap-foods/remap-cuisine: add jdbcType=CLOB, fix CLOB LISTAGG,
  improve retry logic (3 attempts, batch size 5), add error logging
- Add OKE deployment: Dockerfiles, K8s manifests, deploy.sh, deployment guide
- Add Next.js standalone output for Docker builds

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
joungmin
2026-03-09 22:58:09 +09:00
parent 69e1882c2b
commit ff4e8d742d
18 changed files with 853 additions and 41 deletions

View File

@@ -0,0 +1,70 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
namespace: tasteby
spec:
replicas: 1
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
imagePullSecrets:
- name: ocir-secret
containers:
- name: backend
image: icn.ocir.io/idyhsdamac8c/tasteby/backend:latest
ports:
- containerPort: 8000
envFrom:
- configMapRef:
name: tasteby-config
- secretRef:
name: tasteby-secrets
volumeMounts:
- name: oracle-wallet
mountPath: /etc/oracle/wallet
readOnly: true
- name: oci-config
mountPath: /root/.oci
readOnly: true
resources:
requests:
cpu: 500m
memory: 768Mi
limits:
cpu: "1"
memory: 1536Mi
readinessProbe:
tcpSocket:
port: 8000
initialDelaySeconds: 30
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8000
initialDelaySeconds: 60
periodSeconds: 30
volumes:
- name: oracle-wallet
secret:
secretName: oracle-wallet
- name: oci-config
secret:
secretName: oci-config
---
apiVersion: v1
kind: Service
metadata:
name: backend
namespace: tasteby
spec:
selector:
app: backend
ports:
- port: 8000
targetPort: 8000

View File

@@ -0,0 +1,14 @@
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: joungmin@tasteby.net
privateKeySecretRef:
name: letsencrypt-prod-key
solvers:
- http01:
ingress:
class: nginx

14
k8s/configmap.yaml Normal file
View File

@@ -0,0 +1,14 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: tasteby-config
namespace: tasteby
data:
REDIS_HOST: "redis"
REDIS_PORT: "6379"
REDIS_DB: "0"
ORACLE_WALLET: "/etc/oracle/wallet"
OCI_CHAT_ENDPOINT: "https://inference.generativeai.us-ashburn-1.oci.oraclecloud.com"
OCI_GENAI_ENDPOINT: "https://inference.generativeai.us-chicago-1.oci.oraclecloud.com"
OCI_EMBED_MODEL_ID: "cohere.embed-v4.0"
GOOGLE_CLIENT_ID: "635551099330-2l003d3ernjmkqavd4f6s78r8r405iml.apps.googleusercontent.com"

View File

@@ -0,0 +1,53 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
namespace: tasteby
spec:
replicas: 1
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
imagePullSecrets:
- name: ocir-secret
containers:
- name: frontend
image: icn.ocir.io/idyhsdamac8c/tasteby/frontend:latest
ports:
- containerPort: 3001
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
readinessProbe:
httpGet:
path: /
port: 3001
initialDelaySeconds: 10
periodSeconds: 10
livenessProbe:
httpGet:
path: /
port: 3001
initialDelaySeconds: 15
periodSeconds: 30
---
apiVersion: v1
kind: Service
metadata:
name: frontend
namespace: tasteby
spec:
selector:
app: frontend
ports:
- port: 3001
targetPort: 3001

48
k8s/ingress.yaml Normal file
View File

@@ -0,0 +1,48 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tasteby-ingress
namespace: tasteby
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
# Redirect tasteby.net → www.tasteby.net
nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- www.tasteby.net
- tasteby.net
secretName: tasteby-tls
rules:
- host: www.tasteby.net
http:
paths:
- path: /api/
pathType: Prefix
backend:
service:
name: backend
port:
number: 8000
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
number: 3001
- host: tasteby.net
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
number: 3001

4
k8s/namespace.yaml Normal file
View File

@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: tasteby

39
k8s/redis-deployment.yaml Normal file
View File

@@ -0,0 +1,39 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: tasteby
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7-alpine
ports:
- containerPort: 6379
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi
---
apiVersion: v1
kind: Service
metadata:
name: redis
namespace: tasteby
spec:
selector:
app: redis
ports:
- port: 6379
targetPort: 6379

17
k8s/secrets.yaml.template Normal file
View File

@@ -0,0 +1,17 @@
# Copy this to secrets.yaml and fill in real values.
# DO NOT commit secrets.yaml to git!
apiVersion: v1
kind: Secret
metadata:
name: tasteby-secrets
namespace: tasteby
type: Opaque
stringData:
ORACLE_USER: "<oracle-username>"
ORACLE_PASSWORD: "<oracle-password>"
ORACLE_DSN: "<tns-alias>_high?TNS_ADMIN=/etc/oracle/wallet"
JWT_SECRET: "<jwt-secret>"
OCI_COMPARTMENT_ID: "<oci-compartment-id>"
OCI_CHAT_MODEL_ID: "<oci-chat-model-id>"
GOOGLE_MAPS_API_KEY: "<google-maps-api-key>"
YOUTUBE_DATA_API_KEY: "<youtube-data-api-key>"