Add/ai native supp (#385)
* feat(branding): implement dynamic branding in service worker and reports * feat(auth): enhance API key scopes and add bookkeeping write scope - Updated transaction write scope description to include additional tools. - Enhanced reports read scope description to reflect new functionality. - Introduced bookkeeping write scope with relevant description. - Updated SCOPE_GROUPS to include bookkeeping domain. - Modified TOOL_SCOPE_MAP to include new bookkeeping operations. - Updated validateApiKey function to return api_key_id and api_key_name for better actor attribution. feat(tests): add unit tests for MCP resource registry - Created tests for data resources to ensure all required fields are present. - Added tests for resource query parsing and retrieval. feat(resources): implement MCP resources for company and accounting data - Added capabilities resource to expose API key capabilities based on granted scopes. - Implemented chart of accounts resource to retrieve active BAS chart. - Created company current resource to fetch active company details. - Developed active fiscal period resource to check posting eligibility. - Implemented recent activity resource to fetch latest journal entries, invoices, and transactions. - Added VAT treatments resource to provide available VAT rates per customer type. feat(pending-operations): introduce risk tiers for operations - Added risk level classification for pending operations to determine auto-commit eligibility. - Implemented functions to classify operation risk levels and identify high-risk operations. feat(migrations): add actor model and risk tier to pending operations - Updated pending_operations table to include actor type and risk level columns. - Enhanced audit_log to mirror actor information for compliance. - Modified validate_and_increment_api_key function to return actor details. - Expanded operation types in pending_operations to include new high-risk operations. * feat: add auto-commit functionality for low-risk pending operations - Implemented shouldAutoCommit function to determine eligibility for auto-commit based on operation type, actor type, and company settings. - Created commitPendingOperation function to handle execution of pending operations with consistent status updates. - Added tests for shouldAutoCommit to cover various scenarios including high-risk operations, user actors, company opt-in status, and monetary thresholds. - Introduced new columns in company_settings for agent_auto_commit_enabled and agent_auto_commit_max_amount to allow companies to opt-in for auto-commit functionality. - Added SQL migration to update the database schema for new auto-commit settings. * feat(idempotency): implement idempotency key handling for safe retries and cleanup * feat: expand API key scopes and pending operations for bookkeeping - Added 'suppliers:write' scope to API key scopes for supplier invoice management. - Updated SCOPE_GROUPS to include the new 'suppliers:write' scope. - Introduced new pending operation types for bookkeeping: close_period, lock_period, run_year_end, set_opening_balances, run_currency_revaluation, explain_voucher_gap, uncategorize_transaction, approve_supplier_invoice, credit_supplier_invoice, and convert_invoice. - Implemented corresponding commit functions for the new operations in the pending operations module. - Enhanced PendingOperation type to include actor model and risk level attributes. - Added tests for new functionality, ensuring proper behavior and constraints in the database. * feat: implement unlockPeriod functionality and related tests * feat: add agent auto-commit settings and related functionality * feat: add attention resource with comprehensive summary of outstanding tasks * feat: enhance pending operations with 'committing' status and immutability checks, improve idempotency handling, and add original voucher reference for credit notes
This commit is contained in:
+45
-5
@@ -7,13 +7,15 @@ const KEY_PREFIX = 'gnubok_sk_'
|
||||
|
||||
export const API_KEY_SCOPES = {
|
||||
'transactions:read': { label: 'Transaktioner — läs', description: 'Lista transaktioner, mallförslag, kategoriförslag (3 verktyg)' },
|
||||
'transactions:write': { label: 'Transaktioner — skriv', description: 'Kategorisera, kvittomatchning, koppling mot faktura (3 verktyg)' },
|
||||
'transactions:write': { label: 'Transaktioner — skriv', description: 'Kategorisera, av-kategorisera, kvittomatchning, koppling mot faktura (4 verktyg)' },
|
||||
'customers:read': { label: 'Kunder — läs', description: 'Lista kunder (1 verktyg)' },
|
||||
'customers:write': { label: 'Kunder — skriv', description: 'Skapa kunder (1 verktyg)' },
|
||||
'invoices:read': { label: 'Fakturor — läs', description: 'Lista fakturor (1 verktyg)' },
|
||||
'invoices:write': { label: 'Fakturor — skriv', description: 'Skapa, skicka, markera betald/skickad (4 verktyg)' },
|
||||
'suppliers:read': { label: 'Leverantörer — läs', description: 'Lista leverantörer och leverantörsfakturor (2 verktyg)' },
|
||||
'reports:read': { label: 'Rapporter — läs', description: 'Kontoplan, huvudbok, balansräkning, resultaträkning, moms, KPI, reskontra, perioder, bankavstämning (11 verktyg)' },
|
||||
'suppliers:write': { label: 'Leverantörer — skriv', description: 'Godkänn och kreditera leverantörsfakturor (2 verktyg)' },
|
||||
'reports:read': { label: 'Rapporter — läs', description: 'Kontoplan, huvudbok, balansräkning, resultaträkning, moms, KPI, reskontra, perioder, bankavstämning, SIE-export (12 verktyg)' },
|
||||
'bookkeeping:write': { label: 'Bokföring — skriv', description: 'Stänga/låsa perioder, ingående balans, bokslut, SIE-import, voucher-gap-förklaringar' },
|
||||
'payroll:read': { label: 'Löner — läs', description: 'Lista anställda, lönekörningar, lönejournal (3 verktyg)' },
|
||||
'payroll:write': { label: 'Löner — skriv', description: 'Skapa lönekörning, beräkna, generera AGI (3 verktyg)' },
|
||||
} as const
|
||||
@@ -36,8 +38,9 @@ export const SCOPE_GROUPS = [
|
||||
{ domain: 'transactions', label: 'Transaktioner', read: 'transactions:read' as const, write: 'transactions:write' as const },
|
||||
{ domain: 'customers', label: 'Kunder', read: 'customers:read' as const, write: 'customers:write' as const },
|
||||
{ domain: 'invoices', label: 'Fakturor', read: 'invoices:read' as const, write: 'invoices:write' as const },
|
||||
{ domain: 'suppliers', label: 'Leverantörer', read: 'suppliers:read' as const, write: null },
|
||||
{ domain: 'suppliers', label: 'Leverantörer', read: 'suppliers:read' as const, write: 'suppliers:write' as const },
|
||||
{ domain: 'reports', label: 'Rapporter', read: 'reports:read' as const, write: null },
|
||||
{ domain: 'bookkeeping', label: 'Bokföring', read: null, write: 'bookkeeping:write' as const },
|
||||
{ domain: 'payroll', label: 'Löner', read: 'payroll:read' as const, write: 'payroll:write' as const },
|
||||
] as const
|
||||
|
||||
@@ -85,6 +88,26 @@ export const TOOL_SCOPE_MAP: Record<string, ApiKeyScope> = {
|
||||
gnubok_create_salary_run: 'payroll:write',
|
||||
gnubok_calculate_salary_run: 'payroll:write',
|
||||
gnubok_generate_agi: 'payroll:write',
|
||||
// Bookkeeping write (Stream 1 Phase 1) — high-risk, always staged
|
||||
gnubok_close_period: 'bookkeeping:write',
|
||||
gnubok_lock_period: 'bookkeeping:write',
|
||||
gnubok_unlock_period: 'bookkeeping:write',
|
||||
gnubok_run_year_end: 'bookkeeping:write',
|
||||
gnubok_set_opening_balances: 'bookkeeping:write',
|
||||
gnubok_run_currency_revaluation: 'bookkeeping:write',
|
||||
gnubok_explain_voucher_gap: 'bookkeeping:write',
|
||||
gnubok_list_voucher_gaps: 'reports:read',
|
||||
// Transaction reversal (medium-risk)
|
||||
gnubok_uncategorize_transaction: 'transactions:write',
|
||||
// SIE export (read-only) + import (write)
|
||||
gnubok_export_sie: 'reports:read',
|
||||
gnubok_import_sie: 'bookkeeping:write',
|
||||
// Supplier invoice lifecycle
|
||||
gnubok_approve_supplier_invoice: 'suppliers:write',
|
||||
gnubok_credit_supplier_invoice: 'suppliers:write',
|
||||
// Invoice conversion + crediting
|
||||
gnubok_convert_invoice: 'invoices:write',
|
||||
gnubok_credit_invoice: 'invoices:write',
|
||||
}
|
||||
|
||||
export function validateScopes(scopes: unknown): ApiKeyScope[] | null {
|
||||
@@ -126,12 +149,27 @@ export function extractBearerToken(request: Request): string | null {
|
||||
/**
|
||||
* Validate an API key and enforce rate limiting.
|
||||
* Uses the DB RPC for atomic check + increment.
|
||||
* Returns the user_id and effective scopes on success, or an error with HTTP status.
|
||||
* Returns the user_id, company_id, api_key_id, name, and effective scopes on
|
||||
* success, or an error with HTTP status.
|
||||
* null scopes in DB → DEFAULT_SCOPES (read-only).
|
||||
*
|
||||
* api_key_id and api_key_name are returned so callers (e.g. the MCP server)
|
||||
* can record actor attribution on pending_operations and audit_log.
|
||||
* They may be undefined when the deployed DB hasn't yet run the migration
|
||||
* that adds them to the RPC return shape.
|
||||
*/
|
||||
export async function validateApiKey(
|
||||
key: string
|
||||
): Promise<{ userId: string; companyId: string; scopes: ApiKeyScope[] } | { error: string; status: number }> {
|
||||
): Promise<
|
||||
| {
|
||||
userId: string
|
||||
companyId: string
|
||||
apiKeyId?: string
|
||||
apiKeyName?: string
|
||||
scopes: ApiKeyScope[]
|
||||
}
|
||||
| { error: string; status: number }
|
||||
> {
|
||||
if (!key.startsWith(KEY_PREFIX)) {
|
||||
return { error: 'Invalid API key format', status: 401 }
|
||||
}
|
||||
@@ -156,6 +194,8 @@ export async function validateApiKey(
|
||||
return {
|
||||
userId: row.user_id,
|
||||
companyId: row.company_id,
|
||||
apiKeyId: row.api_key_id,
|
||||
apiKeyName: row.api_key_name,
|
||||
scopes: validateScopes(row.scopes) ?? DEFAULT_SCOPES,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user