- Implemented QuestionExpansionService for generating and materializing questions based on combinations and AI distillation.
- Added question metadata classification logic to infer intent and layer of questions.
- Created API handlers for question expansion operations including combination preview, AI distillation, metadata classification, and materialization.
- Introduced database migrations to support new question-related fields and constraints in brand_questions and brand_keywords tables.
- Added caching mechanism for AI distillation results to improve performance.
- Defined JSON schemas for question distillation responses to ensure data integrity.
Adds a new browser-fetch microservice that wraps Lightpanda for rendering
JS-heavy pages, and wires it into the knowledge URL parser as a fallback
when the upstream link reader returns 403/429/5xx for an allow-listed
domain (e.g. zhuanlan.zhihu.com). Includes config/env plumbing, hot-reload
diff support, and full deploy assets (Dockerfile target, docker-compose,
k3s manifests, image-build/package scripts).
- shared/cache: add Options/L1/async/metrics/prefix decorators, multi-key ops, Redis pool tuning, and JSON readthrough metrics
- worker-generate: claim tasks via DB lease + heartbeat, requeue stale queued tasks, expire dead leases with refund/cache invalidation
- tenant: version article cache keys so worker recovery invalidations propagate cleanly
- shared/config: expand Redis (pool/timeouts/TLS) and Generation (lease/recovery) configs with defaults
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the "change-me-before-apply" placeholder with a usable dev
default so the manifest applies cleanly out of the box. Production
deployments should still override this via their own secret source.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Apply with `kubectl apply -f deploy/k3s/addons/kite.yaml` to expose a
Kubernetes management dashboard on NodePort 30082. Documented as
optional and intranet-only since the official manifest binds
cluster-admin.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI workflows now own image publishing: backend-ci and frontend-ci push
service images to the Gitea Registry tagged with commit8. CD workflows
(nas-compose-deploy, nas-compose-service-deploy, offline-package, the
new nas-k3s-deploy) pull and verify those tags instead of rebuilding,
so deployments fail fast when CI hasn't produced the matching image.
The shared deploy/scripts/gitea-registry-images.sh helper drives both
the ensure (CI) and verify (CD) paths, and package.sh can now hydrate
its local images from the registry via SOURCE_IMAGE_REGISTRY.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Lower keep_releases default to 1 to reduce NAS disk usage, and clear
the bundled siliconflow retrieval api_key so deployments must supply
their own credentials.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A fresh production environment only ran migrations, so the four built-in
platform templates were never inserted unless someone manually ran
dev-seed (which also writes broad demo data). Extract the platform
template upsert into a reusable repository.EnsurePlatformTemplates and
add a standalone cmd/seed-platform-templates that calls it. Bake the
binary into the migrate image and chain it after migrate up in both
docker-compose and the k3s migration job (mounting app config so the
binary can dial the right database).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The target-platform supplement only fed legacy prompt builders that read
the now-removed wizard_state platforms field. Drop the YAML entry,
loader struct field, and runtime helper.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Introduce a self-contained kustomize stack under deploy/k3s covering
namespace, config, placeholder secrets, infra StatefulSets, app
Deployments/Services, migration and minio-init Jobs, and Traefik
Ingress for both tenant and ops hosts. Add Dockerfile.ops-web so the
operations frontend can ship as an nginx image, and extend the offline
package script to build and bundle ops-api, kol-assist-worker, and
ops-web alongside the k3s manifests. Wire the new ops/security knobs
through .env.example and the compose stack.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tighten the analyze prompts (runtime + recommendation platform) so the
model returns 8-10 question-style search queries (哪家好/有哪些/怎么选/
价格/排名/避坑 …) instead of generic tag words, and lift the keyword cap
in normalizeAnalyzeResult from 5 to 10 to keep them. Add tests covering
the new ten-keyword window and the question-like guidance in the seeded
analyze prompt.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Open a separate pgx pool for the monitoring database, wire it into the
SiteDomainMappingService, and surface its health in /readyz. Point compose
at the dedicated monitoring-postgres service and align local/dev configs
with the per-instance ports. Also reformat the site_domain_mapping types
with gofmt while the files are touched.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Register site-domain-mappings CRUD endpoints under the authenticated ops
router, add a monitoring_database config block (falling back to the main
ops database when unset) for the service to share the monitoring pool.
Add an IPRegionResolver wrapping the ip2region xdb library and attach it
to AuditService so each appended event records both the raw IP and a
resolved region in a new ops.audit_logs.ip_region column. Loopback and
private addresses short-circuit to local labels; missing xdb data or
lookup errors degrade silently so auditing keeps working without it.
The ops console audit view shows the region beneath the IP. Bundle the
v4/v6 xdb data under internal/ops/app/ipregiondata so the resolver works
out of the box, with config paths/env overrides for swapping in updated
data sets.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds /admin-users CRUD on the ops backend, covering listing, plan/role/KOL
toggles, subscription expiry, status flips and password resets, with a
configurable default plan code. The ops console exposes a new top-level
"用户管理" view and reorganises the sidebar so 操作员管理 and 审计日志
move under a "系统设置" group; AccountsView is renamed accordingly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Introduces ai_points_monthly and ai_point_base_chars on the membership
plan policy, exposes them through TenantPlanAccess and MembershipInfo,
and seeds Pro with a 1500-point monthly allowance across the local,
server, and deploy configs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the ops-api container, ops-config volume, and migrate-ops step so
the operations console backend boots alongside the rest of the stack.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps refresh token lifetime to 720h with env overrides, and stops
clearing the local session for non-401 refresh failures so users aren't
logged out by transient network blips. Adds a 60s retry timer when a
refresh fails for non-auth reasons.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Scheduler now runs a token-protected HTTP server on scheduler.http_port
(default 8081, -1 disables) that exposes Prometheus /metrics and the
daily-task JSON snapshot endpoint. Workers gain a blocking Run(ctx) and
are supervised by a WaitGroup: on SIGINT/SIGTERM the metrics server
shuts down first, worker ticks stop scheduling but ongoing runOnce
calls keep their own context and finish, and the process waits up to
60s before exiting. Adds scheduler.http_host/http_port/internal_metrics_token
to config with SCHEDULER_* env overrides and exposes port 8081 in the
Docker image.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add configurable membership plans (free/plus/pro) synced to DB on boot, a
subscription guard middleware that blocks tenant endpoints on expired or
missing plans, and a MembershipBlockedView that surfaces the reason so
the admin can contact the tenant owner. Quota and brand-library reads now
honor the active plan's policy JSON and expired subscriptions.