Files
accounted/CONTRIBUTING.md
Jakob Wennberg 3d1ed15b6d feat(registry): move community registry source of truth into the public repo (#1458)
* feat(registry): move community registry source of truth into the public repo

The site's registry page says "Lägg till en egen" and links here, but the
MDX entries lived in the private website repo, so an external contributor
had no path to open the PR we were inviting (found by the first person who
tried). This makes the invitation real:

- registry/entries/ + registry/authors/ hold the 20 existing entries and
  2 author profiles, migrated verbatim from the website repo, which now
  syncs FROM this directory instead of owning the content
- registry/README.md documents the frontmatter convention and the flow
- scripts/validate-registry.ts (npm run validate:registry, wired into
  core-build) checks structure and rejects JSX/import/export in bodies:
  the site renders entries through MDX, which would execute those inside
  the website build
- CONTRIBUTING.md points at the registry for listing community work

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>

* fix(registry): close MDX-safety gaps and correct six compliance claims from PR review

Review bot findings on #1458, both verified and addressed:

- The body safety gate only rejected capitalized JSX tags, but MDX also
  evaluates lowercase HTML tags (<div>, <img onerror=...>) and bare {...}
  expressions. The validator now rejects any raw tag and any brace outside
  fenced code and backtick inline code; literal tags in prose go in
  backticks. Verified: a crafted entry with all three bypasses fails, all
  existing content still passes.
- Six factual errors in migrated entries, each checked against the skill
  sources in .claude/skills/ before editing (these were live on the site
  already): traktamente 2026 is 300 kr not 260; employer contributions for
  66+ at year start (67+ from 2026) are 10.21% not "65+: 16.36%", and the
  under-18 0% claim is replaced with the documented 18-22 youth reduction;
  electronics reverse-charge threshold is 100 000 kr excl VAT per invoice
  not 250 000; half prisbasbelopp 2026 is 29 600 not 24 750; kostnadsställe
  is SIE dimension 1 not 7; SRU period suffixes encode the fiscal-year end
  range (P1 jan-apr, P2 maj-aug, P4 sep-dec) not fixed months.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>

---------

Signed-off-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-08 10:54:09 +02:00

102 lines
3.7 KiB
Markdown

# Contributing to Accounted
Thank you for your interest in contributing to Accounted. This guide covers the development workflow, coding standards, and submission process.
Everyone interacting in the project is expected to follow the [Code of Conduct](CODE_OF_CONDUCT.md).
## 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](https://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:
```bash
npm run lint
npm test
npm run build
```
4. Commit using [Conventional Commits](https://www.conventionalcommits.org/):
- `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](https://developercertificate.org/) (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 [ARCHITECTURE.md](ARCHITECTURE.md) and [docs/EXTENSIONS.md](docs/EXTENSIONS.md) for the full extension architecture. Quick start:
```bash
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
## Community Registry
The registry at [gnubok.se/community/registry](https://www.gnubok.se/community/registry) (skills, MCP servers, workflows and apps built on Accounted) is sourced from the [`registry/`](registry/) directory in this repo. To list something you built, add an MDX entry there by PR; see [registry/README.md](registry/README.md) for the format and run `npm run validate:registry` for the local check. No code changes needed.
## 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](SECURITY.md).