diff --git a/.github/workflows/main-deploy.yml b/.github/workflows/main-deploy.yml index afbf625..591d392 100644 --- a/.github/workflows/main-deploy.yml +++ b/.github/workflows/main-deploy.yml @@ -15,8 +15,8 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '24' - cache: 'npm' + node-version: "24" + cache: "npm" - name: Install dependencies run: npm ci diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index bf0eef4..fcc352e 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -16,8 +16,8 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '24' - cache: 'npm' + node-version: "24" + cache: "npm" - name: Install dependencies run: npm ci diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6d58daf..165ea30 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,7 +3,7 @@ name: Release on: push: tags: - - 'v*' + - "v*" permissions: contents: write @@ -19,8 +19,8 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '24' - cache: 'npm' + node-version: "24" + cache: "npm" - name: Install dependencies run: npm ci diff --git a/.prettierrc b/.prettierrc index 7ebb855..1e5915a 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,6 +1,6 @@ { "useTabs": true, - "singleQuote": true, + "singleQuote": false, "trailingComma": "none", "printWidth": 100, "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"], diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 4ba1785..e3bbc0d 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -9,7 +9,7 @@ services: POSTGRES_USER: ${POSTGRES_USER:-postgres} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} ports: - - '${POSTGRES_PORT:-5432}:5432' + - "${POSTGRES_PORT:-5432}:5432" volumes: - postgres_data_dev:/var/lib/postgresql/data - ./init-db:/docker-entrypoint-initdb.d:ro @@ -18,8 +18,8 @@ services: healthcheck: test: [ - 'CMD-SHELL', - 'pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-appointment_booking}' + "CMD-SHELL", + "pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-appointment_booking}" ] interval: 10s timeout: 5s diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 4ec596e..0cba9ec 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -8,7 +8,7 @@ services: POSTGRES_DB_FILE: /run/secrets/postgres_db POSTGRES_USER_FILE: /run/secrets/postgres_user POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password - POSTGRES_INITDB_ARGS: '--auth-host=scram-sha-256 --auth-local=scram-sha-256' + POSTGRES_INITDB_ARGS: "--auth-host=scram-sha-256 --auth-local=scram-sha-256" secrets: - postgres_db - postgres_user @@ -21,8 +21,8 @@ services: healthcheck: test: [ - 'CMD-SHELL', - 'pg_isready -U $$(cat /run/secrets/postgres_user) -d $$(cat /run/secrets/postgres_db)' + "CMD-SHELL", + "pg_isready -U $$(cat /run/secrets/postgres_user) -d $$(cat /run/secrets/postgres_db)" ] interval: 10s timeout: 5s @@ -47,7 +47,7 @@ services: image: open-reception:${VERSION:-latest} container_name: open-reception-app restart: unless-stopped - user: '1001:1001' + user: "1001:1001" environment: NODE_ENV: production secrets: @@ -61,7 +61,7 @@ services: - open-reception-internal healthcheck: test: - ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://127.0.0.1:3000/api/health'] + ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3000/api/health"] interval: 30s timeout: 10s retries: 3 @@ -87,8 +87,8 @@ services: container_name: open-reception-caddy restart: unless-stopped ports: - - '80:80' - - '443:443' + - "80:80" + - "443:443" volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - caddy_data:/data diff --git a/docs/infrastructure.md b/docs/infrastructure.md index 051d525..a8ab6b2 100644 --- a/docs/infrastructure.md +++ b/docs/infrastructure.md @@ -166,18 +166,18 @@ When implementing the SvelteKit application, follow these steps: Create `src/lib/database.js`: ```javascript -import { readFileSync } from 'fs'; -import pg from 'pg'; +import { readFileSync } from "fs"; +import pg from "pg"; function getDatabaseConfig() { - if (process.env.NODE_ENV === 'production') { + if (process.env.NODE_ENV === "production") { // Read from Docker secrets - const user = readFileSync('/run/secrets/postgres_user', 'utf8').trim(); - const password = readFileSync('/run/secrets/postgres_password', 'utf8').trim(); - const database = readFileSync('/run/secrets/postgres_db', 'utf8').trim(); + const user = readFileSync("/run/secrets/postgres_user", "utf8").trim(); + const password = readFileSync("/run/secrets/postgres_password", "utf8").trim(); + const database = readFileSync("/run/secrets/postgres_db", "utf8").trim(); return { - host: 'postgres', + host: "postgres", port: 5432, user, password, @@ -186,11 +186,11 @@ function getDatabaseConfig() { } else { // Development configuration return { - host: 'localhost', + host: "localhost", port: process.env.POSTGRES_PORT || 5432, - user: process.env.POSTGRES_USER || 'postgres', + user: process.env.POSTGRES_USER || "postgres", password: process.env.POSTGRES_PASSWORD, - database: process.env.POSTGRES_DB || 'appointment_booking' + database: process.env.POSTGRES_DB || "appointment_booking" }; } } @@ -203,15 +203,15 @@ export const pool = new pg.Pool(getDatabaseConfig()); Create `src/routes/health/+server.js`: ```javascript -import { json } from '@sveltejs/kit'; -import { pool } from '$lib/database.js'; +import { json } from "@sveltejs/kit"; +import { pool } from "$lib/database.js"; export async function GET() { try { - await pool.query('SELECT 1'); - return json({ status: 'healthy', timestamp: new Date().toISOString() }); + await pool.query("SELECT 1"); + return json({ status: "healthy", timestamp: new Date().toISOString() }); } catch (error) { - return json({ status: 'unhealthy', error: error.message }, { status: 500 }); + return json({ status: "unhealthy", error: error.message }, { status: 500 }); } } ``` @@ -221,13 +221,13 @@ export async function GET() { Update `vite.config.js`: ```javascript -import { sveltekit } from '@sveltejs/kit/vite'; -import { defineConfig } from 'vite'; +import { sveltekit } from "@sveltejs/kit/vite"; +import { defineConfig } from "vite"; export default defineConfig({ plugins: [sveltekit()], server: { - host: '0.0.0.0', + host: "0.0.0.0", port: 5173 } }); diff --git a/drizzle.config.ts b/drizzle.config.ts index d57e081..f42374f 100644 --- a/drizzle.config.ts +++ b/drizzle.config.ts @@ -1,10 +1,10 @@ -import { defineConfig } from 'drizzle-kit'; +import { defineConfig } from "drizzle-kit"; -if (!process.env.DATABASE_URL) throw new Error('DATABASE_URL is not set'); +if (!process.env.DATABASE_URL) throw new Error("DATABASE_URL is not set"); export default defineConfig({ - schema: './src/lib/server/db/schema.ts', - dialect: 'postgresql', + schema: "./src/lib/server/db/schema.ts", + dialect: "postgresql", dbCredentials: { url: process.env.DATABASE_URL }, verbose: true, strict: true diff --git a/e2e/demo.test.ts b/e2e/demo.test.ts index 9985ce1..1f5a374 100644 --- a/e2e/demo.test.ts +++ b/e2e/demo.test.ts @@ -1,6 +1,6 @@ -import { expect, test } from '@playwright/test'; +import { expect, test } from "@playwright/test"; -test('home page has expected h1', async ({ page }) => { - await page.goto('/'); - await expect(page.locator('h1')).toBeVisible(); +test("home page has expected h1", async ({ page }) => { + await page.goto("/"); + await expect(page.locator("h1")).toBeVisible(); }); diff --git a/eslint.config.js b/eslint.config.js index ef07d32..b41ad17 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,13 +1,13 @@ -import prettier from 'eslint-config-prettier'; -import js from '@eslint/js'; -import { includeIgnoreFile } from '@eslint/compat'; -import svelte from 'eslint-plugin-svelte'; -import globals from 'globals'; -import { fileURLToPath } from 'node:url'; -import ts from 'typescript-eslint'; -import svelteConfig from './svelte.config.js'; +import prettier from "eslint-config-prettier"; +import js from "@eslint/js"; +import { includeIgnoreFile } from "@eslint/compat"; +import svelte from "eslint-plugin-svelte"; +import globals from "globals"; +import { fileURLToPath } from "node:url"; +import ts from "typescript-eslint"; +import svelteConfig from "./svelte.config.js"; -const gitignorePath = fileURLToPath(new URL('./.gitignore', import.meta.url)); +const gitignorePath = fileURLToPath(new URL("./.gitignore", import.meta.url)); export default ts.config( includeIgnoreFile(gitignorePath), @@ -20,14 +20,14 @@ export default ts.config( languageOptions: { globals: { ...globals.browser, ...globals.node } }, - rules: { 'no-undef': 'off' } + rules: { "no-undef": "off" } }, { - files: ['**/*.svelte', '**/*.svelte.ts', '**/*.svelte.js'], + files: ["**/*.svelte", "**/*.svelte.ts", "**/*.svelte.js"], languageOptions: { parserOptions: { projectService: true, - extraFileExtensions: ['.svelte'], + extraFileExtensions: [".svelte"], parser: ts.parser, svelteConfig } diff --git a/playwright.config.ts b/playwright.config.ts index f6c81af..6449fa1 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,9 +1,9 @@ -import { defineConfig } from '@playwright/test'; +import { defineConfig } from "@playwright/test"; export default defineConfig({ webServer: { - command: 'npm run build && npm run preview', + command: "npm run build && npm run preview", port: 4173 }, - testDir: 'e2e' + testDir: "e2e" }); diff --git a/src/app.css b/src/app.css index 1c4d2a8..5b46619 100644 --- a/src/app.css +++ b/src/app.css @@ -1,2 +1,2 @@ -@import 'tailwindcss'; +@import "tailwindcss"; @plugin '@tailwindcss/typography'; diff --git a/src/demo.spec.ts b/src/demo.spec.ts index e07cbbd..808401e 100644 --- a/src/demo.spec.ts +++ b/src/demo.spec.ts @@ -1,7 +1,7 @@ -import { describe, it, expect } from 'vitest'; +import { describe, it, expect } from "vitest"; -describe('sum test', () => { - it('adds 1 + 2 to equal 3', () => { +describe("sum test", () => { + it("adds 1 + 2 to equal 3", () => { expect(1 + 2).toBe(3); }); }); diff --git a/src/lib/server/db/index.ts b/src/lib/server/db/index.ts index fb8b355..f915985 100644 --- a/src/lib/server/db/index.ts +++ b/src/lib/server/db/index.ts @@ -1,9 +1,9 @@ -import { drizzle } from 'drizzle-orm/postgres-js'; -import postgres from 'postgres'; -import * as schema from './schema'; -import { env } from '$env/dynamic/private'; +import { drizzle } from "drizzle-orm/postgres-js"; +import postgres from "postgres"; +import * as schema from "./schema"; +import { env } from "$env/dynamic/private"; -if (!env.DATABASE_URL) throw new Error('DATABASE_URL is not set'); +if (!env.DATABASE_URL) throw new Error("DATABASE_URL is not set"); const client = postgres(env.DATABASE_URL); diff --git a/src/lib/server/db/schema.ts b/src/lib/server/db/schema.ts index b256205..bfe8980 100644 --- a/src/lib/server/db/schema.ts +++ b/src/lib/server/db/schema.ts @@ -1,6 +1,6 @@ -import { pgTable, serial, integer } from 'drizzle-orm/pg-core'; +import { pgTable, serial, integer } from "drizzle-orm/pg-core"; -export const user = pgTable('user', { - id: serial('id').primaryKey(), - age: integer('age') +export const user = pgTable("user", { + id: serial("id").primaryKey(), + age: integer("age") }); diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index b93e9ba..2458f08 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,5 +1,5 @@ diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 4aa2754..8052b31 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,11 +1,11 @@ diff --git a/src/routes/api/env/+server.ts b/src/routes/api/env/+server.ts index 00c6841..8f8699f 100644 --- a/src/routes/api/env/+server.ts +++ b/src/routes/api/env/+server.ts @@ -1,17 +1,17 @@ -import { json } from '@sveltejs/kit'; -import dotenv from 'dotenv'; -import dotenvExpand from 'dotenv-expand'; +import { json } from "@sveltejs/kit"; +import dotenv from "dotenv"; +import dotenvExpand from "dotenv-expand"; const cfg = dotenv.config(); dotenvExpand.expand(cfg); export async function GET() { let envOkay = true; - if (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'development') + if (process.env.NODE_ENV !== "production" && process.env.NODE_ENV !== "development") envOkay = false; - if (!process.env.DATABASE_URL?.startsWith('postgres:')) envOkay = false; + if (!process.env.DATABASE_URL?.startsWith("postgres:")) envOkay = false; - console.warn('Environment is okay', envOkay); + console.warn("Environment is okay", envOkay); return json({ envOkay diff --git a/src/routes/api/health/+server.ts b/src/routes/api/health/+server.ts index 9cb83e7..4162e15 100644 --- a/src/routes/api/health/+server.ts +++ b/src/routes/api/health/+server.ts @@ -1,4 +1,4 @@ -import { json } from '@sveltejs/kit'; +import { json } from "@sveltejs/kit"; export async function GET() { return json(true); diff --git a/src/routes/page.svelte.test.ts b/src/routes/page.svelte.test.ts index d259c85..6bf82c9 100644 --- a/src/routes/page.svelte.test.ts +++ b/src/routes/page.svelte.test.ts @@ -1,9 +1,9 @@ -import { describe, test, expect, vi, beforeEach } from 'vitest'; -import '@testing-library/jest-dom/vitest'; -import { render, screen } from '@testing-library/svelte'; -import Page from './+page.svelte'; +import { describe, test, expect, vi, beforeEach } from "vitest"; +import "@testing-library/jest-dom/vitest"; +import { render, screen } from "@testing-library/svelte"; +import Page from "./+page.svelte"; -describe('/+page.svelte', () => { +describe("/+page.svelte", () => { beforeEach(() => { // Mock fetch to avoid the "Invalid URL" error global.fetch = vi.fn(() => @@ -13,8 +13,8 @@ describe('/+page.svelte', () => { ); }); - test('should render h1', () => { + test("should render h1", () => { render(Page); - expect(screen.getByRole('heading', { level: 1 })).toBeInTheDocument(); + expect(screen.getByRole("heading", { level: 1 })).toBeInTheDocument(); }); }); diff --git a/svelte.config.js b/svelte.config.js index e0a641e..9d6e59e 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -1,5 +1,5 @@ -import adapter from '@sveltejs/adapter-node'; -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; +import adapter from "@sveltejs/adapter-node"; +import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"; /** @type {import('@sveltejs/kit').Config} */ const config = { diff --git a/vite.config.ts b/vite.config.ts index 7e61d35..f1fe658 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,31 +1,31 @@ -import tailwindcss from '@tailwindcss/vite'; -import { svelteTesting } from '@testing-library/svelte/vite'; -import { sveltekit } from '@sveltejs/kit/vite'; -import { defineConfig } from 'vite'; +import tailwindcss from "@tailwindcss/vite"; +import { svelteTesting } from "@testing-library/svelte/vite"; +import { sveltekit } from "@sveltejs/kit/vite"; +import { defineConfig } from "vite"; export default defineConfig({ plugins: [tailwindcss(), sveltekit()], test: { projects: [ { - extends: './vite.config.ts', + extends: "./vite.config.ts", plugins: [svelteTesting()], test: { - name: 'client', - environment: 'jsdom', + name: "client", + environment: "jsdom", clearMocks: true, - include: ['src/**/*.svelte.{test,spec}.{js,ts}'], - exclude: ['src/lib/server/**'], - setupFiles: ['./vitest-setup-client.ts'] + include: ["src/**/*.svelte.{test,spec}.{js,ts}"], + exclude: ["src/lib/server/**"], + setupFiles: ["./vitest-setup-client.ts"] } }, { - extends: './vite.config.ts', + extends: "./vite.config.ts", test: { - name: 'server', - environment: 'node', - include: ['src/**/*.{test,spec}.{js,ts}'], - exclude: ['src/**/*.svelte.{test,spec}.{js,ts}'] + name: "server", + environment: "node", + include: ["src/**/*.{test,spec}.{js,ts}"], + exclude: ["src/**/*.svelte.{test,spec}.{js,ts}"] } } ] diff --git a/vitest-setup-client.ts b/vitest-setup-client.ts index ccc8a70..ecda271 100644 --- a/vitest-setup-client.ts +++ b/vitest-setup-client.ts @@ -1,8 +1,8 @@ -import '@testing-library/jest-dom/vitest'; -import { vi } from 'vitest'; +import "@testing-library/jest-dom/vitest"; +import { vi } from "vitest"; // required for svelte5 + jsdom as jsdom does not support matchMedia -Object.defineProperty(window, 'matchMedia', { +Object.defineProperty(window, "matchMedia", { writable: true, enumerable: true, value: vi.fn().mockImplementation((query) => ({