Skip to content

feat(api): merge Acontext-admin fork into main repo#458

Merged
GenerQAQ merged 4 commits intodevfrom
worktree-valiant-moseying-frog
Mar 19, 2026
Merged

feat(api): merge Acontext-admin fork into main repo#458
GenerQAQ merged 4 commits intodevfrom
worktree-valiant-moseying-frog

Conversation

@GenerQAQ
Copy link
Copy Markdown
Contributor

@GenerQAQ GenerQAQ commented Mar 19, 2026

Why we need this PR?

Merge the Acontext-admin fork into the main repo. The admin API was previously maintained in a separate fork (memodb-io/Acontext-admin), but consolidating it simplifies maintenance, deployment, and keeps shared code in sync.

This PR also includes post-merge code review fixes for security, performance, and reliability issues found in the merged code.

Continues from fork tag admin/v0.1.17 — the next release from this repo should be admin/v0.1.18.

Describe your solution

Phase 1: Merge admin fork

Imported admin-specific functionality into the main repo:

  • Admin server entry point (cmd/admin/main.go)
  • Admin Dockerfile (Dockerfile.admin) and CI release workflow (admin-release.yaml)
  • Admin-specific handlers, services, repos, middleware (SupabaseAuth, MetricsAuth)
  • Admin DI container (bootstrap/container_admin.go) and router (router/router_admin.go)
  • Metrics and project management (create/delete projects, usage analytics, Jaeger proxy)

Phase 2: Code review fixes

  1. SupabaseAuth client reuse — initialize supabaseauth.New() once in the middleware constructor closure instead of per-request
  2. Transaction for storage metrics — wrap delete+create in ReplaceStorageMetrics() using db.Transaction() to prevent data loss on crash
  3. http.Client reuse — add *http.Client field to projectService struct, initialized once in constructor
  4. Header whitelist for Jaeger proxy — only forward safe headers (Accept, Content-Type) instead of all headers, preventing Authorization/Cookie leaks to internal Jaeger
  5. Remove bearer token log — removed plaintext secret logging at admin startup

Implementation Tasks

  • Import admin server entry point, Dockerfile, and CI workflow
  • Import admin handlers, services, repos, and middleware
  • Import admin DI container and router
  • Fix SupabaseAuth client created per-request → initialize once in closure
  • Fix no DB transaction around delete+create in storage metrics → wrap in transaction
  • Fix http.Client created per-request in AnalyzeMetrics → inject as struct field
  • Fix raw request headers forwarded to Jaeger → whitelist safe headers only
  • Fix bearer token logged in plaintext at admin startup → remove

Impact Areas

Which part of Acontext would this feature affect?

  • Client SDK (Python)
  • Client SDK (TypeScript)
  • Core Service
  • API Server
  • Dashboard
  • CLI Tool
  • Documentation
  • Other: ...

Checklist

  • Open your pull request against the dev branch.
  • All tests pass in available continuous integration systems (e.g., GitHub Actions).
  • Tests are added or modified as needed to cover code changes.

Docker Image Visibility

⚠️ The acontext-admin container image on ghcr.io is PRIVATE. After the first release from this repo (admin/v0.1.18), verify that the package at ghcr.io/memodb-io/acontext-admin retains its private visibility. Since the package already exists with private visibility, new pushes will inherit it — but confirm after the first tag push.

🤖 Generated with Claude Code

@GenerQAQ GenerQAQ changed the title feat(api): merge Acontext-admin fork into main repo feat: S3 envelope encryption for data-at-rest protection Mar 19, 2026
@GenerQAQ GenerQAQ force-pushed the worktree-valiant-moseying-frog branch from cf11a37 to 03be7a6 Compare March 19, 2026 07:33
@GenerQAQ GenerQAQ changed the title feat: S3 envelope encryption for data-at-rest protection feat(api): merge Acontext-admin fork into main repo Mar 19, 2026
Add admin API as a second entry point (cmd/admin/main.go) sharing the
same Go module. This eliminates the need for a separate fork and manual
sync-api.sh workflow.

- Add admin handlers, services, and repos for project management, usage
  analytics, and metrics
- Add SupabaseAuth and MetricsAuth middleware
- Add admin bootstrap container extending the base DI container
- Add admin router extending the base router with /admin/v1 and
  /metrics/v1 route groups
- Add Dockerfile.admin and CI/CD workflows (admin/vX.Y.Z tags)
- Add MetricsCfg, SupabaseCfg, and JaegerQueryEndpoint config fields
- Add PathMatcher utility for quota route matching

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@GenerQAQ GenerQAQ force-pushed the worktree-valiant-moseying-frog branch from 03be7a6 to 2adbb0d Compare March 19, 2026 07:46
- Reuse SupabaseAuth client across requests instead of creating per-request
- Wrap storage metrics delete+create in a DB transaction to prevent data loss
- Reuse http.Client in projectService instead of creating per-request
- Whitelist safe headers (Accept, Content-Type) for Jaeger proxy instead of forwarding all
- Remove bearer token plaintext log at admin startup

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@GenerQAQ GenerQAQ marked this pull request as ready for review March 19, 2026 08:19
@GenerQAQ GenerQAQ requested a review from a team as a code owner March 19, 2026 08:19
@GenerQAQ
Copy link
Copy Markdown
Contributor Author

