Files
accounted/CONTRIBUTING.md
T
Jakob Wennberg c74b19df1b Accounted rebrand + swarm-skill cleanup + bank-reconciliation fixes (#643)
* feat(reconciliation): close the bank-feed loop on voucher links and re-tag mis-typed opening balances

Two related fixes to bank reconciliation correctness:

1. Auto-reconcile on voucher link. Linking an invoice or supplier invoice to
   an existing voucher previously advanced only the invoice — the bank
   transaction that paid it kept sitting in the Transactions inbox with a null
   journal_entry_id. linkInvoiceToVoucher / linkSupplierInvoiceToVoucher now
   call autoReconcileTransactionForLinkedVoucher (lib/reconciliation), which
   links the bank transaction to the same verifikat when exactly one unbooked
   line matches it. Best-effort and post-commit: a failure here never fails the
   link. The result surfaces reconciledTransactionId; the inbox row leaves the
   list and the UI shows link_success_tx_reconciled.

2. Re-tag mis-typed opening balances. getReconciliationStatus and the GL-line
   matching RPCs identify a cash account's ingående balans solely by
   journal_entries.source_type='opening_balance'. Companies migrated from other
   systems often booked the bank IB as an ordinary voucher (source_type
   'import' or 'manual'), so it was never excluded and surfaced as a phantom
   reconciliation difference equal to the opening balance. Adds:
   - migration mark_entry_as_opening_balance: a GUC-gated carve-out in the
     immutability trigger plus a SECURITY DEFINER RPC that validates the entry
     (balance-sheet lines only, dated on a fiscal-period boundary), flips the
     source_type, and writes an audit row — no blanket data sweep.
   - POST /api/reconciliation/bank/mark-opening-balance + MarkOpeningBalanceSchema.
   - BankReconciliationView action to trigger it from the IB diff.

The gnubok_create_voucher executor now accepts a typed is_opening_balance flag
and derives source_type='opening_balance' only after validating class 1/2 lines
on the period start, so new IBs land correctly typed.

Covered by lib/reconciliation auto-reconcile tests, voucher-executors tests,
and a mark-entry-as-opening-balance pg-real test.

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

* chore: rebrand gnubok → Accounted and prune swarm agent skills

Product rebrand and skills housekeeping. No runtime behaviour change.

Rebrand: replace user-visible "gnubok" with "Accounted" across docs, READMEs,
in-code comments, doc-site content, MCP skill/resource prose, and the
gnubok-mcp package description. The MCP resource URI scheme is moved gnubok://
→ Accounted:// consistently across resource registrations, the event-type
comment, and the resource/skill tests. Deliberately preserved as stable
identifiers (NOT rebranded): the gnubok-company-id cookie, gnubok_sk_ / gnubok_inv_
token prefixes, the gnubok-mcp npm bridge name, and the AGI <gem:Programnamn>
value (kept 'gnubok' per its source comment — it is the software identifier sent
to Skatteverket and must not churn across visual rebrands).

Skills: remove the 27 swarm-* agent SKILL.md atoms (no longer used; already
absent from the agent_atom_registry in prod), refresh the remaining skill docs,
add the .claude/rules/ path-scoped rule set, and regenerate the
seed_agent_atom_bodies migration + .skill-body-manifest.json via
`npm run skills:generate` so the DB-backed skill bodies match the trimmed set.

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 10:52:01 +02:00

3.1 KiB

Contributing to Accounted

Thank you for your interest in contributing to gnubok. This guide covers the development workflow, coding standards, and submission process.

Getting Started

  1. Fork the repository and clone your fork
  2. Install dependencies: npm install
  3. Start the dev server: npm run dev
  4. Run tests: npm test

Supabase Setup

You need a Supabase project for local development:

  1. Create a free project at supabase.com
  2. Run all migrations from supabase/migrations/ against your project
  3. Copy .env.example to .env and fill in your Supabase credentials:
    • NEXT_PUBLIC_SUPABASE_URL
    • NEXT_PUBLIC_SUPABASE_ANON_KEY
    • SUPABASE_SERVICE_ROLE_KEY

Development Workflow

  1. Create a branch from main with a descriptive name
  2. Make your changes following the code style below
  3. Run the full check suite before submitting:
npm run lint
npm test
npm run build
  1. Commit using Conventional Commits:
    • feat: new feature
    • fix: bug fix
    • refactor: code restructuring
    • test: adding or updating tests
    • docs: documentation changes

DCO Sign-Off

All commits must include a Signed-off-by line certifying that you have the right to submit the contribution under the project's license. This is the Developer Certificate of Origin (DCO).

Add the sign-off automatically with git commit -s:

feat: add VAT report export

Signed-off-by: Your Name <your.email@example.com>

If you forget, you can amend: git commit --amend -s.

Pull Requests

  • Keep PRs focused on a single change
  • Include a clear description of what and why
  • Ensure CI passes (the core build resets extensions to empty, so core code must compile standalone)
  • Link related issues if applicable

Extension Development

See CLAUDE.md for the full extension architecture. Quick start:

npx tsx scripts/create-extension.ts --name my-ext --sector general --category operations --description "..."

Then add "my-ext" to extensions.config.json and run npm run setup:extensions.

Constraints:

  • Extensions cannot use dynamic imports (Next.js bundling requirement)
  • Core must build and run with zero extensions enabled
  • Never import from @/extensions/ in core code

What Not to Do

  • Don't modify enforcement triggers in migration 017 (legally required for Swedish accounting law)
  • Don't insert directly into journal tables -- use the engine functions in lib/bookkeeping/engine.ts
  • Don't break the core/extension boundary -- core must compile standalone without extensions
  • Don't delete posted journal entries -- use storno reversal via reverseEntry()

Code Style

  • TypeScript strict mode, no any unless unavoidable
  • English for all code, comments, and commit messages
  • Math.round(x * 100) / 100 for monetary calculations, never toFixed()
  • Account numbers are strings ('1930', not 1930)
  • All shared types go in types/index.ts

Questions?

Open a discussion or issue on GitHub. For security vulnerabilities, see SECURITY.md.