Add/customer mcp (#1055)

* feat(mcp): kontoplan account tools + verifikat notes exposure

Two gaps reported by an MCP-driven user: no account management in the
API, and verifikat notes invisible to agents (they exist in the product
but MCP could neither read nor write them).

- add staged gnubok_create_account / gnubok_update_account (BAS 2026
  prefill for catalog numbers; rename/VAT-default/SRU/activate via
  update; both LOW risk reference data)
- add staged gnubok_set_voucher_note (notes-only annotation, legal on
  posted entries per the 20260608120000 trigger carve-out) and return
  entry_notes from gnubok_query_journal
- new pending_operations types create_account / update_account /
  set_voucher_note (CHECK migration + validate companion, applied to
  staging)
- tools/list payload ceiling 54K -> 56K (documented; wire contract,
  descriptions trimmed first)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(skatteverket): unstick BankID connect flow and stale connection views

- respond to the OAuth callback immediately and run the post-connect
  refresh after the response (next/server after()): users no longer
  stare at Skatteverket's consumed consent page for up to 40s
- open the consent flow in a full tab instead of a 600x750 popup that
  hid the approve button below the fold
- disable connect buttons while the OAuth tab is open (parallel flows
  overwrote oauth_state + the PKCE verifier) and recover via a
  closed-tab watcher plus a delayed status refetch
- persist MISSING_SCOPE token health from the post-connect sync and
  show an actionable "approve all permissions" notice
- refetch connection state on tab visibility (settings connect panel,
  enable-banking panel, /skattekonto) so a connect completed in another
  tab or after a mobile app-switch shows up without a manual reload;
  fix /skattekonto never clearing its not-connected state

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(article-form): add article number field with validation to ArticleForm

* feat(account): enforce account type consistency with BAS class and add validation

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Mattsson
2026-07-17 14:13:53 +02:00
committed by GitHub
co-authored by Claude Fable 5
parent bfd5b42eb1
commit 0e9cca2750
28 changed files with 1944 additions and 101 deletions
+35 -17
View File
@@ -131,6 +131,7 @@ export default function ArticleForm({
const schema = useMemo(
() =>
z.object({
article_number: z.string().trim().max(64, t('number_too_long')).optional(),
name: z.string().min(1, t('name_required')),
name_en: z.string().optional(),
type: z.enum(['vara', 'tjanst']),
@@ -161,6 +162,7 @@ export default function ArticleForm({
} = useForm<FormData>({
resolver: zodResolver(schema),
defaultValues: {
article_number: initialData?.article_number || '',
name: initialData?.name || '',
name_en: initialData?.name_en || '',
type: initialData?.type || 'tjanst',
@@ -180,6 +182,7 @@ export default function ArticleForm({
const onFormSubmit = (data: FormData) => {
onSubmit({
article_number: data.article_number?.trim() || null,
name: data.name,
name_en: data.name_en || null,
type: data.type,
@@ -197,24 +200,39 @@ export default function ArticleForm({
return (
<form onSubmit={handleSubmit(onFormSubmit)} className="space-y-6">
{/* Type */}
<div className="space-y-2">
<Label>{t('type_label')}</Label>
<Controller
name="type"
control={control}
render={({ field }) => (
<Select value={field.value} onValueChange={(v) => { if (v) field.onChange(v) }}>
<SelectTrigger>
<SelectValue placeholder={t('type_placeholder')} />
</SelectTrigger>
<SelectContent>
<SelectItem value="vara">{t('type_vara')}</SelectItem>
<SelectItem value="tjanst">{t('type_tjanst')}</SelectItem>
</SelectContent>
</Select>
{/* Type + article number */}
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
<div className="space-y-2">
<Label>{t('type_label')}</Label>
<Controller
name="type"
control={control}
render={({ field }) => (
<Select value={field.value} onValueChange={(v) => { if (v) field.onChange(v) }}>
<SelectTrigger>
<SelectValue placeholder={t('type_placeholder')} />
</SelectTrigger>
<SelectContent>
<SelectItem value="vara">{t('type_vara')}</SelectItem>
<SelectItem value="tjanst">{t('type_tjanst')}</SelectItem>
</SelectContent>
</Select>
)}
/>
</div>
<div className="space-y-2">
<Label htmlFor="article_number">{t('number_label')}</Label>
<Input
id="article_number"
className="tabular-nums"
{...register('article_number')}
/>
{errors.article_number ? (
<p className="text-sm text-destructive">{errors.article_number.message}</p>
) : (
<p className="text-xs text-muted-foreground">{t('number_hint')}</p>
)}
/>
</div>
</div>
{/* Name */}