mirror of
https://github.com/open-reception/appointment-booking-software.git
synced 2026-09-13 20:57:39 +02:00
Merge branch 'main' of github.com:open-reception/appointment-booking-software into 34-api-structure-and-third-party-libs
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
name: Main Branch Deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
test-build-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "24"
|
||||
cache: "npm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Run type checking
|
||||
run: npm run check
|
||||
|
||||
- name: Run linting
|
||||
run: npm run lint
|
||||
|
||||
- name: Run unit tests
|
||||
run: npm run test:unit -- --run
|
||||
|
||||
- name: Build application
|
||||
run: npm run build
|
||||
|
||||
- name: Install Playwright browsers
|
||||
run: npx playwright install --with-deps
|
||||
|
||||
- name: Run E2E tests
|
||||
run: npm run test:e2e
|
||||
@@ -0,0 +1,35 @@
|
||||
name: PR Checks
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
test-and-build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "24"
|
||||
cache: "npm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Run type checking
|
||||
run: npm run check
|
||||
|
||||
- name: Run linting
|
||||
run: npm run lint
|
||||
|
||||
- name: Run unit tests
|
||||
run: npm run test:unit -- --run
|
||||
|
||||
- name: Build application
|
||||
run: npm run build
|
||||
@@ -0,0 +1,80 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "24"
|
||||
cache: "npm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Update package.json version
|
||||
run: |
|
||||
TAG_VERSION="${{ github.ref_name }}"
|
||||
VERSION="${TAG_VERSION#v}"
|
||||
npm version "$VERSION" --no-git-tag-version
|
||||
|
||||
- name: Run type checking
|
||||
run: npm run check
|
||||
|
||||
- name: Run linting
|
||||
run: npm run lint
|
||||
|
||||
- name: Run unit tests
|
||||
run: npm run test:unit -- --run
|
||||
|
||||
- name: Build application
|
||||
run: npm run build
|
||||
|
||||
- name: Install Playwright browsers
|
||||
run: npx playwright install --with-deps
|
||||
|
||||
- name: Run E2E tests
|
||||
run: npm run test:e2e
|
||||
|
||||
- name: Build and push Docker images
|
||||
run: npm run docker:build-and-push
|
||||
|
||||
- name: Create Release Archive
|
||||
run: |
|
||||
mkdir -p release-assets
|
||||
tar -czf release-assets/open-reception-${{ github.ref_name }}.tar.gz build/
|
||||
|
||||
- name: Create GitHub Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
name: Release ${{ github.ref_name }}
|
||||
generate_release_notes: true
|
||||
body: |
|
||||
## Release ${{ github.ref_name }}
|
||||
|
||||
This release includes the latest version of Open Reception appointment booking software.
|
||||
|
||||
### What's Changed
|
||||
<!-- Release notes will be automatically generated above -->
|
||||
|
||||
### Installation
|
||||
Extract the archive and follow the deployment instructions in the README.
|
||||
|
||||
**Full Changelog**: https://github.com/${{ github.repository }}/compare/${{ github.event.before }}...${{ github.ref_name }}
|
||||
files: |
|
||||
release-assets/open-reception-${{ github.ref_name }}.tar.gz
|
||||
draft: false
|
||||
prerelease: ${{ contains(github.ref_name, '-') }}
|
||||
@@ -16,7 +16,11 @@ services:
|
||||
networks:
|
||||
- appointment-booking-dev
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-appointment_booking}"]
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
"pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-appointment_booking}"
|
||||
]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
@@ -33,4 +37,4 @@ volumes:
|
||||
|
||||
networks:
|
||||
appointment-booking-dev:
|
||||
driver: bridge
|
||||
driver: bridge
|
||||
|
||||
@@ -19,7 +19,11 @@ services:
|
||||
networks:
|
||||
- open-reception-internal
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U $$(cat /run/secrets/postgres_user) -d $$(cat /run/secrets/postgres_db)"]
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
"pg_isready -U $$(cat /run/secrets/postgres_user) -d $$(cat /run/secrets/postgres_db)"
|
||||
]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
@@ -56,7 +60,8 @@ services:
|
||||
networks:
|
||||
- open-reception-internal
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3000/api/health"]
|
||||
test:
|
||||
["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3000/api/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
@@ -119,4 +124,4 @@ volumes:
|
||||
networks:
|
||||
open-reception-internal:
|
||||
driver: bridge
|
||||
internal: false
|
||||
internal: false
|
||||
|
||||
+79
-57
@@ -23,16 +23,20 @@ Development runs only the PostgreSQL database with a public port for development
|
||||
### Setup Steps
|
||||
|
||||
1. **Clone the repository**
|
||||
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd appointment-booking-software
|
||||
```
|
||||
|
||||
2. **Configure environment**
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
Edit `.env` and set secure values:
|
||||
|
||||
```
|
||||
POSTGRES_DB=appointment_booking
|
||||
POSTGRES_USER=postgres
|
||||
@@ -41,20 +45,23 @@ Development runs only the PostgreSQL database with a public port for development
|
||||
```
|
||||
|
||||
3. **Start development database**
|
||||
|
||||
```bash
|
||||
npm run docker:dev:up
|
||||
```
|
||||
|
||||
4. **Verify database connection**
|
||||
|
||||
```bash
|
||||
# Check container status
|
||||
docker ps
|
||||
|
||||
|
||||
# Test connection
|
||||
psql -h localhost -U postgres -d appointment_booking
|
||||
```
|
||||
|
||||
5. **Install SvelteKit dependencies** (when SvelteKit code is added)
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
@@ -91,21 +98,23 @@ Production runs all three containers with security hardening and HTTPS.
|
||||
### Setup Steps
|
||||
|
||||
1. **Configure production secrets**
|
||||
|
||||
|
||||
Edit the secret files in the `secrets/` directory:
|
||||
|
||||
```bash
|
||||
# Database configuration
|
||||
echo "appointment_booking" > secrets/postgres_db.txt
|
||||
echo "postgres" > secrets/postgres_user.txt
|
||||
echo "$(openssl rand -base64 32)" > secrets/postgres_password.txt
|
||||
|
||||
|
||||
# Set proper permissions
|
||||
chmod 600 secrets/*.txt
|
||||
```
|
||||
|
||||
2. **Configure domain**
|
||||
|
||||
|
||||
Edit `Caddyfile` and replace `your-domain.com` with your actual domain:
|
||||
|
||||
```
|
||||
yourdomain.com {
|
||||
# ... rest of configuration
|
||||
@@ -113,22 +122,24 @@ Production runs all three containers with security hardening and HTTPS.
|
||||
```
|
||||
|
||||
3. **Build and start production stack**
|
||||
|
||||
```bash
|
||||
# Build application image
|
||||
npm run docker:prod:build
|
||||
|
||||
|
||||
# Start all services
|
||||
npm run docker:prod:up
|
||||
```
|
||||
|
||||
4. **Verify deployment**
|
||||
|
||||
```bash
|
||||
# Check all containers are running
|
||||
docker ps
|
||||
|
||||
|
||||
# Check application health
|
||||
npm run docker:health
|
||||
|
||||
|
||||
# View logs
|
||||
npm run docker:prod:logs
|
||||
```
|
||||
@@ -143,7 +154,7 @@ npm run docker:prod:down # Stop all services
|
||||
npm run docker:prod:logs # View all logs
|
||||
npm run docker:prod:clean # Remove containers and volumes
|
||||
npm run docker:health # Check container status
|
||||
npm run docker:tag-and-push # Build, tag and push the app image to GHCR (Remember to change username accordingly first)
|
||||
npm run docker:tag-and-push # Build, tag and push the app image to GHCR (Remember to change username accordingly first)
|
||||
```
|
||||
|
||||
## SvelteKit Application Setup
|
||||
@@ -153,34 +164,35 @@ When implementing the SvelteKit application, follow these steps:
|
||||
### Database Connection
|
||||
|
||||
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') {
|
||||
// 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();
|
||||
|
||||
return {
|
||||
host: 'postgres',
|
||||
port: 5432,
|
||||
user,
|
||||
password,
|
||||
database
|
||||
};
|
||||
} else {
|
||||
// Development configuration
|
||||
return {
|
||||
host: 'localhost',
|
||||
port: process.env.POSTGRES_PORT || 5432,
|
||||
user: process.env.POSTGRES_USER || 'postgres',
|
||||
password: process.env.POSTGRES_PASSWORD,
|
||||
database: process.env.POSTGRES_DB || 'appointment_booking'
|
||||
};
|
||||
}
|
||||
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();
|
||||
|
||||
return {
|
||||
host: "postgres",
|
||||
port: 5432,
|
||||
user,
|
||||
password,
|
||||
database
|
||||
};
|
||||
} else {
|
||||
// Development configuration
|
||||
return {
|
||||
host: "localhost",
|
||||
port: process.env.POSTGRES_PORT || 5432,
|
||||
user: process.env.POSTGRES_USER || "postgres",
|
||||
password: process.env.POSTGRES_PASSWORD,
|
||||
database: process.env.POSTGRES_DB || "appointment_booking"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const pool = new pg.Pool(getDatabaseConfig());
|
||||
@@ -189,54 +201,55 @@ export const pool = new pg.Pool(getDatabaseConfig());
|
||||
### Health Check Endpoint
|
||||
|
||||
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() });
|
||||
} catch (error) {
|
||||
return json(
|
||||
{ status: 'unhealthy', error: error.message },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
try {
|
||||
await pool.query("SELECT 1");
|
||||
return json({ status: "healthy", timestamp: new Date().toISOString() });
|
||||
} catch (error) {
|
||||
return json({ status: "unhealthy", error: error.message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### SvelteKit Configuration
|
||||
|
||||
|
||||
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',
|
||||
port: 5173
|
||||
}
|
||||
plugins: [sveltekit()],
|
||||
server: {
|
||||
host: "0.0.0.0",
|
||||
port: 5173
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Security Features
|
||||
|
||||
### Container Security
|
||||
|
||||
- **Rootless containers**: All containers (sans caddy, which needs to access privileged ports) run as non-root users
|
||||
- **Read-only filesystems**: Containers have read-only root filesystems where possible
|
||||
- **No new privileges**: Containers cannot escalate privileges
|
||||
- **Minimal capabilities**: Only necessary Linux capabilities are granted
|
||||
|
||||
### Network Security
|
||||
|
||||
- **Internal networks**: Database and app communicate via internal Docker network
|
||||
- **No exposed ports**: Only Caddy exposes ports to the host
|
||||
- **HTTPS only**: Caddy handles automatic HTTPS with Let's Encrypt
|
||||
|
||||
### Data Security
|
||||
|
||||
- **Docker secrets**: Sensitive data stored as Docker secrets
|
||||
- **Encrypted connections**: Database connections use SSL/TLS
|
||||
- **Security headers**: Comprehensive security headers via Caddy
|
||||
@@ -244,16 +257,19 @@ export default defineConfig({
|
||||
## Monitoring and Logs
|
||||
|
||||
### Log Locations
|
||||
|
||||
- **Caddy logs**: Stored in `/data/access.log` inside Caddy container
|
||||
- **Application logs**: Available via `docker logs`
|
||||
- **Database logs**: Available via `docker logs`
|
||||
|
||||
### Health Checks
|
||||
|
||||
- **Application**: `GET /health` endpoint
|
||||
- **Database**: Built-in PostgreSQL health check
|
||||
- **Caddy**: HTTP response check
|
||||
|
||||
### Monitoring Commands
|
||||
|
||||
```bash
|
||||
# View real-time logs
|
||||
npm run docker:prod:logs
|
||||
@@ -273,37 +289,41 @@ docker logs appointment-booking-caddy
|
||||
### Common Issues
|
||||
|
||||
1. **Container won't start**
|
||||
|
||||
```bash
|
||||
# Check container logs
|
||||
docker logs <container-name>
|
||||
|
||||
|
||||
# Check resource usage
|
||||
docker stats
|
||||
```
|
||||
|
||||
2. **Database connection issues**
|
||||
|
||||
```bash
|
||||
# Test database connectivity
|
||||
docker exec -it appointment-booking-postgres psql -U postgres -d appointment_booking
|
||||
|
||||
|
||||
# Check database logs
|
||||
docker logs appointment-booking-postgres
|
||||
```
|
||||
|
||||
3. **HTTPS certificate issues**
|
||||
|
||||
```bash
|
||||
# Check Caddy logs
|
||||
docker logs appointment-booking-caddy
|
||||
|
||||
|
||||
# Verify domain DNS
|
||||
nslookup yourdomain.com
|
||||
```
|
||||
|
||||
4. **Application not accessible**
|
||||
|
||||
```bash
|
||||
# Check if all containers are running
|
||||
docker ps
|
||||
|
||||
|
||||
# Test internal connectivity
|
||||
docker exec -it appointment-booking-caddy wget -q --spider http://app:3000/health
|
||||
```
|
||||
@@ -323,6 +343,7 @@ npm run docker:prod:up
|
||||
## Backup and Restore
|
||||
|
||||
### Database Backup
|
||||
|
||||
```bash
|
||||
# Create backup
|
||||
docker exec appointment-booking-postgres pg_dump -U postgres appointment_booking > backup.sql
|
||||
@@ -332,7 +353,8 @@ docker exec -i appointment-booking-postgres psql -U postgres appointment_booking
|
||||
```
|
||||
|
||||
### Volume Backup
|
||||
|
||||
```bash
|
||||
# Backup PostgreSQL data volume
|
||||
docker run --rm -v appointment-booking-software_postgres_data:/data -v $(pwd):/backup alpine tar czf /backup/postgres-backup.tar.gz /data
|
||||
```
|
||||
```
|
||||
|
||||
Generated
+9
-6
@@ -10,7 +10,6 @@
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
"@sveltejs/adapter-node": "^5.2.12",
|
||||
"@types/dotenv": "^6.1.1",
|
||||
"dotenv": "^16.5.0",
|
||||
"dotenv-expand": "^12.0.2",
|
||||
"drizzle-orm": "^0.40.0",
|
||||
@@ -27,6 +26,7 @@
|
||||
"@tailwindcss/vite": "^4.0.0",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/svelte": "^5.2.4",
|
||||
"@types/dotenv": "^6.1.1",
|
||||
"@types/node": "^22",
|
||||
"drizzle-kit": "^0.30.2",
|
||||
"eslint": "^9.18.0",
|
||||
@@ -1886,9 +1886,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@sveltejs/kit": {
|
||||
"version": "2.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.21.5.tgz",
|
||||
"integrity": "sha512-P5m7yZtvD1Kx/Z6JcjgJtdMqef/tCGMDrd9B9S2q8j+FMnkeKTMxW1nidnjVzk4HEDRGf4IlBI94/niy6t3hLA==",
|
||||
"version": "2.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.22.0.tgz",
|
||||
"integrity": "sha512-DJm0UxVgzXq+1MUfiJK4Ridk7oIQsIets6JwHiEl97sI6nXScfXe+BeqNhzB7jQIVBb3BM51U4hNk8qQxRXBAA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sveltejs/acorn-typescript": "^1.0.5",
|
||||
@@ -1912,9 +1912,9 @@
|
||||
"node": ">=18.13"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0",
|
||||
"svelte": "^4.0.0 || ^5.0.0-next.0",
|
||||
"vite": "^5.0.3 || ^6.0.0"
|
||||
"vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@sveltejs/vite-plugin-svelte": {
|
||||
@@ -2383,6 +2383,7 @@
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/dotenv/-/dotenv-6.1.1.tgz",
|
||||
"integrity": "sha512-ftQl3DtBvqHl9L16tpqqzA4YzCSXZfi7g8cQceTz5rOlYtk/IZbFjAv3mLOQlNIgOaylCQWQoBdDQHPgEBJPHg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
@@ -2405,6 +2406,7 @@
|
||||
"version": "22.15.32",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.32.tgz",
|
||||
"integrity": "sha512-3jigKqgSjsH6gYZv2nEsqdXfZqIFGAV36XYYjf9KGZ3PSG+IhLecqPnI310RvjutyMwifE2hhhNEklOUrvx/wA==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
@@ -6031,6 +6033,7 @@
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/uri-js": {
|
||||
|
||||
+73
-73
@@ -1,76 +1,76 @@
|
||||
{
|
||||
"name": "open-reception",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"description": "End-to-end encrypted appointment booking platform",
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"prepare": "svelte-kit sync || echo ''",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"format": "prettier --write .",
|
||||
"lint": "prettier --check . && eslint .",
|
||||
"test:unit": "vitest",
|
||||
"test": "npm run test:unit -- --run && npm run test:e2e",
|
||||
"test:e2e": "playwright test",
|
||||
"db:push": "drizzle-kit push",
|
||||
"db:migrate": "drizzle-kit migrate",
|
||||
"db:studio": "drizzle-kit studio",
|
||||
"docker:dev:up": "docker compose -f docker-compose.dev.yml up -d",
|
||||
"docker:dev:down": "docker compose -f docker-compose.dev.yml down",
|
||||
"docker:dev:logs": "docker compose -f docker-compose.dev.yml logs -f",
|
||||
"docker:dev:clean": "docker compose -f docker-compose.dev.yml down -v --remove-orphans",
|
||||
"docker:build": "docker build -t open-reception:latest .",
|
||||
"docker:build:tag": "docker tag open-reception:latest open-reception:$npm_package_version",
|
||||
"docker:push": "docker push open-reception:$npm_package_version && docker push open-reception:latest",
|
||||
"docker:build-and-push": "npm run docker:build && npm run docker:build:tag && npm run docker:push",
|
||||
"docker:prod:up": "docker compose -f docker-compose.prod.yml up -d",
|
||||
"docker:prod:down": "docker compose -f docker-compose.prod.yml down",
|
||||
"docker:prod:logs": "docker compose -f docker-compose.prod.yml logs -f",
|
||||
"docker:prod:clean": "docker compose -f docker-compose.prod.yml down -v --remove-orphans"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/compat": "^1.2.5",
|
||||
"@eslint/js": "^9.18.0",
|
||||
"@playwright/test": "^1.49.1",
|
||||
"@sveltejs/adapter-auto": "^6.0.0",
|
||||
"@sveltejs/kit": "^2.16.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"@tailwindcss/vite": "^4.0.0",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/svelte": "^5.2.4",
|
||||
"@types/node": "^22",
|
||||
"name": "open-reception",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"description": "End-to-end encrypted appointment booking platform",
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"prepare": "svelte-kit sync || echo ''",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"format": "prettier --write .",
|
||||
"lint": "prettier --check . && eslint .",
|
||||
"test:unit": "vitest",
|
||||
"test": "npm run test:unit -- --run && npm run test:e2e",
|
||||
"test:e2e": "playwright test",
|
||||
"db:push": "drizzle-kit push",
|
||||
"db:migrate": "drizzle-kit migrate",
|
||||
"db:studio": "drizzle-kit studio",
|
||||
"docker:dev:up": "docker compose -f docker-compose.dev.yml up -d",
|
||||
"docker:dev:down": "docker compose -f docker-compose.dev.yml down",
|
||||
"docker:dev:logs": "docker compose -f docker-compose.dev.yml logs -f",
|
||||
"docker:dev:clean": "docker compose -f docker-compose.dev.yml down -v --remove-orphans",
|
||||
"docker:build": "docker build -t open-reception:latest .",
|
||||
"docker:build:tag": "docker tag open-reception:latest open-reception:$npm_package_version",
|
||||
"docker:push": "docker push open-reception:$npm_package_version && docker push open-reception:latest",
|
||||
"docker:build-and-push": "npm run docker:build && npm run docker:build:tag && npm run docker:push",
|
||||
"docker:prod:up": "docker compose -f docker-compose.prod.yml up -d",
|
||||
"docker:prod:down": "docker compose -f docker-compose.prod.yml down",
|
||||
"docker:prod:logs": "docker compose -f docker-compose.prod.yml logs -f",
|
||||
"docker:prod:clean": "docker compose -f docker-compose.prod.yml down -v --remove-orphans"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/compat": "^1.2.5",
|
||||
"@eslint/js": "^9.18.0",
|
||||
"@playwright/test": "^1.49.1",
|
||||
"@sveltejs/adapter-auto": "^6.0.0",
|
||||
"@sveltejs/kit": "^2.16.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"@tailwindcss/vite": "^4.0.0",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/svelte": "^5.2.4",
|
||||
"@types/node": "^22",
|
||||
"@types/dotenv": "^6.1.1",
|
||||
"drizzle-kit": "^0.30.2",
|
||||
"eslint": "^9.18.0",
|
||||
"eslint-config-prettier": "^10.0.1",
|
||||
"eslint-plugin-svelte": "^3.0.0",
|
||||
"globals": "^16.0.0",
|
||||
"jsdom": "^26.0.0",
|
||||
"prettier": "^3.4.2",
|
||||
"prettier-plugin-svelte": "^3.3.3",
|
||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||
"svelte": "^5.0.0",
|
||||
"svelte-check": "^4.0.0",
|
||||
"tailwindcss": "^4.0.0",
|
||||
"typescript": "^5.0.0",
|
||||
"typescript-eslint": "^8.20.0",
|
||||
"vite": "^6.2.6",
|
||||
"vitest": "^3.2.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sveltejs/adapter-node": "^5.2.12",
|
||||
"dotenv": "^16.5.0",
|
||||
"dotenv-expand": "^12.0.2",
|
||||
"drizzle-orm": "^0.40.0",
|
||||
"postgres": "^3.4.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=24.0.0"
|
||||
},
|
||||
"license": "AGPL-3.0"
|
||||
"drizzle-kit": "^0.30.2",
|
||||
"eslint": "^9.18.0",
|
||||
"eslint-config-prettier": "^10.0.1",
|
||||
"eslint-plugin-svelte": "^3.0.0",
|
||||
"globals": "^16.0.0",
|
||||
"jsdom": "^26.0.0",
|
||||
"prettier": "^3.4.2",
|
||||
"prettier-plugin-svelte": "^3.3.3",
|
||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||
"svelte": "^5.0.0",
|
||||
"svelte-check": "^4.0.0",
|
||||
"tailwindcss": "^4.0.0",
|
||||
"typescript": "^5.0.0",
|
||||
"typescript-eslint": "^8.20.0",
|
||||
"vite": "^6.2.6",
|
||||
"vitest": "^3.2.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sveltejs/adapter-node": "^5.2.12",
|
||||
"dotenv": "^16.5.0",
|
||||
"dotenv-expand": "^12.0.2",
|
||||
"drizzle-orm": "^0.40.0",
|
||||
"postgres": "^3.4.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=24.0.0"
|
||||
},
|
||||
"license": "AGPL-3.0"
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let envVarsOkay = {};
|
||||
|
||||
onMount(async () => {
|
||||
const response = await fetch('/api/env');
|
||||
envVarsOkay = (await response.json()).envOkay ? "okay" : "not okay";
|
||||
});
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let envVarsOkay = {};
|
||||
|
||||
onMount(async () => {
|
||||
const response = await fetch("/api/env");
|
||||
envVarsOkay = (await response.json()).envOkay ? "okay" : "not okay";
|
||||
});
|
||||
</script>
|
||||
|
||||
<h1>Welcome to SvelteKit</h1>
|
||||
<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p>
|
||||
|
||||
<p>Environment configuration is {envVarsOkay}</p>
|
||||
<p>Environment configuration is {envVarsOkay}</p>
|
||||
|
||||
Vendored
+14
-16
@@ -1,21 +1,19 @@
|
||||
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)
|
||||
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")
|
||||
envOkay = false;
|
||||
if (!process.env.DATABASE_URL?.startsWith("postgres:")) envOkay = false;
|
||||
|
||||
let envOkay = true;
|
||||
if (process.env.NODE_ENV !== "production" && process.env.NODE_ENV !== "development")
|
||||
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
|
||||
});
|
||||
}
|
||||
return json({
|
||||
envOkay
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import { json } from "@sveltejs/kit";
|
||||
|
||||
export async function GET() {
|
||||
return json(true);
|
||||
}
|
||||
return json(true);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
import { describe, test, expect } from "vitest";
|
||||
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", () => {
|
||||
beforeEach(() => {
|
||||
// Mock fetch to avoid the "Invalid URL" error
|
||||
global.fetch = vi.fn(() =>
|
||||
Promise.resolve({
|
||||
json: () => Promise.resolve({ envOkay: true })
|
||||
} as Response)
|
||||
);
|
||||
});
|
||||
|
||||
test("should render h1", () => {
|
||||
render(Page);
|
||||
expect(screen.getByRole("heading", { level: 1 })).toBeInTheDocument();
|
||||
|
||||
+2
-2
@@ -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 = {
|
||||
|
||||
Reference in New Issue
Block a user