Jakob WennbergandClaude Opus 4.7 9c13586b13 feat(invoice-inbox): AI extraction (Bedrock Sonnet 4.6) + editable fields (#415)
* feat(invoice-inbox): AI extraction via Bedrock + editable fields

Two big changes that go together:

1. Replace the regex extractor with Claude Sonnet 4.6 via AWS Bedrock.
   The PDF or image is sent directly to the model — no unpdf, no DOM
   stubs, no worker bundling. Sonnet handles English receipts (Anthropic,
   AWS, Stripe), USD/EUR currency symbols, scanned PDFs and image
   receipts, and Subtotal vs Total disambiguation that the regex layer
   couldn't. Output is JSON, validated with Zod; anything that doesn't
   parse falls back to an empty result so the inbox row still lands.

2. Make the extracted fields editable inline in the workspace. Each
   field is an Input bound to local draft state with debounced
   auto-save (800ms) to a new PATCH /items/:id/fields route. The route
   refuses edits once the item is converted to a supplier invoice. The
   parent updates both the selected-item view and the list rail when a
   field saves so the summary stays in sync.

Drops `unpdf`, adds `@anthropic-ai/bedrock-sdk`. Requires three env vars
in Vercel prod (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION) —
not yet set; when missing, the extractor logs a warning and returns
empty so the upload still works.

All 43 invoice-inbox unit tests pass. tsc clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(invoice-inbox): loading state + #415 review fixes

Loading state for AI extraction:
- Optimistic placeholder row inserted into the workspace list the moment
  an upload starts. Shows the file name + a "Tolkar dokument med AI…"
  spinner instead of timestamp/amount.
- Document preview pane shows a centered loader + same caption while the
  placeholder is selected.
- Fields rail shows 6 skeleton inputs + the same caption.
- Action buttons are hidden until the real row arrives.
- Placeholder is removed on success or failure (toast on error).

PR #415 review follow-ups (Greptile + Swedish compliance bot):
- Bump max_tokens 1500 → 4096 so multi-line invoices don't silently
  truncate mid-JSON and land with all-null fields.
- Tighten NullableDate to range-checked regex + Date.parse refine —
  rejects 2026-13-45 / 2026-02-30 with a clean 400 instead of a 500.
- Make vatRate representation consistent: percent integer (25, 12, 6, 0)
  for both lineItems[].vatRate AND vatBreakdown[].rate. Previously the
  AI was instructed to emit decimals for one and integers for the other.
- EditableFieldsList re-seeds drafts when the parent passes a new data
  snapshot, but only on fields where the local draft still matches the
  previous server value — so a server-normalised currency upper-cases
  cleanly without clobbering an in-progress edit.
- 409 conflict (item already linked to a supplier invoice) shows the
  server's specific Swedish message ("Posten är låst") instead of the
  generic "Kunde inte spara".

Out of scope (separate tickets if needed): live updates for
email-arrived items, AWS_SESSION_TOKEN plumbing, 6 % livsmedel rate
transition validation, server-side totals consistency check.

All 43 invoice-inbox unit tests pass. tsc clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(invoice-inbox): tighten extraction schema per compliance bot review

Three follow-ups from the Swedish compliance bot's second pass on #415:

1. lineItems[].vatRate and vatBreakdown[].rate now refine to 0–100,
   blocking AI hallucinations like 5000% or negative rates while still
   accepting non-Swedish rates (UK 20, DE 19) since gnubok stores foreign
   invoices for reference. The strict Swedish [0, 6, 12, 25] allowlist is
   not enforced here on purpose — that check belongs in the supplier-
   invoice-creation step where the data hits the ledger.

2. accountSuggestion is now coerced to null at parse time via .transform,
   eliminating the brief intermediate window where a hallucinated string
   could appear in the parsed object before the post-validation .map()
   nulled it. Removes the redundant .map() afterwards.

3. PATCH /items/:id/fields currency now requires ISO 4217 format
   (^[A-Z]{3}$). Previously accepted any 3–8 char string, which would
   flow into supplier-invoice creation and produce a faktura with an
   invalid currency.

Test fixture vatRate updated 0.25 → 25 to match the percent-integer
convention introduced in the previous commit.

All 43 invoice-inbox unit tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 15:21:55 +02:00
2026-05-07 13:32:06 +02:00
2026-05-06 11:12:02 +02:00
2026-04-22 15:33:04 +02:00
2026-04-20 21:03:23 +02:00

gnubok

Open-source Swedish accounting software for sole traders (enskild firma) and limited companies (aktiebolag).

License: AGPL-3.0-or-later

What is gnubok?

gnubok implements double-entry bookkeeping compliant with Swedish accounting law (Bokforingslagen). It supports the BAS 2026 chart of accounts, handles VAT declarations (momsdeklaration), SIE import/export, and enforces 7-year document retention. Built for sole traders and limited companies operating in Sweden.

Features

  • Double-entry bookkeeping -- BAS 2026 chart of accounts, draft/commit workflow, sequential voucher numbering
  • Invoicing -- Create, send, and track invoices with mixed VAT rates and PDF generation
  • Bank reconciliation -- PSD2 bank connection via Enable Banking, 4-pass automatic matching
  • VAT declaration -- SKV 4700 form mapping, per-rate breakdown, EU/export handling
  • Tax reports -- NE-bilaga, INK2, SRU export for Skatteverket
  • Supplier invoices -- Registration, payment tracking, input VAT deduction
  • Document archive -- SHA-256 integrity, 7-year retention enforcement, full archive ZIP export
  • SIE import/export -- Standard Swedish accounting interchange format
  • Extension system -- Opt-in plugins for AI categorization, receipt OCR, email, calendar, and more

Self-Hosting

git clone https://github.com/erp-mafia/gnubok.git
cd gnubok
./setup.sh              # Prompts for Supabase credentials, generates .env
docker compose up -d

You need a Supabase project and must apply the database migrations before first use. See SELF-HOSTING.md for the full step-by-step guide, including Supabase setup, auth configuration, optional features (AI, email, push notifications), and troubleshooting.

Development Setup

Prerequisites: Node.js 20+, a Supabase project.

npm install
npm run dev       # Start dev server (auto-generates extension registry)
npm test          # Run tests
npm run build     # Production build
npm run lint      # ESLint

Tech Stack

  • Framework: Next.js 16 (App Router), React 19, TypeScript (strict)
  • Database: Supabase (PostgreSQL + Row Level Security + email/password auth + TOTP MFA)
  • Styling: Tailwind CSS 4 + shadcn/ui
  • Integrations: Enable Banking (PSD2), Anthropic SDK, LangChain, OpenAI, Resend, JSZip

Documentation

  • SELF-HOSTING.md -- Full self-hosting guide (Docker, Supabase setup, migrations, optional features)
  • CLAUDE.md -- Architecture, bookkeeping engine, database conventions, extension system
  • CONTRIBUTING.md -- Development workflow, code style, pull request process
  • SECURITY.md -- Vulnerability reporting policy

Contributing

Contributions are welcome. See CONTRIBUTING.md for the full guide.

All commits require a DCO sign-off (git commit -s).

License

AGPL-3.0-or-later with an extension exception: third-party extensions that interact solely through the documented Extension API may be licensed under any terms, including proprietary. See LICENSE for details and NOTICE for third-party attributions.

S
Description
Accounted — svensk bokföringsmotor (AGPL, BAS 2026, BFL-compliant, 150+ MCP tools). Finance-kapacitet brevet ERPNext. ADR-ENGAGEMENT-001-tillägg.
Readme AGPL-3.0
56 MiB
Languages
TypeScript 93%
PLpgSQL 5.8%
JavaScript 0.4%
HTML 0.3%
MDX 0.2%
Other 0.1%