feat: migrate from SQLite to PostgreSQL - complete schema and API updates

- Remove better-sqlite3, add pg driver
- Convert schema to PostgreSQL types (serial, timestamp, boolean, jsonb)
- Generate fresh PostgreSQL migrations
- Update database connection layer with pg.Pool
- Fix all API routes: remove JSON.parse/stringify, use native timestamps and booleans
- Update drizzle.config.ts and .env.example for PostgreSQL
This commit is contained in:
Marko Djordjevic 2026-02-17 13:43:06 +01:00
parent 4605283d2b
commit 5f70f13da3
37 changed files with 1164 additions and 1825 deletions

248
package-lock.json generated
View file

@ -13,13 +13,12 @@
"@radix-ui/react-label": "^2.1.8",
"@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-slider": "^1.3.6",
"@types/better-sqlite3": "^7.6.13",
"@types/node": "^25.2.3",
"@types/papaparse": "^5.5.2",
"@types/pg": "^8.11.10",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"autoprefixer": "^10.4.24",
"better-sqlite3": "^12.6.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"drizzle-orm": "^0.45.1",
@ -30,6 +29,7 @@
"next": "^16.1.6",
"next-themes": "^0.4.6",
"papaparse": "^5.5.3",
"pg": "^8.13.1",
"postcss": "^8.5.6",
"react": "^19.2.4",
"react-dom": "^19.2.4",
@ -2694,14 +2694,6 @@
"tslib": "^2.4.0"
}
},
"node_modules/@types/better-sqlite3": {
"version": "7.6.13",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/estree": {
"version": "1.0.8",
"license": "MIT"
@ -2728,6 +2720,18 @@
"@types/node": "*"
}
},
"node_modules/@types/pg": {
"version": "8.16.0",
"resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.16.0.tgz",
"integrity": "sha512-RmhMd/wD+CF8Dfo+cVIy3RR5cl8CyfXQ0tGgW6XBL8L4LM/UTEbNXYRbLwU6w+CgrKBNbrQWt4FUtTfaU5jSYQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/node": "*",
"pg-protocol": "*",
"pg-types": "^2.2.0"
}
},
"node_modules/@types/react": {
"version": "19.2.14",
"license": "MIT",
@ -3544,7 +3548,8 @@
"url": "https://feross.org/support"
}
],
"license": "MIT"
"license": "MIT",
"optional": true
},
"node_modules/baseline-browser-mapping": {
"version": "2.9.19",
@ -3553,21 +3558,6 @@
"baseline-browser-mapping": "dist/cli.js"
}
},
"node_modules/better-sqlite3": {
"version": "12.6.2",
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.6.2.tgz",
"integrity": "sha512-8VYKM3MjCa9WcaSAI3hzwhmyHVlH8tiGFwf0RlTsZPWJ1I5MkzjiudCo4KC4DxOaL/53A5B1sI/IbldNFDbsKA==",
"hasInstallScript": true,
"license": "MIT",
"peer": true,
"dependencies": {
"bindings": "^1.5.0",
"prebuild-install": "^7.1.1"
},
"engines": {
"node": "20.x || 22.x || 23.x || 24.x || 25.x"
}
},
"node_modules/binary-extensions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
@ -3584,6 +3574,7 @@
"node_modules/bindings": {
"version": "1.5.0",
"license": "MIT",
"optional": true,
"dependencies": {
"file-uri-to-path": "1.0.0"
}
@ -3591,6 +3582,7 @@
"node_modules/bl": {
"version": "4.1.0",
"license": "MIT",
"optional": true,
"dependencies": {
"buffer": "^5.5.0",
"inherits": "^2.0.4",
@ -3664,6 +3656,7 @@
}
],
"license": "MIT",
"optional": true,
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.1.13"
@ -3804,7 +3797,8 @@
},
"node_modules/chownr": {
"version": "1.1.4",
"license": "ISC"
"license": "ISC",
"optional": true
},
"node_modules/class-variance-authority": {
"version": "0.7.1",
@ -3955,6 +3949,7 @@
"node_modules/decompress-response": {
"version": "6.0.0",
"license": "MIT",
"optional": true,
"dependencies": {
"mimic-response": "^3.1.0"
},
@ -3968,6 +3963,7 @@
"node_modules/deep-extend": {
"version": "0.6.0",
"license": "MIT",
"optional": true,
"engines": {
"node": ">=4.0.0"
}
@ -4009,6 +4005,7 @@
"node_modules/detect-libc": {
"version": "2.1.2",
"license": "Apache-2.0",
"optional": true,
"engines": {
"node": ">=8"
}
@ -4203,6 +4200,7 @@
"node_modules/end-of-stream": {
"version": "1.4.5",
"license": "MIT",
"optional": true,
"dependencies": {
"once": "^1.4.0"
}
@ -4795,6 +4793,7 @@
"node_modules/expand-template": {
"version": "2.0.3",
"license": "(MIT OR WTFPL)",
"optional": true,
"engines": {
"node": ">=6"
}
@ -4858,7 +4857,8 @@
},
"node_modules/file-uri-to-path": {
"version": "1.0.0",
"license": "MIT"
"license": "MIT",
"optional": true
},
"node_modules/fill-range": {
"version": "7.1.1",
@ -4925,7 +4925,8 @@
},
"node_modules/fs-constants": {
"version": "1.0.0",
"license": "MIT"
"license": "MIT",
"optional": true
},
"node_modules/fsevents": {
"version": "2.3.3",
@ -5057,7 +5058,8 @@
},
"node_modules/github-from-package": {
"version": "0.0.0",
"license": "MIT"
"license": "MIT",
"optional": true
},
"node_modules/glob-parent": {
"version": "6.0.2",
@ -5203,7 +5205,8 @@
"url": "https://feross.org/support"
}
],
"license": "BSD-3-Clause"
"license": "BSD-3-Clause",
"optional": true
},
"node_modules/ignore": {
"version": "5.3.2",
@ -5235,11 +5238,13 @@
},
"node_modules/inherits": {
"version": "2.0.4",
"license": "ISC"
"license": "ISC",
"optional": true
},
"node_modules/ini": {
"version": "1.3.8",
"license": "ISC"
"license": "ISC",
"optional": true
},
"node_modules/internal-slot": {
"version": "1.1.0",
@ -5823,6 +5828,7 @@
"node_modules/mimic-response": {
"version": "3.1.0",
"license": "MIT",
"optional": true,
"engines": {
"node": ">=10"
},
@ -5849,7 +5855,8 @@
},
"node_modules/mkdirp-classic": {
"version": "0.5.3",
"license": "MIT"
"license": "MIT",
"optional": true
},
"node_modules/ms": {
"version": "2.1.3",
@ -5885,7 +5892,8 @@
},
"node_modules/napi-build-utils": {
"version": "2.0.0",
"license": "MIT"
"license": "MIT",
"optional": true
},
"node_modules/napi-postinstall": {
"version": "0.3.4",
@ -5994,6 +6002,7 @@
"node_modules/node-abi": {
"version": "3.87.0",
"license": "MIT",
"optional": true,
"dependencies": {
"semver": "^7.3.5"
},
@ -6004,6 +6013,7 @@
"node_modules/node-abi/node_modules/semver": {
"version": "7.7.4",
"license": "ISC",
"optional": true,
"bin": {
"semver": "bin/semver.js"
},
@ -6137,6 +6147,7 @@
"node_modules/once": {
"version": "1.4.0",
"license": "ISC",
"optional": true,
"dependencies": {
"wrappy": "1"
}
@ -6229,6 +6240,96 @@
"version": "1.0.7",
"license": "MIT"
},
"node_modules/pg": {
"version": "8.18.0",
"resolved": "https://registry.npmjs.org/pg/-/pg-8.18.0.tgz",
"integrity": "sha512-xqrUDL1b9MbkydY/s+VZ6v+xiMUmOUk7SS9d/1kpyQxoJ6U9AO1oIJyUWVZojbfe5Cc/oluutcgFG4L9RDP1iQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"pg-connection-string": "^2.11.0",
"pg-pool": "^3.11.0",
"pg-protocol": "^1.11.0",
"pg-types": "2.2.0",
"pgpass": "1.0.5"
},
"engines": {
"node": ">= 16.0.0"
},
"optionalDependencies": {
"pg-cloudflare": "^1.3.0"
},
"peerDependencies": {
"pg-native": ">=3.0.1"
},
"peerDependenciesMeta": {
"pg-native": {
"optional": true
}
}
},
"node_modules/pg-cloudflare": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.3.0.tgz",
"integrity": "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==",
"license": "MIT",
"optional": true
},
"node_modules/pg-connection-string": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.11.0.tgz",
"integrity": "sha512-kecgoJwhOpxYU21rZjULrmrBJ698U2RxXofKVzOn5UDj61BPj/qMb7diYUR1nLScCDbrztQFl1TaQZT0t1EtzQ==",
"license": "MIT"
},
"node_modules/pg-int8": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
"integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
"license": "ISC",
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/pg-pool": {
"version": "3.11.0",
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.11.0.tgz",
"integrity": "sha512-MJYfvHwtGp870aeusDh+hg9apvOe2zmpZJpyt+BMtzUWlVqbhFmMK6bOBXLBUPd7iRtIF9fZplDc7KrPN3PN7w==",
"license": "MIT",
"peerDependencies": {
"pg": ">=8.0"
}
},
"node_modules/pg-protocol": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.11.0.tgz",
"integrity": "sha512-pfsxk2M9M3BuGgDOfuy37VNRRX3jmKgMjcvAcWqNDpZSf4cUmv8HSOl5ViRQFsfARFn0KuUQTgLxVMbNq5NW3g==",
"license": "MIT"
},
"node_modules/pg-types": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
"integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
"license": "MIT",
"dependencies": {
"pg-int8": "1.0.1",
"postgres-array": "~2.0.0",
"postgres-bytea": "~1.0.0",
"postgres-date": "~1.0.4",
"postgres-interval": "^1.1.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/pgpass": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
"integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
"license": "MIT",
"dependencies": {
"split2": "^4.1.0"
}
},
"node_modules/picocolors": {
"version": "1.1.1",
"license": "ISC"
@ -6428,9 +6529,49 @@
"version": "4.2.0",
"license": "MIT"
},
"node_modules/postgres-array": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
"integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/postgres-bytea": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz",
"integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/postgres-date": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
"integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/postgres-interval": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
"integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
"license": "MIT",
"dependencies": {
"xtend": "^4.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/prebuild-install": {
"version": "7.1.3",
"license": "MIT",
"optional": true,
"dependencies": {
"detect-libc": "^2.0.0",
"expand-template": "^2.0.3",
@ -6471,6 +6612,7 @@
"node_modules/pump": {
"version": "3.0.3",
"license": "MIT",
"optional": true,
"dependencies": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
@ -6504,6 +6646,7 @@
"node_modules/rc": {
"version": "1.2.8",
"license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
"optional": true,
"dependencies": {
"deep-extend": "^0.6.0",
"ini": "~1.3.0",
@ -6517,6 +6660,7 @@
"node_modules/rc/node_modules/strip-json-comments": {
"version": "2.0.1",
"license": "MIT",
"optional": true,
"engines": {
"node": ">=0.10.0"
}
@ -6626,6 +6770,7 @@
"node_modules/readable-stream": {
"version": "3.6.2",
"license": "MIT",
"optional": true,
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@ -6780,7 +6925,8 @@
"url": "https://feross.org/support"
}
],
"license": "MIT"
"license": "MIT",
"optional": true
},
"node_modules/safe-push-apply": {
"version": "1.0.0",
@ -7013,7 +7159,8 @@
"url": "https://feross.org/support"
}
],
"license": "MIT"
"license": "MIT",
"optional": true
},
"node_modules/simple-get": {
"version": "4.0.1",
@ -7032,6 +7179,7 @@
}
],
"license": "MIT",
"optional": true,
"dependencies": {
"decompress-response": "^6.0.0",
"once": "^1.3.1",
@ -7062,6 +7210,15 @@
"source-map": "^0.6.0"
}
},
"node_modules/split2": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
"integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
"license": "ISC",
"engines": {
"node": ">= 10.x"
}
},
"node_modules/stable-hash": {
"version": "0.0.5",
"license": "MIT"
@ -7080,6 +7237,7 @@
"node_modules/string_decoder": {
"version": "1.3.0",
"license": "MIT",
"optional": true,
"dependencies": {
"safe-buffer": "~5.2.0"
}
@ -7339,6 +7497,7 @@
"node_modules/tar-fs": {
"version": "2.1.4",
"license": "MIT",
"optional": true,
"dependencies": {
"chownr": "^1.1.1",
"mkdirp-classic": "^0.5.2",
@ -7349,6 +7508,7 @@
"node_modules/tar-stream": {
"version": "2.2.0",
"license": "MIT",
"optional": true,
"dependencies": {
"bl": "^4.0.3",
"end-of-stream": "^1.4.1",
@ -7982,6 +8142,7 @@
"node_modules/tunnel-agent": {
"version": "0.6.0",
"license": "Apache-2.0",
"optional": true,
"dependencies": {
"safe-buffer": "^5.0.1"
},
@ -8230,6 +8391,7 @@
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"devOptional": true,
"license": "MIT"
},
"node_modules/which": {
@ -8331,7 +8493,17 @@
},
"node_modules/wrappy": {
"version": "1.0.2",
"license": "ISC"
"license": "ISC",
"optional": true
},
"node_modules/xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
"license": "MIT",
"engines": {
"node": ">=0.4"
}
},
"node_modules/yallist": {
"version": "3.1.1",