24 KiB
BAS Accounting Guide for Creator Economy
Overview
This document provides the accounting logic layer for automatic transaction categorization using the Swedish BAS-kontoplan. It covers MCC code mapping, expense validation rules, and VAT handling for influencer-specific transactions.
BAS Account Structure
The BAS-kontoplan uses a hierarchical 4-digit system where each position carries semantic meaning:
| Position | Name | Example | Meaning |
|---|---|---|---|
| 1 | Kontoklass | 5410 | Category (5 = External costs) |
| 2 | Kontogrupp | 5410 | Type (54 = Consumables) |
| 3 | Huvudkonto | 5410 | Main account for reporting |
| 4 | Underkonto | 5410 | Detail level, VAT codes |
This enables validation logic built directly on account number structure.
Account Classes Overview
| Class | Swedish | English | Influencer Relevance |
|---|---|---|---|
| 1xxx | Tillgångar | Assets | Equipment, bank accounts |
| 2xxx | Eget kapital & Skulder | Equity & Liabilities | VAT, owner withdrawals |
| 3xxx | Intäkter | Revenue | Platform income, sponsorships |
| 4xxx | Direkta kostnader | Direct costs | Merchandise COGS (rare) |
| 5xxx | Övriga externa kostnader | Other external costs | 90% of expenses land here |
| 6xxx | Övriga externa kostnader | Other external costs | Services, representation |
| 7xxx | Personalkostnader | Personnel costs | AB salary (see salary module) |
| 8xxx | Finansiella poster | Financial items | Interest, currency gains/losses |
Critical BAS Accounts for Influencers
Assets (Class 1)
| Account | Name | Use Case | Notes |
|---|---|---|---|
| 1210 | Maskiner och inventarier | Cameras, computers > 29,400 kr | Depreciate over 5 years (20%/year) |
| 1930 | Företagskonto | Main bank account | Primary reconciliation account |
Equity & Liabilities (Class 2)
| Account | Name | Use Case | Notes |
|---|---|---|---|
| 2010 | Eget kapital | Owner's equity | Rolling balance |
| 2013 | Eget uttag | Private expenses paid with business card | Critical for rejected deductions |
| 2018 | Egen insättning | Owner deposits / travel allowance credit | Traktamente booking |
| 2440 | Leverantörsskulder | Accounts payable | If not paying immediately |
| 2611 | Utgående moms 25% | Output VAT 25% | Swedish domestic sales |
| 2614 | Utg. moms utländska förvärv | Output VAT on foreign purchases | Reverse charge (credit side) |
| 2641 | Ingående moms | Input VAT | Deductible VAT on purchases |
| 2645 | Ing. moms utländska förvärv | Input VAT on foreign purchases | Reverse charge (debit side) |
Revenue (Class 3)
| Account | Name | Use Case | Notes |
|---|---|---|---|
| 3001 | Försäljning 25% | Swedish sponsorships/collaborations | Standard domestic |
| 3044 | Försäljning tjänst EU | AdSense (Ireland), EU affiliates | VAT-free, requires Periodisk sammanställning |
| 3045 | Försäljning tjänst Export | Twitch (USA), non-EU platforms | VAT-free (export) |
| 3900 | Övriga intäkter | Stipends, royalties, misc |
Costs (Class 5-6)
| Account | Name | Use Case | Notes |
|---|---|---|---|
| 5010 | Lokalhyra | Studio rental | Not for home office (strict rules) |
| 5410 | Förbrukningsinventarier | Cameras, computers < 29,400 kr | Direct deduction |
| 5420 | Programvaror | Adobe CC, Epidemic Sound, SaaS | Licenses/subscriptions |
| 5480 | Arbetskläder | Protective gear, uniforms | NOT regular clothes |
| 5490 | Övriga förbrukningsartiklar | Props, consumable supplies | |
| 5800 | Resekostnader | Train, flights, car rental | VAT varies (6% domestic travel) |
| 5820 | Taxikostnader | Taxi, Uber | |
| 5831 | Kost och logi Sverige | Hotels in Sweden | 12% VAT |
| 5832 | Kost och logi utlandet | Hotels abroad | No VAT recovery |
| 5841 | Traktamente, avdragsgillt | Travel allowance | Calculated per Skatteverket rates |
| 5890 | Övriga resekostnader | Non-deductible travel portion | For mixed-use trips |
| 5910 | Annonsering | Facebook Ads, Google Ads | Often triggers reverse charge |
| 5930 | Reklamtrycksaker | Promotional materials | |
| 6071 | Representation, avdragsgill | Simple refreshments (max 60 kr/person) | Very limited deduction |
| 6072 | Representation, ej avdragsgill | Meals for representation | VAT still deductible |
| 6230 | Datakommunikation | Web hosting, domains, internet | Infrastructure |
| 6500 | Övriga externa tjänster | Photographers, editors (with F-skatt) | Consultant services |
| 6991 | Övriga avdragsgilla kostnader | Miscellaneous deductible | Use sparingly |
| 6992 | Övriga ej avdragsgilla | Fines, penalties | No tax effect |
MCC Code Mapping
Merchant Category Codes (MCC) are the primary signal for automatic categorization from bank transactions.
Implementation
// lib/accounting/mcc-mapping.ts
interface MCCMapping {
mcc: string
description: string
riskLevel: 'low' | 'medium' | 'high' | 'very_high'
primaryAccount: string
secondaryAccount?: string
requiresUserInput: boolean
autoRejectReason?: string
logic: string
}
const MCC_MAPPINGS: MCCMapping[] = [
// ADVERTISING & MARKETING
{
mcc: '7311',
description: 'Advertising Services',
riskLevel: 'low',
primaryAccount: '5910',
secondaryAccount: '5930',
requiresUserInput: false,
logic: 'Standard for Facebook/Google Ads. Triggers EU VAT check.'
},
// ELECTRONICS & EQUIPMENT
{
mcc: '5732',
description: 'Electronics Stores',
riskLevel: 'medium',
primaryAccount: '5410',
secondaryAccount: '1210',
requiresUserInput: false,
logic: 'Amount determines routing. >29,400 kr → 1210 (asset).'
},
{
mcc: '5946',
description: 'Camera & Photo Supply',
riskLevel: 'medium',
primaryAccount: '5410',
secondaryAccount: '1210',
requiresUserInput: false,
logic: 'Same as electronics. Check amount threshold.'
},
// RESTAURANTS & FOOD - HIGH RISK
{
mcc: '5812',
description: 'Eating Places/Restaurants',
riskLevel: 'high',
primaryAccount: '6072',
secondaryAccount: '2013',
requiresUserInput: true,
logic: 'Requires user input: Representation or private? Default to private (2013).'
},
{
mcc: '5814',
description: 'Fast Food',
riskLevel: 'high',
primaryAccount: '2013',
requiresUserInput: false,
autoRejectReason: 'Fast food is typically private expense',
logic: 'Default to eget uttag. Rarely valid business expense.'
},
// CLOTHING - VERY HIGH RISK (Almost always rejected)
{
mcc: '5611',
description: "Men's Clothing",
riskLevel: 'very_high',
primaryAccount: '2013',
secondaryAccount: '5480',
requiresUserInput: true,
autoRejectReason: 'Clothes that can be worn privately are not deductible (RÅ81 1:29)',
logic: 'Default MUST be 2013 (private). Only 5480 if protective/uniform.'
},
{
mcc: '5621',
description: "Women's Ready-to-Wear",
riskLevel: 'very_high',
primaryAccount: '2013',
secondaryAccount: '5480',
requiresUserInput: true,
autoRejectReason: 'Clothes that can be worn privately are not deductible',
logic: 'Default MUST be 2013 (private).'
},
{
mcc: '5631',
description: "Women's Accessories",
riskLevel: 'very_high',
primaryAccount: '2013',
requiresUserInput: false,
autoRejectReason: 'Accessories are private expenses',
logic: 'Always 2013.'
},
// COSMETICS - VERY HIGH RISK
{
mcc: '5977',
description: 'Cosmetic Stores',
riskLevel: 'very_high',
primaryAccount: '2013',
secondaryAccount: '5490',
requiresUserInput: true,
autoRejectReason: 'Cosmetics are private expenses unless specific props',
logic: 'Default private (2013). Only 5490 if clearly production props.'
},
// TRAVEL - MEDIUM RISK
{
mcc: '4111',
description: 'Commuter Transport',
riskLevel: 'low',
primaryAccount: '5800',
requiresUserInput: false,
logic: 'Train/bus. 6% VAT in Sweden.'
},
{
mcc: '4112',
description: 'Passenger Railways',
riskLevel: 'low',
primaryAccount: '5800',
requiresUserInput: false,
logic: 'Train tickets. 6% VAT.'
},
{
mcc: '4121',
description: 'Taxicabs/Limousines',
riskLevel: 'medium',
primaryAccount: '5820',
secondaryAccount: '2013',
requiresUserInput: true,
logic: 'Business trip or private? Ask user.'
},
{
mcc: '4722',
description: 'Travel Agencies',
riskLevel: 'medium',
primaryAccount: '5800',
secondaryAccount: '2013',
requiresUserInput: true,
logic: 'Is the trip business-related? May need to split.'
},
{
mcc: '7011',
description: 'Hotels/Motels',
riskLevel: 'medium',
primaryAccount: '5831',
secondaryAccount: '5832',
requiresUserInput: false,
logic: '5831 for Sweden (12% VAT), 5832 for abroad (no VAT).'
},
// SOFTWARE & DIGITAL SERVICES - LOW RISK
{
mcc: '7372',
description: 'Computer Programming',
riskLevel: 'low',
primaryAccount: '6230',
secondaryAccount: '5420',
requiresUserInput: false,
logic: 'Web hosting, domains, SaaS subscriptions.'
},
{
mcc: '5734',
description: 'Computer Software Stores',
riskLevel: 'low',
primaryAccount: '5420',
requiresUserInput: false,
logic: 'Software licenses.'
},
// ALCOHOL - ALWAYS REJECT
{
mcc: '5921',
description: 'Package Stores (Systembolaget)',
riskLevel: 'very_high',
primaryAccount: '2013',
requiresUserInput: false,
autoRejectReason: 'Alcohol is not deductible',
logic: 'Always 2013. No exceptions.'
},
// GROCERIES - HIGH RISK
{
mcc: '5411',
description: 'Grocery Stores',
riskLevel: 'high',
primaryAccount: '2013',
secondaryAccount: '6072',
requiresUserInput: true,
autoRejectReason: 'Food is typically private expense',
logic: 'Default 2013. Only 6072 if documented representation.'
},
// STREAMING SERVICES
{
mcc: '4899',
description: 'Cable/Streaming Services',
riskLevel: 'medium',
primaryAccount: '5420',
secondaryAccount: '2013',
requiresUserInput: true,
logic: 'Netflix for research? Usually private. Ask user.'
},
// GYM & FITNESS - ALWAYS REJECT
{
mcc: '7941',
description: 'Sports Clubs/Gyms',
riskLevel: 'very_high',
primaryAccount: '2013',
requiresUserInput: false,
autoRejectReason: 'Gym memberships are private expenses, even for fitness influencers',
logic: 'Always 2013. IL 9 kap. 2 §'
}
]
Keyword-Based Categorization
For generic MCCs (Amazon, PayPal), analyze transaction description text.
// lib/accounting/keyword-rules.ts
interface KeywordRule {
keywords: string[]
account: string
confidence: 'high' | 'medium' | 'low'
vatTreatment?: 'standard' | 'reverse_charge' | 'none'
}
const KEYWORD_RULES: KeywordRule[] = [
// Software & Subscriptions
{
keywords: ['adobe', 'creative cloud'],
account: '5420',
confidence: 'high',
vatTreatment: 'reverse_charge' // Adobe Ireland
},
{
keywords: ['epidemic sound'],
account: '5420',
confidence: 'high',
vatTreatment: 'standard' // Swedish company
},
{
keywords: ['canva'],
account: '5420',
confidence: 'high',
vatTreatment: 'reverse_charge'
},
{
keywords: ['spotify', 'spotify ab'],
account: '2013', // Usually private
confidence: 'medium'
},
{
keywords: ['spotify for business', 'soundtrack'],
account: '5420',
confidence: 'high'
},
// Web Infrastructure
{
keywords: ['one.com', 'loopia', 'godaddy', 'namecheap', 'cloudflare'],
account: '6230',
confidence: 'high'
},
{
keywords: ['vercel', 'netlify', 'heroku', 'aws', 'digitalocean'],
account: '6230',
confidence: 'high',
vatTreatment: 'reverse_charge'
},
// Advertising Platforms
{
keywords: ['facebook', 'meta', 'instagram ads', 'fb ads'],
account: '5910',
confidence: 'high',
vatTreatment: 'reverse_charge' // Meta Ireland
},
{
keywords: ['google ads', 'adwords'],
account: '5910',
confidence: 'high',
vatTreatment: 'reverse_charge' // Google Ireland
},
{
keywords: ['tiktok ads', 'tiktok for business'],
account: '5910',
confidence: 'high',
vatTreatment: 'reverse_charge'
},
// Transport
{
keywords: ['uber', 'bolt', 'taxi'],
account: '5820',
confidence: 'medium' // Could be private
},
{
keywords: ['sj', 'mtrx', 'sj biljett'],
account: '5800',
confidence: 'high'
},
{
keywords: ['sas', 'norwegian', 'ryanair', 'flygbiljett'],
account: '5800',
confidence: 'medium' // Could be private trip
},
// Always Private
{
keywords: ['systembolaget'],
account: '2013',
confidence: 'high'
},
{
keywords: ['apotek', 'apoteket', 'apotea'],
account: '2013',
confidence: 'high'
},
{
keywords: ['ica', 'coop', 'willys', 'hemköp', 'lidl'],
account: '2013',
confidence: 'medium' // Usually private groceries
}
]
Amount-Based Routing (Asset vs Expense)
// lib/accounting/asset-routing.ts
const PRISBASBELOPP_2025 = 58800
const HALF_PBB = PRISBASBELOPP_2025 / 2 // 29,400 kr
interface AssetDecision {
shouldCapitalize: boolean
account: string
depreciationYears?: number
depreciationRate?: number
}
function routeEquipmentPurchase(
amountExVat: number,
mccCode: string
): AssetDecision {
const isEquipmentMCC = ['5732', '5946', '5045'].includes(mccCode)
if (!isEquipmentMCC) {
return { shouldCapitalize: false, account: '5410' }
}
if (amountExVat > HALF_PBB) {
return {
shouldCapitalize: true,
account: '1210',
depreciationYears: 5,
depreciationRate: 0.20
}
}
return {
shouldCapitalize: false,
account: '5410'
}
}
// Update HALF_PBB annually - Skatteverket publishes in November
Reverse Charge VAT Handling
When purchasing services from foreign (usually EU) companies, Swedish businesses must self-report VAT.
Detection Logic
// lib/accounting/reverse-charge.ts
interface ReverseChargeResult {
applies: boolean
reason: string
bookings: Array<{
account: string
debit?: number
credit?: number
description: string
}>
}
const EU_DIGITAL_SERVICES_VENDORS = [
{ name: 'meta', country: 'IE', keywords: ['facebook', 'meta', 'instagram'] },
{ name: 'google', country: 'IE', keywords: ['google', 'youtube', 'adwords'] },
{ name: 'adobe', country: 'IE', keywords: ['adobe'] },
{ name: 'microsoft', country: 'IE', keywords: ['microsoft', 'office 365', 'azure'] },
{ name: 'amazon', country: 'LU', keywords: ['aws', 'amazon web services'] },
{ name: 'canva', country: 'AU', keywords: ['canva'] }, // Non-EU, different treatment
]
function handleForeignPurchase(
amount: number,
vendorName: string,
vendorCountry: string,
expenseAccount: string
): ReverseChargeResult {
const isEU = isEUCountry(vendorCountry)
const vatRate = 0.25
const vatAmount = amount * vatRate
if (isEU && vendorCountry !== 'SE') {
// EU purchase - reverse charge applies
return {
applies: true,
reason: `Omvänd skattskyldighet - inköp från ${vendorCountry}`,
bookings: [
{ account: expenseAccount, debit: amount, description: 'Kostnad' },
{ account: '2645', debit: vatAmount, description: 'Beräknad ing. moms utl. förvärv' },
{ account: '2614', credit: vatAmount, description: 'Utg. moms utl. förvärv' },
{ account: '1930', credit: amount, description: 'Utbetalning' }
]
}
}
if (!isEU) {
// Non-EU purchase - no reverse charge, just expense
return {
applies: false,
reason: 'Import från land utanför EU',
bookings: [
{ account: expenseAccount, debit: amount, description: 'Kostnad' },
{ account: '1930', credit: amount, description: 'Utbetalning' }
]
}
}
// Swedish domestic
return {
applies: false,
reason: 'Inrikes inköp',
bookings: [] // Normal VAT handling
}
}
Momsdeklaration Mapping
| Scenario | Ruta | Description |
|---|---|---|
| Domestic purchase 25% VAT | 48 (utgående), deduct in 48 | Normal |
| EU service purchase (reverse charge) | 21 (purchase amount), 48 (calculated VAT) | Self-report |
| Non-EU service purchase | No VAT reporting | Just expense |
Revenue Account Selection
// lib/accounting/revenue-routing.ts
interface RevenueRouting {
account: string
vatRate: number
momsRuta: number
requiresPeriodiskSammanstallning: boolean
}
function routeRevenue(
customerCountry: string,
customerType: 'business' | 'consumer',
hasValidVatNumber: boolean
): RevenueRouting {
// Swedish customer
if (customerCountry === 'SE') {
return {
account: '3001', // Försäljning 25%
vatRate: 25,
momsRuta: 5,
requiresPeriodiskSammanstallning: false
}
}
// EU business with VAT number
if (isEUCountry(customerCountry) && customerType === 'business' && hasValidVatNumber) {
return {
account: '3044', // Försäljning tjänst EU
vatRate: 0,
momsRuta: 39,
requiresPeriodiskSammanstallning: true // Quarterly report required!
}
}
// EU consumer (OSS rules may apply if >10k EUR/year)
if (isEUCountry(customerCountry) && customerType === 'consumer') {
return {
account: '3001', // Or OSS-specific account
vatRate: 25, // Swedish VAT until OSS threshold
momsRuta: 5,
requiresPeriodiskSammanstallning: false
}
}
// Non-EU (USA, etc.) - Export
return {
account: '3045', // Försäljning tjänst Export
vatRate: 0,
momsRuta: 40,
requiresPeriodiskSammanstallning: false
}
}
Conservative Bias Principle
The system must be designed with a conservative bias - prefer rejecting deductions over accepting questionable ones.
Rationale
- Burden of proof lies with taxpayer (IL 9 kap. 2 §)
- Skattetillägg (tax surcharge) is 40% of avoided tax
- Better to warn user than cause audit problems
Implementation
// lib/accounting/risk-assessment.ts
interface RiskAssessment {
riskLevel: 'low' | 'medium' | 'high' | 'very_high'
suggestedAccount: string
requiresConfirmation: boolean
warningMessage?: string
legalBasis?: string
}
function assessTransactionRisk(
mcc: string,
amount: number,
description: string
): RiskAssessment {
const mapping = getMCCMapping(mcc)
if (mapping.riskLevel === 'very_high') {
return {
riskLevel: 'very_high',
suggestedAccount: '2013', // Default to private (eget uttag)
requiresConfirmation: true,
warningMessage: mapping.autoRejectReason,
legalBasis: 'IL 9 kap. 2 § - Privata levnadskostnader'
}
}
if (mapping.riskLevel === 'high') {
return {
riskLevel: 'high',
suggestedAccount: mapping.primaryAccount,
requiresConfirmation: true,
warningMessage: `Denna typ av utgift kräver dokumentation. ${mapping.logic}`
}
}
// Low/medium risk - auto-categorize but allow override
return {
riskLevel: mapping.riskLevel,
suggestedAccount: mapping.primaryAccount,
requiresConfirmation: false
}
}
Private Use Split
For items with mixed business/private use:
// lib/accounting/split-usage.ts
interface SplitTransaction {
businessPortion: {
account: string
amount: number
}
privatePortion: {
account: string // Always 2013
amount: number
}
}
function splitMixedUse(
totalAmount: number,
businessPercentage: number,
expenseAccount: string
): SplitTransaction {
const businessAmount = totalAmount * (businessPercentage / 100)
const privateAmount = totalAmount - businessAmount
return {
businessPortion: {
account: expenseAccount,
amount: Math.round(businessAmount * 100) / 100
},
privatePortion: {
account: '2013',
amount: Math.round(privateAmount * 100) / 100
}
}
}
// UI should ask: "Används denna uteslutande i företaget?"
// If no → prompt for percentage split
Travel Allowance (Traktamente)
For business trips, the owner can claim tax-free travel allowance at Skatteverket's rates.
// lib/accounting/traktamente.ts
// 2024 rates - update annually
const TRAKTAMENTE_RATES = {
sweden: {
fullDay: 260, // Hel dag
halfDay: 130, // Halv dag
night: 130 // Nattraktamente
},
// Foreign rates vary by country - see Skatteverket's list
foreign: {
USA: { fullDay: 620, reduced: 434 },
UK: { fullDay: 550, reduced: 385 },
Germany: { fullDay: 420, reduced: 294 },
// ... etc
}
}
interface TraktamenteCalculation {
amount: number
bookings: Array<{
account: string
debit?: number
credit?: number
}>
}
function calculateTraktamente(
destination: 'sweden' | string,
fullDays: number,
halfDays: number,
nights: number
): TraktamenteCalculation {
const rates = destination === 'sweden'
? TRAKTAMENTE_RATES.sweden
: TRAKTAMENTE_RATES.foreign[destination] || TRAKTAMENTE_RATES.sweden
const amount =
(fullDays * rates.fullDay) +
(halfDays * (rates.halfDay || rates.fullDay / 2)) +
(nights * (rates.night || 0))
return {
amount,
bookings: [
{ account: '5841', debit: amount }, // Traktamente, avdragsgillt
{ account: '2018', credit: amount } // Egen insättning (skuld till ägare)
]
}
}
Non-Cash Transactions (Barter/Gifts)
Influencers receive products that must be accounted for even without bank transaction.
// lib/accounting/non-cash.ts
interface BarterTransaction {
productValue: number
hasMotprestation: boolean // Required post/exposure?
usedInBusiness: boolean
bookings: Array<{
account: string
debit?: number
credit?: number
description: string
}>
}
function bookBarterTransaction(
productValue: number,
hasMotprestation: boolean,
usedInBusiness: boolean
): BarterTransaction['bookings'] {
if (!hasMotprestation && productValue < 450) {
// Tax-free promotional gift
return [] // No booking required
}
if (hasMotprestation) {
// Taxable barter - must recognize as income
const bookings = [
{ account: '3001', credit: productValue, description: 'Förmån/Byteshandel' },
{ account: '1510', debit: productValue, description: 'Fordran (kvittad mot produkt)' }
]
if (usedInBusiness) {
// Can also expense it
bookings.push(
{ account: '5490', debit: productValue, description: 'Rekvisita' },
{ account: '1510', credit: productValue, description: 'Kvittning fordran' }
)
} else {
// Private use - eget uttag
bookings.push(
{ account: '2013', debit: productValue, description: 'Eget uttag (förmån)' },
{ account: '1510', credit: productValue, description: 'Kvittning fordran' }
)
}
return bookings
}
// Gift without motprestation but valuable - still taxable
return [
{ account: '3001', credit: productValue, description: 'Skattepliktig gåva' },
{ account: '2013', debit: productValue, description: 'Eget uttag (gåva)' }
]
}
System Configuration
// lib/accounting/config.ts
export const ACCOUNTING_CONFIG = {
// Update annually
prisbasbelopp: 58800, // 2025
halfPrisbasbelopp: 29400,
// VAT rates
vatRates: {
standard: 25,
reduced: 12, // Food, hotels
low: 6, // Transport, books
},
// Depreciation defaults
depreciation: {
equipment: { years: 5, rate: 0.20 },
computers: { years: 3, rate: 0.33 },
vehicles: { years: 5, rate: 0.20 },
},
// Risk thresholds
riskSettings: {
autoRejectVeryHigh: true,
requireConfirmationHigh: true,
allowOverrideMedium: true,
}
}
Integration Points
This guide integrates with:
- Transaction categorization UI (05-UI-SPECIFICATION.md) - Swipe interface uses MCC mapping
- Tax calculator (06-IMPLEMENTATION-GUIDE.md) - Uses account classifications for tax estimation
- Invoice VAT rules (04-API-SPECIFICATION.md) - Revenue account selection aligns with momsdeklaration
- Expense warnings (06-IMPLEMENTATION-GUIDE.md) - Risk levels drive warning display
Annual Maintenance
Update each January:
- Prisbasbelopp (from Skatteverket, published November)
- Traktamente rates (Skatteverket)
- Any BAS account changes (BAS-kontogruppen)
- Tax rates if changed by Riksdag