diff --git a/base/ingress/pingora-config.yaml b/base/ingress/pingora-config.yaml index bb1d73a..544f099 100644 --- a/base/ingress/pingora-config.yaml +++ b/base/ingress/pingora-config.yaml @@ -272,6 +272,11 @@ data: prefix = "/__" backend = "http://calendars-backend.lasuite.svc.cluster.local:80" + [[routes]] + host_prefix = "projects" + backend = "http://projects.lasuite.svc.cluster.local:80" + websocket = true + [[routes]] host_prefix = "s3" backend = "http://seaweedfs-filer.storage.svc.cluster.local:8333" diff --git a/base/lasuite/integration-deployment.yaml b/base/lasuite/integration-deployment.yaml index 3d94f59..c86d1ef 100644 --- a/base/lasuite/integration-deployment.yaml +++ b/base/lasuite/integration-deployment.yaml @@ -21,24 +21,39 @@ data: { "services": [ { - "name": "Reuniões", - "url": "https://meet.DOMAIN_SUFFIX", - "logo": "https://integration.DOMAIN_SUFFIX/logos/visio.svg?v=2" + "name": "Calendar", + "url": "https://cal.DOMAIN_SUFFIX", + "logo": "https://integration.DOMAIN_SUFFIX/logos/calendar.svg?v=1" }, { "name": "Drive", "url": "https://drive.DOMAIN_SUFFIX", "logo": "https://integration.DOMAIN_SUFFIX/logos/drive.svg?v=1" }, + { + "name": "Mail", + "url": "https://mail.DOMAIN_SUFFIX", + "logo": "https://integration.DOMAIN_SUFFIX/logos/mail.svg?v=1" + }, + { + "name": "Meet", + "url": "https://meet.DOMAIN_SUFFIX", + "logo": "https://integration.DOMAIN_SUFFIX/logos/visio.svg?v=2" + }, + { + "name": "Projects", + "url": "https://projects.DOMAIN_SUFFIX", + "logo": "https://integration.DOMAIN_SUFFIX/logos/projects.svg?v=1" + }, + { + "name": "Source Code", + "url": "https://src.DOMAIN_SUFFIX", + "logo": "https://integration.DOMAIN_SUFFIX/logos/docs.svg?v=1" + }, { "name": "Account", "url": "https://auth.DOMAIN_SUFFIX", "logo": "https://integration.DOMAIN_SUFFIX/logos/account.svg?v=1" - }, - { - "name": "Calendário", - "url": "https://cal.DOMAIN_SUFFIX", - "logo": "https://integration.DOMAIN_SUFFIX/logos/calendar.svg?v=1" } ] } diff --git a/base/lasuite/kustomization.yaml b/base/lasuite/kustomization.yaml index 4e99840..973d4d6 100644 --- a/base/lasuite/kustomization.yaml +++ b/base/lasuite/kustomization.yaml @@ -51,6 +51,8 @@ resources: - calendars-frontend-caddyfile.yaml - calendars-frontend-deployment.yaml - calendars-frontend-service.yaml + - projects-config.yaml + - projects-deployment.yaml patches: # Rewrite hardcoded production integration URL + inject theme CSS in people-frontend diff --git a/base/lasuite/oidc-clients.yaml b/base/lasuite/oidc-clients.yaml index ea628da..e5ee360 100644 --- a/base/lasuite/oidc-clients.yaml +++ b/base/lasuite/oidc-clients.yaml @@ -200,3 +200,23 @@ spec: tokenEndpointAuthMethod: client_secret_post secretName: oidc-calendars skipConsent: true +--- +# ── Projects (Kanban) ────────────────────────────────────────────────────── +apiVersion: hydra.ory.sh/v1alpha1 +kind: OAuth2Client +metadata: + name: projects + namespace: lasuite +spec: + clientName: Projects + grantTypes: + - authorization_code + - refresh_token + responseTypes: + - code + scope: openid email profile + redirectUris: + - https://projects.DOMAIN_SUFFIX/oidc-callback + tokenEndpointAuthMethod: client_secret_basic + secretName: oidc-projects + skipConsent: true diff --git a/base/lasuite/projects-config.yaml b/base/lasuite/projects-config.yaml new file mode 100644 index 0000000..a693524 --- /dev/null +++ b/base/lasuite/projects-config.yaml @@ -0,0 +1,40 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: projects-config + namespace: lasuite +data: + BASE_URL: "https://projects.DOMAIN_SUFFIX" + TRUST_PROXY: "1" + NODE_ENV: "production" + + # OIDC — Hydra as the identity provider + OIDC_ISSUER: "https://auth.DOMAIN_SUFFIX/" + OIDC_SCOPES: "openid email profile" + OIDC_ENFORCED: "true" + OIDC_IGNORE_USERNAME: "true" + OIDC_IGNORE_ROLES: "true" + OIDC_ADMIN_ROLES: "*" + OIDC_FULLNAME_ATTRIBUTES: "given_name,family_name" + + # S3 file storage via SeaweedFS + S3_ENDPOINT: "http://seaweedfs-filer.storage.svc.cluster.local:8333" + S3_BUCKET: "projects" + S3_REGION: "us-east-1" + S3_FORCE_PATH_STYLE: "true" + + # SMTP via in-cluster Postfix relay + SMTP_HOST: "postfix.lasuite.svc.cluster.local" + SMTP_PORT: "25" + SMTP_SECURE: "false" + SMTP_FROM: "Projects " + + # La Gaufre waffle menu widget + REACT_APP_LAGAUFRE_WIDGET_API_URL: "https://integration.DOMAIN_SUFFIX/api/v2/services.json" + REACT_APP_LAGAUFRE_WIDGET_PATH: "https://integration.DOMAIN_SUFFIX/api/v2/" + + # Default language for new OIDC users (browser detection fallback if unset) + DEFAULT_LANGUAGE: "en-US" + + # Permissions + ALLOW_ALL_TO_CREATE_PROJECTS: "true" diff --git a/base/lasuite/projects-deployment.yaml b/base/lasuite/projects-deployment.yaml new file mode 100644 index 0000000..c96f3c9 --- /dev/null +++ b/base/lasuite/projects-deployment.yaml @@ -0,0 +1,121 @@ +# Planka-based Kanban project management — single container (SPA bundled into Sails backend). +# Image: src.DOMAIN_SUFFIX/studio/projects:latest +# Built from projects/Dockerfile +# +# Secrets injected via env vars: +# - projects-db-url (VaultDynamicSecret): DATABASE_URL +# - projects-app-secrets (VaultStaticSecret): SECRET_KEY +# - oidc-projects (Hydra Maester): CLIENT_ID, CLIENT_SECRET +# - seaweedfs-s3-credentials (VaultStaticSecret): S3_ACCESS_KEY, S3_SECRET_KEY +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: projects + namespace: lasuite +spec: + replicas: 1 + selector: + matchLabels: + app: projects + template: + metadata: + labels: + app: projects + spec: + initContainers: + - name: db-migrate + image: projects + command: ["node", "db/init.js"] + envFrom: + - configMapRef: + name: projects-config + env: + - name: DATABASE_URL + valueFrom: + secretKeyRef: + name: projects-db-url + key: url + - name: SECRET_KEY + valueFrom: + secretKeyRef: + name: projects-app-secrets + key: SECRET_KEY + resources: + limits: + memory: 256Mi + requests: + memory: 128Mi + cpu: 50m + containers: + - name: projects + image: projects + command: ["node", "app.js", "--prod"] + ports: + - name: http + containerPort: 1337 + envFrom: + - configMapRef: + name: projects-config + env: + - name: DATABASE_URL + valueFrom: + secretKeyRef: + name: projects-db-url + key: url + - name: SECRET_KEY + valueFrom: + secretKeyRef: + name: projects-app-secrets + key: SECRET_KEY + - name: OIDC_CLIENT_ID + valueFrom: + secretKeyRef: + name: oidc-projects + key: CLIENT_ID + - name: OIDC_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: oidc-projects + key: CLIENT_SECRET + - name: S3_ACCESS_KEY + valueFrom: + secretKeyRef: + name: seaweedfs-s3-credentials + key: S3_ACCESS_KEY + - name: S3_SECRET_KEY + valueFrom: + secretKeyRef: + name: seaweedfs-s3-credentials + key: S3_SECRET_KEY + resources: + limits: + memory: 512Mi + requests: + memory: 256Mi + cpu: 50m + livenessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 15 + periodSeconds: 30 + readinessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 10 + periodSeconds: 10 +--- +apiVersion: v1 +kind: Service +metadata: + name: projects + namespace: lasuite +spec: + selector: + app: projects + ports: + - name: http + port: 80 + targetPort: 1337 diff --git a/base/lasuite/vault-secrets.yaml b/base/lasuite/vault-secrets.yaml index ba2a445..87a338f 100644 --- a/base/lasuite/vault-secrets.yaml +++ b/base/lasuite/vault-secrets.yaml @@ -49,6 +49,8 @@ spec: name: messages-backend - kind: Deployment name: messages-worker + - kind: Deployment + name: projects destination: name: seaweedfs-s3-credentials create: true @@ -637,3 +639,79 @@ spec: text: "{{ index .Secrets \"caldav-outbound-api-key\" }}" CALDAV_INTERNAL_API_KEY: text: "{{ index .Secrets \"caldav-internal-api-key\" }}" +--- +# Projects DB credentials from OpenBao database secrets engine (static role, 24h rotation). +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultDynamicSecret +metadata: + name: projects-db-url + namespace: lasuite +spec: + vaultAuthRef: vso-auth + mount: database + path: static-creds/projects + allowStaticCreds: true + refreshAfter: 5m + rolloutRestartTargets: + - kind: Deployment + name: projects + destination: + name: projects-db-url + create: true + overwrite: true + transformation: + excludeRaw: true + templates: + url: + text: "postgresql://{{ index .Secrets \"username\" }}:{{ index .Secrets \"password\" }}@postgres-rw.data.svc.cluster.local:5432/projects_db" +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultStaticSecret +metadata: + name: projects-app-secrets + namespace: lasuite +spec: + vaultAuthRef: vso-auth + mount: secret + type: kv-v2 + path: projects + refreshAfter: 30s + rolloutRestartTargets: + - kind: Deployment + name: projects + destination: + name: projects-app-secrets + create: true + overwrite: true + transformation: + excludeRaw: true + templates: + SECRET_KEY: + text: "{{ index .Secrets \"secret-key\" }}" +--- +# Postfix DKIM signing key from OpenBao KV. +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultStaticSecret +metadata: + name: postfix-dkim + namespace: lasuite +spec: + vaultAuthRef: vso-auth + mount: secret + type: kv-v2 + path: postfix-dkim + refreshAfter: 1h + rolloutRestartTargets: + - kind: Deployment + name: postfix + destination: + name: postfix-dkim + create: true + overwrite: true + transformation: + excludeRaw: true + templates: + private.key: + text: "{{ index .Secrets \"private-key\" }}" + selector: + text: "{{ index .Secrets \"selector\" }}" diff --git a/overlays/local/kustomization.yaml b/overlays/local/kustomization.yaml index 37049e8..bf002ab 100644 --- a/overlays/local/kustomization.yaml +++ b/overlays/local/kustomization.yaml @@ -53,6 +53,11 @@ images: newName: src.DOMAIN_SUFFIX/studio/meet-frontend newTag: latest + # Projects (Kanban) — built and pushed by `sunbeam build projects` + - name: projects + newName: src.DOMAIN_SUFFIX/studio/projects + newTag: latest + # Calendars — built from source and pushed to Gitea registry. - name: calendars-backend newName: src.DOMAIN_SUFFIX/studio/calendars-backend diff --git a/overlays/production/cert-manager.yaml b/overlays/production/cert-manager.yaml index 7cd5917..b0553ef 100644 --- a/overlays/production/cert-manager.yaml +++ b/overlays/production/cert-manager.yaml @@ -71,3 +71,4 @@ spec: - integration.DOMAIN_SUFFIX - livekit.DOMAIN_SUFFIX - cal.DOMAIN_SUFFIX + - projects.DOMAIN_SUFFIX diff --git a/overlays/production/kustomization.yaml b/overlays/production/kustomization.yaml index 30aa1f2..2c96478 100644 --- a/overlays/production/kustomization.yaml +++ b/overlays/production/kustomization.yaml @@ -75,6 +75,11 @@ images: newName: src.DOMAIN_SUFFIX/studio/calendars-frontend newTag: latest + # Projects (Kanban) — built and pushed by `sunbeam build projects` + - name: projects + newName: src.DOMAIN_SUFFIX/studio/projects + newTag: latest + # Tuwunel Matrix homeserver — built and pushed by `sunbeam build tuwunel` - name: tuwunel newName: src.DOMAIN_SUFFIX/studio/tuwunel