docs & feat: update project plan to E2E encrypted server storage & initialize monorepo client/server codebases

This commit is contained in:
2026-05-27 21:22:02 +02:00
parent d4b3cc2d74
commit db8b454a9e
43 changed files with 10646 additions and 206 deletions
+1826
View File
File diff suppressed because it is too large Load Diff
+27
View File
@@ -0,0 +1,27 @@
{
"name": "server",
"version": "1.0.0",
"description": "Backend API for Kapteins Daagbox",
"main": "dist/index.js",
"type": "module",
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "tsx watch src/index.ts"
},
"dependencies": {
"@prisma/client": "^5.10.2",
"@simplewebauthn/server": "^9.0.3",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.19.2"
},
"devDependencies": {
"@types/cors": "^2.8.17",
"@types/express": "^4.17.21",
"@types/node": "^20.11.24",
"prisma": "^5.10.2",
"tsx": "^4.7.1",
"typescript": "^5.3.3"
}
}
+90
View File
@@ -0,0 +1,90 @@
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model User {
id String @id @default(uuid())
username String @unique
createdAt DateTime @default(now())
credentials Credential[]
logbooks Logbook[]
}
model Credential {
id String @id @default(uuid())
userId String
credentialId String @unique
publicKey Bytes
counter BigInt
transports String[] // WebAuthn transports list
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
}
model Logbook {
id String @id @default(uuid())
userId String
encryptedTitle String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
yachts YachtPayload[]
crews CrewPayload[]
deviations DeviationPayload[]
entries EntryPayload[]
@@index([userId])
}
model YachtPayload {
id String @id @default(uuid())
logbookId String @unique
encryptedData String
iv String
tag String
updatedAt DateTime @updatedAt
logbook Logbook @relation(fields: [logbookId], references: [id], onDelete: Cascade)
}
model CrewPayload {
id String @id @default(uuid())
logbookId String
payloadId String
encryptedData String
iv String
tag String
updatedAt DateTime @updatedAt
logbook Logbook @relation(fields: [logbookId], references: [id], onDelete: Cascade)
@@unique([logbookId, payloadId])
}
model DeviationPayload {
id String @id @default(uuid())
logbookId String @unique
encryptedData String
iv String
tag String
updatedAt DateTime @updatedAt
logbook Logbook @relation(fields: [logbookId], references: [id], onDelete: Cascade)
}
model EntryPayload {
id String @id @default(uuid())
logbookId String
payloadId String
encryptedData String
iv String
tag String
updatedAt DateTime @updatedAt
logbook Logbook @relation(fields: [logbookId], references: [id], onDelete: Cascade)
@@unique([logbookId, payloadId])
@@index([logbookId])
}
+24
View File
@@ -0,0 +1,24 @@
import express from 'express'
import cors from 'cors'
import dotenv from 'dotenv'
dotenv.config()
const app = express()
const PORT = process.env.PORT || 5000
app.use(cors())
app.use(express.json())
// Health check endpoint
app.get('/api/health', (req, res) => {
res.json({
status: 'ok',
timestamp: new Date().toISOString(),
service: 'Kapteins Daagbox Backend'
})
})
app.listen(PORT, () => {
console.log(`[server] Server running on http://localhost:${PORT}`)
})
+16
View File
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"lib": ["ES2022"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true
},
"include": ["src/**/*"]
}