Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
working-directory: kubelab-backend
strategy:
matrix:
goVer: [1.22]
goVer: [1.24]

steps:
- name: Set up Go ${{ matrix.goVer }}
Expand Down Expand Up @@ -50,6 +50,8 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 'lts/*'
- name: Install dependencies
run: npm install --legacy-peer-deps
- name: Build
Expand Down
15 changes: 12 additions & 3 deletions .github/workflows/docker-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,32 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to the Container registry
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@60a0d343a0d8a18aedee9d34e62251f752153bdb
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

- name: Build and push Docker image
uses: docker/build-push-action@5176d81f87c23d6fc96624dfdbcd9f3830bbe445
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
13 changes: 7 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.22-alpine AS backend-builder
FROM golang:1.24-alpine AS backend-builder
WORKDIR /build
COPY kubelab-backend/go.mod kubelab-backend/go.sum kubelab-backend/main.go ./
COPY kubelab-backend/hooks ./hooks
Expand All @@ -9,16 +9,17 @@ RUN apk --no-cache add upx make git gcc libtool musl-dev ca-certificates dumb-in
&& CGO_ENABLED=0 go build \
&& upx kubelab

FROM node:lts-slim as ui-builder
FROM node:22-alpine AS ui-builder
WORKDIR /build
# Install build dependencies for native modules
RUN apk add --no-cache python3 make g++
COPY ./kubelab-ui/package*.json ./
RUN rm -rf ./node_modules
RUN rm -rf ./build
COPY ./kubelab-ui .
RUN npm install --legacy-peer-deps
# Clean install to ensure optional dependencies are properly resolved
RUN npm ci --legacy-peer-deps || npm install --legacy-peer-deps
RUN npm run build

FROM alpine as runtime
FROM alpine AS runtime
WORKDIR /app/kubelab
COPY --from=backend-builder /build/kubelab /app/kubelab/kubelab
COPY --from=backend-builder /build/vcluster-values.yaml /app/kubelab/vcluster-values.yaml
Expand Down
46 changes: 46 additions & 0 deletions kubelab-backend/.air.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"

[build]
bin = "./dev.sh"
cmd = "go build -o ./tmp/main ."
delay = 1000
exclude_dir = ["assets", "tmp", "vendor", "testdata", "pb_data", "pb_migrations"]
exclude_file = []
exclude_regex = ["_test.go"]
exclude_unchanged = false
follow_symlink = false
full_bin = ""
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html"]
include_file = []
kill_delay = "0s"
log = "build-errors.log"
poll = false
poll_interval = 0
post_cmd = []
pre_cmd = []
rerun = false
rerun_delay = 500
send_interrupt = false
stop_on_error = false

[color]
app = ""
build = "yellow"
main = "magenta"
runner = "green"
watcher = "cyan"

[log]
main_only = false
time = false

[misc]
clean_on_exit = false

[screen]
clear_on_rebuild = false
keep_scroll = true

4 changes: 4 additions & 0 deletions kubelab-backend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
/pocketbase*.zip
/pb_data
/pb_data_old
/pb_data_backup_*
/pb_migrations_old
/tmp
/bin
./pocketbase
kubelab
# Air build artifacts
build-errors.log
216 changes: 216 additions & 0 deletions kubelab-backend/COLLECTIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
# Kubelab Collections Structure

This document describes the PocketBase collections used in Kubelab.

## Collections Overview

All collections are created programmatically in `pkg/collections/collections.go` on application bootstrap. No manual migration files are needed.

### 1. **users** (Auth Collection)
The main user authentication collection.

**Custom Fields:**
- `role` (text, required) - User role: "user" or "admin"
- `plan` (text) - Associated plan ID
- `company` (text) - Company name
- `workshop` (boolean) - Workshop participant flag

**Access Rules:**
- List/View: Authenticated users only
- Update/Delete: Own record or admin

---

### 2. **labs**
Lab courses that contain multiple exercises.

**Fields:**
- `name` (text, required) - Lab name
- `description` (editor) - Lab description
- `icon` (text) - Icon identifier
- `order` (number) - Display order
- `active` (boolean) - Active status
- `difficulty` (text) - Difficulty level

**Access Rules:**
- List/View: Authenticated users
- Create/Update/Delete: Admins only

---

### 3. **exercises**
Individual exercises within labs.

