feat: CI badges per project card, reorder Poimen after Homelab
Build & Push Portfolio Image / build-push (push) Successful in 3m31s

This commit is contained in:
Story Crater Bot
2026-09-03 08:18:58 -07:00
parent b3631211af
commit 7f0c12d029
4 changed files with 210 additions and 87 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ import { NextRequest, NextResponse } from 'next/server'
const FORGEJO_URL = 'https://forgejo.riotpiao.com' const FORGEJO_URL = 'https://forgejo.riotpiao.com'
const DEFAULT_REPO = 'rock/riotpiao.com' const DEFAULT_REPO = 'rock/riotpiao.com'
const ALLOWED_REPOS = ['rock/riotpiao.com', 'rock/homelab', 'rock/homelab-frontend', 'rock/poimen', 'rock/poimen-memory', 'rock/poimen-workflows'] const ALLOWED_REPOS = ['rock/riotpiao.com', 'rock/homelab', 'rock/homelab-frontend', 'rock/poimen', 'rock/poimen-memory', 'rock/poimen-workflows', 'rock/kmsvc-manage']
export async function GET(request: NextRequest) { export async function GET(request: NextRequest) {
const repo = request.nextUrl.searchParams.get('repo') || DEFAULT_REPO const repo = request.nextUrl.searchParams.get('repo') || DEFAULT_REPO
+15 -16
View File
@@ -13,31 +13,30 @@ export default function Home() {
const [bioModalOpen, setBioModalOpen] = useState(false) const [bioModalOpen, setBioModalOpen] = useState(false)
const { t } = useLanguage() const { t } = useLanguage()
// Order: 0=Homelab, 1=Poimen Memory, 2=Poimen Workflow, 3=RBC, 4=AWS
const projects = t.projects.items.map((item, index) => ({ const projects = t.projects.items.map((item, index) => ({
...item, ...item,
id: index === 0 id: ['project-homelab', 'project-poimen-memory', 'project-poimen-workflow', 'project-rbc', 'project-aws'][index],
? 'project-homelab' status: index === 3
: index === 1
? 'project-rbc'
: index === 2
? 'project-aws'
: index === 3
? 'project-poimen-memory'
: index === 4
? 'project-poimen-workflow'
: undefined,
status: index === 1
? 'completed' as const ? 'completed' as const
: index >= 3 : index <= 2
? 'building' as const ? 'building' as const
: 'live' as const, : 'live' as const,
media: index === 1 media: index === 3
? { type: 'image' as const, url: '/rbc-images.jpeg' } ? { type: 'image' as const, url: '/rbc-images.jpeg' }
: index === 2 : index === 4
? { type: 'video' as const, url: 'https://www.youtube.com/watch?v=wdJ5DN15jus' } ? { type: 'video' as const, url: 'https://www.youtube.com/watch?v=wdJ5DN15jus' }
: undefined, : undefined,
videoUrl: '#', videoUrl: '#',
articleUrl: index === 2 ? 'https://lnkd.in/p/gm2PZkWw' : '#', articleUrl: index === 4 ? 'https://lnkd.in/p/gm2PZkWw' : '#',
ciRepos: index === 0 ? [
{ label: 'portfolio', repo: 'rock/riotpiao.com', forgejoBase: 'https://forgejo.riotpiao.com/rock/riotpiao.com' },
{ label: 'kmsvc', repo: 'rock/kmsvc-manage', forgejoBase: 'https://forgejo.riotpiao.com/rock/kmsvc-manage' },
] : index === 1 ? [
{ label: 'poimen-mem', repo: 'rock/poimen-memory', forgejoBase: 'https://forgejo.riotpiao.com/rock/poimen-memory' },
] : index === 2 ? [
{ label: 'poimen-wf', repo: 'rock/poimen-workflows', forgejoBase: 'https://forgejo.riotpiao.com/rock/poimen-workflows' },
] : undefined,
})) }))
return ( return (
+57 -1
View File
@@ -1,9 +1,55 @@
'use client' 'use client'
import { motion } from 'framer-motion' import { motion } from 'framer-motion'
import { ExternalLink, MessageSquare } from 'lucide-react' import { ExternalLink, MessageSquare, CheckCircle, XCircle, Loader2, AlertCircle } from 'lucide-react'
import { useState, useEffect } from 'react'
import { useTerminal } from '@/lib/TerminalContext' import { useTerminal } from '@/lib/TerminalContext'
function RepoCIBadge({ label, repo, forgejoBase }: { label: string; repo: string; forgejoBase: string }) {
const [ci, setCI] = useState<{ sha: string; status: string } | null>(null)
useEffect(() => {
fetch(`/api/ci-status?repo=${repo}`)
.then(r => r.json())
.then(data => setCI({
sha: data.sha?.substring(0, 7) || '',
status: data.conclusion || data.status || 'unknown',
}))
.catch(() => null)
}, [repo])
const icon = !ci ? <Loader2 size={11} className="animate-spin text-gray-400" />
: ci.status === 'success' ? <CheckCircle size={11} className="text-green-500" />
: ci.status === 'failure' ? <XCircle size={11} className="text-red-500" />
: <AlertCircle size={11} className="text-yellow-500" />
return (
<div className="flex items-center gap-1.5 text-xs">
<span className="text-gray-500 dark:text-gray-400 font-medium w-20 truncate">{label}</span>
{ci?.sha ? (
<a
href={`${forgejoBase}/commit/${ci.sha}`}
target="_blank"
rel="noopener noreferrer"
className="font-mono text-blue-600 dark:text-blue-400 hover:underline"
>
{ci.sha}
</a>
) : (
<span className="font-mono text-gray-400">···</span>
)}
<span className="text-gray-300 dark:text-gray-600">|</span>
{icon}
</div>
)
}
interface CIRepo {
label: string
repo: string
forgejoBase: string
}
interface ProjectShowcaseProps { interface ProjectShowcaseProps {
id?: string id?: string
title: string title: string
@@ -26,6 +72,7 @@ interface ProjectShowcaseProps {
label: string label: string
url: string url: string
} }
ciRepos?: CIRepo[]
} }
export function ProjectShowcase({ export function ProjectShowcase({
@@ -44,6 +91,7 @@ export function ProjectShowcase({
askPoimenText = 'Ask Poimen for technical details', askPoimenText = 'Ask Poimen for technical details',
bullets, bullets,
deepDive, deepDive,
ciRepos,
}: ProjectShowcaseProps) { }: ProjectShowcaseProps) {
const { setIsOpen } = useTerminal() const { setIsOpen } = useTerminal()
@@ -139,6 +187,13 @@ export function ProjectShowcase({
</a> </a>
)} )}
</div> </div>
{ciRepos ? (
<div className="ml-4 flex flex-col gap-1.5 shrink-0">
{ciRepos.map((r) => (
<RepoCIBadge key={r.repo} label={r.label} repo={r.repo} forgejoBase={r.forgejoBase} />
))}
</div>
) : (
<span <span
className={`ml-4 px-3 py-1 rounded-full text-xs font-semibold whitespace-nowrap ${ className={`ml-4 px-3 py-1 rounded-full text-xs font-semibold whitespace-nowrap ${
statusColors[status] statusColors[status]
@@ -146,6 +201,7 @@ export function ProjectShowcase({
> >
{status.charAt(0).toUpperCase() + status.slice(1)} {status.charAt(0).toUpperCase() + status.slice(1)}
</span> </span>
)}
</div> </div>
{/* Stat */} {/* Stat */}
+128 -60
View File
@@ -41,27 +41,61 @@
"skills": { "skills": {
"infrastructure": { "infrastructure": {
"title": "Infrastructure", "title": "Infrastructure",
"items": ["Kubernetes", "Talos", "ArgoCD", "Terraform", "Docker", "OpenShift"] "items": [
"Kubernetes",
"Talos",
"ArgoCD",
"Terraform",
"Docker",
"OpenShift"
]
}, },
"cloud": { "cloud": {
"title": "Cloud & Distributed", "title": "Cloud & Distributed",
"items": ["AWS", "DynamoDB", "CloudWatch", "gRPC", "Cloudflare"] "items": [
"AWS",
"DynamoDB",
"CloudWatch",
"gRPC",
"Cloudflare"
]
}, },
"languages": { "languages": {
"title": "Languages", "title": "Languages",
"items": ["Go", "Java", "Python", "C++", "TypeScript"] "items": [
"Go",
"Java",
"Python",
"C++",
"TypeScript"
]
}, },
"data": { "data": {
"title": "Data & Messaging", "title": "Data & Messaging",
"items": ["Kafka", "PostgreSQL", "Temporal", "Redis"] "items": [
"Kafka",
"PostgreSQL",
"Temporal",
"Redis"
]
}, },
"aiml": { "aiml": {
"title": "AI/ML", "title": "AI/ML",
"items": ["vLLM", "PyTorch", "Ollama", "KServe"] "items": [
"vLLM",
"PyTorch",
"Ollama",
"KServe"
]
}, },
"observability": { "observability": {
"title": "Observability", "title": "Observability",
"items": ["Prometheus", "Grafana", "Loki", "OpenTelemetry"] "items": [
"Prometheus",
"Grafana",
"Loki",
"OpenTelemetry"
]
} }
} }
}, },
@@ -128,6 +162,30 @@
"url": "/homelab" "url": "/homelab"
} }
}, },
{
"title": "Poimen Memory System",
"description": "Distributed Graph-RAG infrastructure with hierarchical RBAC and wiki-link indexing.",
"longDescription": "Three-tier context retrieval pipeline with PageRank-style link scoring, hybrid search fusion (HNSW + BM25), and OIDC-based access control for multi-tenant knowledge graphs.",
"stat": "Graph-RAG, pgvector, OpenSearch, Rust + Actix-web",
"highlight": "Bidirectional wiki-link indexing with RRF fusion + hierarchical RBAC — 50ms signature match tier, graph-boosted hybrid search tier, Obsidian fallback.",
"bullets": [
"Graph-RAG with Wiki-Link Indexing (Rust, pgvector, OpenSearch): Built bidirectional link graph from [[wiki-link]] syntax during ingestion. PageRank-style score propagation boosts linked documents' relevance. RRF fusion merges HNSW cosine (pgvector) + BM25 lexical (OpenSearch). WikiScopedFilter constrains traversal to project boundaries.",
"Three-Tier Context Retrieval (Actix-web, tokio): Async pipeline — Tier 1: MD5 signature match (<50ms), Tier 2: graph-boosted hybrid search with link-distance decay, Tier 3: Obsidian API fallback. Budget-aware assembly drops lower tiers first. Shingle-based Jaccard deduplication (>0.5) prevents redundant chunks.",
"Hierarchical RBAC (Authentik OIDC, JWT, Kubernetes): Role → AccessRule[] → AccessScope model with project/visibility/owner/group constraints. JWT roles claim maps to YAML rules; AccessGuard.filter_resources() applies post-retrieval filtering. Dual-write indexer (eventual consistency via queue) maintains RBAC-aware views. SOPS/age encryption, ArgoCD deployment."
]
},
{
"title": "Poimen: Agent Workflow Orchestration",
"description": "Temporal-powered orchestration that transforms natural language into durable, scalable workflow executions.",
"longDescription": "LLM router analyzes user intent, retrieves relevant knowledge from semantic memory, and generates executable workflow specs—enabling agent deployment at scale where any activity can be wired as a step in the reconciliation pipeline.",
"stat": "Temporal, LLM Routing, 9 Composable Activities",
"highlight": "Natural language → executable WorkflowSpec via reasoning model + memory-augmented context retrieval + durable state machine execution.",
"bullets": [
"LLM-Powered Workflow Routing: Natural language → executable WorkflowSpec via reasoning model (api.riotpiao.com). Activity Knowledge Base (9 activities) informs the LLM about timeouts, retry policies, and dependencies—intelligent step ordering and error handling strategies.",
"Memory-Augmented Context Retrieval: RetrieveMemoryActivity queries poimen-memory (Rust semantic search service) for relevant skills and lessons before routing—injecting domain knowledge into prompts for context-aware workflow generation.",
"Generic State Machine Executor: RoutingWorkflow executes any JSON workflow spec with JSONPath parameter chaining (${Step1.output.path}), automatic retries for flaky activities, catch blocks for error recovery, and Temporal's durable execution guarantees—every registered activity a composable building block."
]
},
{ {
"title": "RBC: Multi-Cloud Platform", "title": "RBC: Multi-Cloud Platform",
"description": "Unified infrastructure platform consolidating public cloud and on-prem.", "description": "Unified infrastructure platform consolidating public cloud and on-prem.",
@@ -158,30 +216,6 @@
"Solved distributed edge cases: race conditions, concurrent updates, dependent service failures, message deduplication", "Solved distributed edge cases: race conditions, concurrent updates, dependent service failures, message deduplication",
"Owned oncall for the service—built CloudWatch dashboards, wrote runbooks, debugged production live" "Owned oncall for the service—built CloudWatch dashboards, wrote runbooks, debugged production live"
] ]
},
{
"title": "Poimen Memory System",
"description": "Distributed Graph-RAG infrastructure with hierarchical RBAC and wiki-link indexing.",
"longDescription": "Three-tier context retrieval pipeline with PageRank-style link scoring, hybrid search fusion (HNSW + BM25), and OIDC-based access control for multi-tenant knowledge graphs.",
"stat": "Graph-RAG, pgvector, OpenSearch, Rust + Actix-web",
"highlight": "Bidirectional wiki-link indexing with RRF fusion + hierarchical RBAC — 50ms signature match tier, graph-boosted hybrid search tier, Obsidian fallback.",
"bullets": [
"Graph-RAG with Wiki-Link Indexing (Rust, pgvector, OpenSearch): Built bidirectional link graph from [[wiki-link]] syntax during ingestion. PageRank-style score propagation boosts linked documents' relevance. RRF fusion merges HNSW cosine (pgvector) + BM25 lexical (OpenSearch). WikiScopedFilter constrains traversal to project boundaries.",
"Three-Tier Context Retrieval (Actix-web, tokio): Async pipeline — Tier 1: MD5 signature match (<50ms), Tier 2: graph-boosted hybrid search with link-distance decay, Tier 3: Obsidian API fallback. Budget-aware assembly drops lower tiers first. Shingle-based Jaccard deduplication (>0.5) prevents redundant chunks.",
"Hierarchical RBAC (Authentik OIDC, JWT, Kubernetes): Role → AccessRule[] → AccessScope model with project/visibility/owner/group constraints. JWT roles claim maps to YAML rules; AccessGuard.filter_resources() applies post-retrieval filtering. Dual-write indexer (eventual consistency via queue) maintains RBAC-aware views. SOPS/age encryption, ArgoCD deployment."
]
},
{
"title": "Poimen: Agent Workflow Orchestration",
"description": "Temporal-powered orchestration that transforms natural language into durable, scalable workflow executions.",
"longDescription": "LLM router analyzes user intent, retrieves relevant knowledge from semantic memory, and generates executable workflow specs—enabling agent deployment at scale where any activity can be wired as a step in the reconciliation pipeline.",
"stat": "Temporal, LLM Routing, 9 Composable Activities",
"highlight": "Natural language → executable WorkflowSpec via reasoning model + memory-augmented context retrieval + durable state machine execution.",
"bullets": [
"LLM-Powered Workflow Routing: Natural language → executable WorkflowSpec via reasoning model (api.riotpiao.com). Activity Knowledge Base (9 activities) informs the LLM about timeouts, retry policies, and dependencies—intelligent step ordering and error handling strategies.",
"Memory-Augmented Context Retrieval: RetrieveMemoryActivity queries poimen-memory (Rust semantic search service) for relevant skills and lessons before routing—injecting domain knowledge into prompts for context-aware workflow generation.",
"Generic State Machine Executor: RoutingWorkflow executes any JSON workflow spec with JSONPath parameter chaining (${Step1.output.path}), automatic retries for flaky activities, catch blocks for error recovery, and Temporal's durable execution guarantees—every registered activity a composable building block."
]
} }
] ]
}, },
@@ -274,27 +308,61 @@
"skills": { "skills": {
"infrastructure": { "infrastructure": {
"title": "基础设施", "title": "基础设施",
"items": ["Kubernetes", "Talos", "ArgoCD", "Terraform", "Docker", "OpenShift"] "items": [
"Kubernetes",
"Talos",
"ArgoCD",
"Terraform",
"Docker",
"OpenShift"
]
}, },
"cloud": { "cloud": {
"title": "云 & 分布式", "title": "云 & 分布式",
"items": ["AWS", "DynamoDB", "CloudWatch", "gRPC", "Cloudflare"] "items": [
"AWS",
"DynamoDB",
"CloudWatch",
"gRPC",
"Cloudflare"
]
}, },
"languages": { "languages": {
"title": "编程语言", "title": "编程语言",
"items": ["Go", "Java", "Python", "C++", "TypeScript"] "items": [
"Go",
"Java",
"Python",
"C++",
"TypeScript"
]
}, },
"data": { "data": {
"title": "数据 & 消息", "title": "数据 & 消息",
"items": ["Kafka", "PostgreSQL", "Temporal", "Redis"] "items": [
"Kafka",
"PostgreSQL",
"Temporal",
"Redis"
]
}, },
"aiml": { "aiml": {
"title": "AI/ML", "title": "AI/ML",
"items": ["vLLM", "PyTorch", "Ollama", "KServe"] "items": [
"vLLM",
"PyTorch",
"Ollama",
"KServe"
]
}, },
"observability": { "observability": {
"title": "可观测性", "title": "可观测性",
"items": ["Prometheus", "Grafana", "Loki", "OpenTelemetry"] "items": [
"Prometheus",
"Grafana",
"Loki",
"OpenTelemetry"
]
} }
} }
}, },
@@ -361,6 +429,30 @@
"url": "/homelab" "url": "/homelab"
} }
}, },
{
"title": "Poimen记忆系统",
"description": "具有分层RBAC的分布式图RAG基础设施和维基链接索引。",
"longDescription": "三层上下文检索管道,支持PageRank风格的链接评分、混合搜索融合(HNSW + BM25)和基于OIDC的多租户知识图访问控制。",
"stat": "图-RAG, pgvector, OpenSearch, Rust + Actix-web",
"highlight": "双向维基链接索引配RRF融合 + 分层RBAC——50ms签名匹配层、图增强混合搜索层、Obsidian兜底。",
"bullets": [
"图-RAG维基链接索引化(Rust、pgvector、OpenSearch):从[[维基链接]]语法构建双向链接图。PageRank风格评分传播提升链接文档的相关性。RRF融合合并HNSW余弦相似度(pgvector+ BM25词汇排名(OpenSearch)。WikiScopedFilter将遍历限制在项目边界内。",
"三层上下文检索(Actix-web, tokio):异步管道——第1层:MD5签名匹配(<50ms),第2层:图增强混合搜索含链接距离衰减,第3层:Obsidian API兜底。预算感知的响应组装优先丢弃低优先层。基于瓦片的Jaccard去重(>0.5)防止冗余块。",
"分层RBACAuthentik OIDC、JWT、Kubernetes):角色→AccessRule[]→AccessScope模型,包含项目/可见性/所有者/组约束。JWT角色声明映射到YAML规则;AccessGuard.filter_resources()应用检索后过滤。双写索引器(通过队列保证最终一致性)维护RBAC感知视图。SOPS/age加密,ArgoCD部署。"
]
},
{
"title": "Poimen: 智能体工作流编排",
"description": "Temporal驱动的编排平台,将自然语言转化为持久、可扩展的工作流执行。",
"longDescription": "LLM路由器分析用户意图,从语义记忆中检索相关知识,生成可执行工作流规格——支持大规模智能体部署,任何活动可作为协调管道的步骤。",
"stat": "Temporal, LLM路由, 9个可组合活动",
"highlight": "自然语言 → 可执行WorkflowSpec:推理模型 + 记忆增强上下文检索 + 持久状态机执行。",
"bullets": [
"LLM工作流路由:自然语言 → 可执行WorkflowSpec,通过推理模型。活动知识库(9个活动)告知LLM超时、重试策略和依赖关系——智能步骤排序和错误处理策略。",
"记忆增强上下文检索:RetrieveMemoryActivity查询poimen-memoryRust语义搜索服务)获取相关技能和经验——将领域知识注入提示词,实现上下文感知的工作流生成。",
"通用状态机执行器:RoutingWorkflow执行任何JSON工作流规格,支持JSONPath参数链接、自动重试、catch错误恢复和Temporal持久执行保证——每个注册活动都是可组合的构建块。"
]
},
{ {
"title": "RBC: 多云平台", "title": "RBC: 多云平台",
"description": "统一基础设施平台,整合公有云和本地部署。", "description": "统一基础设施平台,整合公有云和本地部署。",
@@ -391,30 +483,6 @@
"解决分布式边缘场景:竞态条件、并发更新、依赖服务故障、消息去重", "解决分布式边缘场景:竞态条件、并发更新、依赖服务故障、消息去重",
"负责服务oncall——构建CloudWatch仪表盘,编写runbook,实时调试生产问题" "负责服务oncall——构建CloudWatch仪表盘,编写runbook,实时调试生产问题"
] ]
},
{
"title": "Poimen记忆系统",
"description": "具有分层RBAC的分布式图RAG基础设施和维基链接索引。",
"longDescription": "三层上下文检索管道,支持PageRank风格的链接评分、混合搜索融合(HNSW + BM25)和基于OIDC的多租户知识图访问控制。",
"stat": "图-RAG, pgvector, OpenSearch, Rust + Actix-web",
"highlight": "双向维基链接索引配RRF融合 + 分层RBAC——50ms签名匹配层、图增强混合搜索层、Obsidian兜底。",
"bullets": [
"图-RAG维基链接索引化(Rust、pgvector、OpenSearch):从[[维基链接]]语法构建双向链接图。PageRank风格评分传播提升链接文档的相关性。RRF融合合并HNSW余弦相似度(pgvector+ BM25词汇排名(OpenSearch)。WikiScopedFilter将遍历限制在项目边界内。",
"三层上下文检索(Actix-web, tokio):异步管道——第1层:MD5签名匹配(<50ms),第2层:图增强混合搜索含链接距离衰减,第3层:Obsidian API兜底。预算感知的响应组装优先丢弃低优先层。基于瓦片的Jaccard去重(>0.5)防止冗余块。",
"分层RBACAuthentik OIDC、JWT、Kubernetes):角色→AccessRule[]→AccessScope模型,包含项目/可见性/所有者/组约束。JWT角色声明映射到YAML规则;AccessGuard.filter_resources()应用检索后过滤。双写索引器(通过队列保证最终一致性)维护RBAC感知视图。SOPS/age加密,ArgoCD部署。"
]
},
{
"title": "Poimen: 智能体工作流编排",
"description": "Temporal驱动的编排平台,将自然语言转化为持久、可扩展的工作流执行。",
"longDescription": "LLM路由器分析用户意图,从语义记忆中检索相关知识,生成可执行工作流规格——支持大规模智能体部署,任何活动可作为协调管道的步骤。",
"stat": "Temporal, LLM路由, 9个可组合活动",
"highlight": "自然语言 → 可执行WorkflowSpec:推理模型 + 记忆增强上下文检索 + 持久状态机执行。",
"bullets": [
"LLM工作流路由:自然语言 → 可执行WorkflowSpec,通过推理模型。活动知识库(9个活动)告知LLM超时、重试策略和依赖关系——智能步骤排序和错误处理策略。",
"记忆增强上下文检索:RetrieveMemoryActivity查询poimen-memoryRust语义搜索服务)获取相关技能和经验——将领域知识注入提示词,实现上下文感知的工作流生成。",
"通用状态机执行器:RoutingWorkflow执行任何JSON工作流规格,支持JSONPath参数链接、自动重试、catch错误恢复和Temporal持久执行保证——每个注册活动都是可组合的构建块。"
]
} }
] ]
}, },