feat: tiered costs feature + admin tier management + tag selection
Build & Push Docker Image / build (push) Successful in 6m52s

- costs: nullable notes (fix create without notes), drop renewalDate
  (schema + API + UI), gate POST/PATCH/DELETE to admin + costs feature
- feature middleware: admin-aware hasFeature + getEntitlements union;
  /auth/me and login return resolved entitlements
- users: tier enum (free/premium/enterprise) in create/update/list,
  admin UI tier select + tier badge
- tags: GET /tags/all, TagInput autocomplete in new/edit tool forms,
  feature suggestions on focus, query invalidation on create/update
- openapi: nullable ToolUpdate urls, ToolUpdate tier fields, listAllTags
- Dockerfile: push-force to drop renewal_date column
This commit is contained in:
opencode
2026-08-02 01:10:47 +02:00
parent cd4efd16f6
commit 01c70085db
27 changed files with 478 additions and 86 deletions
+33 -3
View File
@@ -325,6 +325,21 @@ paths:
items:
type: string
/tags/all:
get:
operationId: listAllTags
tags: [tools]
summary: List all distinct tag strings across all tools
responses:
"200":
description: All known tags
content:
application/json:
schema:
type: array
items:
type: string
/auth/mode:
get:
operationId: getAuthMode
@@ -553,6 +568,9 @@ components:
role:
type: string
enum: [admin, user]
tier:
type: string
enum: [free, premium, enterprise]
createdAt:
type: string
format: date-time
@@ -572,14 +590,19 @@ components:
role:
type: string
enum: [admin, user]
tier:
type: string
enum: [free, premium, enterprise]
UserRoleUpdate:
type: object
required: [role]
properties:
role:
type: string
enum: [admin, user]
tier:
type: string
enum: [free, premium, enterprise]
AuditLog:
type: object
@@ -714,9 +737,9 @@ components:
category:
type: string
websiteUrl:
type: string
type: ["string", "null"]
iconUrl:
type: string
type: ["string", "null"]
features:
type: array
items:
@@ -849,6 +872,13 @@ components:
role:
type: string
enum: [admin, user]
tier:
type: string
enum: [free, premium, enterprise]
entitlements:
type: array
items:
type: string
isLocal:
type: boolean