mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-15 01:01:09 +02:00
- Add uload project with apps/web structure
- Reorganize from flat to monorepo structure
- Remove PocketBase binary and local data
- Update to pnpm and @uload/web namespace
- Add picture project to monorepo
- Remove embedded git repository
- Unify all package names to @{project}/{app} schema:
- @maerchenzauber/* (was @storyteller/*)
- @manacore/* (was manacore-*, manacore)
- @manadeck/* (was web, backend, manadeck)
- @memoro/* (was memoro-web, landing, memoro)
- @picture/* (already unified)
- @uload/web
- Add convenient dev scripts for all apps:
- pnpm dev:{project}:web
- pnpm dev:{project}:landing
- pnpm dev:{project}:mobile
- pnpm dev:{project}:backend
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
389 lines
8.4 KiB
JavaScript
389 lines
8.4 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
/**
|
|
* Script to create the unified cards collection in PocketBase
|
|
* Run this with: node scripts/create-unified-cards-collection.js
|
|
*/
|
|
|
|
const PocketBase = require('pocketbase');
|
|
|
|
const pb = new PocketBase('http://127.0.0.1:8090');
|
|
|
|
async function createUnifiedCardsCollection() {
|
|
try {
|
|
// Admin authentication
|
|
await pb.admins.authWithPassword(
|
|
process.env.POCKETBASE_ADMIN_EMAIL || 'admin@example.com',
|
|
process.env.POCKETBASE_ADMIN_PASSWORD || 'admin123456'
|
|
);
|
|
|
|
console.log('✅ Authenticated as admin');
|
|
|
|
// Define the unified cards collection schema
|
|
const collection = {
|
|
name: 'cards',
|
|
type: 'base',
|
|
schema: [
|
|
// Core relationships
|
|
{
|
|
name: 'user_id',
|
|
type: 'relation',
|
|
required: false, // null for system templates
|
|
options: {
|
|
collectionId: '_pb_users_auth_',
|
|
cascadeDelete: true,
|
|
minSelect: null,
|
|
maxSelect: 1,
|
|
displayFields: ['email', 'username']
|
|
}
|
|
},
|
|
|
|
// Card type and origin
|
|
{
|
|
name: 'type',
|
|
type: 'select',
|
|
required: true,
|
|
options: {
|
|
values: ['user', 'template', 'system'],
|
|
maxSelect: 1
|
|
}
|
|
},
|
|
{
|
|
name: 'source',
|
|
type: 'select',
|
|
required: false,
|
|
options: {
|
|
values: ['created', 'duplicated', 'imported', 'migrated'],
|
|
maxSelect: 1
|
|
}
|
|
},
|
|
{
|
|
name: 'template_id',
|
|
type: 'relation',
|
|
required: false,
|
|
options: {
|
|
collectionId: 'cards', // Self-reference
|
|
cascadeDelete: false,
|
|
minSelect: null,
|
|
maxSelect: 1,
|
|
displayFields: ['metadata']
|
|
}
|
|
},
|
|
|
|
// Card configuration (unified structure)
|
|
{
|
|
name: 'config',
|
|
type: 'json',
|
|
required: true,
|
|
options: {
|
|
maxSize: 1000000 // 1MB max
|
|
}
|
|
},
|
|
{
|
|
name: 'metadata',
|
|
type: 'json',
|
|
required: false,
|
|
options: {
|
|
maxSize: 100000 // 100KB max
|
|
}
|
|
},
|
|
{
|
|
name: 'constraints',
|
|
type: 'json',
|
|
required: false,
|
|
options: {
|
|
maxSize: 10000 // 10KB max
|
|
}
|
|
},
|
|
|
|
// Organization
|
|
{
|
|
name: 'page',
|
|
type: 'text',
|
|
required: false,
|
|
options: {
|
|
min: 0,
|
|
max: 100,
|
|
pattern: ''
|
|
}
|
|
},
|
|
{
|
|
name: 'position',
|
|
type: 'number',
|
|
required: false,
|
|
options: {
|
|
min: 0,
|
|
max: 9999,
|
|
noDecimal: true
|
|
}
|
|
},
|
|
{
|
|
name: 'folder_id',
|
|
type: 'relation',
|
|
required: false,
|
|
options: {
|
|
collectionId: 'folders',
|
|
cascadeDelete: false,
|
|
minSelect: null,
|
|
maxSelect: 1,
|
|
displayFields: ['name']
|
|
}
|
|
},
|
|
|
|
// Visibility and sharing
|
|
{
|
|
name: 'visibility',
|
|
type: 'select',
|
|
required: true,
|
|
options: {
|
|
values: ['private', 'public', 'unlisted'],
|
|
maxSelect: 1
|
|
}
|
|
},
|
|
{
|
|
name: 'is_featured',
|
|
type: 'bool',
|
|
required: false
|
|
},
|
|
{
|
|
name: 'allow_duplication',
|
|
type: 'bool',
|
|
required: false
|
|
},
|
|
|
|
// Statistics
|
|
{
|
|
name: 'usage_count',
|
|
type: 'number',
|
|
required: false,
|
|
options: {
|
|
min: 0,
|
|
max: 999999,
|
|
noDecimal: true
|
|
}
|
|
},
|
|
{
|
|
name: 'likes_count',
|
|
type: 'number',
|
|
required: false,
|
|
options: {
|
|
min: 0,
|
|
max: 999999,
|
|
noDecimal: true
|
|
}
|
|
},
|
|
|
|
// Search and categorization
|
|
{
|
|
name: 'tags',
|
|
type: 'json',
|
|
required: false,
|
|
options: {
|
|
maxSize: 10000
|
|
}
|
|
},
|
|
{
|
|
name: 'category',
|
|
type: 'select',
|
|
required: false,
|
|
options: {
|
|
values: ['personal', 'creative', 'minimal', 'social', 'portfolio', 'other'],
|
|
maxSelect: 1
|
|
}
|
|
},
|
|
|
|
// Variant for styling
|
|
{
|
|
name: 'variant',
|
|
type: 'select',
|
|
required: false,
|
|
options: {
|
|
values: ['default', 'compact', 'hero', 'minimal', 'glass', 'gradient'],
|
|
maxSelect: 1
|
|
}
|
|
}
|
|
],
|
|
|
|
// Indexes for performance
|
|
indexes: [
|
|
'CREATE INDEX idx_cards_user_id ON cards (user_id)',
|
|
'CREATE INDEX idx_cards_type ON cards (type)',
|
|
'CREATE INDEX idx_cards_page ON cards (page)',
|
|
'CREATE INDEX idx_cards_visibility ON cards (visibility)',
|
|
'CREATE INDEX idx_cards_template_id ON cards (template_id)',
|
|
'CREATE INDEX idx_cards_position ON cards (position)'
|
|
],
|
|
|
|
// API Rules
|
|
listRule:
|
|
'@request.auth.id = user_id || visibility = "public" || (visibility = "unlisted" && @request.query.id != "")',
|
|
viewRule: '@request.auth.id = user_id || visibility != "private"',
|
|
createRule: '@request.auth.id != ""',
|
|
updateRule:
|
|
'@request.auth.id = user_id || (@request.auth.id != "" && type = "system" && @request.auth.admin = true)',
|
|
deleteRule: '@request.auth.id = user_id && type != "system"',
|
|
|
|
options: {}
|
|
};
|
|
|
|
// Create the collection
|
|
const result = await pb.collections.create(collection);
|
|
console.log('✅ Created unified cards collection:', result.name);
|
|
|
|
// Create some default system templates
|
|
await createDefaultTemplates(pb);
|
|
|
|
console.log('🎉 Successfully created unified cards collection!');
|
|
} catch (error) {
|
|
console.error('❌ Error creating collection:', error);
|
|
|
|
// If collection already exists, try to update it
|
|
if (error.response?.code === 400) {
|
|
console.log('Collection might already exist. Trying to update...');
|
|
try {
|
|
const existing = await pb.collections.getOne('cards');
|
|
await pb.collections.update(existing.id, collection);
|
|
console.log('✅ Updated existing cards collection');
|
|
} catch (updateError) {
|
|
console.error('❌ Failed to update:', updateError);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
async function createDefaultTemplates(pb) {
|
|
const templates = [
|
|
{
|
|
type: 'template',
|
|
visibility: 'public',
|
|
is_featured: true,
|
|
allow_duplication: true,
|
|
category: 'personal',
|
|
variant: 'default',
|
|
config: {
|
|
mode: 'beginner',
|
|
modules: [
|
|
{
|
|
id: 'header-1',
|
|
type: 'header',
|
|
props: {
|
|
title: 'John Doe',
|
|
subtitle: 'Software Developer'
|
|
},
|
|
order: 0
|
|
},
|
|
{
|
|
id: 'content-1',
|
|
type: 'content',
|
|
props: {
|
|
text: 'Passionate about creating amazing digital experiences.'
|
|
},
|
|
order: 1
|
|
},
|
|
{
|
|
id: 'links-1',
|
|
type: 'links',
|
|
props: {
|
|
links: [
|
|
{ label: 'GitHub', href: 'https://github.com', icon: '🔗' },
|
|
{ label: 'LinkedIn', href: 'https://linkedin.com', icon: '💼' }
|
|
],
|
|
style: 'button'
|
|
},
|
|
order: 2
|
|
}
|
|
]
|
|
},
|
|
metadata: {
|
|
name: 'Simple Profile',
|
|
description: 'A clean and simple profile card',
|
|
version: '1.0.0',
|
|
tags: ['profile', 'minimal', 'clean']
|
|
},
|
|
constraints: {
|
|
aspectRatio: '16/9'
|
|
},
|
|
usage_count: 0,
|
|
likes_count: 0
|
|
},
|
|
{
|
|
type: 'template',
|
|
visibility: 'public',
|
|
is_featured: true,
|
|
allow_duplication: true,
|
|
category: 'personal',
|
|
variant: 'gradient',
|
|
config: {
|
|
mode: 'advanced',
|
|
template: `
|
|
<div class="professional-card">
|
|
<h1>{{name}}</h1>
|
|
<p class="tagline">{{tagline}}</p>
|
|
<div class="contact">
|
|
<a href="mailto:{{email}}">{{email}}</a>
|
|
<a href="tel:{{phone}}">{{phone}}</a>
|
|
</div>
|
|
</div>
|
|
`,
|
|
css: `
|
|
.professional-card {
|
|
padding: 2rem;
|
|
text-align: center;
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
color: white;
|
|
}
|
|
.tagline {
|
|
font-size: 1.2rem;
|
|
margin: 1rem 0;
|
|
opacity: 0.9;
|
|
}
|
|
.contact {
|
|
display: flex;
|
|
justify-content: center;
|
|
gap: 2rem;
|
|
margin-top: 2rem;
|
|
}
|
|
.contact a {
|
|
color: white;
|
|
text-decoration: none;
|
|
}
|
|
`,
|
|
variables: [
|
|
{ name: 'name', type: 'text', label: 'Your Name' },
|
|
{ name: 'tagline', type: 'text', label: 'Tagline' },
|
|
{ name: 'email', type: 'text', label: 'Email' },
|
|
{ name: 'phone', type: 'text', label: 'Phone' }
|
|
],
|
|
values: {
|
|
name: 'Your Name',
|
|
tagline: 'Your tagline here',
|
|
email: 'contact@example.com',
|
|
phone: '+1 234 567 890'
|
|
}
|
|
},
|
|
metadata: {
|
|
name: 'Professional Card',
|
|
description: 'Professional contact card template',
|
|
version: '1.0.0',
|
|
tags: ['professional', 'contact']
|
|
},
|
|
constraints: {
|
|
aspectRatio: '16/9'
|
|
},
|
|
usage_count: 0,
|
|
likes_count: 0
|
|
}
|
|
];
|
|
|
|
for (const template of templates) {
|
|
try {
|
|
await pb.collection('cards').create(template);
|
|
console.log(`✅ Created template: ${template.metadata.name}`);
|
|
} catch (error) {
|
|
console.error(`❌ Failed to create template: ${template.metadata.name}`, error);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Run the script
|
|
createUnifiedCardsCollection();
|