38a890c8d1 fix(underlag): carry the phone photo that is too big to send, and say why when we cannot (#1550)
* fix(whatsapp-inbox): register the channel question event types

Every follow-up question the WhatsApp intake asks has been failing its
processing_history append in production: ChannelQuestionAsked,
ChannelQuestionAnswered and ChannelQuestionExpired were never added to
the processing_event_types catalog the event_type FK points at.

appendQuestionHistory() catches and logs that failure by design, so the
reply to the sender still goes out and nothing looked broken from the
outside. What was lost is the durable record of the exchange, which is
part of how the underlag was obtained (BFNAR 2013:2 kap 8).

Catalog rows only: aggregate_type 'System' already passes the CHECK.

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

* fix(underlag): say why an upload failed, and get out of an expired session

A user reported that none of the three ways to add a receipt from a
phone worked, all of them answering "Uppladdning misslyckades. Nagot
gick fel, forsok igen" immediately. Production told us nothing: every
upload request that reached the route in the same 24 hours returned 200.

Both halves of that are the same bug. The workspace read failures as
`throw new Error(json.error)`, which loses a body that is not JSON (the
res.json() call throws first) and stringifies the structured envelope to
"[object Object]", so anything the route did not answer with a plain
string arrived as the generic fallback. The middleware 401 for an
expired cookie session is exactly that envelope shape, and a phone tab
left open is exactly where the session expires unnoticed: the
controller's timers are throttled in the background, so the request the
user just made is what finds out.

Now the response is resolved where it fails, through the house helper
that already knows the status map, and an expired session is announced
on the session-timeout BroadcastChannel so the controller signs out and
routes to /login the same way it does for an expired heartbeat. Failed
uploads also post metadata (status, size, mime type, resolved reason) to
/api/log, the one API path exempt from the timeout gate, so a request
answered before the route runs stops being invisible.

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

* fix(underlag): carry the phone photo that is too big to send

The reported failure was not the account and not the session: hosted
rejects any request body over 4.5 MB itself, before the function runs.
Measured against production, 4.4 MB reaches the route and 4.6 MB comes
back as a plain-text FUNCTION_PAYLOAD_TOO_LARGE. Nothing invokes the
function, so nothing lands in the logs, which is why one user's failing
uploads were invisible while every upload that arrived returned 200. An
iPhone photo in "Most Compatible" mode is 4-12 MB, so whether it worked
depended on whose phone took the picture. Meanwhile the route advertises
a 10 MB limit it can never be handed.

Photos are now re-encoded in the browser when they exceed what the
platform will carry: 2400px on the long edge at JPEG q0.85, stepping the
quality down only if that is not enough. That keeps the small print on a
receipt legible, which is what BFL 7 kap asks of an archived underlag
("varaktigt läsbart skick", a faithful reproduction), and a refusal is
not. What cannot be shrunk (a PDF, or HEIC where the browser will not
decode it) is refused before the upload starts, naming its actual size
and the limit rather than failing in transit.

413 joins the HTTP status map so a rejection we cannot pre-empt still
says what happened: the platform's body is plain text, so the status is
the only thing there is to translate.

Self-hosted Docker has no proxy in front of the app, so none of this
applies there and the route's own MAX_FILE_SIZE keeps governing.

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

---------

Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-13 09:39:23 +02:00
2026-07-21 23:00:15 +02:00
2026-06-12 16:35:30 +02:00
2026-07-21 23:00:15 +02:00
2026-07-24 15:03:50 +02:00
2026-07-21 23:00:15 +02:00
2026-07-05 03:05:09 +02:00
2026-07-24 15:03:50 +02:00
2026-07-23 16:16:55 +02:00
2026-07-05 03:05:09 +02:00
2026-07-05 03:05:09 +02:00

Accounted

Open-source Swedish accounting software for sole traders (enskild firma) and limited companies (aktiebolag). Double-entry bookkeeping that complies with Swedish accounting law, built to be operated by you or by your AI agent.

License: AGPL-3.0-or-later Core Build pg-real tests Docker

Website · Hosted app · Documentation

Why Accounted?

Compliant by construction. Accounted implements double-entry bookkeeping under Swedish accounting law (Bokföringslagen). Voucher immutability, sequential voucher numbering, period locks, and 7-year document retention are enforced by database triggers, not by convention. Corrections are made the legal way, with reversal entries (storno), never by editing history. See ARCHITECTURE.md for how.

Agent-native. The full bookkeeping engine is exposed as 100+ MCP (Model Context Protocol) tools with scoped API keys, so an AI agent can do the books in Accounted: categorize transactions, draft vouchers, reconcile periods, and prepare declarations. Posting is staged for human approval, so the agent proposes and you decide.

Yours to run. AGPL-3.0 licensed and fully self-hostable with Docker and Supabase. Use the hosted version at app.gnubok.se or run your own.

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
  • Payroll -- Salary runs, payslips, and AGI (arbetsgivardeklaration) employer declarations
  • 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
  • Agent access (MCP) -- 100+ bookkeeping tools over the Model Context Protocol, with scoped API keys and staged approvals
  • Extension system -- Opt-in plugins for AI categorization, receipt OCR, email, calendar, and more

Self-Hosting

git clone https://github.com/erp-mafia/accounted.git
cd accounted
./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 docs/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

See CONTRIBUTING.md for the full development workflow.

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

Community

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%