SecureShare is a tutorial and reference implementation of a one-time-use message sharing web-app, developed using Next.JS 14, TypeScript, Prisma, and styled with Tailwind CSS
Important Note: This project is part of an in-person tutorial series and serves as a reference implementation for educational purposes. The goal is to demonstrate how to build a simple product with real-world utility beyond academic exercises. It is not intended for production use.
SecureShare is a tutorial and reference implementation of a one-time-use message sharing web-app, developed using Next.JS 14, TypeScript, Prisma, and styled with Tailwind CSS
See Sequence diagram below for a detailed overview of the process
Framework: Next.js 14
Language: TypeScript
ORM: Prisma (for PostgreSQL)
Styling: Tailwind CSS
git clone [email protected]:johanns/ref-secure-share.git
npm install
or
bun install
.env
file in the project root and add the following environment variables:DATABASE_URL="postgresql://<username>:<password>@localhost:5432/<database>"
NOTE: Replace <username>
, <password>
, and <database>
with your PostgreSQL credentials.
npx prisma migrate dev
or
bun run prisma migrate dev
npm run dev
or
bun run dev
http://localhost:3000
.prisma
├── migrations/ -- Database migration files
└── schema.prisma -- Prisma schema definition
src
├── app
│ ├── api
│ │ └── message
│ │ ├── route.ts -- Message creation endpoint (POST)
│ │ └── [stub]
│ │ └── route.ts -- Message retrieval endpoint (GET, DELETE)
│ ├── layout.tsx -- Application layout
│ ├── page.tsx -- Message creation page
│ └── [stub]
│ └── page.tsx -- Message retrieval page
├── assets
│ └── css
│ └── globals.css
├── lib
│ ├── crypto.ts - Client-side encryption/decryption functions
│ ├── modelValidationError.ts - Model validation error handler
│ └── prisma.ts - Prisma client initialization
└── models
└── message.ts - Message model
sequenceDiagram
autonumber
Sender->>Server: GET / <br/>
Server-->>Sender: Render <br /> /app/page.tsx
note over Sender,Server: On form submit
Sender->>Sender: Generate encryption key <br /> /lib/crypto.ts
Sender->>Sender: Encrypt data <br /> /lib/crypto.ts
Sender->>+Server: Submit encrypted form data
Server<<-->>Database: Find unique retrieval stub <br /> /models/message.ts
Server<<-->>Database: Store encrypted form data <br /> /models/message.ts
Server-->>-Sender: Render JSON: {stub: stub}
Sender->>Sender: Construct retrieval URL <br /> (stub + key)
note over Sender,Server: Show retrieval URL
sequenceDiagram
autonumber
Recipient->>+Server: GET /<stub> <br /> /app/[stub]/page.tsx
Server-->>-Recipient: Render page
note over Recipient,Server: On page load <br /> useEffect(...)
Recipient->>+Server: GET /api/message/[stub] <br /> /app/api/message/[stub]/route.ts
Server<<-->>Database: Find encrypted data <br /> /models/message.ts
Server<<-->>Database: Mark message as read <br /> /models/message.ts
Server-->>-Recipient: Render JSON: {data: encryptedData}
Recipient->>Recipient: Extract key from URL <br /> /lib/crypto.ts
Recipient->>Recipient: Decrypt data <br /> /lib/crypto.ts
note over Recipient,Server: Show decrypted data or already read notice