Skip to content

Commit 5909cdd

Browse files
committed
Fixed environment variables and sensible defaults
1 parent b847cff commit 5909cdd

26 files changed

+225
-178
lines changed

.env.example

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# -----------------------------------------------------------------------------
77
# Application Environment
88
# -----------------------------------------------------------------------------
9-
NODE_ENV=development
9+
ENVIRONMENT=development
1010

1111
# -----------------------------------------------------------------------------
1212
# Server Configuration
@@ -22,11 +22,6 @@ CLIENT_PORT=5173
2222
# -----------------------------------------------------------------------------
2323
# API Configuration
2424
# -----------------------------------------------------------------------------
25-
# Base URL for API calls (used by frontend)
26-
# In development: http://localhost:3000
27-
# In production: your domain or leave empty for relative URLs
28-
API_BASE_URL=http://localhost:3000
29-
3025
# SvelteKit public environment variables (PUBLIC_ prefix required)
3126
PUBLIC_API_BASE_URL=http://localhost:3000
3227

@@ -39,9 +34,6 @@ DATABASE_PATH=./vehicles.db
3934
# -----------------------------------------------------------------------------
4035
# Application Features
4136
# -----------------------------------------------------------------------------
42-
# Enable demo mode (disables certain features for public demos)
43-
DEMO_MODE=false
44-
4537
# SvelteKit public demo mode (PUBLIC_ prefix required)
4638
PUBLIC_DEMO_MODE=false
4739

app/backend/index.ts

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
import { config } from "dotenv";
2-
import { resolve } from "path";
3-
4-
// Load environment variables from root directory
5-
config({ path: resolve(process.cwd(), "../../.env") });
6-
71
import express from "express";
82
import cors from "cors";
93
import pinRoutes from "@routes/pinRoutes.js";
@@ -21,21 +15,21 @@ const app = express();
2115
// Configure CORS - simplified for development
2216
const corsOptions = env.isDevelopment()
2317
? {
24-
// In development, allow all origins for easier debugging
25-
origin: true,
26-
credentials: true,
27-
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
28-
allowedHeaders: ["Content-Type", "Authorization", "X-User-PIN"],
29-
optionsSuccessStatus: 200,
30-
}
18+
// In development, allow all origins for easier debugging
19+
origin: true,
20+
credentials: true,
21+
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
22+
allowedHeaders: ["Content-Type", "Authorization", "X-User-PIN"],
23+
optionsSuccessStatus: 200,
24+
}
3125
: {
32-
// In production, use strict origin checking
33-
origin: env.CORS_ORIGINS,
34-
credentials: true,
35-
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
36-
allowedHeaders: ["Content-Type", "Authorization", "X-User-PIN"],
37-
optionsSuccessStatus: 200,
38-
};
26+
// In production, use strict origin checking
27+
origin: env.CORS_ORIGINS,
28+
credentials: true,
29+
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
30+
allowedHeaders: ["Content-Type", "Authorization", "X-User-PIN"],
31+
optionsSuccessStatus: 200,
32+
};
3933

4034
app.use(cors(corsOptions));
4135

@@ -69,14 +63,14 @@ initializeDatabase()
6963
console.log(
7064
`🚀 Server running at http://${env.SERVER_HOST}:${env.SERVER_PORT}`
7165
);
72-
console.log(`📊 Environment: ${env.NODE_ENV}`);
73-
console.log(`🗄️ Database: ${env.DATABASE_PATH}`);
74-
console.log(`🎭 Demo Mode: ${env.DEMO_MODE ? "Enabled" : "Disabled"}`);
66+
console.log(`Environment: ${env.ENVIRONMENT}`);
67+
console.log(`Database: ${env.DATABASE_PATH}`);
68+
console.log(`Demo Mode: ${env.DEMO_MODE ? "Enabled" : "Disabled"}`);
7569
console.log(
76-
`🌐 CORS: ${env.isDevelopment() ? "Permissive (Development)" : "Strict (Production)"}`
70+
`CORS: ${env.isDevelopment() ? "Permissive (Development)" : "Strict (Production)"}`
7771
);
7872
if (!env.isDevelopment()) {
79-
console.log(`📋 Allowed origins: ${env.CORS_ORIGINS.join(", ")}`);
73+
console.log(`Allowed origins: ${env.CORS_ORIGINS.join(", ")}`);
8074
}
8175
console.log("─".repeat(75));
8276
});

