Update API and storage to support license attributes#11
Conversation
This commit introduces support for storing and handling license attributes in the backend and frontend. In the backend, the `licenseManagementResponse` struct in `internal/api/management_licenses.go` is updated to include an `Attributes` map. Correspondingly, `marshalGenerateResponseBody` in `internal/storage/store.go` is updated to include `Attributes` in the response payload. The database schema in `internal/storage/schema.sql` is updated to add an `attributes` JSONB column to the licenses table. In the API layer, `issueOfflineToken` in `internal/api/offline_tokens.go` is updated to accept and use an `attributes` map. License handlers in `internal/api/license_handlers.go` are updated to handle and validate these attributes, including a new validation function `validateAttributes`. In the frontend, `LicensesView.vue` is updated to include an `attributes` reactive property in the form state. Similarly, `SlugsView.vue` updates the form state for attributes. The `slugAPI` in `ui/src/stores/api.ts` is updated to include an `attributes` field in the data
📝 WalkthroughWalkthroughThis PR extends the license server with support for attributes—arbitrary JSON metadata stored at the slug and license level. Attributes are defined when creating or updating slug templates, automatically flow into generated licenses, and are embedded into offline JWT tokens for runtime use. The implementation spans database schema, storage persistence, API contracts and validation, and full UI support for editing and viewing attributes. ChangesLicense & Slug Attributes Support
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
internal/storage/slug_management.go (1)
162-187: ⚖️ Poor tradeoffUnify
attributesJSONB handling (map vs[]byte) for predictability.
internal/storage/slug_management.gopersistsslugs.attributesby passingmap[string]anydirectly (copyMetadata(params.Attributes)/copyMetadata(attributes)) and scanning JSONB straight intomap[string]any(scanSlugRecord/loadSlugOptionsByName). In contrast,internal/storage/store.gopersistslicenses.metadata/licenses.attributesby explicitly marshaling to[]byte(metadataToJSON) and unmarshaling on read (json.Unmarshal).There’s no evidence of
pgxSimpleProtocol usage in this repo, so the currentmap[string]any<->jsonbpath forslugs.attributesshould be fine today; standardizing the approach across tables would mainly reduce future refactor risk.
copyMetadata(nil)already returns an empty map ({}), which matchesslugs.attributes JSONB NOT NULL DEFAULT '{}'::jsonb.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/storage/slug_management.go` around lines 162 - 187, Unify JSONB handling for slugs.attributes by storing marshaled bytes and unmarshaling on read: replace direct map passing in the INSERT (where copyMetadata(params.Attributes) is used) with the same metadataToJSON(...) call used for licenses, and update readers (scanSlugRecord and loadSlugOptionsByName) to expect []byte from slugs.attributes and json.Unmarshal into a map[string]any; keep copyMetadata(...) behavior (empty map for nil) but ensure persistence uses metadataToJSON and reads perform json.Unmarshal for consistency with metadata/attributes handling in store.go.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@internal/storage/slug_management.go`:
- Around line 162-187: Unify JSONB handling for slugs.attributes by storing
marshaled bytes and unmarshaling on read: replace direct map passing in the
INSERT (where copyMetadata(params.Attributes) is used) with the same
metadataToJSON(...) call used for licenses, and update readers (scanSlugRecord
and loadSlugOptionsByName) to expect []byte from slugs.attributes and
json.Unmarshal into a map[string]any; keep copyMetadata(...) behavior (empty map
for nil) but ensure persistence uses metadataToJSON and reads perform
json.Unmarshal for consistency with metadata/attributes handling in store.go.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 089eba0b-1600-40b5-a3de-e7397953b8ba
📒 Files selected for processing (16)
internal/api/license_handlers.gointernal/api/management_licenses.gointernal/api/management_slugs.gointernal/api/offline_tokens.gointernal/api/server.gointernal/api/server_test.gointernal/offlinejwt/offlinejwt.gointernal/storage/generate_license_test.gointernal/storage/license_management.gointernal/storage/schema.sqlinternal/storage/slug_management.gointernal/storage/store.gointernal/version/version.goui/src/stores/api.tsui/src/views/LicensesView.vueui/src/views/SlugsView.vue
This commit introduces support for storing and handling license attributes in the backend and frontend. In the backend, the
licenseManagementResponsestruct ininternal/api/management_licenses.gois updated to include anAttributesmap. Correspondingly,marshalGenerateResponseBodyininternal/storage/store.gois updated to includeAttributesin the response payload. The database schema ininternal/storage/schema.sqlis updated to add anattributesJSONB column to the licenses table. In the API layer,issueOfflineTokenininternal/api/offline_tokens.gois updated to accept and use anattributesmap. License handlers ininternal/api/license_handlers.goare updated to handle and validate these attributes, including a new validation functionvalidateAttributes. In the frontend,LicensesView.vueis updated to include anattributesreactive property in the form state. Similarly,SlugsView.vueupdates the form state for attributes. TheslugAPIinui/src/stores/api.tsis updated to include anattributesfield in the dataSummary by CodeRabbit
Release Notes
New Features
UI Enhancements
Chores