diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ddb0c99 --- /dev/null +++ b/Makefile @@ -0,0 +1,172 @@ +.PHONY: help install dev build clean db-up db-down db-restart db-clean db-migrate db-generate db-push db-studio docker-down docker-clean dev-client dev-server dev-landing dev-all clean-deps clean-build clean-all format lint check-types + +# Default target - show help +help: + @echo "MemoBrain - Available Make Commands" + @echo "" + @echo "πŸ“¦ Installation & Setup:" + @echo " make install - Install all dependencies" + @echo "" + @echo "πŸ—„οΈ Database Commands:" + @echo " make db-up - Start database container" + @echo " make db-down - Stop database container" + @echo " make db-restart - Restart database container" + @echo " make db-clean - Stop and remove database container & volumes" + @echo " make db-generate - Generate Drizzle migrations" + @echo " make db-push - Push schema changes to database" + @echo " make db-migrate - Run database migrations" + @echo " make db-studio - Open Drizzle Studio" + @echo "" + @echo "🐳 Docker Commands:" + @echo " make docker-down - Stop all Docker containers" + @echo " make docker-clean - Remove all containers, volumes, and images" + @echo "" + @echo "πŸš€ Development Commands:" + @echo " make dev - Run all apps in development mode (turbo)" + @echo " make dev-client - Run client app only" + @echo " make dev-server - Run server app only" + @echo " make dev-landing - Run landing app only" + @echo " make dev-all - Run all apps individually (parallel)" + @echo "" + @echo "πŸ—οΈ Build Commands:" + @echo " make build - Build all apps" + @echo " make build-client - Build client app only" + @echo " make build-server - Build server app only" + @echo " make build-landing - Build landing app only" + @echo "" + @echo "🧹 Cleanup Commands:" + @echo " make clean-deps - Remove all node_modules" + @echo " make clean-build - Remove all build artifacts" + @echo " make clean-all - Remove all generated files (deps + builds)" + @echo " make clean - Alias for clean-all" + @echo "" + @echo "πŸ”§ Utility Commands:" + @echo " make format - Format code with Prettier" + @echo " make lint - Lint all packages" + @echo " make check-types - Type-check all packages" + @echo "" + +# Installation +install: + @echo "πŸ“¦ Installing dependencies..." + bun install + +# Database Commands +db-up: + @echo "πŸ—„οΈ Starting database..." + cd packages/db && docker compose up -d + +db-down: + @echo "πŸ›‘ Stopping database..." + cd packages/db && docker compose down + +db-restart: + @echo "πŸ”„ Restarting database..." + cd packages/db && docker compose restart + +db-clean: + @echo "🧹 Cleaning database (removing containers and volumes)..." + cd packages/db && docker compose down -v + +db-generate: + @echo "πŸ”¨ Generating Drizzle migrations..." + cd packages/db && bun run drizzle:generate + +db-push: + @echo "⬆️ Pushing schema to database..." + cd packages/db && bun run drizzle:push + +db-migrate: + @echo "πŸš€ Running database migrations..." + cd packages/db && bun run drizzle:migrate + +db-studio: + @echo "🎨 Opening Drizzle Studio..." + cd packages/db && bun run drizzle:studio + +# Docker Commands +docker-down: + @echo "🐳 Stopping all Docker containers..." + docker compose down + +docker-clean: + @echo "🧹 Cleaning all Docker resources..." + docker compose down -v --rmi all --remove-orphans + +# Development Commands +dev: + @echo "πŸš€ Starting all apps in development mode..." + bun run dev + +dev-client: + @echo "πŸš€ Starting client app..." + cd apps/client && bun run dev + +dev-server: + @echo "πŸš€ Starting server app..." + cd apps/server && bun run dev + +dev-landing: + @echo "πŸš€ Starting landing app..." + cd apps/landing && bun run dev + +dev-all: + @echo "πŸš€ Starting all apps individually..." + @echo "Note: Run each in a separate terminal or use a process manager" + @echo "Terminal 1: make dev-client" + @echo "Terminal 2: make dev-server" + @echo "Terminal 3: make dev-landing" + +# Build Commands +build: + @echo "πŸ—οΈ Building all apps..." + bun run build + +build-client: + @echo "πŸ—οΈ Building client app..." + cd apps/client && bun run build + +build-server: + @echo "πŸ—οΈ Building server app..." + cd apps/server && bun run build + +build-landing: + @echo "πŸ—οΈ Building landing app..." + cd apps/landing && bun run build + +# Cleanup Commands +clean-deps: + @echo "🧹 Removing all node_modules..." + rm -rf node_modules + rm -rf apps/*/node_modules + rm -rf packages/*/node_modules + @echo "βœ… Dependencies cleaned!" + +clean-build: + @echo "🧹 Removing build artifacts..." + rm -rf apps/client/dist + rm -rf apps/landing/.next + rm -rf apps/server/dist + rm -rf packages/*/dist + rm -rf .turbo + @echo "βœ… Build artifacts cleaned!" + +clean-all: clean-build clean-deps + @echo "🧹 Removing all generated files..." + rm -rf bun.lockb + @echo "βœ… All cleaned! Run 'make install' to reinstall." + +clean: clean-all + +# Utility Commands +format: + @echo "✨ Formatting code..." + bun run format + +lint: + @echo "πŸ” Linting code..." + bun run lint + +check-types: + @echo "πŸ”Ž Type-checking..." + bun run check-types \ No newline at end of file diff --git a/apps/client/package.json b/apps/client/package.json index c7feea0..2fa47d2 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -11,6 +11,7 @@ "check-types": "tsc --noEmit" }, "dependencies": { + "@assets": "workspace:*", "react": "^19.1.1", "react-dom": "^19.1.1" }, diff --git a/apps/client/src/index.css b/apps/client/src/index.css index da7f15a..5e31d6c 100644 --- a/apps/client/src/index.css +++ b/apps/client/src/index.css @@ -1,70 +1,22 @@ +@import "tailwindcss"; @import "@repo/tailwind-config/theme.css"; :root { font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; line-height: 1.5; font-weight: 400; - - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; - font-synthesis: none; text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} -a:hover { - color: #535bf2; -} - body { margin: 0; - display: flex; - place-items: center; min-width: 320px; min-height: 100vh; -} - -h1 { - font-size: 3.2em; - line-height: 1.1; -} - -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; -} -button:hover { - border-color: #646cff; -} -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } + display: flex; + place-items: center; + /* Use shared Tailwind color tokens from packages/tailwind-config/theme.css */ + @apply bg-background text-text; } diff --git a/apps/client/vite.config.ts b/apps/client/vite.config.ts index 8b0f57b..4bd471b 100644 --- a/apps/client/vite.config.ts +++ b/apps/client/vite.config.ts @@ -1,7 +1,13 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' +import path from 'node:path' // https://vite.dev/config/ export default defineConfig({ plugins: [react()], + resolve: { + alias: { + '@assets': path.resolve(__dirname, '../..', 'packages/assets'), + }, + }, }) diff --git a/apps/landing/app/globals.css b/apps/landing/app/globals.css index 3df93cd..1f0c148 100644 --- a/apps/landing/app/globals.css +++ b/apps/landing/app/globals.css @@ -1,53 +1,8 @@ @import "tailwindcss"; @import "@repo/tailwind-config/theme.css"; -:root { - --background: #ffffff; - --foreground: #171717; -} - -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; - } -} - html, body { max-width: 100vw; overflow-x: hidden; -} - -body { - color: var(--foreground); - background: var(--background); -} - -* { - box-sizing: border-box; - padding: 0; - margin: 0; -} - -a { - color: inherit; - text-decoration: none; -} - -.imgDark { - display: none; -} - -@media (prefers-color-scheme: dark) { - html { - color-scheme: dark; - } - - .imgLight { - display: none; - } - .imgDark { - display: unset; - } -} +} \ No newline at end of file diff --git a/apps/landing/app/layout.tsx b/apps/landing/app/layout.tsx index 8469537..7b653f9 100644 --- a/apps/landing/app/layout.tsx +++ b/apps/landing/app/layout.tsx @@ -22,7 +22,7 @@ export default function RootLayout({ children: React.ReactNode; }>) { return ( - + {children} diff --git a/apps/landing/app/page.module.css b/apps/landing/app/page.module.css deleted file mode 100644 index 3630662..0000000 --- a/apps/landing/app/page.module.css +++ /dev/null @@ -1,188 +0,0 @@ -.page { - --gray-rgb: 0, 0, 0; - --gray-alpha-200: rgba(var(--gray-rgb), 0.08); - --gray-alpha-100: rgba(var(--gray-rgb), 0.05); - - --button-primary-hover: #383838; - --button-secondary-hover: #f2f2f2; - - display: grid; - grid-template-rows: 20px 1fr 20px; - align-items: center; - justify-items: center; - min-height: 100svh; - padding: 80px; - gap: 64px; - font-synthesis: none; -} - -@media (prefers-color-scheme: dark) { - .page { - --gray-rgb: 255, 255, 255; - --gray-alpha-200: rgba(var(--gray-rgb), 0.145); - --gray-alpha-100: rgba(var(--gray-rgb), 0.06); - - --button-primary-hover: #ccc; - --button-secondary-hover: #1a1a1a; - } -} - -.main { - display: flex; - flex-direction: column; - gap: 32px; - grid-row-start: 2; -} - -.main ol { - font-family: var(--font-geist-mono); - padding-left: 0; - margin: 0; - font-size: 14px; - line-height: 24px; - letter-spacing: -0.01em; - list-style-position: inside; -} - -.main li:not(:last-of-type) { - margin-bottom: 8px; -} - -.main code { - font-family: inherit; - background: var(--gray-alpha-100); - padding: 2px 4px; - border-radius: 4px; - font-weight: 600; -} - -.ctas { - display: flex; - gap: 16px; -} - -.ctas a { - appearance: none; - border-radius: 128px; - height: 48px; - padding: 0 20px; - border: none; - font-family: var(--font-geist-sans); - border: 1px solid transparent; - transition: background 0.2s, color 0.2s, border-color 0.2s; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - font-size: 16px; - line-height: 20px; - font-weight: 500; -} - -a.primary { - background: var(--foreground); - color: var(--background); - gap: 8px; -} - -a.secondary { - border-color: var(--gray-alpha-200); - min-width: 180px; -} - -button.secondary { - appearance: none; - border-radius: 128px; - height: 48px; - padding: 0 20px; - border: none; - font-family: var(--font-geist-sans); - border: 1px solid transparent; - transition: background 0.2s, color 0.2s, border-color 0.2s; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - font-size: 16px; - line-height: 20px; - font-weight: 500; - background: transparent; - border-color: var(--gray-alpha-200); - min-width: 180px; -} - -.footer { - font-family: var(--font-geist-sans); - grid-row-start: 3; - display: flex; - gap: 24px; -} - -.footer a { - display: flex; - align-items: center; - gap: 8px; -} - -.footer img { - flex-shrink: 0; -} - -/* Enable hover only on non-touch devices */ -@media (hover: hover) and (pointer: fine) { - a.primary:hover { - background: var(--button-primary-hover); - border-color: transparent; - } - - a.secondary:hover { - background: var(--button-secondary-hover); - border-color: transparent; - } - - .footer a:hover { - text-decoration: underline; - text-underline-offset: 4px; - } -} - -@media (max-width: 600px) { - .page { - padding: 32px; - padding-bottom: 80px; - } - - .main { - align-items: center; - } - - .main ol { - text-align: center; - } - - .ctas { - flex-direction: column; - } - - .ctas a { - font-size: 14px; - height: 40px; - padding: 0 16px; - } - - a.secondary { - min-width: auto; - } - - .footer { - flex-wrap: wrap; - align-items: center; - justify-content: center; - } -} - -@media (prefers-color-scheme: dark) { - .logo { - filter: invert(); - } -} diff --git a/apps/landing/app/page.tsx b/apps/landing/app/page.tsx index 23d4d59..5356054 100644 --- a/apps/landing/app/page.tsx +++ b/apps/landing/app/page.tsx @@ -1,8 +1,10 @@ import React from 'react' -import "./page.module.css"; +import Nav from '../components/Header/Header' export default function App() { return ( -
Coming Soon!
+
+
) } diff --git a/apps/landing/app/tailwind.config.ts b/apps/landing/app/tailwind.config.ts index 357f3ec..c081153 100644 --- a/apps/landing/app/tailwind.config.ts +++ b/apps/landing/app/tailwind.config.ts @@ -1,9 +1,12 @@ -import tailwindThemeConfig from "@repo/tailwind-config/tailwind.config" import type { Config } from "tailwindcss"; +import tailwindConfig from "@repo/tailwind-config/tailwind.config"; const config: Config = { - presets: [tailwindThemeConfig], - content: ["./src/**/*.{js,ts,jsx,tsx}"], + presets: [tailwindConfig], + content: [ + "./app/**/*.{js,ts,jsx,tsx,mdx}", + "./components/**/*.{js,ts,jsx,tsx,mdx}", + ], }; export default config; \ No newline at end of file diff --git a/apps/landing/components/Header/DesignStripe.tsx b/apps/landing/components/Header/DesignStripe.tsx new file mode 100644 index 0000000..416d978 --- /dev/null +++ b/apps/landing/components/Header/DesignStripe.tsx @@ -0,0 +1,14 @@ +'use client' +import React from 'react' +import { motion } from 'motion/react' + +export default function DesignStripe({ className }: { className: string }) { + return ( + + ) +} diff --git a/apps/landing/components/Header/Header.tsx b/apps/landing/components/Header/Header.tsx new file mode 100644 index 0000000..b861842 --- /dev/null +++ b/apps/landing/components/Header/Header.tsx @@ -0,0 +1,15 @@ +import React from 'react' +import HeaderDesign from './HeaderDesign' +import Nav from './Nav/Nav' + +export default function Header() { + return ( +
+ +
+
+ +
+ ) +} diff --git a/apps/landing/components/Header/HeaderDesign.tsx b/apps/landing/components/Header/HeaderDesign.tsx new file mode 100644 index 0000000..554d4de --- /dev/null +++ b/apps/landing/components/Header/HeaderDesign.tsx @@ -0,0 +1,71 @@ +"use client" + +import React from 'react' +import DesignStripe from './DesignStripe' +import { motion } from 'motion/react' + +type HeaderDesignProps = { + side: 'left' | 'right' + className?: string +} + +type StripeConfig = { + position: string + size: string + rotate?: string +} + +// Configuration for each individual stripe on each side. +// You can tweak these class strings to fine‑tune position, size, and rotation. +const LEFT_STRIPES: StripeConfig[] = [ + { position: '-top-6 -left-8', size: 'w-4 h-[120%]', rotate: 'rotate-18' }, + { position: '-top-6 -left-4', size: 'w-4 h-[120%]', rotate: 'rotate-18' }, + { position: '-top-6 left-4', size: 'w-6 h-[110%]', rotate: 'rotate-18' }, + { position: '-top-6 left-10', size: 'w-6 h-[100%]', rotate: 'rotate-16' }, + { position: '-top-6 left-19', size: 'w-4 h-[85%]', rotate: 'rotate-18' }, + { position: '-top-6 left-22', size: 'w-5 h-[110%]', rotate: 'rotate-18' }, + { position: '-top-6 left-33', size: 'w-6 h-[100%]', rotate: 'rotate-18' }, + { position: '-top-6 left-38', size: 'w-6 h-[120%]', rotate: 'rotate-14' }, + { position: '-top-6 left-60', size: 'w-1 h-[100%]', rotate: 'rotate-24' }, + { position: '-top-6 left-68', size: 'w-1 h-[120%]', rotate: 'rotate-14' }, + { position: '-top-6 left-72', size: 'w-1 h-[100%]', rotate: 'rotate-16' }, +] + +const RIGHT_STRIPES: StripeConfig[] = [ + { position: '-top-6 -right-8', size: 'w-4 h-[120%]', rotate: '-rotate-18' }, + { position: '-top-6 -right-4', size: 'w-4 h-[120%]', rotate: '-rotate-18' }, + { position: '-top-6 right-4', size: 'w-6 h-[110%]', rotate: '-rotate-18' }, + { position: '-top-6 right-10', size: 'w-6 h-[100%]', rotate: '-rotate-16' }, + { position: '-top-6 right-19', size: 'w-4 h-[85%]', rotate: '-rotate-18' }, + { position: '-top-6 right-22', size: 'w-5 h-[110%]', rotate: '-rotate-18' }, + { position: '-top-6 right-33', size: 'w-6 h-[100%]', rotate: '-rotate-18' }, + { position: '-top-6 right-38', size: 'w-6 h-[120%]', rotate: '-rotate-14' }, + { position: '-top-6 right-60', size: 'w-1 h-[100%]', rotate: '-rotate-24' }, + { position: '-top-6 right-68', size: 'w-1 h-[120%]', rotate: '-rotate-14' }, + { position: '-top-6 right-72', size: 'w-1 h-[100%]', rotate: '-rotate-16' }, +] + +export default function HeaderDesign({ side, className = '' }: HeaderDesignProps) { + const isLeft = side === 'left' + + const stripes = isLeft ? LEFT_STRIPES : RIGHT_STRIPES + + return ( +
+ + + + {stripes.map((stripe, index) => ( + + ))} +
+ ) +} diff --git a/apps/landing/components/Header/Nav/GetStarted.tsx b/apps/landing/components/Header/Nav/GetStarted.tsx new file mode 100644 index 0000000..855bbd2 --- /dev/null +++ b/apps/landing/components/Header/Nav/GetStarted.tsx @@ -0,0 +1,7 @@ +import React from 'react' + +export default function GetStarted() { + return ( +
GetStarted
+ ) +} diff --git a/apps/landing/components/Header/Nav/Logo.tsx b/apps/landing/components/Header/Nav/Logo.tsx new file mode 100644 index 0000000..0c0e6d0 --- /dev/null +++ b/apps/landing/components/Header/Nav/Logo.tsx @@ -0,0 +1,7 @@ +import React from 'react' + +export default function Logo() { + return ( +
Logo
+ ) +} diff --git a/apps/landing/components/Header/Nav/Nav.tsx b/apps/landing/components/Header/Nav/Nav.tsx new file mode 100644 index 0000000..8e5cbd6 --- /dev/null +++ b/apps/landing/components/Header/Nav/Nav.tsx @@ -0,0 +1,24 @@ +import React from 'react' +import GetStarted from './GetStarted' +import Logo from './Logo' +import Option from './Option' + +const options = [ + { href: "/", name: "Home" }, + { href: "/about", name: "About" }, + { href: "/contact", name: "Contact" }, +] + +export default function Nav() { + return ( +
+ +
+ {options.map((option) => ( +
+ +
+ ) +} diff --git a/apps/landing/components/Header/Nav/Option.tsx b/apps/landing/components/Header/Nav/Option.tsx new file mode 100644 index 0000000..7c59387 --- /dev/null +++ b/apps/landing/components/Header/Nav/Option.tsx @@ -0,0 +1,12 @@ +import React from 'react' +import Link from 'next/link' + +export default function Option({ href, name }: { href: string, name: string }) { + return ( +
+ + { name } + +
+ ) +} diff --git a/apps/landing/next.config.js b/apps/landing/next.config.js index 03e59bf..2afead6 100644 --- a/apps/landing/next.config.js +++ b/apps/landing/next.config.js @@ -1,6 +1,6 @@ /** @type {import('next').NextConfig} */ const nextConfig = { - transpilePackages: ["@repo/tailwind-theme"], + transpilePackages: ["@repo/tailwind-theme", "@assets"], }; export default nextConfig; diff --git a/apps/landing/package.json b/apps/landing/package.json index 9d9adae..c900639 100644 --- a/apps/landing/package.json +++ b/apps/landing/package.json @@ -12,6 +12,8 @@ }, "dependencies": { "@repo/ui": "*", + "@assets": "workspace:*", + "motion": "^12.23.25", "next": "^15.5.0", "react": "^19.1.0", "react-dom": "^19.1.0" diff --git a/apps/server/.env.example b/apps/server/.env.example new file mode 100644 index 0000000..8043f37 --- /dev/null +++ b/apps/server/.env.example @@ -0,0 +1,22 @@ +GOOGLE_CLIENT_ID= +GOOGLE_CLIENT_SECRET= +GOOGLE_REDIRECT_URI= + +DATABASE_USER= +DATABASE_PASSWORD= +DATABASE_HOST= +DATABASE_PORT= +DATABASE_NAME= + +ACCESS_JWT_SECRET= +REFRESH_JWT_SECRET= + +ACCESS_TOKEN_COOKIE_NAME= +REFRESH_TOKEN_COOKIE_NAME= +ACCESS_TOKEN_EXPIRE= +REFRESH_TOKEN_EXPIRE= + +CLIENT_APP_URL= + +HASH_ALGORITHM= +HASH_SALT_ROUNDS= \ No newline at end of file diff --git a/bun.lockb b/bun.lockb index 0261bcb..3d5dc4e 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 173d5f3..472ecd8 100644 --- a/package.json +++ b/package.json @@ -9,12 +9,12 @@ "check-types": "turbo run check-types" }, "devDependencies": { - "@tailwindcss/postcss": "^4.1.13", - "autoprefixer": "^10.4.21", + "@tailwindcss/postcss": "^4.1.18", + "autoprefixer": "^10.4.23", "postcss": "^8.5.6", - "prettier": "^3.6.2", - "tailwindcss": "^4.1.13", - "turbo": "^2.5.8", + "prettier": "^3.8.1", + "tailwindcss": "^4.1.18", + "turbo": "^2.7.6", "typescript": "5.9.2" }, "engines": { diff --git a/packages/assets/images.d.ts b/packages/assets/images.d.ts new file mode 100644 index 0000000..c43d4d5 --- /dev/null +++ b/packages/assets/images.d.ts @@ -0,0 +1,29 @@ +declare module "*.png" { + const value: string; + export default value; +} + +declare module "*.jpg" { + const value: string; + export default value; +} + +declare module "*.jpeg" { + const value: string; + export default value; +} + +declare module "*.gif" { + const value: string; + export default value; +} + +declare module "*.svg" { + const value: string; + export default value; +} + +declare module "*.webp" { + const value: string; + export default value; +} diff --git a/packages/assets/index.ts b/packages/assets/index.ts new file mode 100644 index 0000000..fd9ee43 --- /dev/null +++ b/packages/assets/index.ts @@ -0,0 +1,3 @@ +export { default as logo } from './logo.png'; + + diff --git a/packages/assets/logo.png b/packages/assets/logo.png new file mode 100644 index 0000000..76cdfea Binary files /dev/null and b/packages/assets/logo.png differ diff --git a/packages/assets/package.json b/packages/assets/package.json new file mode 100644 index 0000000..0462780 --- /dev/null +++ b/packages/assets/package.json @@ -0,0 +1,17 @@ +{ + "name": "@assets", + "version": "0.1.0", + "private": false, + "main": "dist/index.js", + "module": "dist/index.mjs", + "types": "dist/index.d.ts", + "scripts": { + "build": "tsc -p tsconfig.json", + "check-types": "tsc --noEmit" + }, + "peerDependencies": { + "react": "^18 || ^19" + } +} + + diff --git a/packages/assets/public/.gitkeep b/packages/assets/public/.gitkeep new file mode 100644 index 0000000..139597f --- /dev/null +++ b/packages/assets/public/.gitkeep @@ -0,0 +1,2 @@ + + diff --git a/packages/assets/tsconfig.json b/packages/assets/tsconfig.json new file mode 100644 index 0000000..a0c62fb --- /dev/null +++ b/packages/assets/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "@repo/typescript-config/react-library.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": ["index.ts", "images.d.ts"], + "exclude": ["node_modules", "dist"] +} + + diff --git a/packages/db/Makefile b/packages/db/Makefile deleted file mode 100644 index fd78b9e..0000000 --- a/packages/db/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -docker-up: - docker-compose up -d - - \ No newline at end of file diff --git a/packages/db/docker-compose.yml b/packages/db/docker-compose.yml index c77a57f..d298cd3 100644 --- a/packages/db/docker-compose.yml +++ b/packages/db/docker-compose.yml @@ -1,6 +1,6 @@ services: postgres: - image: postgres:17-alpine + image: postgres:18-alpine restart: always environment: - POSTGRES_USER=postgres diff --git a/packages/db/drizzle/0001_milky_gorilla_man.sql b/packages/db/drizzle/0001_milky_gorilla_man.sql new file mode 100644 index 0000000..fd84f70 --- /dev/null +++ b/packages/db/drizzle/0001_milky_gorilla_man.sql @@ -0,0 +1,37 @@ +CREATE TABLE "slice_access" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "slice_id" uuid NOT NULL, + "user_id" uuid NOT NULL, + "role" text NOT NULL +); +--> statement-breakpoint +CREATE TABLE "refresh_tokens" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "user_id" uuid NOT NULL, + "token_hash" varchar(256) NOT NULL, + "expires_at" timestamp NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + "revoked_at" timestamp +); +--> statement-breakpoint +ALTER TABLE "slices" RENAME COLUMN "title" TO "name";--> statement-breakpoint +ALTER TABLE "slices" RENAME COLUMN "author_id" TO "owner_id";--> statement-breakpoint +ALTER TABLE "users" RENAME COLUMN "password" TO "password_hash";--> statement-breakpoint +ALTER TABLE "slices" DROP CONSTRAINT "slices_author_id_users_id_fk"; +--> statement-breakpoint +ALTER TABLE "memos" ADD COLUMN "content_type" text NOT NULL;--> statement-breakpoint +ALTER TABLE "memos" ADD COLUMN "owner_id" uuid NOT NULL;--> statement-breakpoint +ALTER TABLE "users" ADD COLUMN "name" varchar(256) NOT NULL;--> statement-breakpoint +ALTER TABLE "users" ADD COLUMN "google_id" varchar(256);--> statement-breakpoint +ALTER TABLE "slice_access" ADD CONSTRAINT "slice_access_slice_id_slices_id_fk" FOREIGN KEY ("slice_id") REFERENCES "public"."slices"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "slice_access" ADD CONSTRAINT "slice_access_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "refresh_tokens" ADD CONSTRAINT "refresh_tokens_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "memos" ADD CONSTRAINT "memos_owner_id_users_id_fk" FOREIGN KEY ("owner_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "slices" ADD CONSTRAINT "slices_owner_id_users_id_fk" FOREIGN KEY ("owner_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "memos" DROP COLUMN "updated_at";--> statement-breakpoint +ALTER TABLE "slices" DROP COLUMN "updated_at";--> statement-breakpoint +ALTER TABLE "users" DROP COLUMN "first_name";--> statement-breakpoint +ALTER TABLE "users" DROP COLUMN "last_name";--> statement-breakpoint +ALTER TABLE "users" DROP COLUMN "updated_at";--> statement-breakpoint +ALTER TABLE "users" DROP COLUMN "refresh_token";--> statement-breakpoint +ALTER TABLE "users" ADD CONSTRAINT "users_google_id_unique" UNIQUE("google_id"); \ No newline at end of file diff --git a/packages/db/drizzle/meta/0001_snapshot.json b/packages/db/drizzle/meta/0001_snapshot.json new file mode 100644 index 0000000..d21d47f --- /dev/null +++ b/packages/db/drizzle/meta/0001_snapshot.json @@ -0,0 +1,364 @@ +{ + "id": "5cc85520-26f0-4db0-be94-22cbe6659dd2", + "prevId": "1741049b-4fbe-45ed-b4a3-ac4463ace398", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.memos": { + "name": "memos", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "owner_id": { + "name": "owner_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "slice_id": { + "name": "slice_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "memos_owner_id_users_id_fk": { + "name": "memos_owner_id_users_id_fk", + "tableFrom": "memos", + "tableTo": "users", + "columnsFrom": [ + "owner_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "memos_slice_id_slices_id_fk": { + "name": "memos_slice_id_slices_id_fk", + "tableFrom": "memos", + "tableTo": "slices", + "columnsFrom": [ + "slice_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "google_id": { + "name": "google_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "password_hash": { + "name": "password_hash", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + }, + "users_google_id_unique": { + "name": "users_google_id_unique", + "nullsNotDistinct": false, + "columns": [ + "google_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.slices": { + "name": "slices", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "owner_id": { + "name": "owner_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "slices_owner_id_users_id_fk": { + "name": "slices_owner_id_users_id_fk", + "tableFrom": "slices", + "tableTo": "users", + "columnsFrom": [ + "owner_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.slice_access": { + "name": "slice_access", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "slice_id": { + "name": "slice_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "slice_access_slice_id_slices_id_fk": { + "name": "slice_access_slice_id_slices_id_fk", + "tableFrom": "slice_access", + "tableTo": "slices", + "columnsFrom": [ + "slice_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "slice_access_user_id_users_id_fk": { + "name": "slice_access_user_id_users_id_fk", + "tableFrom": "slice_access", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.refresh_tokens": { + "name": "refresh_tokens", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "token_hash": { + "name": "token_hash", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "refresh_tokens_user_id_users_id_fk": { + "name": "refresh_tokens_user_id_users_id_fk", + "tableFrom": "refresh_tokens", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/db/drizzle/meta/_journal.json b/packages/db/drizzle/meta/_journal.json index ccebc75..1d7b042 100644 --- a/packages/db/drizzle/meta/_journal.json +++ b/packages/db/drizzle/meta/_journal.json @@ -8,6 +8,13 @@ "when": 1760458602500, "tag": "0000_swift_quasimodo", "breakpoints": true + }, + { + "idx": 1, + "version": "7", + "when": 1769503693113, + "tag": "0001_milky_gorilla_man", + "breakpoints": true } ] } \ No newline at end of file diff --git a/packages/db/package.json b/packages/db/package.json index 0372bd2..cfd268b 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -1,12 +1,16 @@ { - "name": "db", - "module": ".src/index.ts", + "name": "@repo/db", + "module": "./src/index.ts", "scripts": { "drizzle:generate": "drizzle-kit generate", "drizzle:push": "drizzle-kit push", "drizzle:studio": "drizzle-kit studio", "drizzle:migrate": "drizzle-kit migrate" }, + "exports": { + ".": "./src/index.ts" + }, + "types": "./src/index.ts", "type": "module", "devDependencies": { "@types/bun": "latest", diff --git a/packages/db/src/index.ts b/packages/db/src/index.ts index 6db665d..663ffaa 100644 --- a/packages/db/src/index.ts +++ b/packages/db/src/index.ts @@ -1,6 +1,14 @@ -// Make sure to install the 'pg' package -import { drizzle } from 'drizzle-orm/node-postgres'; +import { drizzle } from "drizzle-orm/node-postgres"; +import * as schema from "./schema"; -const db = drizzle(process.env.DATABASE_URL as string); +const db = drizzle(process.env.DATABASE_URL as string, { schema }); -export { db } \ No newline at end of file +export { db, schema }; +export * from "./schema"; + +// Explicit exports for better TypeScript resolution +export { users, userRelations } from "./schema/user"; +export { slices, sliceRelations } from "./schema/slice"; +export { sliceAccess, sliceAccessRelations } from "./schema/sliceAccess"; +export { memos, memoRelations } from "./schema/memo"; +export { refreshTokens, refreshTokenRelations } from "./schema/refreshToken"; diff --git a/packages/db/src/schema/index.ts b/packages/db/src/schema/index.ts new file mode 100644 index 0000000..6250c26 --- /dev/null +++ b/packages/db/src/schema/index.ts @@ -0,0 +1,8 @@ +export * from "./user"; +export * from "./slice"; +export * from "./sliceAccess"; +export * from "./memo"; +export * from "./refreshToken"; + +// Since brain and memo are the same per user requirement +export { memos as brains, memoRelations as brainRelations } from "./memo"; diff --git a/packages/db/src/schema/memo.ts b/packages/db/src/schema/memo.ts index 7dfb252..8444a34 100644 --- a/packages/db/src/schema/memo.ts +++ b/packages/db/src/schema/memo.ts @@ -1,15 +1,17 @@ import { pgTable, uuid, text, timestamp, primaryKey } from "drizzle-orm/pg-core" import { relations, sql } from "drizzle-orm" import { slices } from "./slice" +import { users } from "./user" export const memos = pgTable('memos', { id: uuid('id').primaryKey().default(sql`gen_random_uuid()`).notNull(), title: text('title').notNull(), description: text('description').notNull(), + contentType: text('content_type').notNull(), // "text" | "url" | "image" | "video" | "file" content: text('content').notNull(), + ownerId: uuid('owner_id').references(() => users.id).notNull(), sliceId: uuid('slice_id').references(() => slices.id).notNull(), createdAt: timestamp("created_at").default(sql`now()`).notNull(), - updatedAt: timestamp("updated_at").default(sql`now()`).notNull(), }) export const memoRelations = relations(memos, ({ one }) => ( @@ -17,6 +19,10 @@ export const memoRelations = relations(memos, ({ one }) => ( slice: one(slices, { fields: [memos.sliceId], references: [slices.id], + }), + owner: one(users, { + fields: [memos.ownerId], + references: [users.id], }) } )) \ No newline at end of file diff --git a/packages/db/src/schema/refreshToken.ts b/packages/db/src/schema/refreshToken.ts new file mode 100644 index 0000000..3ca0e34 --- /dev/null +++ b/packages/db/src/schema/refreshToken.ts @@ -0,0 +1,31 @@ +import { + pgTable, + uuid, + varchar, + timestamp, +} from "drizzle-orm/pg-core"; +import { relations, sql } from "drizzle-orm"; +import { users } from "./user"; + +export const refreshTokens = pgTable("refresh_tokens", { + id: uuid("id") + .primaryKey() + .default(sql`gen_random_uuid()`) + .notNull(), + userId: uuid("user_id") + .references(() => users.id) + .notNull(), + tokenHash: varchar("token_hash", { length: 256 }).notNull(), + expiresAt: timestamp("expires_at").notNull(), + createdAt: timestamp("created_at") + .default(sql`now()`) + .notNull(), + revokedAt: timestamp("revoked_at"), +}); + +export const refreshTokenRelations = relations(refreshTokens, ({ one }) => ({ + user: one(users, { + fields: [refreshTokens.userId], + references: [users.id], + }), +})); diff --git a/packages/db/src/schema/slice.ts b/packages/db/src/schema/slice.ts index b952d5d..ce2e782 100644 --- a/packages/db/src/schema/slice.ts +++ b/packages/db/src/schema/slice.ts @@ -1,28 +1,33 @@ -import { pgTable, uuid, text, timestamp, primaryKey } from "drizzle-orm/pg-core" -import { relations, sql } from "drizzle-orm" -import { users } from "./user" -import { memos } from "./memo" +import { + pgTable, + uuid, + text, + timestamp, + primaryKey, +} from "drizzle-orm/pg-core"; +import { relations, sql } from "drizzle-orm"; +import { users } from "./user"; +import { memos } from "./memo"; -export const slices = pgTable('slices', { - id: uuid('id').primaryKey().default(sql`gen_random_uuid()`).notNull(), - title: text('title').notNull(), - description: text('description').notNull(), - authorId: uuid('author_id').references(() => users.id).notNull(), - createdAt: timestamp("created_at").default(sql`now()`).notNull(), - updatedAt: timestamp("updated_at").default(sql`now()`).notNull(), -}) +export const slices = pgTable("slices", { + id: uuid("id") + .primaryKey() + .default(sql`gen_random_uuid()`) + .notNull(), + name: text("name").notNull(), + description: text("description").notNull(), + ownerId: uuid("owner_id") + .references(() => users.id) + .notNull(), + createdAt: timestamp("created_at") + .default(sql`now()`) + .notNull(), +}); -export const userSlices = relations(slices, ({ one }) => ( - { - author: one(users, { - fields: [slices.authorId], - references: [users.id], - }) - } -)) - -export const sliceMemos = relations(slices, ({ many }) => ( - { - memos: many(memos), - } -)) \ No newline at end of file +export const sliceRelations = relations(slices, ({ one, many }) => ({ + owner: one(users, { + fields: [slices.ownerId], + references: [users.id], + }), + memos: many(memos), +})); diff --git a/packages/db/src/schema/sliceAccess.ts b/packages/db/src/schema/sliceAccess.ts new file mode 100644 index 0000000..2299566 --- /dev/null +++ b/packages/db/src/schema/sliceAccess.ts @@ -0,0 +1,24 @@ +import { pgTable, uuid, text, primaryKey } from "drizzle-orm/pg-core" +import { relations, sql } from "drizzle-orm" +import { users } from "./user" +import { slices } from "./slice" + +export const sliceAccess = pgTable('slice_access', { + id: uuid('id').default(sql`gen_random_uuid()`).primaryKey().notNull(), + sliceId: uuid('slice_id').references(() => slices.id).notNull(), + userId: uuid('user_id').references(() => users.id).notNull(), + role: text('role').notNull(), // "viewer" | "editor" +}) + +export const sliceAccessRelations = relations(sliceAccess, ({ one }) => ( + { + slice: one(slices, { + fields: [sliceAccess.sliceId], + references: [slices.id], + }), + user: one(users, { + fields: [sliceAccess.userId], + references: [users.id], + }) + } +)) diff --git a/packages/db/src/schema/user.ts b/packages/db/src/schema/user.ts index 4e25369..b76babb 100644 --- a/packages/db/src/schema/user.ts +++ b/packages/db/src/schema/user.ts @@ -1,20 +1,21 @@ -import { pgTable, varchar, uuid, timestamp, index } from "drizzle-orm/pg-core" -import { relations, sql } from "drizzle-orm" -import { slices } from "./slice" +import { pgTable, varchar, uuid, timestamp, index } from "drizzle-orm/pg-core"; +import { relations, sql } from "drizzle-orm"; +import { slices } from "./slice"; -export const users = pgTable('users', { - id: uuid('id').primaryKey().default(sql`gen_random_uuid()`).notNull(), - firstName: varchar("first_name", { length: 256 }).notNull(), - lastName: varchar("last_name", { length: 256 }).notNull(), +export const users = pgTable("users", { + id: uuid("id") + .primaryKey() + .default(sql`gen_random_uuid()`) + .notNull(), + name: varchar("name", { length: 256 }).notNull(), email: varchar("email", { length: 256 }).notNull().unique(), - password: varchar("password", { length: 256 }).notNull(), - createdAt: timestamp("created_at").default(sql`now()`).notNull(), - updatedAt: timestamp("updated_at").default(sql`now()`).notNull(), - refreshToken: varchar("refresh_token", { length: 256 }).notNull(), -}) + googleId: varchar("google_id", { length: 256 }).unique(), + passwordHash: varchar("password_hash", { length: 256 }), + createdAt: timestamp("created_at") + .default(sql`now()`) + .notNull(), +}); -export const userSlices = relations(users, ({ many }) => ( - { - slices: many(slices), - } -)) \ No newline at end of file +export const userRelations = relations(users, ({ many }) => ({ + slices: many(slices), +})); diff --git a/packages/tailwind-config/theme.css b/packages/tailwind-config/theme.css index cc47852..8521036 100644 --- a/packages/tailwind-config/theme.css +++ b/packages/tailwind-config/theme.css @@ -1,13 +1,10 @@ -@layer base { - :root { - --color-primary: #2563eb; - --color-secondary: #9333ea; - --color-background: #f9fafb; - --color-text: #1f2937; - } +@theme { + --color-primary: #2563eb; + --color-secondary: #9333ea; + --color-background: #f9fafb; + --color-text: #1f2937; +} - body { - background-color: var(--color-background); - color: var(--color-text); - } +@layer base { + } \ No newline at end of file diff --git a/packages/types/README.md b/packages/types/README.md new file mode 100644 index 0000000..d4ce042 --- /dev/null +++ b/packages/types/README.md @@ -0,0 +1,36 @@ +# @packages/types + +TypeScript type definitions generated from database schemas. + +## Usage + +```typescript +import type { User, NewUser, Slice, Memo, RefreshToken } from 'types'; + +// Use the types in your application +const user: User = { + id: '...', + name: 'John Doe', + email: 'john@example.com', + // ... +}; +``` + +## Available Types + +### Database Models + +- `User` / `NewUser` - User table types +- `Slice` / `NewSlice` - Slice table types +- `SliceAccess` / `NewSliceAccess` - Slice access control types +- `Memo` / `NewMemo` - Memo table types +- `RefreshToken` / `NewRefreshToken` - Refresh token types + +### Enums + +- `ContentType` - "text" | "url" | "image" | "video" | "file" +- `SliceAccessRole` - "viewer" | "editor" + +## Notes + +Types are automatically inferred from the database schema using Drizzle ORM's `InferSelectModel` and `InferInsertModel` utilities. diff --git a/packages/types/package.json b/packages/types/package.json new file mode 100644 index 0000000..6b01507 --- /dev/null +++ b/packages/types/package.json @@ -0,0 +1,21 @@ +{ + "name": "@repo/types", + "version": "0.0.0", + "private": true, + "main": "./src/index.ts", + "types": "./src/index.ts", + "exports": { + ".": "./src/index.ts" + }, + "scripts": { + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "typescript": "^5.0.0" + }, + "dependencies": { + "@repo/db": "workspace:*", + "drizzle-orm": "^0.44.6" + } +} diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts new file mode 100644 index 0000000..96fe994 --- /dev/null +++ b/packages/types/src/index.ts @@ -0,0 +1,36 @@ +import type { InferSelectModel, InferInsertModel } from 'drizzle-orm'; +import { + users, + slices, + sliceAccess, + memos, + refreshTokens +} from '@repo/db'; + +// User types +export type User = InferSelectModel; +export type NewUser = InferInsertModel; + +// Slice types +export type Slice = InferSelectModel; +export type NewSlice = InferInsertModel; + +// SliceAccess types +export type SliceAccess = InferSelectModel; +export type NewSliceAccess = InferInsertModel; + +// Memo / Brain types +export type Memo = InferSelectModel; +export type NewMemo = InferInsertModel; +export type Brain = Memo; +export type NewBrain = NewMemo; + +// RefreshToken types +export type RefreshToken = InferSelectModel; +export type NewRefreshToken = InferInsertModel; + +// Content type enum +export type ContentType = "text" | "url" | "image" | "video" | "file"; + +// SliceAccess role enum +export type SliceAccessRole = "viewer" | "editor"; diff --git a/packages/types/tsconfig.json b/packages/types/tsconfig.json new file mode 100644 index 0000000..4657fd5 --- /dev/null +++ b/packages/types/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../typescript-config/base.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +}