diff --git a/.env.example b/.env.example
index ed1c2c2..ad870fe 100644
--- a/.env.example
+++ b/.env.example
@@ -4,6 +4,7 @@ ACTUAL_SYNC_ID=your-sync-id
 ACTUAL_SERVER_URL=http://your-server-url:5006
 ACTUAL_PASSWORD=your-password
 ACTUAL_ACCOUNT_IDS=your-account-id1,your-account-id2
+ACTUAL_DATA_DIR=.cache
 # Bank
 BANK_INITIAL_REFRESH_TOKEN=initial-valid-refresh-token
 BANK_OAUTH_CLIENT_ID=your-client-id
@@ -13,3 +14,4 @@ BANK_OAUTH_REDIRECT_URI=http://your-redirect-uri.com
 BANK_ACCOUNT_IDS=your-account-id1,your-account-id2
 # Configuration
 LOG_LEVEL=info# trace | error | warn | info | debug | trace
+DB_FILENAME=default
diff --git a/config.ts b/config.ts
index 7720f08..c6a75fb 100644
--- a/config.ts
+++ b/config.ts
@@ -3,12 +3,14 @@ import dotenv from "dotenv"
 
 dotenv.config()
 
+// Actual
 export const ACTUAL_SYNC_ID = getOrThrow("ACTUAL_SYNC_ID")
 export const ACTUAL_SERVER_URL = getOrThrow("ACTUAL_SERVER_URL")
 export const ACTUAL_PASSWORD = getOrThrow("ACTUAL_PASSWORD")
 export const ACTUAL_ACCOUNT_IDS = getArrayOrThrow("ACTUAL_ACCOUNT_IDS")
-export const ACTUAL_DATA_DIR = ".cache"
+export const ACTUAL_DATA_DIR = getOrDefault("ACTUAL_DATA_DIR", ".cache")
 
+// Bank
 export const BANK_INITIAL_REFRESH_TOKEN = getOrThrow(
   "BANK_INITIAL_REFRESH_TOKEN",
 )
@@ -16,6 +18,14 @@ export const BANK_OAUTH_CLIENT_ID = getOrThrow("BANK_OAUTH_CLIENT_ID")
 export const BANK_OAUTH_CLIENT_SECRET = getOrThrow("BANK_OAUTH_CLIENT_SECRET")
 export const BANK_ACCOUNT_IDS = getArrayOrThrow("BANK_ACCOUNT_IDS")
 
+// Configuration
+export const DB_FILENAME = getOrDefault("DB_FILENAME", "default")
+export const LOG_LEVEL = getOrDefault("LOG_LEVEL", "info")
+
+function getOrDefault(key: string, def: string): string {
+  return process.env[key] || def
+}
+
 function getOrThrow(key: string): string {
   const value = process.env[key]
   assert(value, `Missing environment variable: ${key}`)
diff --git a/package.json b/package.json
index 4f5fe0c..4dd6943 100644
--- a/package.json
+++ b/package.json
@@ -5,6 +5,7 @@
   "main": "index.js",
   "scripts": {
     "start": "dotenvx run --env-file=.env.local -- node --import=tsx ./src/main.ts | pino-pretty",
+    "start-once": "ONCE=true dotenvx run --env-file=.env.local -- node --import=tsx ./src/main.ts | pino-pretty",
     "test": "dotenvx run --env-file=.env.test.local -- node --experimental-vm-modules node_modules/jest/bin/jest.js | pino-pretty",
     "format": "prettier --write \"./**/*.{js,mjs,ts,md,json}\""
   },
diff --git a/src/date.ts b/src/date.ts
index 0d33fc1..a1212fc 100644
--- a/src/date.ts
+++ b/src/date.ts
@@ -1,5 +1,3 @@
 import { type Dayjs } from "dayjs"
 
-export function toISODateString(day: Dayjs): string {
-  return `${day.year()}-${(day.month() + 1).toString().padStart(2, "0")}-${day.date().toString().padStart(2, "0")}`
-}
+export const toISODateString = (day: Dayjs): string => day.format("YYYY-MM-DD")
diff --git a/src/logger.ts b/src/logger.ts
index a85ed1e..0f6698f 100644
--- a/src/logger.ts
+++ b/src/logger.ts
@@ -1,8 +1,9 @@
 import pino from "pino"
+import { LOG_LEVEL } from "../config.ts"
 
 /**
  * / Returns a logging instance with the default log-level "info"
  */
 export default pino({
-  level: process.env.LOG_LEVEL as string || "info",
+  level: LOG_LEVEL,
 })
diff --git a/src/main.ts b/src/main.ts
index b41d595..691256f 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -10,6 +10,7 @@ import {
   ACTUAL_ACCOUNT_IDS,
   ACTUAL_DATA_DIR,
   BANK_ACCOUNT_IDS,
+  DB_FILENAME,
 } from "../config.ts"
 import logger from "@/logger.ts"
 import type { UUID } from "node:crypto"
@@ -17,7 +18,6 @@ import { createDb } from "@/bank/db/queries.ts"
 import * as fs from "node:fs"
 
 // TODO Transports api for pino https://github.com/pinojs/pino/blob/HEAD/docs/transports.md
-// TODO create .cache if missing
 
 export async function daily(actual: Actual, bank: Bank): Promise<void> {
   // Fetch transactions from the bank
@@ -59,29 +59,40 @@ function createCacheDirIfMissing(): void {
   }
 }
 
-// TODO add a script to run an immediate job, without cron
-// TODO catch ^C to stop server
 async function main(): Promise<void> {
   logger.info("Starting application")
 
   createCacheDirIfMissing()
 
   const actual = await ActualImpl.init()
-  const databaseFileName = "default.sqlite" // TODO move name to env
+  const databaseFileName = `${DB_FILENAME}.sqlite`
   const db = createDb(databaseFileName)
   logger.info(`Started SQLlite database with filename="${databaseFileName}"`)
 
+  process.on("SIGINT", async () => {
+    logger.info("Caught interrupt signal")
+    await shutdown()
+  })
+
+  if (process.env.ONCE) {
+    await daily(actual, new Sparebank1Impl(db))
+    await shutdown()
+    return
+  }
+
   logger.info("Waiting for CRON job to start")
+  const cronJob = cronJobDaily(async () => {
+    logger.info("Running daily job")
+    await daily(actual, new Sparebank1Impl(db))
+    logger.info("Finished daily job")
+  })
 
-  // cronJobDaily(async () => {
-  logger.info("Running daily job")
-  await daily(actual, new Sparebank1Impl(db))
-  logger.info("Finished daily job")
-  // })
-
-  logger.info("Shutting down")
-  await actual.shutdown()
-  db.close()
+  async function shutdown(): Promise<void> {
+    logger.info("Shutting down")
+    await actual.shutdown()
+    db.close()
+    cronJob.stop()
+  }
 }
 
 void main()