app/backend/nodemon.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
{
2-
"watch": ["./**/*.ts"],
2+
"watch": [
3+
"./**/*.ts"
4+
],
35
"ext": "ts",
46
"exec": "tsx index.ts",
57
"env": {
6-
"NODE_ENV": "development"
8+
"ENVIRONMENT": "development"
79
}
8-
}
10+
}

app/backend/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "server",
2+
"name": "backend",
33
"version": "0.0.1",
44
"description": "Tractor backend",
55
"main": "dist/index.js",
@@ -45,4 +45,4 @@
4545
"tsx": "^4.20.3",
4646
"typescript": "^5.8.3"
4747
}
48-
}
48+
}

app/backend/src/config/env.ts

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,36 @@
1-
/**
2-
* Environment Configuration
3-
* Centralized environment variable management for the backend
4-
*/
1+
import { config } from "dotenv";
2+
import { resolve } from "path";
3+
4+
// Load environment variables from root directory
5+
config({
6+
path: resolve(process.cwd(), "../../.env"),
7+
override: true,
8+
quiet: true,
9+
});
10+
11+
12+
const getOrigins = (): string[] => {
13+
const origins = process.env.CORS_ORIGINS;
14+
if (!origins) {
15+
// Allow localhost by default in development
16+
if (process.env.ENVIRONMENT === "development") {
17+
return ["*"];
18+
} else {
19+
return [
20+
"http://localhost:5173",
21+
"http://localhost:3000",
22+
"http://127.0.0.1:5173",
23+
"http://127.0.0.1:3000",
24+
]
25+
}
26+
}
27+
28+
return origins.split(",").map(origin => origin.trim()).filter(Boolean);
29+
}
530

