You are tasked with building a fully functional, multi-page MVP of a privacy-focused digital sanctuary and creative workspace application using the Next.js App Router. The core problem this application addresses is the 'Cognitive Dark Forest' phenomenon, where individuals feel their freedom of thought and expression is curtailed by the pervasive surveillance and data exploitation prevalent on the open internet. This app provides a secure, user-controlled environment for deep work, idea generation, and project development, inspired by the open, permissionless spirit of early web development but with modern privacy and security standards.
PROJECT OVERVIEW:
'Mind Sanctuary' (Turkish: 'Zihin Sığınağı') is a SaaS platform enabling users to create and manage private digital workspaces ('gardens') for thinking, coding, writing, and creative projects. It aims to replicate the feeling of the early internet's freedom and lack of gatekeepers, offering a secure, user-owned space free from external tracking and data exploitation. The value proposition is "Your thoughts, your space, your control." It solves the problem of a 'digital dark forest' where expressing ideas publicly can lead to unintended consequences, by providing a safe haven for creation and controlled sharing.
TECH STACK:
- Frontend Framework: Next.js (App Router)
- UI Library: shadcn/ui (built with Tailwind CSS)
- Styling: Tailwind CSS
- State Management: React Context API and Zustand (for global state if needed, e.g., theme, auth status)
- Database ORM: Drizzle ORM
- Database: PostgreSQL (recommended for Drizzle)
- Authentication: NextAuth.js (for email/password and OAuth providers like Google, GitHub)
- Form Handling: React Hook Form + Zod for validation
- Other Packages: `react-icons`, `date-fns`, `react-markdown`, `codemirror` or `monaco-editor` for code editing, `uuid` for unique IDs.
DATABASE SCHEMA (using Drizzle ORM syntax conceptual example for PostgreSQL):
```typescript
import { pgTable, uuid, varchar, text, timestamp, boolean, integer, primaryKey, foreignKey } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';
// User Table
export const users = pgTable('users', {
id: uuid('id').primaryKey().defaultRandom(),
name: varchar('name'),
email: varchar('email', { length: 255 }).notNull().unique(),
emailVerified: timestamp('email_verified_at'),
image: varchar('image'),
createdAt: timestamp('created_at').defaultNow(),
updatedAt: timestamp('updated_at').defaultNow(),
});
export const accounts = pgTable(
'accounts',
{
userId: uuid('user_id')
.notNull()
.references(() => users.id, { onDelete: 'cascade' }),
type: varchar('type', {
length: 255,
})
// ... other fields like provider, providerAccountId, refresh_token etc.
},
(account) => ({
compoundKey: primaryKey(account.provider, account.providerAccountId),
}),
);
export const sessions = pgTable('sessions', {
sessionToken: varchar('session_token', { length: 255 }).primaryKey(),
userId: uuid('user_id')
.notNull()
.references(() => users.id, { onDelete: 'cascade' }),
expires: timestamp('expires').notNull(),
});
export const verificationTokens = pgTable(
'verification_tokens',
{
identifier: varchar('identifier', { length: 255 }).notNull(),
token: varchar('token', { length: 255 }).notNull(),
expires: timestamp('expires').notNull(),
},
(vt) => ({
compoundKey: primaryKey(vt.identifier, vt.token),
}),
);
// Workspace (Digital Garden) Table
export const workspaces = pgTable('workspaces', {
id: uuid('id').primaryKey().defaultRandom(),
userId: uuid('user_id')
.notNull()
.references(() => users.id, { onDelete: 'cascade' }),
name: varchar('name', { length: 100 }).notNull(),
slug: varchar('slug', { length: 100 }).notNull().unique(), // URL-friendly identifier
description: text('description'),
isPublic: boolean('is_public').default(false),
sharePassword: varchar('share_password'), // Optional password for private sharing
createdAt: timestamp('created_at').defaultNow(),
updatedAt: timestamp('updated_at').defaultNow(),
});
// Document/Note Table
export const documents = pgTable('documents', {
id: uuid('id').primaryKey().defaultRandom(),
workspaceId: uuid('workspace_id')
.notNull()
.references(() => workspaces.id, { onDelete: 'cascade' }),
parentId: uuid('parent_id').references(() => documents.id, { onDelete: 'set_null' }), // For folder structure
title: varchar('title', { length: 255 }).notNull(),
content: text('content'), // Markdown or rich text content
contentType: varchar('content_type', { length: 50 }).default('markdown'), // e.g., 'markdown', 'code', 'rich-text'
createdAt: timestamp('created_at').defaultNow(),
updatedAt: timestamp('updated_at').defaultNow(),
});
// Relations (Conceptual)
export const userRelations = relations(users, ({ many }) => ({
workspaces: many(workspaces),
}));
export const workspaceRelations = relations(workspaces, ({ one, many }) => ({
user: one(users, {
fields: [workspaces.userId],
references: [users.id],
}),
documents: many(documents),
}));
export const documentRelations = relations(documents, ({ one, many }) => ({
workspace: one(workspaces, {
fields: [documents.workspaceId],
references: [workspaces.id],
}),
parent: one(documents, {
fields: [documents.parentId],
references: [documents.id],
}),
children: many(documents, {
relationName: 'children',
references: [documents.parentId],
}),
}));
```
CORE FEATURES & USER FLOW:
1. **Authentication Flow:**
* Users arrive at the landing page.
* Options: Sign Up (Email/Password, Google, GitHub), Log In.
* Sign Up: Enter email, password, confirm password. Receive verification email (optional for MVP, can rely on OAuth). Use NextAuth.js for handling credentials and OAuth.
* Log In: Enter email/password or use OAuth provider.
* After login/signup, redirect to the user's dashboard.
* Protected Routes: All authenticated routes require a valid session. Use NextAuth.js middleware or session checks in layout/page components.
2. **Dashboard:**
* Displays a list of the user's workspaces ('gardens').
* "Create New Workspace" button.
* Each workspace card shows name, description, last updated, and links to open it.
* User Profile/Settings access.
3. **Workspace Creation/Editing:**
* Modal or dedicated page for creating a new workspace.
* Fields: Name (required), Slug (auto-generated from name, unique), Description (optional).
* Settings for 'Public Access' (boolean) and optional 'Share Password'.
* Editing existing workspace details follows the same flow.
4. **Workspace View (Core Editor):**
* Layout: Sidebar for documents/folders, Main area for content editing.
* Sidebar: Tree view of documents and folders within the workspace. "Create New Document/Folder" buttons.
* Main Area:
* If a document is selected: Displays a split-pane view (or tabbed view) with a Markdown editor (using `react-markdown` and a syntax highlighting library like `codemirror` or `monaco-editor`) on one side and a live preview on the other.
* If a folder is selected: Displays files within that folder, allowing creation/management.
* Toolbar: Save button, formatting options (bold, italic, etc.), options to change content type (markdown, code), view options (split pane toggle).
* Auto-save functionality with visual indicator (e.g., "Saving...", "Saved").
* Document Title Editing: Directly editable at the top.
* User Flow: Click document in sidebar -> Loads into editor -> Edit content -> Click Save (or auto-save triggers) -> Content updated in DB.
5. **Selective Sharing:**
* Within Workspace Settings: Enable 'Public Access' or set a 'Share Password'.
* Generate a unique, shareable link (e.g., `app.com/w/[workspaceSlug]/share?password=[password]` or `app.com/w/[workspaceSlug]/public`).
* Shared View: A read-only, potentially simpler view of the workspace/document content. No editing capabilities. Password protected if set.
API & DATA FETCHING (Next.js API Routes / Server Actions):
- `/api/auth/*`: Handled by NextAuth.js.
- `/api/workspaces` (POST, GET, PUT, DELETE): CRUD operations for workspaces.
* POST `/api/workspaces`: `{
"name": "My Project",
"description": "Initial thoughts",
"isPublic": false,
"sharePassword": null
}` -> Returns created workspace object.
* GET `/api/workspaces`: Returns array of user's workspaces.
* GET `/api/workspaces/[slug]`: Returns specific workspace details.
- `/api/workspaces/[workspaceId]/documents` (POST, GET):
* POST: `{
"title": "New Note",
"content": "# Hello World",
"parentId": null // Optional for folder structure
}` -> Returns created document.
* GET: Returns list of documents within a workspace (hierarchical structure).
- `/api/documents/[documentId]` (GET, PUT, DELETE):
* GET: Fetch single document content.
* PUT: `{
"title": "Updated Title",
"content": "Updated content..."
}` -> Updates document.
- Data Fetching: Utilize Server Components for initial data loading where possible (e.g., dashboard lists, workspace document trees). Client Components will fetch data as needed, especially for the editor, using libraries like `swr` or `react-query`, or direct `fetch` calls within `useEffect`.
COMPONENT BREAKDOWN (Next.js App Router Structure):
```
app/
├── layout.tsx # Root layout (includes AuthProvider, global styles)
├── page.tsx # Landing Page
├── api/
│ └── auth/[...nextauth]
│ └── route.ts # NextAuth.js route handler
├── dashboard/
│ ├── layout.tsx # Dashboard layout (sidebar nav)
│ ├── page.tsx # List user's workspaces
│ └── create/
│ └── page.tsx # Create workspace form
├── workspace/
│ ├── layout.tsx # Workspace layout (sidebar + editor)
│ ├── [slug]/
│ │ └── page.tsx # Main workspace view (requires auth)
│ ├── components/
│ │ ├── Sidebar.tsx # Workspace file tree navigation
│ │ ├── Editor.tsx # Markdown/Code editor component
│ │ ├── Preview.tsx # Live preview pane
│ │ ├── WorkspaceSettings.tsx # Settings modal/page
│ │ └── DocumentItem.tsx # Renders a file/folder in sidebar
│ └── _components/ # Reusable components within workspace module
├── settings/
│ ├── layout.tsx # Settings layout
│ └── page.tsx # User profile and account settings
├── share/
│ └── [slug]/
│ └── page.tsx # Public/password-protected share view
└── globals.css
└── ...
```
- **State Management:** Primarily client-side state for UI elements within components. Global state for auth status and user info managed via React Context or Zustand. Server Components handle initial data fetching.
- **Auth Handling:** Wrap relevant parts of the app (Dashboard, Workspace) with auth checks or use `useSession` hook from `next-auth/react`.
UI/UX DESIGN & VISUAL IDENTITY:
- **Style:** "Minimalist Clean" with subtle futuristic/cyberpunk accents.
- **Color Palette:**
* Primary: Dark/Deep Blue (`#0A192F`)
* Secondary: Dark Grey (`#282C34`)
* Accent: Electric Cyan (`#61DAFB`) or Neon Green (`#7FFF00`)
* Text: Light Grey (`#ABB2BF`)
* Subtle UI Elements: Muted Purple (`#4A4A7E`)
- **Typography:** A clean, modern sans-serif font like 'Inter' or 'Manrope' for body text. A slightly more stylized but readable font like 'Orbitron' or 'Rajdhani' for headings.
- **Layout:** Focus on clean grids, ample whitespace, clear information hierarchy. Sidebar-first navigation within workspaces. Responsive design adapting gracefully from mobile to desktop.
- **Sections:** Clear separation of concerns. Sidebar, main editing area, toolbars, settings modals.
- **Visual Elements:** Subtle gradients on buttons or headers, soft glowing effects on active elements, clean icons.
ANIMATIONS:
- **Page Transitions:** Smooth fade-in/fade-out using Next.js's built-in router or libraries like `Framer Motion` for more elaborate transitions between pages and layouts.
- **Hover Effects:** Subtle scaling or color changes on interactive elements (buttons, links, workspace cards).
- **Loading States:** Skeleton loaders for content areas (e.g., workspace list, document content) while data is fetching. Use spinners or pulsing animations.
- **Editor Interactions:** Smooth expansion/collapse of sidebar, subtle animations for save status changes ("Saving..." -> "Saved").
- **Micro-interactions:** Button click feedback, form validation feedback.
EDGE CASES:
- **Authentication:** Handle expired sessions, failed login attempts, OAuth callback errors gracefully. Provide clear error messages.
- **Authorization:** Ensure users can only access and modify their own workspaces and documents. Public/password-protected shares should be read-only.
- **Empty States:** Display helpful messages and clear calls-to-action when a user has no workspaces, or a workspace has no documents.
- **Validation:** Implement robust client-side (using Zod) and server-side validation for all form inputs (workspace names, document titles, etc.).
- **Error Handling:** Implement global error handling (e.g., using an Error Boundary in React) and specific error handling for API calls. Display user-friendly error messages.
- **Concurrency:** Implement basic handling for concurrent edits if multiple sessions are possible (though less likely for a personal workspace MVP), possibly via optimistic UI updates and conflict resolution prompts.
- **Data Integrity:** Ensure database constraints (unique slugs, foreign keys) are maintained.
SAMPLE/MOCK DATA:
1. **User:** `{
"id": "uuid-for-user-1",
"name": "Alice Wonderland",
"email": "alice@example.com",
"image": "/api/auth/me/avatar.jpg"
}`
2. **Workspace List (Dashboard):** `[
{
"id": "uuid-ws-1",
"name": "Project Phoenix",
"slug": "project-phoenix",
"description": "AI-powered journaling app concept",
"updatedAt": "2024-03-15T10:30:00Z"
},
{
"id": "uuid-ws-2",
"name": "Personal Notes",
"slug": "personal-notes",
"description": "Random thoughts and snippets",
"updatedAt": "2024-03-14T18:00:00Z"
}
]`
3. **Document Tree (Sidebar):** `[
{
"id": "uuid-doc-1",
"title": "README.md",
"isFolder": false,
"children": []
},
{
"id": "uuid-doc-2",
"title": "src",
"isFolder": true,
"children": [
{
"id": "uuid-doc-3",
"title": "main.js",
"isFolder": false,
"children": []
}
]
},
{
"id": "uuid-doc-4",
"title": "Doodle Ideas",
"isFolder": false,
"children": []
}
]`
4. **Editor Content (Document):** `{
"id": "uuid-doc-1",
"title": "README.md",
"content": "# Project Phoenix\n\nAn AI-powered journaling application that helps users understand their thought patterns. Built with Next.js and Drizzle ORM.\n\n## Features\n* Sentiment Analysis\n* Topic Clustering\n* Private & Secure\n\n## Getting Started\n1. Clone the repo\n2. Run `npm install`\n3. Set up database connection.",
"contentType": "markdown",
"updatedAt": "2024-03-15T10:30:00Z"
}`
5. **Code Document Content:** `{
"id": "uuid-doc-3",
"title": "main.js",
"content": "console.log('Hello, Dark Forest!');\n\nfunction greet(name) {\n return `Hello, ${name}!`;\n}\n\nconsole.log(greet('World'));",
"contentType": "javascript",
"updatedAt": "2024-03-15T11:00:00Z"
}`
6. **Workspace Settings (for editing):** `{
"id": "uuid-ws-1",
"name": "Project Phoenix",
"slug": "project-phoenix",
"description": "AI-powered journaling app concept",
"isPublic": true,
"sharePassword": "p3o3n1x"
}`
7. **Empty Workspace State:** (Message displayed in main area) "This digital garden is currently quiet. Start by creating your first document or folder."
8. **Empty Document List State:** (Message displayed in sidebar) "No documents found in this workspace. Let's plant a new idea! [Create Document Button]"
9. **Share Link View (Read-only):** Displays only the content of the specified document or workspace without any editing controls or sidebar, respecting the public/password setting.