diff --git a/.github/workflows/core-build.yml b/.github/workflows/core-build.yml new file mode 100644 index 00000000..2d52aa8e --- /dev/null +++ b/.github/workflows/core-build.yml @@ -0,0 +1,30 @@ +name: Core Build (no extensions) + +on: [pull_request] + +jobs: + core-only: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - run: npm ci + - name: Reset extensions config + run: echo '{"extensions":[]}' > extensions.config.json + - run: npm run setup:extensions + - run: npm run build + - run: npm test + - name: Check no core imports from extensions + run: | + VIOLATIONS=$(grep -r "from '@/extensions/" lib/ app/api/ components/ --include="*.ts" --include="*.tsx" \ + | grep -v "app/api/extensions/" \ + | grep -v "components/extensions/" \ + | grep -v "lib/extensions/_generated/" \ + | grep -v "lib/extensions/loader.ts" || true) + if [ -n "$VIOLATIONS" ]; then + echo "ERROR: Core code imports from @/extensions/:" + echo "$VIOLATIONS" + exit 1 + fi diff --git a/.gitignore b/.gitignore index b3f47885..c8247446 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,8 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + +# Extension registry (auto-generated but defaults are committed) +# Run `npm run setup:extensions` to regenerate after changing extensions.config.json +# The empty defaults in lib/extensions/_generated/ are committed so core compiles +# out of the box without running the generator. diff --git a/CLAUDE.md b/CLAUDE.md index a87b7dbd..9ad17b9f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -17,11 +17,12 @@ erp-base is a Swedish-focused accounting SaaS for sole traders (enskild firma) a ## Commands ```bash -npm run dev # Start development server -npm run build # Production build -npm run lint # ESLint -npm test # Run all Vitest tests -npx vitest run
Kostnad
-{p.totalCost.toLocaleString('sv-SE')} kr
-Intakt
-{p.totalRevenue.toLocaleString('sv-SE')} kr
-Marginal
-{p.margin}%
-{p.name}
-{p.name}
-= 0 ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400' - )}> - {p.margin}% marginal -
-- Lagg till kunder under fliken "Kunder" for att borja berakna ROT-avdrag. -
-{newCustomerPnrError}
- )} -Inga kunder tillagda annu.
- ) : ( -{cust.name}
- {cust.personalNumber && ( -{cust.personalNumber}
- )} -Inga jobb registrerade for {selectedYear}.
- ) : ( -{editCustomerPnrError}
- )} -Inga ordrar hittades.
- ) : ( - <> -- {filteredOrders.length} ordrar totalt -
-{error}
-Växelkurser
-- {formatSEK(report.totals.currentSekValue)} -
-SEK (aktuell kurs)
-- Inga öppna fordringar i utländsk valuta. -
-- Inga realiserade kursdifferenser för {year}. -
- ) : ( -Omvärdering vid periodbokslut
-- Om bokslut görs idag: netto orealiserad{' '} - = 0 ? 'text-green-600' : 'text-red-600' - )}> - {report.revalPreview.totalUnrealizedGainLoss >= 0 ? 'vinst' : 'förlust'}{' '} - {report.revalPreview.totalUnrealizedGainLoss >= 0 ? '+' : ''} - {formatSEK(report.revalPreview.totalUnrealizedGainLoss)} SEK - -
- {report.revalPreview.gains > 0 && ( -- Konto 3969 (orealiserad kursvinst): {formatSEK(report.revalPreview.gains)} kr -
- )} - {report.revalPreview.losses > 0 && ( -- Konto 7969 (orealiserad kursförlust): {formatSEK(report.revalPreview.losses)} kr -
- )} -- Bokföringsposterna skapas inte av detta tillägg. Använd värdena ovan som underlag vid periodbokslut. -
-- {sym}{formatAmount(exposure.totalForeignAmount)} -
-- {formatSEK(exposure.currentSekValue)} SEK -
-{error}
-Inlämningsdeadline
-- {formatDeadlineDate(report.deadline)} -
-- {report.daysUntilDeadline > 0 - ? `${report.daysUntilDeadline} dagar kvar` - : report.daysUntilDeadline === 0 - ? 'Deadline idag!' - : `${Math.abs(report.daysUntilDeadline)} dagar försenad` - } -
-Avstämning mot huvudbok
- {report.crossCheck ? ( -- Ingen bokföringsdata tillgänglig för perioden. -
- )} -- Inga EU-försäljningar hittades för vald period. -
- ) : ( -{error}
-Tröskelvärde Intrastat (utförsel)
-Fakturerat värde
-{formatSEK(report.totals.invoicedValue)}
-SEK
-Nettovikt
-{report.totals.netMass.toLocaleString('sv-SE')}
-kg
-Deklarationsrader
-{report.totals.lineCount}
-{report.invoiceCount} fakturor
-- Inga produkter registrerade. Lägg till produkter med CN-kod och vikt för att generera Intrastat-deklarationer. -
- ) : ( -- Inga EU-varuförsäljningar hittades för perioden. -
- ) : ( -{error}
-{label}
-- {formatSEK(data.amount)} -
-- {report.vatSummary.isRefund ? 'Moms att få tillbaka' : 'Moms att betala'} -
-Belaggning (nuvarande)
-Belaggning (foregaende)
- {prevOccupancyPct}% -Foregaende period
- {prevPeriod.start} — {prevPeriod.end} -Belagda rum (foregaende)
- - {prevDaysInRange > 0 - ? Math.round(prevTotalOccupied / prevDaysInRange) - : 0} snitt / dag - -Dagar med data (foregaende)
- {prevDaysInRange} dagar -- Belagda rum ({formOccupied}) + ur drift ({formOoo}) = {formOccupied + formOoo} overstiger totalt antal rum ({totalRooms}). -
- )} -Ingen data registrerad i vald period.
- ) : ( -- Belagda rum ({editOccupiedNum}) + ur drift ({editOooNum}) = {editOccupiedNum + editOooNum} overstiger totalt antal rum ({totalRooms}). -
- )} -RevPAR
-- Foregaende: {prev.revpar.toLocaleString('sv-SE')} kr -
-ADR
-- Foregaende: {prev.adr.toLocaleString('sv-SE')} kr -
-Belaggning
-- Foregaende: {prev.occupancyPct}% -
-- Foregaende period: {prevPeriod.start} — {prevPeriod.end} -
-{roomsSoldError}
- )} -{roomRevenueError}
- )} -Ingen data registrerad i vald period.
- ) : ( -{editRoomsSoldError}
- )} -{editRoomRevenueError}
- )} -Ange ett giltigt antal rum (minst 1)
- )} -Uppskattad vs bokford intakt
-- Differens baserat pa snittkr/liter per kategori -
-- {(Math.round((estimatedRevenue - alcoholRevenue) * 100) / 100).toLocaleString('sv-SE')} kr -
-Inga registreringar i vald period.
- ) : ( -Intakt/liter (nuvarande)
-{earningsPerLiter.toLocaleString('sv-SE')} kr/l
- {prevEarningsPerLiter > 0 && ( -Liter (nuvarande)
-{(Math.round(totalLiters * 100) / 100).toLocaleString('sv-SE')} l
- {prevTotalLiters > 0 && ( -Uppsk. intakt (nuvarande)
-{estimatedRevenue.toLocaleString('sv-SE')} kr
- {prevEstimatedRevenue > 0 && ( -Lagg till, ta bort eller byt namn pa dryckkategorier.
-- Anvands for att berakna uppskattad intakt per kategori. -
-Food Cost % (nuvarande)
-Food Cost % (foregaende)
- {prevFoodCostPct}% -Foregaende period
- {prevPeriod.start} — {prevPeriod.end} -Varuinkop (foregaende)
- {prevTotalPurchases.toLocaleString('sv-SE')} kr -Intakter (foregaende)
- {prevTotalRevenue.toLocaleString('sv-SE')} kr -Malvarde
-- Riktvarde for food cost (vanligtvis 25-35%) -
-Anteckningar for {currentMonth}
-- Notera avvikelser och forklaringar for perioden -
-{currentNote.text}
- ) : ( -Inga anteckningar for denna period.
- )} -Ingen data importerad annu.
- ) : ( - <> -- Visar {page * PAGE_SIZE + 1}-{Math.min((page + 1) * PAGE_SIZE, dailySales.length)} av {dailySales.length} rader -
-- Lagg till anstallda under fliken "Anstallda" for att borja registrera dricks. -
-Inga registreringar i vald period.
- ) : ( -Inga anstallda tillagda annu.
- ) : ( -- Fordela dricks fran en gemensam pool till utvalda anstallda. -
-Inga aktiva anstallda.
- ) : ( -- Summa: {customPctTotal}% {Math.abs(customPctTotal - 100) >= 0.01 && '(maste vara 100%)'} -
-- Lagg till projekt under fliken "Projekt" for att borja rapportera tid. -
-Ingen tid registrerad idag.
- ) : ( -- Lagg till projekt under fliken "Projekt" for att borja rapportera tid. -
-Inga projekt att visa.
- ) : ( -{p.budget.toLocaleString('sv-SE')} kr
-{formatKr(p.totalBilled).toLocaleString('sv-SE')} kr
-{formatKr(p.totalCosts).toLocaleString('sv-SE')} kr
-= 0 ? 'text-green-600' : 'text-red-600' - )}> - {p.margin}% -
-Inga faktureringsrader annu.
- )} -Inga kostnader registrerade annu.
- )} -Inga aktiva projekt. Skapa ett nytt projekt ovan.
- )} - - {/* Completed projects */} - {completedProjects.length > 0 && ( -Ingen fakturering registrerad annu.
- ) : ( -- Skapar automatiskt bokföringsposter för transaktioner med hög konfidens -
-- Importerade transaktioner som inte automatiskt bokförs visas som - "obokförda" på transaktionssidan. Du kan bokföra dem manuellt - efteråt. + Importerade transaktioner visas som "obokförda" på + transaktionssidan. Du kan bokföra dem manuellt efteråt.
Osaker? Prova dessa mallar:
-