631
export const env = {
732
// Application Environment
8-
NODE_ENV: process.env.NODE_ENV || "development",
33+
ENVIRONMENT: process.env.NODE_ENV || "development",
934

1035
// Server Configuration
1136
SERVER_HOST: process.env.SERVER_HOST || "0.0.0.0",
@@ -15,26 +40,19 @@ export const env = {
1540
DATABASE_PATH: process.env.DATABASE_PATH || "./vehicles.db",
1641

1742
// Application Features
18-
DEMO_MODE: process.env.DEMO_MODE === "true",
43+
DEMO_MODE: process.env.PUBLIC_DEMO_MODE === "true",
1944

2045
// CORS Configuration
21-
CORS_ORIGINS: process.env.CORS_ORIGINS?.split(",").map((origin) =>
22-
origin.trim(),
23-
) || [
24-
"http://localhost:5173",
25-
"http://localhost:3000",
26-
"http://127.0.0.1:5173",
27-
"http://127.0.0.1:3000",
28-
],
46+
CORS_ORIGINS: getOrigins(),
2947

3048
// Logging Configuration
3149
LOG_LEVEL: process.env.LOG_LEVEL || "info",
3250
LOG_REQUESTS: process.env.LOG_REQUESTS === "true",
3351

3452
// Helper methods
35-
isDevelopment: () => process.env.NODE_ENV === "development",
36-
isProduction: () => process.env.NODE_ENV === "production",
37-
isTest: () => process.env.NODE_ENV === "test",
53+
isDevelopment: () => !process.env.ENVIRONMENT || process.env.ENVIRONMENT === "development",
54+
isProduction: () => process.env.ENVIRONMENT === "production",
55+
isTest: () => process.env.ENVIRONMENT === "test",
3856
} as const;
3957

4058
export default env;
@@ -43,7 +61,7 @@ export default env;
4361
* Validate required environment variables
4462
*/
4563
export function validateEnvironment(): void {
46-
const required = ["NODE_ENV"];
64+
const required: string[] = [];
4765
const missing = required.filter((key) => !process.env[key]);
4866

4967
if (missing.length > 0) {
@@ -65,4 +83,4 @@ export function validateEnvironment(): void {
6583
}
6684

6785
console.log("✅ Environment validation passed");
68-
}
86+
}

app/backend/src/db/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,13 @@ import { db } from "./db.js";
66
const __filename = fileURLToPath(import.meta.url);
77
const __dirname = path.dirname(__filename);
88

9+
// Determine if we're running in development (TypeScript) or production (compiled JavaScript)
10+
const isProduction = __filename.includes("/dist/");
11+
const migrationExtension = isProduction ? "js" : "ts";
12+
913
const umzug = new Umzug({
1014
migrations: {
11-
glob: path.join(__dirname, "migrations/*.js"),
15+
glob: path.join(__dirname, `migrations/*.${migrationExtension}`),
1216
resolve: ({ name, path: migrationPath }) => {
1317
return {
1418
name,
@@ -36,7 +40,7 @@ type Migration = typeof umzug._types.migration;
3640
const performDbMigrations = async () => {
3741
try {
3842
console.log("Running database migrations...");
39-
await umzug.up();
43+
await umzug.up({});
4044
console.log("Migrations completed successfully");
4145
} catch (error) {
4246
console.error("Migration failed:", error);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { Request, Response, NextFunction } from "express";
2+
3+
// Wrapper to catch async errors and pass them to Express error handler
4+
export const asyncHandler = (fn: Function) => {
5+
return (req: Request, res: Response, next: NextFunction) => {
6+
Promise.resolve(fn(req, res, next)).catch(next);
7+
};
8+
};
Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,47 @@
1-
import { Request, Response } from "express";
1+
import { Request, Response, NextFunction } from "express";
22
import { ValidationError } from "sequelize";
33

44
export const errorHandler = (
55
err: any,
66
req: Request,
77
res: Response,
8-
next: any,
8+
next: NextFunction
99
) => {
10+
// Log the error for debugging
11+
console.error(`Error in ${req.method} ${req.path}:`, err);
12+
1013
res.setHeader("Content-Type", "application/json");
14+
15+
let statusCode = 500;
1116
let body = {};
17+
1218
switch (err.name) {
1319
case "SequelizeValidationError":
20+
statusCode = 400;
1421
body = {
1522
type: "ValidationError",
16-
errors: err.errors.map((e: any) => {
17-
return {
18-
message: e.message,
19-
path: e.path,
20-
};
21-
}),
23+
errors: err.errors.map((e: any) => ({
24+
message: e.message,
25+
path: e.path,
26+
})),
2227
};
2328
break;
24-
default:
29+
case "AuthError":
30+
// Use the status from the error if available, otherwise default to 500
31+
statusCode = err.status || 500;
2532
body = {
26-
type: err.name,
33+
type: "AuthError",
2734
errors: [{ message: err.message }],
2835
};
36+
break;
37+
default:
38+
// Check if error has a status property
39+
statusCode = err.status || err.statusCode || 500;
40+
body = {
41+
type: err.name || "Error",
42+
errors: [{ message: err.message || "Internal server error" }],
43+
};
2944
}
3045

31-
console.error(err.name);
32-
res.status(500);
33-
res.send(JSON.stringify(body));
46+
res.status(statusCode).json(body);
3447
};

app/backend/src/routes/configRoutes.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ import {
44
getConfigByKey,
55
updateConfig,
66
} from "@controllers/ConfigController.js";
7+
import { asyncHandler } from "@middleware/async-handler.js";
78

89
const router = Router();
910

10-
router.get("/", getConfig);
11-
router.get("/:key", getConfigByKey); // Alias for getConfig
12-
router.put("/", updateConfig);
11+
router.get("/", asyncHandler(getConfig));
12+
router.get("/:key", asyncHandler(getConfigByKey)); // Alias for getConfig
13+
router.put("/", asyncHandler(updateConfig));
1314

1415
export default router;

app/backend/src/routes/fuelLogRoutes.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ import {
77
deleteFuelLog,
88
} from "@controllers/FuelLogController.js";
99
import { authenticatePin } from "@middleware/auth.js";
10+
import { asyncHandler } from "@middleware/async-handler.js";
1011

1112
const router = Router({ mergeParams: true });
1213

13-
router.post("/", authenticatePin, addFuelLog);
14-
router.get("/", authenticatePin, getFuelLogs);
15-
router.get("/:id", authenticatePin, getFuelLogById);
16-
router.put("/:id", authenticatePin, updateFuelLog);
17-
router.delete("/:id", authenticatePin, deleteFuelLog);
14+
router.post("/", authenticatePin, asyncHandler(addFuelLog));
15+
router.get("/", authenticatePin, asyncHandler(getFuelLogs));
16+
router.get("/:id", authenticatePin, asyncHandler(getFuelLogById));
17+
router.put("/:id", authenticatePin, asyncHandler(updateFuelLog));
18+
router.delete("/:id", authenticatePin, asyncHandler(deleteFuelLog));
1819

1920
export default router;

0 commit comments

Comments
 (0)