Docs
Tech Stack
The technical stack and architecture decisions for CraftlyNow.
Tech Stack
Core stack
| Layer | Technology | Purpose |
|---|---|---|
| Frontend | Nuxt.js + Nuxt UI | App framework and UI components |
| Backend / DB | Supabase | Database, auth, storage, API |
| Hosting | Vercel | Deployment and edge functions |
| Editor | TipTap | Rich text editing for video descriptions |
Supabase
Supabase handles everything on the backend:
- Auth — user sign-in and session management
- Database — courses, videos, transcripts, metadata
- Storage — any assets attached to courses
- RLS — row-level security ensures users only manage their own courses
Core tables
courses
id uuid primary key
user_id uuid references auth.users
title text
description text
is_published boolean default false
share_token text unique
created_at timestamptz
course_videos
id uuid primary key
course_id uuid references courses
youtube_url text
youtube_title text
youtube_thumb text
youtube_desc text
transcript text
notes text -- TipTap JSON or HTML
position integer
created_at timestamptz
YouTube data layer
YouTube metadata and transcripts are pulled server-side to avoid CORS issues and to keep API keys off the client.
Metadata pull (YouTube oEmbed / Data API):
- Title
- Thumbnail
- Description
- Channel name
Transcript pull:
- Uses the YouTube transcript API (unofficial) or a Supabase edge function
- If no transcript is available, the field is set to null
- Transcript is stored once and not re-fetched
TipTap editor
TipTap is used for the per-video description / notes field.
- Renders as a rich text editor for authenticated users
- Renders as read-only formatted content for viewers
- AI generation writes into TipTap's content format
- Supports text, headings, bullet lists, bold, italic as a minimum
AI summary generation
The AI summary is generated from the stored transcript using a server-side API call.
- Triggered manually by the user (not automatic on save)
- Output is written into the TipTap description field
- The user can edit, regenerate, or ignore the AI output
- No AI generation if transcript is null
Sharing architecture
Each course has a share_token — a unique random string generated on creation.
- Private share URL:
/c/[share_token] - Public URL:
/courses/[id]or/courses/[slug]— only active whenis_published = true
Public courses appear on the landing page via a Supabase query filtered to is_published = true.