**Fields:**
- `name` (text, required) - Exercise name
- `description` (editor) - Exercise description
- `lab` (relation, required) - Parent lab
- `bootstrap` (URL) - Bootstrap script URL
- `check` (URL) - Validation script URL
- `order` (number) - Display order
- `maxScore` (number) - Maximum achievable score
- `active` (boolean) - Active status

**Access Rules:**
- List/View: Authenticated users
- Create/Update/Delete: Admins only

---

### 4. **lab_sessions**
User progress for labs (manages vcluster lifecycle).

**Fields:**
- `user` (relation, required) - User ID
- `lab` (relation, required) - Lab ID
- `clusterRunning` (boolean) - vcluster status
- `lastClusterStart` (date) - Last start timestamp
- `lastClusterStop` (date) - Last stop timestamp

**Access Rules:**
- List/View: Own records or admin
- Create: Authenticated users
- Update/Delete: Own records or admin

---

### 5. **exercise_sessions**
User progress for individual exercises.

**Fields:**
- `user` (relation, required) - User ID
- `exercise` (relation, required) - Exercise ID
- `agentRunning` (boolean) - Agent deployment status
- `score` (number) - Current score
- `lastAgentStart` (date) - Last start timestamp
- `lastAgentStop` (date) - Last stop timestamp
- `solved` (boolean) - Completion status
- `solvedAt` (date) - Completion timestamp

**Access Rules:**
- List/View: Own records or admin
- Create: Authenticated users
- Update/Delete: Own records or admin

---

### 6. **exercise_session_logs**
Logs for exercise session events.

**Fields:**
- `user` (relation, required) - User ID
- `exercise_session` (relation, required) - Exercise session ID
- `message` (text, required) - Log message
- `type` (text, required) - Log type/severity

**Access Rules:**
- List/View: Own records or admin
- Create: Authenticated users
- Delete: Admins only (no updates)

---

### 7. **hooks**
Configurable event hooks for automation.

**Fields:**
- `table` (text, required) - Target collection
- `event` (text, required) - Event type (insert/update/delete)
- `actionType` (text, required) - Action to perform
- `actionMeta` (text) - Additional action metadata
- `disabled` (boolean) - Enable/disable hook

**Access Rules:**
- All operations: Admins only

---

### 8. **plans**
Subscription/pricing plans.

**Fields:**
- `name` (text, required) - Plan name
- `description` (text) - Plan description
- `price` (number) - Plan price
- `active` (boolean) - Active status

**Access Rules:**
- List/View: Authenticated users
- Create/Update/Delete: Admins only

---

### 9. **features**
Features associated with plans.

**Fields:**
- `name` (text, required) - Feature name
- `plan` (relation) - Associated plan

**Access Rules:**
- List/View: Authenticated users
- Create/Update/Delete: Admins only

---

### 10. **faqs**
Frequently asked questions.

**Fields:**
- `question` (text, required) - Question text
- `answer` (text, required) - Answer text
- `order` (number) - Display order

**Access Rules:**
- List/View: Public (no auth required)
- Create/Update/Delete: Admins only

---

### 11. **companies**
Company logos for landing page.

**Fields:**
- `name` (text, required) - Company name
- `logo` (file, max 5MB) - Company logo image
- `order` (number) - Display order

**Access Rules:**
- List/View: Public (no auth required)
- Create/Update/Delete: Admins only

---

### 12. **notifications**
User notifications.

**Fields:**
- `user` (relation, required) - User ID
- `message` (text, required) - Notification message
- `type` (text, required) - Notification type
- `read` (boolean) - Read status

**Access Rules:**
- List/View: Own records or admin
- Create: Authenticated users
- Update/Delete: Own records or admin

---

## Initialization

Collections are automatically created on application bootstrap via `collections.InitializeCollections()` in `main.go`. If a collection already exists, it's skipped - no data is lost.

## First Run Setup

1. Start the backend: `npm run dev:backend` (from kubelab-ui directory)
2. Open the admin dashboard: http://localhost:8090/_/
3. Create your first admin account
4. Collections will be automatically created on first bootstrap

## Notes

- Old JS migrations in `pb_migrations_old/` are kept for reference but not used
- All schema changes should now be done in `pkg/collections/collections.go`
- For production, you may want to add collection schema versioning

3 changes: 3 additions & 0 deletions kubelab-backend/dev.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh
LOCAL=true ./tmp/main serve --http 0.0.0.0:8090 --publicDir ../kubelab-ui/build

Loading
Loading