34 Commits

Author SHA1 Message Date
Ryan Moon
199b9ab3b3 fix: install bun then move binary to /usr/local/bin
All checks were successful
Build Devpod / build (push) Successful in 2m10s
Build & Release / build (push) Successful in 17s
2026-04-04 11:38:06 -05:00
Ryan Moon
2b141d45f3 fix: bootstrap Claude Code on first boot since it installs to /root (PVC)
Some checks failed
Build Devpod / build (push) Failing after 6s
Build & Release / build (push) Successful in 16s
2026-04-04 11:31:51 -05:00
Ryan Moon
1c56023491 fix: install bun to /usr/local/bin so it persists when /root is PVC-mounted
Some checks failed
Build Devpod / build (push) Failing after 50s
Build & Release / build (push) Has been cancelled
2026-04-04 11:30:54 -05:00
Ryan Moon
93450a1eb7 feat: add nano, vim, htop, zip, netcat, dnsutils, ping to devpod
All checks were successful
Build Devpod / build (push) Successful in 3m9s
Build & Release / build (push) Successful in 16s
2026-04-04 10:47:20 -05:00
Ryan Moon
7aa81c4e7c docs: add infrastructure, build pipeline, and dev box sections to CLAUDE.md
All checks were successful
Build & Release / build (push) Successful in 15s
2026-04-04 10:30:40 -05:00
Ryan Moon
b318345fdf fix: use haproxy to strip PROXY protocol before sshd — nginx sends PROXY headers on all TCP
All checks were successful
Build Devpod / build (push) Successful in 3m0s
Build & Release / build (push) Successful in 17s
2026-04-04 10:04:42 -05:00
Ryan Moon
cc5ab41da4 fix: enable PermitRootLogin for SSH key access
All checks were successful
Build Devpod / build (push) Successful in 8s
Build & Release / build (push) Successful in 16s
2026-04-04 09:49:29 -05:00
Ryan Moon
c54069ad99 fix: switch code-server to no-auth, Cloudflare Access handles authentication
All checks were successful
Build Devpod / build (push) Successful in 9s
Build & Release / build (push) Successful in 16s
2026-04-04 09:10:48 -05:00
Ryan Moon
04420dbd12 fix: push versioned devpod tag per build to avoid DOCR tag caching
All checks were successful
Build & Release / build (push) Successful in 18s
2026-04-04 09:04:55 -05:00
Ryan Moon
f538c60f3d fix: bootstrap .profile and .gitconfig on fresh PVC
All checks were successful
Build Devpod / build (push) Successful in 8s
Build & Release / build (push) Successful in 16s
2026-04-04 08:56:20 -05:00
Ryan Moon
1524153cfb fix: bootstrap .bashrc and PATH on fresh PVC mount
All checks were successful
Build Devpod / build (push) Successful in 7s
Build & Release / build (push) Successful in 15s
2026-04-04 08:55:26 -05:00
Ryan Moon
4c31357428 fix: create .ssh dir before writing authorized_keys
All checks were successful
Build Devpod / build (push) Successful in 9s
Build & Release / build (push) Successful in 16s
2026-04-04 08:54:52 -05:00
Ryan Moon
b3e67d1483 fix: set workdir and code-server root to /root for persistent home
All checks were successful
Build Devpod / build (push) Successful in 19s
Build & Release / build (push) Successful in 16s
2026-04-04 08:43:36 -05:00
Ryan Moon
3d081ee01f fix: push devpod image to manager repo as devpod-latest tag
All checks were successful
Build & Release / build (push) Successful in 18s
2026-04-04 08:36:08 -05:00
Ryan Moon
9942a5638f feat: add psql, redis-cli, helm, k9s to devpod image
Some checks failed
Build & Release / build (push) Failing after 8s
Build Devpod / build (push) Failing after 6s
2026-04-04 07:14:12 -05:00
Ryan Moon
b40bab0391 feat: add devpod image — code-server, Claude Code, bun, kubectl
Some checks failed
Build & Release / build (push) Successful in 22s
Build Devpod / build (push) Failing after 5s
2026-04-04 06:56:56 -05:00
Ryan Moon
de70fb47f9 fix: switch from compiled bun binary to bun run to fix Fastify plugin name crash
All checks were successful
Build & Release / build (push) Successful in 1m11s
2026-04-03 21:52:50 -05:00
Ryan Moon
c5d618698b fix: remove untagged manifest cleanup, deletes tagged chart by shared digest
All checks were successful
Build & Release / build (push) Successful in 26s
2026-04-03 21:46:41 -05:00
Ryan Moon
54943ea1b7 fix: clean up untagged helm OCI manifests after chart push
All checks were successful
Build & Release / build (push) Successful in 30s
2026-04-03 21:40:21 -05:00
Ryan Moon
ba1c385937 fix: simplify CI to use run number for versioning, remove commit-back step
All checks were successful
Build & Release / build (push) Successful in 28s
2026-04-03 21:36:23 -05:00
lunarfront-bot
2231f06234 chore: bump version to v0.1.1
All checks were successful
Build & Release / build (push) Has been skipped
2026-04-04 02:31:04 +00:00
Ryan Moon
fe29e548fb revert: remove incorrect /api ingress rule, frontend nginx handles /v1 proxy
Some checks failed
Build & Release / build (push) Has been cancelled
2026-04-03 21:29:19 -05:00
Ryan Moon
3d72f04b14 fix: add /api ingress path routing to backend 2026-04-03 21:29:19 -05:00
lunarfront-bot
36eb377583 chore: bump version to v0.1.0
All checks were successful
Build & Release / build (push) Has been skipped
2026-04-04 01:08:32 +00:00
Ryan Moon
b8f0c7ecba feat: add Spaces env vars to backend deployment
All checks were successful
Build & Release / build (push) Successful in 18s
2026-04-03 20:07:32 -05:00
lunarfront-bot
0034e0b8b3 chore: bump version to v0.0.29
All checks were successful
Build & Release / build (push) Has been skipped
2026-04-04 00:49:46 +00:00
Ryan Moon
d9a7409f9c chore: remove valkey chart templates
Some checks failed
Build & Release / build (push) Has been cancelled
2026-04-03 19:48:48 -05:00
Ryan Moon
358e07b1d5 feat: remove per-customer valkey, use managed Valkey with REDIS_KEY_PREFIX 2026-04-03 19:48:48 -05:00
lunarfront-bot
5df914a40f chore: bump version to v0.0.28
All checks were successful
Build & Release / build (push) Has been skipped
2026-04-04 00:47:43 +00:00
Ryan Moon
1f8002629f fix: add libstdc++ to runtime image for bun compiled binary
All checks were successful
Build & Release / build (push) Successful in 1m52s
2026-04-03 19:45:48 -05:00
lunarfront-bot
ff2e4586f3 chore: bump version to v0.0.27
All checks were successful
Build & Release / build (push) Has been skipped
2026-04-04 00:36:04 +00:00
Ryan Moon
019867f1fa fix: update GIT_REMOTE to git.lunarfront.tech
Some checks failed
Build & Release / build (push) Has been cancelled
2026-04-03 19:35:45 -05:00
Ryan Moon
48d49a068a fix: include chart files in version bump commit to prevent rebase conflict
Some checks failed
Build & Release / build (push) Failing after 16s
2026-04-03 19:34:31 -05:00
11f81cfd8e Merge pull request 'feat: add Helm chart and switch image builds to DOCR' (#3) from fix/ci-only-on-pr into main
Some checks failed
Build & Release / build (push) Failing after 16s
Reviewed-on: #3
2026-04-03 23:56:55 +00:00
13 changed files with 319 additions and 117 deletions

View File

@@ -0,0 +1,34 @@
name: Build Devpod
on:
push:
branches: [main]
paths:
- Dockerfile.devpod
- entrypoint-devpod.sh
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
env:
REGISTRY: registry.digitalocean.com/lunarfront
DOCKER_HOST: tcp://localhost:2375
VERSION: devpod-0.1.${{ github.run_number }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Login to DOCR
run: echo "${{ secrets.DOCR_TOKEN }}" | docker login registry.digitalocean.com -u token --password-stdin
- name: Build and push devpod
run: |
docker build \
-t $REGISTRY/manager:$VERSION \
-t $REGISTRY/manager:devpod-latest \
-f Dockerfile.devpod .
docker push $REGISTRY/manager:$VERSION
docker push $REGISTRY/manager:devpod-latest

View File

@@ -12,53 +12,20 @@ concurrency:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: "!startsWith(github.event.head_commit.message, 'chore: bump version')"
env: env:
REGISTRY: registry.digitalocean.com/lunarfront REGISTRY: registry.digitalocean.com/lunarfront
GIT_REMOTE: git2.lunarfront.tech
DOCKER_HOST: tcp://localhost:2375 DOCKER_HOST: tcp://localhost:2375
VERSION: 0.1.${{ github.run_number }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.BOT_TOKEN }}
- name: Determine version bump
id: bump
run: |
COMMIT_MSG=$(git log -1 --pretty=%s)
if echo "$COMMIT_MSG" | grep -qiE "^breaking(\(.+\))?:|^.+!:"; then
echo "type=major" >> $GITHUB_OUTPUT
elif echo "$COMMIT_MSG" | grep -qiE "^feat(\(.+\))?:"; then
echo "type=minor" >> $GITHUB_OUTPUT
else
echo "type=patch" >> $GITHUB_OUTPUT
fi
- name: Bump version in package.json
id: version
run: |
VERSION=$(node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('packages/backend/package.json', 'utf8'));
const [major, minor, patch] = pkg.version.split('.').map(Number);
const type = '${{ steps.bump.outputs.type }}';
if (type === 'major') pkg.version = \`\${major + 1}.0.0\`;
else if (type === 'minor') pkg.version = \`\${major}.\${minor + 1}.0\`;
else pkg.version = \`\${major}.\${minor}.\${patch + 1}\`;
fs.writeFileSync('packages/backend/package.json', JSON.stringify(pkg, null, 2) + '\n');
console.log(pkg.version);
")
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Login to DOCR - name: Login to DOCR
run: echo "${{ secrets.DOCR_TOKEN }}" | docker login registry.digitalocean.com -u token --password-stdin run: echo "${{ secrets.DOCR_TOKEN }}" | docker login registry.digitalocean.com -u token --password-stdin
- name: Build and push backend - name: Build and push backend
run: | run: |
VERSION=${{ steps.version.outputs.version }}
SHA=$(git rev-parse --short HEAD) SHA=$(git rev-parse --short HEAD)
docker build \ docker build \
--build-arg APP_VERSION=$VERSION \ --build-arg APP_VERSION=$VERSION \
@@ -72,7 +39,6 @@ jobs:
- name: Build and push frontend - name: Build and push frontend
run: | run: |
VERSION=${{ steps.version.outputs.version }}
SHA=$(git rev-parse --short HEAD) SHA=$(git rev-parse --short HEAD)
docker build \ docker build \
-t $REGISTRY/lunarfront-frontend:$VERSION \ -t $REGISTRY/lunarfront-frontend:$VERSION \
@@ -84,31 +50,17 @@ jobs:
docker push $REGISTRY/lunarfront-frontend:latest docker push $REGISTRY/lunarfront-frontend:latest
- name: Install Helm - name: Install Helm
run: | run: curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
- name: Package and push Helm chart - name: Package and push Helm chart
run: | run: |
VERSION=${{ steps.version.outputs.version }}
# Update chart version to match app version
sed -i "s/^version:.*/version: $VERSION/" chart/Chart.yaml sed -i "s/^version:.*/version: $VERSION/" chart/Chart.yaml
sed -i "s/^appVersion:.*/appVersion: \"$VERSION\"/" chart/Chart.yaml sed -i "s/^appVersion:.*/appVersion: \"$VERSION\"/" chart/Chart.yaml
# Update default image tags in values.yaml to this version sed -i "s|tag: .*|tag: $VERSION|g" chart/values.yaml
sed -i "s|tag: latest|tag: $VERSION|g" chart/values.yaml
helm registry login registry.digitalocean.com -u token --password "${{ secrets.DOCR_TOKEN }}" helm registry login registry.digitalocean.com -u token --password "${{ secrets.DOCR_TOKEN }}"
helm package chart/ helm package chart/
helm push lunarfront-$VERSION.tgz oci://registry.digitalocean.com/lunarfront helm push lunarfront-$VERSION.tgz oci://registry.digitalocean.com/lunarfront
- name: Commit version bump
run: |
git config user.name "lunarfront-bot"
git config user.email "bot@lunarfront.tech"
git remote set-url origin https://lunarfront-bot:${{ secrets.BOT_TOKEN }}@$GIT_REMOTE/ryan/lunarfront-app.git
git add packages/backend/package.json
git commit -m "chore: bump version to v${{ steps.version.outputs.version }}"
git pull --rebase origin main
git push origin main
- name: Logout - name: Logout
if: always() if: always()
run: docker logout registry.digitalocean.com run: docker logout registry.digitalocean.com

112
CLAUDE.md
View File

@@ -63,3 +63,115 @@
- API routes are thin — validate with Zod, call a service, return result - API routes are thin — validate with Zod, call a service, return result
- All financial events must be auditable (append-only audit records) - All financial events must be auditable (append-only audit records)
- JSON structured logging with request IDs on every log line - JSON structured logging with request IDs on every log line
---
## Infrastructure
### Overview
LunarFront runs on DigitalOcean Kubernetes (DOKS). Each customer gets an isolated namespace, database, and Helm release managed by ArgoCD.
### Key Services
- **Cluster:** `lunarfront` DOKS cluster, region NYC
- **Registry:** `registry.digitalocean.com/lunarfront` (DOCR) — stores Docker images and Helm charts
- **Git:** `git.lunarfront.tech` — self-hosted Gitea, source of truth for code and charts
- **CI:** Gitea Actions — builds Docker images and Helm charts on push to `main`
- **CD:** ArgoCD at `argocd.lunarfront.tech` — deploys from `lunarfront-charts` repo
- **Database:** DO Managed PostgreSQL — one database per customer, plus manager DB
- **Cache/Queue:** DO Managed Valkey — shared across all customers (key-prefixed per customer)
- **Ingress:** nginx ingress controller with Cloudflare proxy in front
- **TLS:** cert-manager with Let's Encrypt (letsencrypt-prod cluster issuer)
- **DNS:** Cloudflare — wildcard `*.lunarfront.tech` → cluster LB IP `167.99.21.170`
### Node Pools
- `system` — 2x s-2vcpu-4gb, runs ingress, ArgoCD, manager, pgbouncer
- `customers` — autoscales 0→N, s-4vcpu-8gb, runs customer app pods (tainted `role=customer`)
- `dev` — autoscales 0→1, s-4vcpu-8gb, runs dev pod only (tainted `dedicated=dev:NoSchedule`)
### Repos
- `lunarfront-app` — main application code (this repo)
- `lunarfront-charts` — Helm charts and ArgoCD app definitions
- `lunarfront-infra` — Terraform for DO infrastructure (DOKS, managed DBs, registry, DNS)
- `lunarfront-manager` — internal ops tool for provisioning/deprovisioning customers
---
## Build & Deploy Pipeline
### How it works
1. Push code to `main` on `lunarfront-app`
2. Gitea Actions runs `.gitea/workflows/build.yml`:
- Builds `lunarfront-app` Docker image → pushes as `0.1.{run_number}`, `{sha}`, `latest`
- Builds `lunarfront-frontend` Docker image → same tags
- Packages Helm chart → pushes as `0.1.{run_number}` to DOCR OCI registry
3. ArgoCD image updater detects new image digests → updates customer deployments
4. New customer provisions always get the latest chart version (queried from DOCR at provision time)
5. Existing customers upgraded via `POST /customers/:slug/upgrade` or `POST /customers/upgrade-all` in the manager
### Versioning
- Version format: `0.1.{gitea_run_number}` — always incrementing, no git commit-back needed
- No version stored in git — source of truth is DOCR tags
- Chart version and app version are kept in sync
### Key files
- `Dockerfile` — backend image (bun runtime, runs `packages/backend/src/main.ts` directly)
- `Dockerfile.frontend` — frontend nginx image
- `chart/` — Helm chart for customer app deployments
- `.gitea/workflows/build.yml` — CI pipeline
- `.gitea/workflows/build-devpod.yml` — builds dev box image on Dockerfile.devpod changes
---
## Dev Box
### What it is
A persistent development pod running in the `dev` namespace on the cluster. Provides a full remote dev environment accessible from anywhere.
- **VS Code in browser:** `dev.lunarfront.tech` (Cloudflare Access protected, OTP to email)
- **SSH:** `ssh -p 2222 root@dev-ssh.lunarfront.tech`
- **Storage:** 100GB DO block storage PVC mounted at `/root` — everything in home dir persists
- **Image:** `registry.digitalocean.com/lunarfront/manager:devpod-latest`
- **Tools:** bun, Claude Code CLI, code-server, kubectl, helm, k9s, doctl, psql, redis-cli, git
### Managing the dev pod
```bash
# Scale up (provisions node automatically)
kubectl scale deployment dev -n dev --replicas=1
# Scale down (node auto-terminates after ~15 min)
kubectl scale deployment dev -n dev --replicas=0
```
### Running the app locally on the dev box (no containers)
The dev box runs the app as plain Bun processes, connecting to the same DO managed services as production.
**Required env vars** (create a `.env` file in the repo root or export in `.bashrc`):
```bash
DATABASE_URL=postgresql://... # DO managed postgres, lunarfront database
REDIS_URL=rediss://... # DO managed valkey
JWT_SECRET=... # any random hex string for local dev
PORT=8000
```
**Start the app:**
```bash
cd ~/lunarfront-app
bun run dev
```
Access the running backend at `dev.lunarfront.tech/proxy/8000/` in the browser (code-server proxy), or via SSH port forward:
```bash
ssh -p 2222 -L 8000:localhost:8000 root@dev-ssh.lunarfront.tech
```
**Run migrations against the dev database:**
```bash
bunx drizzle-kit migrate
```
### Workflow
1. Edit code in VS Code at `dev.lunarfront.tech` or via SSH
2. Run and test locally with `bun run dev` — app connects to DO managed postgres/valkey
3. Push to `main` → Gitea Actions builds and pushes new Docker image + Helm chart
4. ArgoCD deploys to the cluster automatically
5. Use manager at `manager.lunarfront.tech` to upgrade customer instances if needed

View File

@@ -6,8 +6,9 @@ COPY packages/backend/package.json packages/backend/
COPY packages/admin/package.json packages/admin/ COPY packages/admin/package.json packages/admin/
RUN bun install --frozen-lockfile RUN bun install --frozen-lockfile
FROM oven/bun:1.3.11-alpine AS build FROM oven/bun:1.3.11-alpine
ARG APP_VERSION=dev ARG APP_VERSION=dev
ENV APP_VERSION=${APP_VERSION}
WORKDIR /app WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules COPY --from=deps /app/node_modules ./node_modules
COPY --from=deps /app/packages/shared/node_modules ./packages/shared/node_modules COPY --from=deps /app/packages/shared/node_modules ./packages/shared/node_modules
@@ -16,18 +17,11 @@ COPY packages/shared ./packages/shared
COPY packages/backend ./packages/backend COPY packages/backend ./packages/backend
COPY package.json ./ COPY package.json ./
COPY tsconfig.base.json ./ COPY tsconfig.base.json ./
WORKDIR /app/packages/backend
RUN bun build src/main.ts --compile --outfile /app/server \
--define "process.env.APP_VERSION='${APP_VERSION}'"
FROM alpine:3.21
RUN addgroup -S app && adduser -S app -G app RUN addgroup -S app && adduser -S app -G app
WORKDIR /app COPY packages/backend/src/db/migrations ./migrations
COPY --from=build /app/server ./server
COPY --from=build /app/packages/backend/src/db/migrations ./migrations
ENV MIGRATIONS_DIR=/app/migrations ENV MIGRATIONS_DIR=/app/migrations
EXPOSE 8000 EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \ HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
CMD wget -qO- http://localhost:8000/v1/health || exit 1 CMD wget -qO- http://localhost:8000/v1/health || exit 1
USER app USER app
CMD ["./server"] CMD ["bun", "run", "packages/backend/src/main.ts"]

47
Dockerfile.devpod Normal file
View File

@@ -0,0 +1,47 @@
FROM ubuntu:24.04
ENV DEBIAN_FRONTEND=noninteractive
ENV HOME=/root
ENV PATH="/usr/local/bin:/root/.bun/bin:$PATH"
# Base tools
RUN apt-get update && apt-get install -y --no-install-recommends \
curl wget git openssh-server ca-certificates gnupg \
build-essential unzip zip jq tmux zsh ripgrep \
postgresql-client redis-tools haproxy \
nano vim htop netcat-openbsd dnsutils iputils-ping \
&& rm -rf /var/lib/apt/lists/*
# Bun — install then move to /usr/local/bin so it's on the image filesystem, not the /root PVC
RUN curl -fsSL https://bun.sh/install | bash \
&& mv /root/.bun/bin/bun /usr/local/bin/bun \
&& ln -sf /usr/local/bin/bun /usr/local/bin/bunx \
&& rm -rf /root/.bun
# code-server (VS Code in browser)
RUN curl -fsSL https://code-server.dev/install.sh | sh
# kubectl
RUN curl -fsSL "https://dl.k8s.io/release/$(curl -fsSL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" \
-o /usr/local/bin/kubectl && chmod +x /usr/local/bin/kubectl
# doctl
RUN curl -fsSL https://github.com/digitalocean/doctl/releases/download/v1.119.0/doctl-1.119.0-linux-amd64.tar.gz \
| tar xz -C /usr/local/bin
# helm
RUN curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# k9s
RUN curl -fsSL https://github.com/derailed/k9s/releases/latest/download/k9s_Linux_amd64.tar.gz \
| tar xz -C /usr/local/bin k9s
# SSH setup — host keys generated at runtime via entrypoint
RUN mkdir -p /run/sshd /root/.ssh && chmod 700 /root/.ssh
COPY entrypoint-devpod.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
WORKDIR /root
EXPOSE 8080 22
ENTRYPOINT ["/entrypoint.sh"]

View File

@@ -2,5 +2,5 @@ apiVersion: v2
name: lunarfront name: lunarfront
description: LunarFront small business management platform description: LunarFront small business management platform
type: application type: application
version: 0.1.0 version: 0.1.1
appVersion: "0.0.0" appVersion: "0.1.1"

View File

@@ -38,6 +38,36 @@ spec:
secretKeyRef: secretKeyRef:
name: lunarfront-secrets name: lunarfront-secrets
key: redis-url key: redis-url
- name: REDIS_KEY_PREFIX
valueFrom:
secretKeyRef:
name: lunarfront-secrets
key: redis-key-prefix
- name: SPACES_KEY
valueFrom:
secretKeyRef:
name: lunarfront-secrets
key: spaces-key
- name: SPACES_SECRET
valueFrom:
secretKeyRef:
name: lunarfront-secrets
key: spaces-secret
- name: SPACES_BUCKET
valueFrom:
secretKeyRef:
name: lunarfront-secrets
key: spaces-bucket
- name: SPACES_ENDPOINT
valueFrom:
secretKeyRef:
name: lunarfront-secrets
key: spaces-endpoint
- name: SPACES_PREFIX
valueFrom:
secretKeyRef:
name: lunarfront-secrets
key: spaces-prefix
- name: JWT_SECRET - name: JWT_SECRET
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:

View File

@@ -1,24 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-valkey
namespace: {{ .Release.Namespace }}
labels:
{{- include "lunarfront.labels" . | nindent 4 }}
spec:
replicas: 1
selector:
matchLabels:
app: {{ .Release.Name }}-valkey
template:
metadata:
labels:
app: {{ .Release.Name }}-valkey
spec:
containers:
- name: valkey
image: "{{ .Values.valkey.image.repository }}:{{ .Values.valkey.image.tag }}"
ports:
- containerPort: {{ .Values.valkey.port }}
resources:
{{- toYaml .Values.valkey.resources | nindent 12 }}

View File

@@ -1,13 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: {{ .Release.Name }}-valkey
namespace: {{ .Release.Namespace }}
labels:
{{- include "lunarfront.labels" . | nindent 4 }}
spec:
selector:
app: {{ .Release.Name }}-valkey
ports:
- port: {{ .Values.valkey.port }}
targetPort: {{ .Values.valkey.port }}

View File

@@ -1,7 +1,7 @@
backend: backend:
image: image:
repository: registry.digitalocean.com/lunarfront/lunarfront-app repository: registry.digitalocean.com/lunarfront/lunarfront-app
tag: latest tag: 0.0.27
pullPolicy: Always pullPolicy: Always
port: 8000 port: 8000
resources: resources:
@@ -15,7 +15,7 @@ backend:
frontend: frontend:
image: image:
repository: registry.digitalocean.com/lunarfront/lunarfront-frontend repository: registry.digitalocean.com/lunarfront/lunarfront-frontend
tag: latest tag: 0.0.27
pullPolicy: Always pullPolicy: Always
port: 80 port: 80
resources: resources:
@@ -26,19 +26,6 @@ frontend:
cpu: 200m cpu: 200m
memory: 128Mi memory: 128Mi
valkey:
image:
repository: valkey/valkey
tag: "8"
port: 6379
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
ingress: ingress:
host: "" host: ""
className: nginx className: nginx

82
entrypoint-devpod.sh Normal file
View File

@@ -0,0 +1,82 @@
#!/bin/bash
set -e
# Generate SSH host keys if not present
ssh-keygen -A
# Write authorized keys from env if provided
if [ -n "$SSH_AUTHORIZED_KEYS" ]; then
mkdir -p /root/.ssh
chmod 700 /root/.ssh
echo "$SSH_AUTHORIZED_KEYS" > /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys
fi
# Bootstrap home dir on fresh PVC
if [ ! -f /root/.bashrc ]; then
cp /etc/skel/.bashrc /root/.bashrc 2>/dev/null || true
cat >> /root/.bashrc <<'EOF'
export PATH="/usr/local/bin:$PATH"
export HISTFILE=/root/.bash_history
export HISTSIZE=10000
EOF
fi
if [ ! -f /root/.profile ]; then
cat > /root/.profile <<'EOF'
export PATH="/usr/local/bin:$PATH"
[ -f /root/.bashrc ] && . /root/.bashrc
EOF
fi
if [ ! -f /root/.gitconfig ]; then
cat > /root/.gitconfig <<'EOF'
[user]
name = ryan
email = ryan@lunartech.com
[init]
defaultBranch = main
[core]
editor = code --wait
EOF
fi
# Install Claude Code on first boot (installs to /root/.claude, persists on PVC)
if [ ! -f /root/.claude/bin/claude ]; then
curl -fsSL https://claude.ai/install.sh | bash
fi
# Allow root login via SSH key, listen on internal port 2222
echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
echo "Port 2222" >> /etc/ssh/sshd_config
# Start SSH daemon on internal port 2222
/usr/sbin/sshd
# Start haproxy on port 22 to accept PROXY protocol from nginx and forward to sshd:2222
cat > /etc/haproxy/haproxy.cfg <<'EOF'
global
daemon
maxconn 256
defaults
mode tcp
timeout connect 5s
timeout client 60s
timeout server 60s
frontend ssh
bind *:22 accept-proxy
default_backend sshd
backend sshd
server local 127.0.0.1:2222
EOF
haproxy -f /etc/haproxy/haproxy.cfg
# Start code-server
exec code-server \
--bind-addr 0.0.0.0:8080 \
--auth none \
--disable-telemetry \
/root

View File

@@ -1,6 +1,6 @@
{ {
"name": "@lunarfront/backend", "name": "@lunarfront/backend",
"version": "0.0.26", "version": "0.1.1",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {

View File

@@ -9,7 +9,8 @@ declare module 'fastify' {
export const redisPlugin = fp(async (app) => { export const redisPlugin = fp(async (app) => {
const redisUrl = process.env.REDIS_URL ?? 'redis://localhost:6379' const redisUrl = process.env.REDIS_URL ?? 'redis://localhost:6379'
const redis = new Redis(redisUrl) const keyPrefix = process.env.REDIS_KEY_PREFIX ? `${process.env.REDIS_KEY_PREFIX}:` : ''
const redis = new Redis(redisUrl, { keyPrefix })
app.decorate('redis', redis) app.decorate('redis', redis)