Code review

Found 1 issue:

  1. MetricTags constants in Go diverge from the Python MetricTags class. The Go comment on line 9 explicitly states "These should match the MetricTags class in Python (acontext_core/constants.py)," and AGENTS.md requires syncing between API and CORE. Go adds storage.usage, space.learned, search.experience.agentic, search.experience.embedding with no Python counterpart, and Python's sandbox.alive is absent from Go. (AGENTS.md says "Both API and CORE have their ORMs, which should be synced")

// MetricTags defines the constants for metric tag values
// These should match the MetricTags class in Python (acontext_core/constants.py)
const (
MetricTagStorageUsage = "storage.usage"
MetricTagTaskCreated = "task.created"
MetricTagSpaceLearned = "space.learned"
MetricTagSearchExperienceAgentic = "search.experience.agentic"
MetricTagSearchExperienceEmbedding = "search.experience.embedding"
)

Python side for reference:

class MetricTags:
new_task_created = "task.created"
new_sandbox_alive = "sandbox.alive"

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

Remove unused MetricTag constants to align Go with Python, update
config.admin.yaml pool defaults to match PR #457, fix Swagger BasePath
annotation, whitelist Jaeger proxy query params, and filter unsafe
response headers in Jaeger proxy.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@GenerQAQ
Copy link
Copy Markdown
Contributor Author

Code review

Found 3 issues:

  1. Query references the dropped spaces table, causing a runtime PostgreSQL error. The spaces table was removed in commit f4ca8eba (Jan 2026), but the admin fork code still joins on it in AnalyzeUsages. Any call to the usages endpoint with new_spaces field will return a 500.

TO_CHAR(ds.date, 'YYYY-MM-DD') AS date,
COUNT(sp.id) AS count
FROM date_series ds
LEFT JOIN spaces sp ON DATE(sp.created_at) = ds.date AND sp.project_id = ?
GROUP BY ds.date
ORDER BY ds.date ASC
`, intervalDays, projectID).Scan(&rows).Error; err != nil {

  1. Query references the dropped tool_references table, causing a runtime PostgreSQL error. The tool_references table was removed in commit 48e69462 (Feb 2026), but the admin fork code still queries it in AnalyzeStatistics. Every call to the statistics endpoint will return a 500.

if err := r.db.WithContext(ctx).Model(&struct {
ID uuid.UUID `gorm:"type:uuid"`
}{}).
Table("tool_references").
Where("project_id = ?", projectID).
Count(&skillCount).Error; err != nil {
return nil, err

  1. GORM autoUpdateTime tag overwrites epoch sentinel timestamps on quota metrics. ProcessQuotaItems sets UpdatedAt: time.Unix(0, 0) to exclude quota metrics from date-range queries, but the Metric model's gorm:"autoUpdateTime" tag forces GORM to overwrite UpdatedAt with time.Now() on every Create/Update. The epoch value is never persisted, so quota metrics will appear in ListByDateRange results.

metricsToSave = append(metricsToSave, model.Metric{
ProjectID: projectID,
Tag: tag,
Increment: 1,
// Set created_at and updated_at to the start of Unix epoch to ensure they are not retrieved
CreatedAt: time.Unix(0, 0),
UpdatedAt: time.Unix(0, 0),
})

CreatedAt time.Time `gorm:"autoCreateTime;not null;default:CURRENT_TIMESTAMP;index:idx_metric_project_id_tag_created_at,priority:3;index:idx_metric_created_at" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime;not null;default:CURRENT_TIMESTAMP" json:"updated_at"`

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

… merge

- Replace removed `spaces` table with `learning_spaces` in AnalyzeUsages
- Replace removed `tool_references` table with `agent_skills` in AnalyzeStatistics
- Remove autoUpdateTime from Metric model to preserve epoch sentinel values set by quota logic

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@GenerQAQ
Copy link
Copy Markdown
Contributor Author

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

@GenerQAQ GenerQAQ merged commit b7dc937 into dev Mar 19, 2026
7 checks passed
@GenerQAQ GenerQAQ deleted the worktree-valiant-moseying-frog branch March 19, 2026 10:13
GenerQAQ added a commit that referenced this pull request Mar 22, 2026
After merging Acontext-admin fork (#458), the admin router's /api/v1
auth was replaced by the SDK-oriented HMAC secret key lookup, breaking
all Dashboard requests (which use base64 JSON tokens with project_id
+ signature). This adds AdminProjectAuth middleware and a
ProjectAuthOverride mechanism so the admin router uses the correct
token format while the regular API server remains unchanged.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
GenerQAQ added a commit that referenced this pull request Mar 22, 2026
After merging Acontext-admin fork (#458), the admin router's /api/v1
auth was replaced by the SDK-oriented HMAC secret key lookup, breaking
all Dashboard requests (which use base64 JSON tokens with project_id
+ signature). This adds AdminProjectAuth middleware and a
ProjectAuthOverride mechanism so the admin router uses the correct
token format while the regular API server remains unchanged.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant