From 3747db9af06b7096bb337e998b2f4ff703fe38a6 Mon Sep 17 00:00:00 2001
From: "cto-new[bot]" <140088366+cto-new[bot]@users.noreply.github.com>
Date: Thu, 18 Dec 2025 07:39:58 +0000
Subject: [PATCH] feat(living-page): implement collaborative block-based living
page with per-block versioning
Implement a single living page where users can add, edit, soft-delete, and reorder blocks. Each edit creates an immutable version; the page renders the latest version for all blocks. Built on Vite + Firebase template with UI components for inline editing, version history, and a minimal header.
BREAKING CHANGE: none
---
README.md | 90 +++++++++-
USAGE.md | 175 +++++++++++++++++++
firestore.indexes.json | 19 +++
firestore.rules | 15 ++
src/App.tsx | 4 +-
src/components/AddBlockDialog.tsx | 77 +++++++++
src/components/BlockItem.tsx | 222 +++++++++++++++++++++++++
src/components/DeleteConfirmDialog.tsx | 34 ++++
src/components/Header.tsx | 54 ++++++
src/components/LivingPage.test.tsx | 28 ++++
src/components/LivingPage.tsx | 108 ++++++++++++
src/components/VersionHistory.tsx | 110 ++++++++++++
src/hooks/useBlocks.ts | 112 +++++++++++++
src/lib/firebase.ts | 4 +-
src/theme.ts | 24 ++-
src/types/block.ts | 21 +++
16 files changed, 1083 insertions(+), 14 deletions(-)
create mode 100644 USAGE.md
create mode 100644 firestore.indexes.json
create mode 100644 firestore.rules
create mode 100644 src/components/AddBlockDialog.tsx
create mode 100644 src/components/BlockItem.tsx
create mode 100644 src/components/DeleteConfirmDialog.tsx
create mode 100644 src/components/Header.tsx
create mode 100644 src/components/LivingPage.test.tsx
create mode 100644 src/components/LivingPage.tsx
create mode 100644 src/components/VersionHistory.tsx
create mode 100644 src/hooks/useBlocks.ts
create mode 100644 src/types/block.ts
diff --git a/README.md b/README.md
index 44b7617..6cd030f 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,25 @@
-# Vite React Template
+# Living Page
-A modern React template using Vite, TypeScript, Material-UI, and testing setup.
+A collaborative web application where any user can add and improve content for everyone else. Built with Vite, React, TypeScript, Material-UI, and Firebase.
+
+## Concept
+
+The Living Page is a single, shared document composed of ordered blocks. Any authenticated user can:
+
+- Add new blocks
+- Edit existing blocks
+- Delete blocks (soft delete)
+- Reorder blocks
+
+Every edit creates a new immutable version, enabling full version history tracking.
## Features
- โก๏ธ Vite for super fast development
- ๐จ Material-UI with emotion styling
- ๐ TypeScript support
+- ๐ฅ Firebase Authentication & Firestore
+- ๐ฆ Block-based content system with versioning
- โ Testing setup with Vitest and Testing Library
- ๐ ESLint + Prettier configuration
- ๐ฑ Responsive design ready
@@ -18,7 +31,13 @@ A modern React template using Vite, TypeScript, Material-UI, and testing setup.
```bash
pnpm i
```
-3. Start the development server:
+3. Set up Firebase:
+ - Create a Firebase project at https://console.firebase.google.com
+ - Enable Firestore Database
+ - Enable Google Authentication
+ - Copy your Firebase config and base64 encode it
+ - Create a `.env` file based on `.env.example` and add your encoded config
+4. Start the development server:
```bash
make emulator
```
@@ -40,12 +59,65 @@ A modern React template using Vite, TypeScript, Material-UI, and testing setup.
```
src/
- โโโ App.tsx # Root application component
- โโโ components/ # Reusable components & their tests
- โโโ test/ # Test configuration
- โโโ types/ # TypeScript definitions
- โโโ theme.ts # Theme configuration
- โโโ main.tsx # Application entry point
+ โโโ App.tsx # Root application component
+ โโโ components/
+ โ โโโ LivingPage.tsx # Main living page component
+ โ โโโ BlockItem.tsx # Individual block with edit/delete/reorder
+ โ โโโ AddBlockDialog.tsx # Dialog for adding new blocks
+ โ โโโ VersionHistory.tsx # Version history viewer
+ โ โโโ Login.tsx # Authentication UI
+ โโโ context/
+ โ โโโ AuthContext.tsx # Firebase auth provider
+ โโโ hooks/
+ โ โโโ useAuth.ts # Auth hook
+ โ โโโ useBlocks.ts # Block CRUD operations
+ โโโ lib/
+ โ โโโ firebase.ts # Firebase initialization
+ โโโ types/
+ โ โโโ block.ts # Block & version types
+ โโโ test/ # Test configuration
+ โโโ theme.ts # Theme configuration
+ โโโ main.tsx # Application entry point
+```
+
+## How It Works
+
+### Block System
+
+- Each block has an ordered position in the page
+- Blocks contain multiple versions (immutable history)
+- Only the current version is displayed
+- Soft deletes keep data but hide blocks from view
+
+### Versioning
+
+- Every edit creates a new version with:
+ - Unique version ID
+ - Content snapshot
+ - Timestamp
+ - Author information
+- All versions are preserved in Firestore
+- Users can view complete version history
+
+### Firestore Structure
+
+```
+blocks/
+ {blockId}/
+ order: number
+ isDeleted: boolean
+ currentVersionId: string
+ createdAt: timestamp
+ createdBy: userId
+ versions: [
+ {
+ id: string
+ content: string
+ createdAt: timestamp
+ createdBy: userId
+ createdByEmail: string
+ }
+ ]
```
## Contributing
diff --git a/USAGE.md b/USAGE.md
new file mode 100644
index 0000000..7323b11
--- /dev/null
+++ b/USAGE.md
@@ -0,0 +1,175 @@
+# Living Page - Usage Guide
+
+## Overview
+
+The Living Page is a collaborative document where authenticated users can add, edit, delete, and reorder blocks of content. Every edit is versioned, creating an immutable history.
+
+## Features
+
+### Authentication
+
+- Sign in with Google SSO
+- All users must be authenticated to view or edit content
+- User information (email, avatar) displayed in header
+- Logout functionality available
+
+### Block Management
+
+#### Adding a Block
+
+1. Click the blue floating action button (FAB) in the bottom-right corner
+2. Enter your content in the dialog
+3. Click "Add Block" or press Cmd+Enter (Mac) / Ctrl+Enter (Windows/Linux)
+
+#### Editing a Block
+
+1. Hover over a block to reveal action buttons
+2. Click the Edit icon (pencil)
+3. Modify the content in the text field
+4. Click Save icon or press Cmd+Enter to save
+5. Press Escape to cancel
+
+#### Deleting a Block
+
+1. Hover over a block to reveal action buttons
+2. Click the Delete icon (trash can)
+3. Confirm deletion in the dialog
+4. Block is soft-deleted (hidden but preserved in database)
+
+#### Reordering Blocks
+
+1. Hover over a block to reveal action buttons
+2. Click the up arrow to move block up
+3. Click the down arrow to move block down
+4. Changes are saved immediately
+
+#### Viewing Version History
+
+1. Hover over a block to reveal action buttons
+2. Click the History icon (clock)
+3. View all versions in chronological order
+4. Current version is highlighted
+5. Each version shows:
+ - Content
+ - Timestamp
+ - Author email
+ - Version number
+
+## Keyboard Shortcuts
+
+- **Cmd+Enter** (Mac) / **Ctrl+Enter** (Windows/Linux): Save edit or add block
+- **Escape**: Cancel edit or close dialog
+
+## UI Elements
+
+### Header
+
+- **Living Page** title
+- User avatar and email (desktop only)
+- Logout button
+
+### Block Card
+
+- Content display
+- Action buttons (visible on hover on desktop, always visible on mobile):
+ - Edit
+ - Move up
+ - Move down
+ - Version history
+ - Delete
+- Version info (if edited): "v{number} ยท Edited by {email}"
+
+### Empty State
+
+- Displays when no blocks exist
+- "Add First Block" button to get started
+
+### Floating Action Button (FAB)
+
+- Fixed position in bottom-right corner
+- Quick access to add new blocks
+- Visible on all screen sizes
+
+## Data Structure
+
+### Block
+
+- Ordered position in the page
+- Soft delete flag
+- Reference to current version
+- Array of all versions
+
+### Version
+
+- Unique ID
+- Content snapshot
+- Creation timestamp
+- Author information (ID and email)
+
+## Best Practices
+
+1. **Be Collaborative**: Remember that everyone can see and edit all content
+2. **Write Clear Content**: Make blocks easy to understand
+3. **Check Version History**: Before editing, review what others have contributed
+4. **Respect Others' Work**: Build on existing content rather than replacing it
+5. **Use Soft Delete**: Deleted blocks can be recovered by administrators
+
+## Mobile Experience
+
+- All features available on mobile devices
+- Action buttons always visible (no hover required)
+- Touch-optimized interface
+- Responsive layout
+
+## Technical Details
+
+### Firebase Services Used
+
+- **Authentication**: Google provider
+- **Firestore**: Real-time database for blocks
+
+### Security
+
+- All operations require authentication
+- Firestore security rules enforce permissions
+- User identity tracked with every change
+
+### Performance
+
+- Real-time updates via Firestore listeners
+- Optimistic UI updates
+- Indexed queries for fast loading
+
+## Troubleshooting
+
+### Can't sign in
+
+- Ensure Firebase Authentication is enabled
+- Check that Google provider is configured
+- Verify your email is authorized (if using restricted access)
+
+### Blocks not loading
+
+- Check browser console for errors
+- Verify Firestore is enabled in Firebase project
+- Ensure security rules are properly configured
+
+### Changes not saving
+
+- Check network connectivity
+- Verify you're still authenticated
+- Check browser console for Firestore errors
+
+## Future Enhancements
+
+Potential features for future development:
+
+- Rich text editing
+- Block templates
+- Search functionality
+- Comments on blocks
+- User permissions and roles
+- Block types (text, code, image, etc.)
+- Export functionality
+- Undo/redo
+- Real-time collaboration indicators
diff --git a/firestore.indexes.json b/firestore.indexes.json
new file mode 100644
index 0000000..2b7b08c
--- /dev/null
+++ b/firestore.indexes.json
@@ -0,0 +1,19 @@
+{
+ "indexes": [
+ {
+ "collectionGroup": "blocks",
+ "queryScope": "COLLECTION",
+ "fields": [
+ {
+ "fieldPath": "isDeleted",
+ "order": "ASCENDING"
+ },
+ {
+ "fieldPath": "order",
+ "order": "ASCENDING"
+ }
+ ]
+ }
+ ],
+ "fieldOverrides": []
+}
diff --git a/firestore.rules b/firestore.rules
new file mode 100644
index 0000000..fbcea56
--- /dev/null
+++ b/firestore.rules
@@ -0,0 +1,15 @@
+rules_version = '2';
+service cloud.firestore {
+ match /databases/{database}/documents {
+ match /blocks/{blockId} {
+ allow read: if request.auth != null;
+ allow create: if request.auth != null
+ && request.resource.data.createdBy == request.auth.uid
+ && request.resource.data.keys().hasAll(['order', 'isDeleted', 'currentVersionId', 'createdAt', 'createdBy', 'versions'])
+ && request.resource.data.isDeleted == false;
+ allow update: if request.auth != null
+ && (request.resource.data.diff(resource.data).affectedKeys().hasOnly(['currentVersionId', 'versions', 'isDeleted', 'order']));
+ allow delete: if false;
+ }
+ }
+}
diff --git a/src/App.tsx b/src/App.tsx
index 46d1937..3a0f095 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,5 +1,5 @@
import { CssBaseline, ThemeProvider } from '@mui/material'
-import Profile from './components/Profile'
+import { LivingPage } from './components/LivingPage'
import { theme } from './theme'
export function App() {
@@ -7,7 +7,7 @@ export function App() {