Skip to content
This repository was archived by the owner on Jan 14, 2026. It is now read-only.

Commit f50a422

Browse files
Merge pull request #97 from dcsil/dev-frontend
Dev frontend
2 parents 3831325 + 4a98f6f commit f50a422

38 files changed

+5127
-153
lines changed
853 KB
Loading

architecture/adrs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ For any architectural/engineering decisions we make, we will create an ADR (Arch
2121
- [ADR 006: Postiz](./adr-006.md)
2222
- [ADR 007: Gemini](./adr-007.md)
2323
- [ADR 008: Azure Virtual Machine (Deployment)](./adr-008.md)
24+
- [ADR 009: Cloudinary](./adr-009.md)

architecture/adrs/adr-009.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
## ADR 009: Cloudinary
2+
3+
## Context
4+
5+
We need reliable cloud storage for media assets uploaded by users for social media posts. Our social media management workflow requires:
6+
- Secure storage for images and videos uploaded by musicians
7+
- Public URLs for media files that can be accessed by social media APIs
8+
- Integration with our Next.js backend and Postiz scheduling system
9+
- Separation of concerns between media storage and post scheduling
10+
11+
### Options
12+
13+
1) Self-hosted storage on our server
14+
2) AWS S3
15+
3) Cloudinary
16+
17+
## Decision
18+
19+
We will use Cloudinary for media asset storage and management.
20+
21+
Reasons for choosing Cloudinary:
22+
1) Provides reliable cloud infrastructure with built-in CDN, ensuring consistent access to media files for social media APIs regardless of our server status.
23+
2) Offers straightforward Node.js SDK integration that works seamlessly with our Next.js backend.
24+
3) Generates public URLs automatically, simplifying the handoff between our upload flow and Postiz's scheduling system.
25+
26+
Reasons for not choosing alternatives:
27+
1) Self-hosted storage couples media availability to our server uptime, which creates a single point of failure that could break scheduled posts if the server goes down.
28+
2) AWS S3 requires more configuration for public URL management and CDN setup. This adds complexity without significant benefit for our use case.
29+
3) Separating storage from our Postiz container improves system reliability, as Postiz can focus on scheduling while Cloudinary handles media delivery.
30+
31+
32+
## Status
33+
34+
Accepted
35+
36+
## Consequences
37+
38+
Using Cloudinary decouples media storage from our application server, which improves reliability for scheduled social media posts. The managed service reduces operational burden and provides a CDN out of the box. However, we accept vendor lock-in to Cloudinary's platform and potential costs if usage exceeds the free tier. The separation of concerns between storage (Cloudinary) and scheduling (Postiz) creates a more resilient architecture where each component can operate independently.
39+
40+
## Potential Backups
41+
42+
- AWS S3 with CloudFront, if Cloudinary pricing becomes prohibitive or we need more storage control.
43+
- Self-hosted storage on the server, for complete data ownership and no vendor lock-in, though this would require additional infrastructure management.

architecture/diagram.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
The frontend is made possible by a React web app. It connects to Next.js in the backend. In the MVP, the setup is as allows: the backend connects to a social media management API, specifically Postiz, which allows management of multiple social media platforms. The LLM API is Gemini. For the database, Prisma ORM and SQLite are used. (Longer term features include billing and authentication, which will be enabled by APIs.)
22

3-
<img src="./diagram.png" width="1000">
3+
<img src="./ArchitectureDiagram.png" width="1000">

package-lock.json

Lines changed: 163 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"@prisma/studio": "^0.511.0",
1818
"bcryptjs": "^2.4.3",
1919
"class-variance-authority": "^0.7.1",
20+
"cloudinary": "^2.8.0",
2021
"clsx": "^2.1.1",
2122
"jsonwebtoken": "^9.0.2",
2223
"lucide-react": "^0.545.0",
@@ -34,13 +35,15 @@
3435
"@eslint/eslintrc": "^3",
3536
"@tailwindcss/postcss": "^4",
3637
"@testing-library/dom": "^10.4.1",
38+
"@testing-library/jest-dom": "^6.9.1",
3739
"@testing-library/react": "^16.3.0",
3840
"@types/bcryptjs": "^2.4.6",
3941
"@types/jsonwebtoken": "^9.0.7",
4042
"@types/node": "^20",
4143
"@types/react": "^19",
4244
"@types/react-dom": "^19",
4345
"@vitejs/plugin-react": "^5.0.4",
46+
"@vitest/coverage-istanbul": "^3.2.4",
4447
"@vitest/coverage-v8": "^3.2.4",
4548
"eslint": "^9",
4649
"eslint-config-next": "15.5.4",

prisma/schema.prisma

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ model User {
120120
121121
// Relations
122122
preferences UserPreference?
123+
profile UserProfile?
123124
authAccounts AuthAccount[]
124125
refreshTokens RefreshToken[]
125126
emailVerifications EmailVerificationToken[]
@@ -161,6 +162,24 @@ model UserPreference {
161162
updatedAt DateTime @updatedAt
162163
}
163164

165+
// User onboarding profile
166+
model UserProfile {
167+
id String @id @default(cuid())
168+
userId String @unique
169+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
170+
171+
// Onboarding answers
172+
hasReleasePlan Boolean? // Do they have a release plan?
173+
releaseProgress String? // "not_started" | "planning" | "in_progress" | "ready_to_launch"
174+
helpNeeded String @default("[]") // JSON array: ["project_planning", "time_management", "social_media_promotion", "networking"]
175+
176+
// Track completion
177+
onboardingCompleted Boolean @default(false)
178+
179+
createdAt DateTime @default(now())
180+
updatedAt DateTime @updatedAt
181+
}
182+
164183
// OAuth accounts for authentication (e.g., Google/Apple for sign-in)
165184
model AuthAccount {
166185
id String @id @default(cuid())

0 commit comments

Comments
 (0)