.cursor/skills/k8s/SKILL.md
Common patterns for Kubernetes manifests in infra/k8s. Use when editing or adding K8s manifests, changing deployment config, adding env vars to ConfigMaps, or working with ArgoCD/Kustomize/SOPS.
npx skillsauth add podverse/podverse podverse-k8s-patternsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill provides quick reference for common patterns used in the Podverse Kubernetes infrastructure.
Use this skill when:
infra/k8s/infra/k8s/
├── alpha-application.yaml # Root ArgoCD app (App of Apps)
├── base/ # Shared manifests (all environments)
│ ├── api/
│ │ ├── 01-configmap.yaml
│ │ ├── 02-service.yaml
│ │ ├── 03-deployment.yaml
│ │ └── kustomization.yaml
│ ├── web/
│ ├── workers/
│ ├── db/
│ ├── mq/
│ ├── keyvaldb/
│ ├── cron/
│ ├── ops/
│ └── common/ # Shared resources (Ingress, TLS)
├── alpha/ # Alpha environment overlays
│ ├── apps/ # ArgoCD Application definitions
│ │ ├── api.yaml
│ │ ├── web.yaml
│ │ ├── common.yaml
│ │ └── ...
│ ├── api/
│ │ ├── kustomization.yaml
│ │ └── deployment-link-patch.yaml
│ ├── web/
│ ├── workers/
│ └── ...
├── system/ # Cluster-wide config
│ └── traefik-config.yaml
└── scripts/ # Helper scripts
├── create_*_secret.sh
├── db-connect.sh
└── README.md
The deployment uses ArgoCD's App of Apps pattern:
alpha-application.yaml) syncs the alpha/apps/ directoryalpha/apps/api.yaml, alpha/apps/web.yaml) appear in ArgoCDFlow:
alpha-application.yaml → alpha/apps/*.yaml → alpha/<component>/kustomization.yaml → base/<component>/*.yaml
Always use the --load-restrictor LoadRestrictionsNone flag because bases live outside overlay folders:
# From repo root
kustomize build --load-restrictor LoadRestrictionsNone infra/k8s/alpha/api/
kustomize build --load-restrictor LoadRestrictionsNone infra/k8s/alpha/workers/
Add dry-run to validate before pushing to Git:
kustomize build --load-restrictor LoadRestrictionsNone infra/k8s/alpha/api/ | kubectl apply -f - --dry-run=client
Base manifests (base/<component>/):
01-configmap.yaml, 02-service.yaml, 03-deployment.yamlpodverse-api-config, podverse-workers-configAlpha overlays (alpha/<component>/):
kustomization.yamlnamespace: podverse-alphaincludeSelectors: trueconfigMapGenerator (behavior: merge)images: sectiondeployment-link-patch.yaml)ConfigMaps in base/<component>/01-configmap.yaml should mirror the structure of the authoritative app .env.example files (e.g. apps/api/.env.example, apps/workers/.env.example). Infra env-templates for apps are link-only stubs.
##### App / General #####)# Mapped from apps/<component>/.env.example# in secrets comment# in secrets (or # in secrets (...)), align the # in secrets part vertically (same column) by padding with spaces after the value so the comment starts at the same positionk8s/secrets/secretRef in Deployment envFrom to load secretsExample (aligned # in secrets in a sequence):
# In ConfigMap – consecutive "in secrets" lines aligned
# DB_READ_USERNAME: "" # in secrets
# DB_PASSWORD: "" # in secrets
# DB_READ_WRITE_USERNAME: "" # in secrets
# DB_READ_WRITE_PASSWORD: "" # in secrets
# In Deployment
envFrom:
- configMapRef:
name: podverse-api-config
- secretRef:
name: podverse-api-opaque
Override ConfigMap values in alpha (or other environment) overlays using configMapGenerator:
# alpha/api/kustomization.yaml
configMapGenerator:
- name: podverse-api-config
behavior: merge
literals:
- API_ALLOWED_CORS_ORIGINS="http://podverse-web:3000,https://alpha-podverse.k.podverse.fm"
- COOKIE_DOMAIN=".k.podverse.fm"
Base deployments:
image: ghcr.io/podverse/podverse/apiOverlay kustomization:
images: sectionimages:
- name: ghcr.io/podverse/podverse-api/podverse-api
newTag: '5.1.28-alpha.0'
Child applications in alpha/apps/<component>.yaml define:
metadata.name: e.g., podverse-alpha-apispec.project: podversespec.source.repoURL: GitHub repo URLspec.source.targetRevision: branch name (e.g., alpha)spec.source.path: path to overlay (e.g., k8s/alpha/api)spec.destination.namespace: podverse-alphaspec.syncPolicy.automated: prune: true, selfHeal: trueUse helper scripts in infra/k8s/scripts/:
# Run from repo root with nix develop
bash infra/k8s/scripts/create_db_secret.sh
bash infra/k8s/scripts/create_api_secret.sh
bash infra/k8s/scripts/create_mq_secret.sh
# ... etc
Secrets are SOPS-encrypted and stored in k8s/secrets/podverse-<env>-<component>-opaque.enc.yaml.
Manual apply:
sops -d k8s/secrets/podverse-alpha-db-opaque.enc.yaml | kubectl apply -f -
ArgoCD: Consumes encrypted files directly (SOPS plugin configured).
.gitignore should exclude decrypted secret filesinfra/k8s/ uses its own Prettier rules (not repo-wide YAML rules):
.prettierrc.json, overrides section for infra/k8s/**/*.yml and infra/k8s/**/*.yamlsingleQuote: false (double quotes for strings)tabWidth: 2 (2-space indentation)printWidth: 140 (wider than repo default of 100 to avoid wrapping long env values and list items)infra/k8s/npm run prettier:write
npm run lint:fix
lint-staged runs Prettier on staged k8s YAML filesinfra/k8s/ to .prettierignore (it was previously ignored but now uses overrides)printWidth matches existing k8s patterns and avoids unnecessary line breaksUse numbered prefixes for ordering:
01-configmap.yaml - Configuration02-service.yaml - Service03-deployment.yaml or 03-statefulset.yaml - Workload04-, 05-, etc.podverse-<component>-config (e.g., podverse-api-config)podverse-<component> (e.g., podverse-db)podverse-<component> (e.g., podverse-api)podverse-<component>-opaque (e.g., podverse-db-opaque)Apply consistent labels in overlays:
labels:
- pairs:
app: podverse-api
environment: alpha
includeSelectors: true
apps/<component>/.env.example (if not secret)base/<component>/01-configmap.yaml with same section/commentsalpha/<component>/kustomization.yamlbase/<component>/ directory01-configmap.yaml, 02-service.yaml, 03-deployment.yamlbase/<component>/kustomization.yaml listing resourcesalpha/<component>/ overlay with kustomization.yamlalpha/apps/<component>.yamlinfra/k8s/scripts/create_<component>_secret.shEdit the overlay's kustomization.yaml (e.g., alpha/api/kustomization.yaml):
images:
- name: ghcr.io/podverse/podverse-api/podverse-api
newTag: '5.1.29-alpha.0' # Update this
ArgoCD will detect the change and sync automatically.
Located in infra/k8s/scripts/:
| Script | Purpose |
| --------------------------- | -------------------------------------------- |
| create_db_secret.sh | Generate encrypted DB credentials |
| create_api_secret.sh | Generate encrypted API secrets (JWT, mailer) |
| create_mq_secret.sh | Generate encrypted message queue credentials |
| create_keyvaldb_secret.sh | Generate encrypted Valkey/Redis password |
| create_firebase_secret.sh | Generate encrypted Firebase service account |
| db-connect.sh | Port-forward and connect to PostgreSQL |
| keyvaldb-gui-connect.sh | Port-forward to RedisInsight GUI |
| mq-connect.sh | Port-forward to message queue |
See infra/k8s/scripts/README.md for details.
documentation
Per-job env validation and config patterns for the workers app. Use when adding or changing worker commands, touching workers startup validation, or documenting worker env vars.
development
Common patterns and examples for the podverse-web Next.js application
tools
Ensures client-side time displays use formatDateTimeAbbrev for localized, readable timestamps. Use when rendering dates/times in the UI or when the user mentions time formatting or local timezone display.
testing
--- name: podverse-testing-policy description: Skip test implementation unless the user explicitly asks. Use when a plan or task includes adding unit tests, a test phase, or "Phase 3: Tests". version: 1.0.0 --- # Testing policy — skip tests for now ## When to use - When a plan or task includes adding unit tests, a test phase, or "Phase 3: Tests". - When deciding whether to implement tests for a feature. ## Rules 1. **We are not concerning ourselves with tests at this time.** Skip test imp