refactor(db): consolidate ~20+ databases into 2 (mana_platform + mana_sync)

Mirrors the frontend unification (single IndexedDB) on the backend.
All services now use pgSchema() for isolation within one shared database,
enabling cross-schema JOINs, simplified ops, and zero DB setup for new apps.

- Migrate 7 services from pgTable() to pgSchema(): mana-user (usr),
  mana-media (media), todo, traces, presi, uload, cards
- Update all DATABASE_URLs in .env.development, docker-compose, configs
- Rewrite init-db scripts for 2 databases + 12 schemas
- Rewrite setup-databases.sh for consolidated architecture
- Update shared-drizzle-config default to mana_platform
- Update CLAUDE.md with new database architecture docs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-04-02 14:31:28 +02:00
parent b1a5c95f1d
commit 3ea28b9065
44 changed files with 311 additions and 346 deletions

View file

@ -58,7 +58,7 @@ S3_SECRET_KEY=minioadmin
# ============================================ # ============================================
MANA_CORE_AUTH_PORT=3001 MANA_CORE_AUTH_PORT=3001
MANA_CORE_AUTH_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/manacore MANA_CORE_AUTH_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
JWT_ACCESS_TOKEN_EXPIRY=15m JWT_ACCESS_TOKEN_EXPIRY=15m
JWT_REFRESH_TOKEN_EXPIRY=7d JWT_REFRESH_TOKEN_EXPIRY=7d
JWT_ISSUER=manacore JWT_ISSUER=manacore
@ -155,7 +155,7 @@ UMAMI_WEBSITE_ID_MUKKE_LANDING=b2c9ab34-3c53-4463-9dde-1ecf098886a5
# Chat Backend # Chat Backend
CHAT_BACKEND_PORT=3002 CHAT_BACKEND_PORT=3002
CHAT_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/chat CHAT_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
DEV_BYPASS_AUTH=true DEV_BYPASS_AUTH=true
DEV_USER_ID=00000000-0000-0000-0000-000000000000 DEV_USER_ID=00000000-0000-0000-0000-000000000000
@ -187,7 +187,7 @@ MAERCHENZAUBER_REPLICATE_API_KEY=YOUR_KEY
# ============================================ # ============================================
CARDS_BACKEND_PORT=3009 CARDS_BACKEND_PORT=3009
CARDS_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/cards CARDS_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
CARDS_APP_ID=cea4bfc6-a4de-4e17-91e2-54275940156e CARDS_APP_ID=cea4bfc6-a4de-4e17-91e2-54275940156e
# ============================================ # ============================================
@ -196,7 +196,7 @@ CARDS_APP_ID=cea4bfc6-a4de-4e17-91e2-54275940156e
PICTURE_BACKEND_PORT=3006 PICTURE_BACKEND_PORT=3006
PICTURE_BACKEND_URL=http://localhost:3006 PICTURE_BACKEND_URL=http://localhost:3006
PICTURE_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/picture PICTURE_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
# Replicate API Token for AI image generation # Replicate API Token for AI image generation
PICTURE_REPLICATE_API_TOKEN=r8_QlvkstNhIc6NBX1ktpQ6ibvzOE2d2UQ1Emamd PICTURE_REPLICATE_API_TOKEN=r8_QlvkstNhIc6NBX1ktpQ6ibvzOE2d2UQ1Emamd
@ -214,7 +214,7 @@ PICTURE_MANA_CORE_SERVICE_KEY=
# ============================================ # ============================================
NUTRIPHI_BACKEND_PORT=3023 NUTRIPHI_BACKEND_PORT=3023
NUTRIPHI_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/nutriphi NUTRIPHI_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
NUTRIPHI_APP_ID=nutriphi NUTRIPHI_APP_ID=nutriphi
# Google Gemini API for food image analysis # Google Gemini API for food image analysis
@ -228,14 +228,14 @@ NUTRIPHI_S3_PUBLIC_URL=http://localhost:9000/nutriphi-storage
# ============================================ # ============================================
ZITARE_BACKEND_PORT=3007 ZITARE_BACKEND_PORT=3007
ZITARE_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/zitare ZITARE_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
# ============================================ # ============================================
# ZITARE TELEGRAM BOT # ZITARE TELEGRAM BOT
# ============================================ # ============================================
ZITARE_BOT_PORT=3303 ZITARE_BOT_PORT=3303
ZITARE_BOT_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/zitare_bot ZITARE_BOT_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
ZITARE_BOT_TELEGRAM_TOKEN=8489424174:AAHHG_mlLVeu6xAWY6U2ZGXO0D8JKWnqBvg ZITARE_BOT_TELEGRAM_TOKEN=8489424174:AAHHG_mlLVeu6xAWY6U2ZGXO0D8JKWnqBvg
# ============================================ # ============================================
@ -243,7 +243,7 @@ ZITARE_BOT_TELEGRAM_TOKEN=8489424174:AAHHG_mlLVeu6xAWY6U2ZGXO0D8JKWnqBvg
# ============================================ # ============================================
TODO_BOT_PORT=3304 TODO_BOT_PORT=3304
TODO_BOT_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/todo_bot TODO_BOT_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
TODO_BOT_TELEGRAM_TOKEN=8363906368:AAHzNC1DPSb0TUb2a3UGWWH1_rrAQFdBv2w TODO_BOT_TELEGRAM_TOKEN=8363906368:AAHzNC1DPSb0TUb2a3UGWWH1_rrAQFdBv2w
TODO_BOT_API_URL=http://localhost:3018 TODO_BOT_API_URL=http://localhost:3018
@ -252,14 +252,14 @@ TODO_BOT_API_URL=http://localhost:3018
# ============================================ # ============================================
PRESI_BACKEND_PORT=3008 PRESI_BACKEND_PORT=3008
PRESI_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/presi PRESI_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
# ============================================ # ============================================
# VOXEL-LAVA PROJECT # VOXEL-LAVA PROJECT
# ============================================ # ============================================
VOXEL_LAVA_BACKEND_PORT=3010 VOXEL_LAVA_BACKEND_PORT=3010
VOXEL_LAVA_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/voxel_lava VOXEL_LAVA_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
VOXEL_LAVA_API_URL=http://localhost:3010 VOXEL_LAVA_API_URL=http://localhost:3010
# ============================================ # ============================================
@ -267,7 +267,7 @@ VOXEL_LAVA_API_URL=http://localhost:3010
# ============================================ # ============================================
CONTACTS_BACKEND_PORT=3015 CONTACTS_BACKEND_PORT=3015
CONTACTS_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/contacts CONTACTS_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
# S3 Storage for contact photos # S3 Storage for contact photos
CONTACTS_S3_BUCKET=contacts-photos CONTACTS_S3_BUCKET=contacts-photos
@ -286,7 +286,7 @@ CONTACTS_GOOGLE_REDIRECT_URI=http://localhost:5184/import?tab=google
CALENDAR_BACKEND_PORT=3014 CALENDAR_BACKEND_PORT=3014
CALENDAR_BACKEND_URL=http://localhost:3014 CALENDAR_BACKEND_URL=http://localhost:3014
CALENDAR_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/calendar CALENDAR_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
# Speech-to-Text Service (mana-stt) # Speech-to-Text Service (mana-stt)
# Production: https://stt-api.mana.how # Production: https://stt-api.mana.how
@ -298,7 +298,7 @@ STT_URL=https://stt-api.mana.how
# ============================================ # ============================================
CONTEXT_BACKEND_PORT=3020 CONTEXT_BACKEND_PORT=3020
CONTEXT_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/context CONTEXT_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
# AI API Keys (server-side only) # AI API Keys (server-side only)
CONTEXT_AZURE_OPENAI_API_KEY=YOUR_KEY CONTEXT_AZURE_OPENAI_API_KEY=YOUR_KEY
@ -310,7 +310,7 @@ CONTEXT_GOOGLE_API_KEY=YOUR_KEY
# ============================================ # ============================================
STORAGE_BACKEND_PORT=3016 STORAGE_BACKEND_PORT=3016
STORAGE_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/storage STORAGE_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
STORAGE_S3_PUBLIC_URL=http://localhost:9000/storage-storage STORAGE_S3_PUBLIC_URL=http://localhost:9000/storage-storage
STORAGE_MAX_FILE_SIZE=104857600 STORAGE_MAX_FILE_SIZE=104857600
STORAGE_MAX_FILES_PER_UPLOAD=10 STORAGE_MAX_FILES_PER_UPLOAD=10
@ -320,7 +320,7 @@ STORAGE_MAX_FILES_PER_UPLOAD=10
# ============================================ # ============================================
CLOCK_BACKEND_PORT=3017 CLOCK_BACKEND_PORT=3017
CLOCK_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/clock CLOCK_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
# ============================================ # ============================================
# TODO PROJECT # TODO PROJECT
@ -328,14 +328,14 @@ CLOCK_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/clock
TODO_BACKEND_PORT=3018 TODO_BACKEND_PORT=3018
TODO_BACKEND_URL=http://localhost:3018 TODO_BACKEND_URL=http://localhost:3018
TODO_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/todo TODO_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
# ============================================ # ============================================
# MOODLIT PROJECT # MOODLIT PROJECT
# ============================================ # ============================================
MOODLIT_BACKEND_PORT=3012 MOODLIT_BACKEND_PORT=3012
MOODLIT_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/moods MOODLIT_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
# ============================================ # ============================================
# MANA-GAMES PROJECT # MANA-GAMES PROJECT
@ -364,14 +364,14 @@ MANA_GAMES_GITHUB_REPO=mana-games
# ============================================ # ============================================
FINANCE_BACKEND_PORT=3019 FINANCE_BACKEND_PORT=3019
FINANCE_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/finance FINANCE_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
# ============================================ # ============================================
# INVENTORY PROJECT # INVENTORY PROJECT
# ============================================ # ============================================
INVENTORY_BACKEND_PORT=3020 INVENTORY_BACKEND_PORT=3020
INVENTORY_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/inventory INVENTORY_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
INVENTORY_S3_PUBLIC_URL=http://localhost:9000/inventory-storage INVENTORY_S3_PUBLIC_URL=http://localhost:9000/inventory-storage
# ============================================ # ============================================
@ -379,14 +379,14 @@ INVENTORY_S3_PUBLIC_URL=http://localhost:9000/inventory-storage
# ============================================ # ============================================
TECHBASE_BACKEND_PORT=3021 TECHBASE_BACKEND_PORT=3021
TECHBASE_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/techbase TECHBASE_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
# ============================================ # ============================================
# PLANTA PROJECT # PLANTA PROJECT
# ============================================ # ============================================
PLANTA_BACKEND_PORT=3022 PLANTA_BACKEND_PORT=3022
PLANTA_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/planta PLANTA_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
PLANTA_S3_PUBLIC_URL=http://localhost:9000/planta-storage PLANTA_S3_PUBLIC_URL=http://localhost:9000/planta-storage
# Google Gemini API for plant vision analysis # Google Gemini API for plant vision analysis
@ -397,27 +397,27 @@ PLANTA_GEMINI_API_KEY=AIzaSyC_-hPWpVttTlqJdU4jbXR5H0OAnRi2LgI
# ============================================ # ============================================
TRACES_BACKEND_PORT=3026 TRACES_BACKEND_PORT=3026
TRACES_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/traces TRACES_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
# ============================================ # ============================================
# SKILLTREE PROJECT # SKILLTREE PROJECT
# ============================================ # ============================================
SKILLTREE_BACKEND_PORT=3024 SKILLTREE_BACKEND_PORT=3024
SKILLTREE_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/skilltree SKILLTREE_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
# ============================================ # ============================================
# MUKKE PROJECT # MUKKE PROJECT
# ============================================ # ============================================
MUKKE_BACKEND_PORT=3010 MUKKE_BACKEND_PORT=3010
MUKKE_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mukke MUKKE_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
# ============================================ # ============================================
# CITYCORNERS PROJECT # CITYCORNERS PROJECT
# ============================================ # ============================================
CITYCORNERS_BACKEND_PORT=3025 CITYCORNERS_BACKEND_PORT=3025
CITYCORNERS_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/citycorners CITYCORNERS_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mana_platform
CITYCORNERS_WEB_PORT=5196 CITYCORNERS_WEB_PORT=5196
# ============================================ # ============================================

View file

@ -666,12 +666,51 @@ import { createAuthService } from '@manacore/shared-auth';
import { formatDate, truncate } from '@manacore/shared-utils'; import { formatDate, truncate } from '@manacore/shared-utils';
``` ```
## Database (Supabase) ## Database Architecture (PostgreSQL)
- All projects use Supabase for PostgreSQL database, auth, and storage All backend data lives in **2 PostgreSQL databases**:
- Row Level Security (RLS) policies enforce access control via JWT claims
- Each project has its own Supabase project/schema | Database | Purpose | Tech |
- Types typically generated via `supabase gen types` |----------|---------|------|
| **mana_platform** | All services + app server-side tables | Drizzle ORM, pgSchema isolation |
| **mana_sync** | Sync engine (write-heavy, append-only) | Go + pgx |
### Schema Mapping (mana_platform)
Each service owns a PostgreSQL schema within the shared database:
| Schema | Service | Tables |
|--------|---------|--------|
| `auth` | mana-auth | users, sessions, orgs, passkeys |
| `credits` | mana-credits | balances, transactions, packages |
| `gifts` | mana-credits | gift codes, redemptions |
| `subscriptions` | mana-subscriptions | plans, invoices |
| `feedback` | mana-analytics | user feedback, votes |
| `usr` | mana-user | settings, tags, tag groups |
| `media` | mana-media | CAS, thumbnails, references |
| `todo` | todo server | tasks, projects, reminders |
| `traces` | traces server | locations, cities, POIs, guides |
| `presi` | presi server | decks, slides, themes, shares |
| `uload` | uload server | users, links, clicks |
| `cards` | cards package | decks, cards, study progress |
### Using pgSchema
All tables must use `pgSchema('name').table()` — never plain `pgTable()`:
```typescript
import { pgSchema } from 'drizzle-orm/pg-core';
const mySchema = pgSchema('myapp');
export const items = mySchema.table('items', { ... });
```
### Adding a New Schema
1. Add schema to `docker/init-db/01-create-databases.sql`
2. Add schema to `scripts/setup-databases.sh` (PLATFORM_SCHEMAS array)
3. Create `drizzle.config.ts` with `schemaFilter: ['myschema']`
4. All DATABASE_URLs point to `mana_platform` (one DB for everything)
## Object Storage (MinIO) ## Object Storage (MinIO)

View file

@ -6,7 +6,7 @@
import { drizzle } from 'drizzle-orm/postgres-js'; import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres'; import postgres from 'postgres';
import { import {
pgTable, pgSchema,
uuid, uuid,
text, text,
boolean, boolean,
@ -18,7 +18,7 @@ import {
import { relations } from 'drizzle-orm'; import { relations } from 'drizzle-orm';
const DATABASE_URL = const DATABASE_URL =
process.env.DATABASE_URL ?? 'postgresql://manacore:devpassword@localhost:5432/presi'; process.env.DATABASE_URL ?? 'postgresql://manacore:devpassword@localhost:5432/mana_platform';
const connection = postgres(DATABASE_URL, { const connection = postgres(DATABASE_URL, {
max: 5, max: 5,
@ -27,7 +27,9 @@ const connection = postgres(DATABASE_URL, {
// ─── Schema (read-only for share lookups) ──────────────── // ─── Schema (read-only for share lookups) ────────────────
export const decks = pgTable('decks', { export const presiSchema = pgSchema('presi');
export const decks = presiSchema.table('decks', {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),
userId: text('user_id').notNull(), userId: text('user_id').notNull(),
title: text('title').notNull(), title: text('title').notNull(),
@ -38,7 +40,7 @@ export const decks = pgTable('decks', {
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(), updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
}); });
export const slides = pgTable( export const slides = presiSchema.table(
'slides', 'slides',
{ {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),
@ -50,7 +52,7 @@ export const slides = pgTable(
(table) => [index('slides_deck_order_idx').on(table.deckId, table.order)] (table) => [index('slides_deck_order_idx').on(table.deckId, table.order)]
); );
export const themes = pgTable('themes', { export const themes = presiSchema.table('themes', {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),
name: text('name').notNull(), name: text('name').notNull(),
colors: jsonb('colors'), colors: jsonb('colors'),
@ -58,7 +60,7 @@ export const themes = pgTable('themes', {
isDefault: boolean('is_default').default(false), isDefault: boolean('is_default').default(false),
}); });
export const sharedDecks = pgTable( export const sharedDecks = presiSchema.table(
'shared_decks', 'shared_decks',
{ {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),

View file

@ -8,7 +8,7 @@
import { drizzle } from 'drizzle-orm/postgres-js'; import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres'; import postgres from 'postgres';
import { import {
pgTable, pgSchema,
uuid, uuid,
text, text,
timestamp, timestamp,
@ -20,16 +20,20 @@ import {
} from 'drizzle-orm/pg-core'; } from 'drizzle-orm/pg-core';
const DATABASE_URL = const DATABASE_URL =
process.env.DATABASE_URL ?? 'postgresql://manacore:devpassword@localhost:5432/todo'; process.env.DATABASE_URL ?? 'postgresql://manacore:devpassword@localhost:5432/mana_platform';
const connection = postgres(DATABASE_URL, { const connection = postgres(DATABASE_URL, {
max: 5, max: 5,
idle_timeout: 20, idle_timeout: 20,
}); });
// ─── Schema ────────────────
export const todoSchema = pgSchema('todo');
// ─── Minimal Schema (only what server needs) ──────────────── // ─── Minimal Schema (only what server needs) ────────────────
export const tasks = pgTable('tasks', { export const tasks = todoSchema.table('tasks', {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),
userId: text('user_id').notNull(), userId: text('user_id').notNull(),
projectId: uuid('project_id'), projectId: uuid('project_id'),
@ -55,12 +59,12 @@ export const tasks = pgTable('tasks', {
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(), updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
}); });
export const projects = pgTable('projects', { export const projects = todoSchema.table('projects', {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),
userId: text('user_id').notNull(), userId: text('user_id').notNull(),
}); });
export const reminders = pgTable( export const reminders = todoSchema.table(
'reminders', 'reminders',
{ {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),

View file

@ -17,7 +17,7 @@ import { GuideService } from './services/guide';
const PORT = parseInt(process.env.PORT || '3026', 10); const PORT = parseInt(process.env.PORT || '3026', 10);
const DB_URL = const DB_URL =
process.env.DATABASE_URL || 'postgresql://manacore:devpassword@localhost:5432/traces'; process.env.DATABASE_URL || 'postgresql://manacore:devpassword@localhost:5432/mana_platform';
const LLM_URL = process.env.MANA_LLM_URL || 'http://localhost:3025'; const LLM_URL = process.env.MANA_LLM_URL || 'http://localhost:3025';
const SEARCH_URL = process.env.MANA_SEARCH_URL || 'http://localhost:3021'; const SEARCH_URL = process.env.MANA_SEARCH_URL || 'http://localhost:3021';
const CORS_ORIGINS = (process.env.CORS_ORIGINS || 'http://localhost:5173').split(','); const CORS_ORIGINS = (process.env.CORS_ORIGINS || 'http://localhost:5173').split(',');

View file

@ -1,5 +1,5 @@
import { import {
pgTable, pgSchema,
uuid, uuid,
text, text,
doublePrecision, doublePrecision,
@ -10,6 +10,8 @@ import {
uniqueIndex, uniqueIndex,
} from 'drizzle-orm/pg-core'; } from 'drizzle-orm/pg-core';
export const tracesSchema = pgSchema('traces');
// ============================================ // ============================================
// Enums // Enums
// ============================================ // ============================================
@ -49,7 +51,7 @@ export const guideStatusEnum = pgEnum('guide_status', ['generating', 'ready', 'e
// Tables // Tables
// ============================================ // ============================================
export const locations = pgTable( export const locations = tracesSchema.table(
'locations', 'locations',
{ {
id: uuid('id').defaultRandom().primaryKey(), id: uuid('id').defaultRandom().primaryKey(),
@ -80,7 +82,7 @@ export const locations = pgTable(
] ]
); );
export const cities = pgTable( export const cities = tracesSchema.table(
'cities', 'cities',
{ {
id: uuid('id').defaultRandom().primaryKey(), id: uuid('id').defaultRandom().primaryKey(),
@ -94,7 +96,7 @@ export const cities = pgTable(
(table) => [uniqueIndex('cities_name_country_code_idx').on(table.name, table.countryCode)] (table) => [uniqueIndex('cities_name_country_code_idx').on(table.name, table.countryCode)]
); );
export const cityVisits = pgTable( export const cityVisits = tracesSchema.table(
'city_visits', 'city_visits',
{ {
id: uuid('id').defaultRandom().primaryKey(), id: uuid('id').defaultRandom().primaryKey(),
@ -115,7 +117,7 @@ export const cityVisits = pgTable(
] ]
); );
export const places = pgTable( export const places = tracesSchema.table(
'places', 'places',
{ {
id: uuid('id').defaultRandom().primaryKey(), id: uuid('id').defaultRandom().primaryKey(),
@ -139,7 +141,7 @@ export const places = pgTable(
] ]
); );
export const pois = pgTable( export const pois = tracesSchema.table(
'pois', 'pois',
{ {
id: uuid('id').defaultRandom().primaryKey(), id: uuid('id').defaultRandom().primaryKey(),
@ -165,7 +167,7 @@ export const pois = pgTable(
] ]
); );
export const guides = pgTable( export const guides = tracesSchema.table(
'guides', 'guides',
{ {
id: uuid('id').defaultRandom().primaryKey(), id: uuid('id').defaultRandom().primaryKey(),
@ -190,7 +192,7 @@ export const guides = pgTable(
] ]
); );
export const guidePois = pgTable( export const guidePois = tracesSchema.table(
'guide_pois', 'guide_pois',
{ {
id: uuid('id').defaultRandom().primaryKey(), id: uuid('id').defaultRandom().primaryKey(),

View file

@ -22,8 +22,7 @@ let client: ReturnType<typeof postgres> | null = null;
export function getDb(): ReturnType<typeof drizzle<typeof schema>> { export function getDb(): ReturnType<typeof drizzle<typeof schema>> {
if (!db) { if (!db) {
const connectionString = const connectionString =
process.env.DATABASE_URL || process.env.DATABASE_URL || 'postgresql://manacore:devpassword@localhost:5432/mana_platform';
'postgresql://uload:uload_dev_password_123@localhost:5432/uload_dev';
client = postgres(connectionString, { client = postgres(connectionString, {
max: 10, max: 10,

View file

@ -1,5 +1,5 @@
import { import {
pgTable, pgSchema,
uuid, uuid,
text, text,
boolean, boolean,
@ -10,10 +10,12 @@ import {
} from 'drizzle-orm/pg-core'; } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm'; import { relations } from 'drizzle-orm';
export const uloadSchema = pgSchema('uload');
// ============================================ // ============================================
// Users Table // Users Table
// ============================================ // ============================================
export const users = pgTable( export const users = uloadSchema.table(
'users', 'users',
{ {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),
@ -48,7 +50,7 @@ export const users = pgTable(
// ============================================ // ============================================
// Accounts Table // Accounts Table
// ============================================ // ============================================
export const accounts = pgTable( export const accounts = uloadSchema.table(
'accounts', 'accounts',
{ {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),
@ -70,7 +72,7 @@ export const accounts = pgTable(
// ============================================ // ============================================
// Workspaces Table // Workspaces Table
// ============================================ // ============================================
export const workspaces = pgTable( export const workspaces = uloadSchema.table(
'workspaces', 'workspaces',
{ {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),
@ -92,7 +94,7 @@ export const workspaces = pgTable(
// ============================================ // ============================================
// Links Table // Links Table
// ============================================ // ============================================
export const links = pgTable( export const links = uloadSchema.table(
'links', 'links',
{ {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),
@ -129,7 +131,7 @@ export const links = pgTable(
// ============================================ // ============================================
// Clicks Table // Clicks Table
// ============================================ // ============================================
export const clicks = pgTable( export const clicks = uloadSchema.table(
'clicks', 'clicks',
{ {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),

View file

@ -10,7 +10,7 @@ services:
container_name: manacore-postgres container_name: manacore-postgres
restart: unless-stopped restart: unless-stopped
environment: environment:
POSTGRES_DB: manacore POSTGRES_DB: mana_platform
POSTGRES_USER: ${POSTGRES_USER:-manacore} POSTGRES_USER: ${POSTGRES_USER:-manacore}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-devpassword} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-devpassword}
volumes: volumes:
@ -113,7 +113,7 @@ services:
environment: environment:
NODE_ENV: development NODE_ENV: development
PORT: 3001 PORT: 3001
DATABASE_URL: postgresql://${POSTGRES_USER:-manacore}:${POSTGRES_PASSWORD:-devpassword}@postgres:5432/mana_auth DATABASE_URL: postgresql://${POSTGRES_USER:-manacore}:${POSTGRES_PASSWORD:-devpassword}@postgres:5432/mana_platform
BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET:-dev-secret-change-me} BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET:-dev-secret-change-me}
BETTER_AUTH_URL: http://localhost:3001 BETTER_AUTH_URL: http://localhost:3001
CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:3000,http://localhost:5173,http://localhost:8081} CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:3000,http://localhost:5173,http://localhost:8081}
@ -136,7 +136,7 @@ services:
environment: environment:
NODE_ENV: development NODE_ENV: development
PORT: 3002 PORT: 3002
DATABASE_URL: postgresql://${POSTGRES_USER:-manacore}:${POSTGRES_PASSWORD:-devpassword}@postgres:5432/chat DATABASE_URL: postgresql://${POSTGRES_USER:-manacore}:${POSTGRES_PASSWORD:-devpassword}@postgres:5432/mana_platform
DB_HOST: postgres DB_HOST: postgres
DB_PORT: 5432 DB_PORT: 5432
DB_USER: ${POSTGRES_USER:-manacore} DB_USER: ${POSTGRES_USER:-manacore}

View file

@ -29,7 +29,7 @@ services:
restart: always restart: always
mem_limit: 1024m mem_limit: 1024m
environment: environment:
POSTGRES_DB: mana POSTGRES_DB: mana_platform
POSTGRES_USER: postgres POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-mana123} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-mana123}
volumes: volumes:
@ -263,13 +263,13 @@ services:
TZ: Europe/Berlin TZ: Europe/Berlin
NODE_ENV: production NODE_ENV: production
PORT: 3001 PORT: 3001
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_auth DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_platform
BASE_URL: https://auth.mana.how BASE_URL: https://auth.mana.how
COOKIE_DOMAIN: .mana.how COOKIE_DOMAIN: .mana.how
MANA_CORE_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY} MANA_CORE_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY}
MANA_CREDITS_URL: http://mana-credits:3061 MANA_CREDITS_URL: http://mana-credits:3061
MANA_SUBSCRIPTIONS_URL: http://mana-subscriptions:3063 MANA_SUBSCRIPTIONS_URL: http://mana-subscriptions:3063
SYNC_DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana SYNC_DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_platform
BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET:-${JWT_SECRET:-your-jwt-secret-change-me}} BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET:-${JWT_SECRET:-your-jwt-secret-change-me}}
SMTP_HOST: smtp-relay.brevo.com SMTP_HOST: smtp-relay.brevo.com
SMTP_PORT: 587 SMTP_PORT: 587
@ -305,7 +305,7 @@ services:
environment: environment:
TZ: Europe/Berlin TZ: Europe/Berlin
PORT: 3002 PORT: 3002
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_credits DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_platform
MANA_CORE_AUTH_URL: http://mana-auth:3001 MANA_CORE_AUTH_URL: http://mana-auth:3001
MANA_CORE_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY} MANA_CORE_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY}
STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-} STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}
@ -339,7 +339,7 @@ services:
environment: environment:
TZ: Europe/Berlin TZ: Europe/Berlin
PORT: 3062 PORT: 3062
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_user DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_platform
MANA_CORE_AUTH_URL: http://mana-auth:3001 MANA_CORE_AUTH_URL: http://mana-auth:3001
MANA_CORE_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY} MANA_CORE_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY}
CORS_ORIGINS: https://mana.how,https://calc.mana.how,https://calendar.mana.how,https://chat.mana.how,https://clock.mana.how,https://contacts.mana.how,https://context.mana.how,https://cards.mana.how,https://mukke.mana.how,https://nutriphi.mana.how,https://photos.mana.how,https://picture.mana.how,https://planta.mana.how,https://presi.mana.how,https://questions.mana.how,https://storage.mana.how,https://todo.mana.how,https://zitare.mana.how CORS_ORIGINS: https://mana.how,https://calc.mana.how,https://calendar.mana.how,https://chat.mana.how,https://clock.mana.how,https://contacts.mana.how,https://context.mana.how,https://cards.mana.how,https://mukke.mana.how,https://nutriphi.mana.how,https://photos.mana.how,https://picture.mana.how,https://planta.mana.how,https://presi.mana.how,https://questions.mana.how,https://storage.mana.how,https://todo.mana.how,https://zitare.mana.how
@ -365,7 +365,7 @@ services:
environment: environment:
TZ: Europe/Berlin TZ: Europe/Berlin
PORT: 3063 PORT: 3063
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_subscriptions DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_platform
MANA_CORE_AUTH_URL: http://mana-auth:3001 MANA_CORE_AUTH_URL: http://mana-auth:3001
MANA_CORE_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY} MANA_CORE_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY}
STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-} STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}
@ -394,7 +394,7 @@ services:
environment: environment:
TZ: Europe/Berlin TZ: Europe/Berlin
PORT: 3064 PORT: 3064
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_analytics DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_platform
MANA_CORE_AUTH_URL: http://mana-auth:3001 MANA_CORE_AUTH_URL: http://mana-auth:3001
MANA_LLM_URL: http://mana-llm:3025 MANA_LLM_URL: http://mana-llm:3025
CORS_ORIGINS: https://mana.how CORS_ORIGINS: https://mana.how
@ -427,7 +427,7 @@ services:
environment: environment:
TZ: Europe/Berlin TZ: Europe/Berlin
PORT: 3016 PORT: 3016
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana?sslmode=disable DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_platform?sslmode=disable
REDIS_HOST: redis REDIS_HOST: redis
REDIS_PORT: 6379 REDIS_PORT: 6379
REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123} REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123}
@ -510,7 +510,7 @@ services:
condition: service_healthy condition: service_healthy
environment: environment:
PORT: 3010 PORT: 3010
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana?sslmode=disable DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_sync?sslmode=disable
JWKS_URL: http://mana-auth:3001/api/v1/auth/jwks JWKS_URL: http://mana-auth:3001/api/v1/auth/jwks
CORS_ORIGINS: "https://mana.how,https://*.mana.how" CORS_ORIGINS: "https://mana.how,https://*.mana.how"
ports: ports:
@ -535,7 +535,7 @@ services:
condition: service_healthy condition: service_healthy
environment: environment:
PORT: 3013 PORT: 3013
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana?sslmode=disable DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_platform?sslmode=disable
SERVICE_KEY: ${NOTIFY_SERVICE_KEY:-dev-service-key} SERVICE_KEY: ${NOTIFY_SERVICE_KEY:-dev-service-key}
MANA_CORE_AUTH_URL: http://mana-auth:3001 MANA_CORE_AUTH_URL: http://mana-auth:3001
SMTP_HOST: ${SMTP_HOST:-smtp-relay.brevo.com} SMTP_HOST: ${SMTP_HOST:-smtp-relay.brevo.com}
@ -571,7 +571,7 @@ services:
environment: environment:
TZ: Europe/Berlin TZ: Europe/Berlin
PORT: 3014 PORT: 3014
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana?sslmode=disable DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_platform?sslmode=disable
REDIS_HOST: redis REDIS_HOST: redis
REDIS_PORT: 6379 REDIS_PORT: 6379
REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123} REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123}
@ -603,7 +603,7 @@ services:
environment: environment:
NODE_ENV: production NODE_ENV: production
PORT: 3011 PORT: 3011
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_media DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_platform
REDIS_HOST: redis REDIS_HOST: redis
REDIS_PORT: 6379 REDIS_PORT: 6379
REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123} REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123}

View file

@ -1,43 +1,15 @@
-- Create databases for all services -- Create additional databases for services
-- This script runs on first container initialization -- Note: mana_platform is already created as POSTGRES_DB by Docker
-- Core databases -- Sync database: separate for I/O isolation (write-heavy, append-only)
CREATE DATABASE IF NOT EXISTS glitchtip; CREATE DATABASE mana_sync;
CREATE DATABASE IF NOT EXISTS chat;
CREATE DATABASE IF NOT EXISTS zitare;
CREATE DATABASE IF NOT EXISTS contacts;
CREATE DATABASE IF NOT EXISTS calendar;
CREATE DATABASE IF NOT EXISTS clock;
CREATE DATABASE IF NOT EXISTS todo;
CREATE DATABASE IF NOT EXISTS cards;
CREATE DATABASE IF NOT EXISTS storage;
CREATE DATABASE IF NOT EXISTS mail;
CREATE DATABASE IF NOT EXISTS moodlit;
CREATE DATABASE IF NOT EXISTS finance;
CREATE DATABASE IF NOT EXISTS inventory;
CREATE DATABASE IF NOT EXISTS techbase;
CREATE DATABASE IF NOT EXISTS voxel_lava;
CREATE DATABASE IF NOT EXISTS figgos;
CREATE DATABASE IF NOT EXISTS context;
CREATE DATABASE IF NOT EXISTS citycorners;
-- Grant all privileges to the default user -- Infrastructure databases (external tools)
GRANT ALL PRIVILEGES ON DATABASE chat TO manacore; CREATE DATABASE glitchtip;
GRANT ALL PRIVILEGES ON DATABASE zitare TO manacore; CREATE DATABASE umami;
GRANT ALL PRIVILEGES ON DATABASE contacts TO manacore;
GRANT ALL PRIVILEGES ON DATABASE calendar TO manacore; -- Grant privileges
GRANT ALL PRIVILEGES ON DATABASE clock TO manacore; GRANT ALL PRIVILEGES ON DATABASE mana_platform TO manacore;
GRANT ALL PRIVILEGES ON DATABASE todo TO manacore; GRANT ALL PRIVILEGES ON DATABASE mana_sync TO manacore;
GRANT ALL PRIVILEGES ON DATABASE cards TO manacore;
GRANT ALL PRIVILEGES ON DATABASE storage TO manacore;
GRANT ALL PRIVILEGES ON DATABASE mail TO manacore;
GRANT ALL PRIVILEGES ON DATABASE moodlit TO manacore;
GRANT ALL PRIVILEGES ON DATABASE finance TO manacore;
GRANT ALL PRIVILEGES ON DATABASE inventory TO manacore;
GRANT ALL PRIVILEGES ON DATABASE techbase TO manacore;
GRANT ALL PRIVILEGES ON DATABASE voxel_lava TO manacore;
GRANT ALL PRIVILEGES ON DATABASE figgos TO manacore;
GRANT ALL PRIVILEGES ON DATABASE context TO manacore;
GRANT ALL PRIVILEGES ON DATABASE citycorners TO manacore;
GRANT ALL PRIVILEGES ON DATABASE glitchtip TO manacore; GRANT ALL PRIVILEGES ON DATABASE glitchtip TO manacore;
GRANT ALL PRIVILEGES ON DATABASE manacore TO manacore; GRANT ALL PRIVILEGES ON DATABASE umami TO manacore;

View file

@ -0,0 +1,27 @@
#!/bin/bash
# Create schemas within mana_platform database
# Docker entrypoint runs .sh files after .sql files
set -e
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname mana_platform <<-EOSQL
-- Core service schemas
CREATE SCHEMA IF NOT EXISTS auth;
CREATE SCHEMA IF NOT EXISTS credits;
CREATE SCHEMA IF NOT EXISTS gifts;
CREATE SCHEMA IF NOT EXISTS subscriptions;
CREATE SCHEMA IF NOT EXISTS feedback;
CREATE SCHEMA IF NOT EXISTS usr;
CREATE SCHEMA IF NOT EXISTS media;
-- App server-side schemas
CREATE SCHEMA IF NOT EXISTS todo;
CREATE SCHEMA IF NOT EXISTS traces;
CREATE SCHEMA IF NOT EXISTS presi;
CREATE SCHEMA IF NOT EXISTS uload;
CREATE SCHEMA IF NOT EXISTS cards;
-- Grant schema usage
GRANT ALL ON SCHEMA auth, credits, gifts, subscriptions, feedback, usr, media,
todo, traces, presi, uload, cards TO manacore;
EOSQL

View file

@ -1,12 +1,14 @@
import { defineConfig } from 'drizzle-kit'; import { defineConfig } from 'drizzle-kit';
export default defineConfig({ export default defineConfig({
schema: './src/schema/index.ts', schema: './src/schema/*.ts',
out: './drizzle', out: './drizzle',
dialect: 'postgresql', dialect: 'postgresql',
dbCredentials: { dbCredentials: {
url: process.env.DATABASE_URL!, url:
process.env.DATABASE_URL || 'postgresql://manacore:devpassword@localhost:5432/mana_platform',
}, },
schemaFilter: ['cards'],
verbose: true, verbose: true,
strict: true, strict: true,
}); });

View file

@ -1,6 +1,7 @@
import { pgTable, uuid, text, varchar, timestamp, jsonb, index, pgEnum } from 'drizzle-orm/pg-core'; import { uuid, text, varchar, timestamp, jsonb, index, pgEnum } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm'; import { relations } from 'drizzle-orm';
import { decks } from './decks.js'; import { cardsSchema } from './schema';
import { decks } from './decks';
// AI generation status enum // AI generation status enum
export const aiGenerationStatusEnum = pgEnum('ai_generation_status', [ export const aiGenerationStatusEnum = pgEnum('ai_generation_status', [
@ -21,7 +22,7 @@ export interface AIGenerationMetadata {
[key: string]: unknown; [key: string]: unknown;
} }
export const aiGenerations = pgTable( export const aiGenerations = cardsSchema.table(
'ai_generations', 'ai_generations',
{ {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),

View file

@ -1,5 +1,4 @@
import { import {
pgTable,
uuid, uuid,
text, text,
integer, integer,
@ -10,7 +9,8 @@ import {
unique, unique,
} from 'drizzle-orm/pg-core'; } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm'; import { relations } from 'drizzle-orm';
import { cards } from './cards.js'; import { cardsSchema } from './schema';
import { cards } from './cards';
// Progress status enum (SM-2 algorithm states) // Progress status enum (SM-2 algorithm states)
export const progressStatusEnum = pgEnum('progress_status', [ export const progressStatusEnum = pgEnum('progress_status', [
@ -20,7 +20,7 @@ export const progressStatusEnum = pgEnum('progress_status', [
'relearning', 'relearning',
]); ]);
export const cardProgress = pgTable( export const cardProgress = cardsSchema.table(
'card_progress', 'card_progress',
{ {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),

View file

@ -1,5 +1,4 @@
import { import {
pgTable,
uuid, uuid,
varchar, varchar,
text, text,
@ -11,8 +10,9 @@ import {
pgEnum, pgEnum,
} from 'drizzle-orm/pg-core'; } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm'; import { relations } from 'drizzle-orm';
import { decks } from './decks.js'; import { cardsSchema } from './schema';
import { cardProgress } from './cardProgress.js'; import { decks } from './decks';
import { cardProgress } from './cardProgress';
// Card type enum // Card type enum
export const cardTypeEnum = pgEnum('card_type', ['text', 'flashcard', 'quiz', 'mixed']); export const cardTypeEnum = pgEnum('card_type', ['text', 'flashcard', 'quiz', 'mixed']);
@ -46,7 +46,7 @@ export interface MixedContent {
export type CardContent = TextContent | FlashcardContent | QuizContent | MixedContent; export type CardContent = TextContent | FlashcardContent | QuizContent | MixedContent;
export const cards = pgTable( export const cards = cardsSchema.table(
'cards', 'cards',
{ {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),

View file

@ -1,16 +1,7 @@
import { import { uuid, text, date, integer, decimal, timestamp, index, unique } from 'drizzle-orm/pg-core';
pgTable, import { cardsSchema } from './schema';
uuid,
text,
date,
integer,
decimal,
timestamp,
index,
unique,
} from 'drizzle-orm/pg-core';
export const dailyProgress = pgTable( export const dailyProgress = cardsSchema.table(
'daily_progress', 'daily_progress',
{ {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),

View file

@ -1,5 +1,4 @@
import { import {
pgTable,
uuid, uuid,
varchar, varchar,
text, text,
@ -9,6 +8,7 @@ import {
jsonb, jsonb,
index, index,
} from 'drizzle-orm/pg-core'; } from 'drizzle-orm/pg-core';
import { cardsSchema } from './schema';
// Template data structure // Template data structure
export interface DeckTemplateData { export interface DeckTemplateData {
@ -21,7 +21,7 @@ export interface DeckTemplateData {
tags?: string[]; tags?: string[];
} }
export const deckTemplates = pgTable( export const deckTemplates = cardsSchema.table(
'deck_templates', 'deck_templates',
{ {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),

View file

@ -1,19 +1,11 @@
import { import { uuid, text, varchar, boolean, timestamp, jsonb, index } from 'drizzle-orm/pg-core';
pgTable,
uuid,
text,
varchar,
boolean,
timestamp,
jsonb,
index,
} from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm'; import { relations } from 'drizzle-orm';
import { cards } from './cards.js'; import { cardsSchema } from './schema';
import { studySessions } from './studySessions.js'; import { cards } from './cards';
import { aiGenerations } from './aiGenerations.js'; import { studySessions } from './studySessions';
import { aiGenerations } from './aiGenerations';
export const decks = pgTable( export const decks = cardsSchema.table(
'decks', 'decks',
{ {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),

View file

@ -1,16 +1,19 @@
// Export schema definition
export * from './schema';
// Export all schemas // Export all schemas
export * from './decks.js'; export * from './decks';
export * from './cards.js'; export * from './cards';
export * from './studySessions.js'; export * from './studySessions';
export * from './cardProgress.js'; export * from './cardProgress';
export * from './deckTemplates.js'; export * from './deckTemplates';
export * from './aiGenerations.js'; export * from './aiGenerations';
export * from './userStats.js'; export * from './userStats';
export * from './dailyProgress.js'; export * from './dailyProgress';
// Re-export relations for use with Drizzle query builder // Re-export relations for use with Drizzle query builder
export { decksRelations } from './decks.js'; export { decksRelations } from './decks';
export { cardsRelations } from './cards.js'; export { cardsRelations } from './cards';
export { studySessionsRelations } from './studySessions.js'; export { studySessionsRelations } from './studySessions';
export { cardProgressRelations } from './cardProgress.js'; export { cardProgressRelations } from './cardProgress';
export { aiGenerationsRelations } from './aiGenerations.js'; export { aiGenerationsRelations } from './aiGenerations';

View file

@ -0,0 +1,3 @@
import { pgSchema } from 'drizzle-orm/pg-core';
export const cardsSchema = pgSchema('cards');

View file

@ -1,11 +1,12 @@
import { pgTable, uuid, text, integer, timestamp, index, pgEnum } from 'drizzle-orm/pg-core'; import { uuid, text, integer, timestamp, index, pgEnum } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm'; import { relations } from 'drizzle-orm';
import { decks } from './decks.js'; import { cardsSchema } from './schema';
import { decks } from './decks';
// Study mode enum // Study mode enum
export const studyModeEnum = pgEnum('study_mode', ['all', 'new', 'review', 'favorites', 'random']); export const studyModeEnum = pgEnum('study_mode', ['all', 'new', 'review', 'favorites', 'random']);
export const studySessions = pgTable( export const studySessions = cardsSchema.table(
'study_sessions', 'study_sessions',
{ {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),

View file

@ -1,6 +1,7 @@
import { pgTable, text, integer, decimal, date, timestamp, index } from 'drizzle-orm/pg-core'; import { text, integer, decimal, date, timestamp, index } from 'drizzle-orm/pg-core';
import { cardsSchema } from './schema';
export const userStats = pgTable( export const userStats = cardsSchema.table(
'user_stats', 'user_stats',
{ {
userId: text('user_id').primaryKey(), userId: text('user_id').primaryKey(),

View file

@ -3,9 +3,9 @@ import { defineConfig, type Config } from 'drizzle-kit';
export interface DrizzleConfigOptions { export interface DrizzleConfigOptions {
/** /**
* Database name for fallback URL when DATABASE_URL is not set * Database name for fallback URL when DATABASE_URL is not set
* Example: 'calendar' -> postgresql://manacore:devpassword@localhost:5432/calendar * @default 'mana_platform'
*/ */
dbName: string; dbName?: string;
/** /**
* Path to schema file(s) * Path to schema file(s)
@ -82,7 +82,7 @@ const DEFAULT_PG_PASSWORD = 'devpassword';
*/ */
export function createDrizzleConfig(options: DrizzleConfigOptions): Config { export function createDrizzleConfig(options: DrizzleConfigOptions): Config {
const { const {
dbName, dbName = 'mana_platform',
schemaPath = './src/db/schema/index.ts', schemaPath = './src/db/schema/index.ts',
outDir = './src/db/migrations', outDir = './src/db/migrations',
envVar = 'DATABASE_URL', envVar = 'DATABASE_URL',

View file

@ -36,7 +36,7 @@ export function createDb<TSchema extends Record<string, unknown>>(
const url = const url =
opts?.url ?? opts?.url ??
process.env.DATABASE_URL ?? process.env.DATABASE_URL ??
'postgresql://manacore:devpassword@localhost:5432/mana'; 'postgresql://manacore:devpassword@localhost:5432/mana_platform';
const connection = postgres(url, { const connection = postgres(url, {
max: opts?.maxConnections ?? 5, max: opts?.maxConnections ?? 5,

View file

@ -4,8 +4,10 @@
# Usage: ./scripts/setup-databases.sh [service] # Usage: ./scripts/setup-databases.sh [service]
# Examples: # Examples:
# ./scripts/setup-databases.sh # Setup all # ./scripts/setup-databases.sh # Setup all
# ./scripts/setup-databases.sh chat # Setup only chat # ./scripts/setup-databases.sh auth # Setup only auth schema
# ./scripts/setup-databases.sh auth # Setup only auth #
# Architecture: 2 databases (mana_platform + mana_sync)
# All service schemas live in mana_platform as separate PostgreSQL schemas.
set -e set -e
@ -21,7 +23,7 @@ YELLOW='\033[1;33m'
RED='\033[0;31m' RED='\033[0;31m'
NC='\033[0m' # No Color NC='\033[0m' # No Color
echo -e "${GREEN}🗄️ Database Setup Script${NC}" echo -e "${GREEN}Database Setup Script${NC}"
echo "======================================" echo "======================================"
# Function to create database if it doesn't exist # Function to create database if it doesn't exist
@ -40,12 +42,19 @@ create_db_if_not_exists() {
fi fi
} }
# Function to create schema within a database
create_schema_if_not_exists() {
local db_name=$1
local schema_name=$2
PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $db_name -c \
"CREATE SCHEMA IF NOT EXISTS $schema_name;" > /dev/null 2>&1
}
# Function to push schema for a service # Function to push schema for a service
push_schema() { push_schema() {
local filter=$1 local filter=$1
local name=$2 local name=$2
echo -e "${YELLOW}Pushing schema for ${name}...${NC}" echo -e "${YELLOW}Pushing schema for ${name}...${NC}"
# Use --force to auto-approve in development (skips interactive prompts)
if pnpm --filter "$filter" db:push --force 2>/dev/null; then if pnpm --filter "$filter" db:push --force 2>/dev/null; then
echo -e " ${GREEN}✓ Schema pushed${NC}" echo -e " ${GREEN}✓ Schema pushed${NC}"
else else
@ -53,41 +62,20 @@ push_schema() {
fi fi
} }
# All databases that should exist # All schemas in mana_platform
ALL_DATABASES=( PLATFORM_SCHEMAS=(
"manacore" "auth"
"mana_auth" "credits"
"chat" "gifts"
"zitare" "subscriptions"
"contacts" "feedback"
"calendar" "usr"
"clock" "media"
"todo" "todo"
"cards"
"storage"
"presi"
"moodlit"
"inventory"
"planta"
"nutriphi"
"photos"
"projectdoc"
"zitare_bot"
"todo_bot"
"nutriphi_bot"
"questions"
"skilltree"
"mukke"
"traces" "traces"
"context" "presi"
"citycorners"
"uload" "uload"
# Hono service databases (extracted from former mana-core-auth) "cards"
"mana_credits"
"mana_user"
"mana_subscriptions"
"mana_analytics"
"mana_sync"
) )
# Check if specific service requested # Check if specific service requested
@ -98,112 +86,41 @@ setup_service() {
case $service in case $service in
auth|mana-auth) auth|mana-auth)
create_db_if_not_exists "mana_auth"
push_schema "@mana/auth" "mana-auth" push_schema "@mana/auth" "mana-auth"
;; ;;
chat) credits|mana-credits)
create_db_if_not_exists "chat" push_schema "@mana/credits" "mana-credits"
push_schema "@chat/server" "chat"
;; ;;
zitare) user|mana-user)
create_db_if_not_exists "zitare" push_schema "@mana/user" "mana-user"
# Schema managed by mana-sync (backend removed)
;; ;;
contacts) subscriptions|mana-subscriptions)
create_db_if_not_exists "contacts" push_schema "@mana/subscriptions" "mana-subscriptions"
# Schema managed by mana-sync (local-first)
;; ;;
calendar) analytics|mana-analytics)
create_db_if_not_exists "calendar" push_schema "@mana/analytics" "mana-analytics"
# Schema managed by mana-sync (local-first)
;; ;;
clock) media|mana-media)
create_db_if_not_exists "clock" push_schema "@mana/media" "mana-media"
# Schema managed by mana-sync (backend removed)
;; ;;
todo) todo)
create_db_if_not_exists "todo"
push_schema "@todo/server" "todo" push_schema "@todo/server" "todo"
;; ;;
cards)
create_db_if_not_exists "cards"
# Schema managed by mana-sync (local-first)
;;
moodlit)
create_db_if_not_exists "moodlit"
push_schema "@moodlit/server" "moodlit"
;;
picture)
create_db_if_not_exists "picture"
# Schema managed by mana-sync (local-first)
;;
photos)
create_db_if_not_exists "photos"
# Schema managed by mana-sync (backend removed)
;;
planta)
create_db_if_not_exists "planta"
push_schema "@planta/server" "planta"
;;
nutriphi)
create_db_if_not_exists "nutriphi"
# Schema managed by mana-sync (local-first)
;;
presi)
create_db_if_not_exists "presi"
# Schema managed by mana-sync (NestJS backend removed, Hono server for shares)
;;
storage)
create_db_if_not_exists "storage"
# Schema managed by mana-sync (local-first)
;;
projectdoc)
create_db_if_not_exists "projectdoc"
push_schema "@manacore/telegram-project-doc-bot" "projectdoc"
;;
zitare_bot|zitare-bot)
create_db_if_not_exists "zitare_bot"
push_schema "@manacore/telegram-zitare-bot" "zitare-bot"
;;
todo_bot|todo-bot)
create_db_if_not_exists "todo_bot"
push_schema "@manacore/telegram-todo-bot" "todo-bot"
;;
nutriphi_bot|nutriphi-bot)
create_db_if_not_exists "nutriphi_bot"
push_schema "@manacore/telegram-nutriphi-bot" "nutriphi-bot"
;;
questions)
create_db_if_not_exists "questions"
# Schema managed by mana-sync (local-first)
;;
skilltree)
create_db_if_not_exists "skilltree"
# Schema managed by mana-sync (backend removed)
;;
mukke)
create_db_if_not_exists "mukke"
push_schema "@mukke/server" "mukke"
;;
traces) traces)
create_db_if_not_exists "traces"
push_schema "@traces/server" "traces" push_schema "@traces/server" "traces"
;; ;;
context) presi)
create_db_if_not_exists "context" push_schema "@presi/server" "presi"
push_schema "@context/server" "context"
;;
citycorners)
create_db_if_not_exists "citycorners"
# Schema managed by mana-sync (backend removed)
;; ;;
uload) uload)
create_db_if_not_exists "uload" push_schema "@manacore/uload-database" "uload"
# Schema managed by mana-sync (local-first app) ;;
cards)
push_schema "@manacore/cards-database" "cards"
;; ;;
*) *)
echo -e "${RED}Unknown service: $service${NC}" echo -e "${RED}Unknown service: $service${NC}"
echo "Available services: auth, chat, zitare, contacts, calendar, clock, todo, cards, moodlit, picture, photos, planta, nutriphi, presi, storage, projectdoc, zitare_bot, todo_bot, nutriphi_bot, questions, skilltree, mukke, traces, context, citycorners, uload" echo "Available services: auth, credits, user, subscriptions, analytics, media, todo, traces, presi, uload, cards"
exit 1 exit 1
;; ;;
esac esac
@ -219,15 +136,21 @@ fi
# Setup all databases # Setup all databases
echo -e "\n${GREEN}Step 1: Creating databases${NC}" echo -e "\n${GREEN}Step 1: Creating databases${NC}"
echo "--------------------------------------" echo "--------------------------------------"
for db in "${ALL_DATABASES[@]}"; do create_db_if_not_exists "mana_platform"
create_db_if_not_exists "$db" create_db_if_not_exists "mana_sync"
echo -e "\n${GREEN}Step 2: Creating schemas in mana_platform${NC}"
echo "--------------------------------------"
for schema in "${PLATFORM_SCHEMAS[@]}"; do
echo -e " ${YELLOW}Creating schema: ${schema}${NC}"
create_schema_if_not_exists "mana_platform" "$schema"
echo -e " ${GREEN}${schema}${NC}"
done done
echo -e "\n${GREEN}Step 2: Pushing schemas${NC}" echo -e "\n${GREEN}Step 3: Pushing schemas${NC}"
echo "--------------------------------------" echo "--------------------------------------"
# Push schemas for all known services for service in auth credits user subscriptions analytics media todo traces presi uload cards; do
for service in auth chat zitare contacts calendar clock todo cards picture photos moodlit planta nutriphi presi storage questions skilltree mukke traces context citycorners; do
setup_service "$service" 2>/dev/null || true setup_service "$service" 2>/dev/null || true
done done

View file

@ -6,7 +6,7 @@ export default defineConfig({
dialect: 'postgresql', dialect: 'postgresql',
dbCredentials: { dbCredentials: {
url: url:
process.env.DATABASE_URL || 'postgresql://manacore:devpassword@localhost:5432/mana_analytics', process.env.DATABASE_URL || 'postgresql://manacore:devpassword@localhost:5432/mana_platform',
}, },
schemaFilter: ['feedback'], schemaFilter: ['feedback'],
}); });

View file

@ -13,7 +13,7 @@ export function loadConfig(): Config {
port: parseInt(env('PORT', '3064'), 10), port: parseInt(env('PORT', '3064'), 10),
databaseUrl: env( databaseUrl: env(
'DATABASE_URL', 'DATABASE_URL',
'postgresql://manacore:devpassword@localhost:5432/mana_analytics' 'postgresql://manacore:devpassword@localhost:5432/mana_platform'
), ),
manaAuthUrl: env('MANA_CORE_AUTH_URL', 'http://localhost:3001'), manaAuthUrl: env('MANA_CORE_AUTH_URL', 'http://localhost:3001'),
manaLlmUrl: env('MANA_LLM_URL', 'http://localhost:3025'), manaLlmUrl: env('MANA_LLM_URL', 'http://localhost:3025'),

View file

@ -5,7 +5,8 @@ export default defineConfig({
out: './drizzle', out: './drizzle',
dialect: 'postgresql', dialect: 'postgresql',
dbCredentials: { dbCredentials: {
url: process.env.DATABASE_URL || 'postgresql://manacore:devpassword@localhost:5432/mana_auth', url:
process.env.DATABASE_URL || 'postgresql://manacore:devpassword@localhost:5432/mana_platform',
}, },
schemaFilter: ['auth'], schemaFilter: ['auth'],
}); });

View file

@ -22,7 +22,10 @@ export function loadConfig(): Config {
const env = (key: string, fallback?: string) => process.env[key] || fallback || ''; const env = (key: string, fallback?: string) => process.env[key] || fallback || '';
return { return {
port: parseInt(env('PORT', '3001'), 10), port: parseInt(env('PORT', '3001'), 10),
databaseUrl: env('DATABASE_URL', 'postgresql://manacore:devpassword@localhost:5432/mana_auth'), databaseUrl: env(
'DATABASE_URL',
'postgresql://manacore:devpassword@localhost:5432/mana_platform'
),
syncDatabaseUrl: env( syncDatabaseUrl: env(
'SYNC_DATABASE_URL', 'SYNC_DATABASE_URL',
'postgresql://manacore:devpassword@localhost:5432/mana_sync' 'postgresql://manacore:devpassword@localhost:5432/mana_sync'

View file

@ -6,7 +6,7 @@ export default defineConfig({
dialect: 'postgresql', dialect: 'postgresql',
dbCredentials: { dbCredentials: {
url: url:
process.env.DATABASE_URL || 'postgresql://manacore:devpassword@localhost:5432/mana_credits', process.env.DATABASE_URL || 'postgresql://manacore:devpassword@localhost:5432/mana_platform',
}, },
schemaFilter: ['credits', 'gifts'], schemaFilter: ['credits', 'gifts'],
}); });

View file

@ -28,7 +28,7 @@ export function loadConfig(): Config {
port: parseInt(process.env.PORT || '3061', 10), port: parseInt(process.env.PORT || '3061', 10),
databaseUrl: requiredEnv( databaseUrl: requiredEnv(
'DATABASE_URL', 'DATABASE_URL',
'postgresql://manacore:devpassword@localhost:5432/mana_credits' 'postgresql://manacore:devpassword@localhost:5432/mana_platform'
), ),
manaAuthUrl: requiredEnv('MANA_CORE_AUTH_URL', 'http://localhost:3001'), manaAuthUrl: requiredEnv('MANA_CORE_AUTH_URL', 'http://localhost:3001'),
serviceKey: requiredEnv('MANA_CORE_SERVICE_KEY', 'dev-service-key'), serviceKey: requiredEnv('MANA_CORE_SERVICE_KEY', 'dev-service-key'),

View file

@ -1,6 +1,7 @@
import { createDrizzleConfig } from '@manacore/shared-drizzle-config'; import { createDrizzleConfig } from '@manacore/shared-drizzle-config';
export default createDrizzleConfig({ export default createDrizzleConfig({
dbName: 'mana_media', dbName: 'mana_platform',
schemaPath: './src/db/schema/index.ts', schemaPath: './src/db/schema/index.ts',
schemaFilter: ['media'],
}); });

View file

@ -1,5 +1,5 @@
import { import {
pgTable, pgSchema,
uuid, uuid,
text, text,
timestamp, timestamp,
@ -11,11 +11,13 @@ import {
} from 'drizzle-orm/pg-core'; } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm'; import { relations } from 'drizzle-orm';
export const mediaSchema = pgSchema('media');
/** /**
* Core media table - stores unique files by content hash (SHA-256) * Core media table - stores unique files by content hash (SHA-256)
* This is the Content-Addressable Storage (CAS) approach * This is the Content-Addressable Storage (CAS) approach
*/ */
export const media = pgTable( export const media = mediaSchema.table(
'media', 'media',
{ {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),
@ -70,7 +72,7 @@ export const media = pgTable(
* Media references - tracks which user/app owns a reference to a media item * Media references - tracks which user/app owns a reference to a media item
* Multiple users can reference the same media (deduplication) * Multiple users can reference the same media (deduplication)
*/ */
export const mediaReferences = pgTable( export const mediaReferences = mediaSchema.table(
'media_references', 'media_references',
{ {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),
@ -101,7 +103,7 @@ export const mediaReferences = pgTable(
* Lazy-generated thumbnails cache * Lazy-generated thumbnails cache
* Stores on-the-fly generated thumbnails with specific parameters * Stores on-the-fly generated thumbnails with specific parameters
*/ */
export const mediaThumbnails = pgTable( export const mediaThumbnails = mediaSchema.table(
'media_thumbnails', 'media_thumbnails',
{ {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),

View file

@ -6,8 +6,7 @@ export default defineConfig({
dialect: 'postgresql', dialect: 'postgresql',
dbCredentials: { dbCredentials: {
url: url:
process.env.DATABASE_URL || process.env.DATABASE_URL || 'postgresql://manacore:devpassword@localhost:5432/mana_platform',
'postgresql://manacore:devpassword@localhost:5432/mana_subscriptions',
}, },
schemaFilter: ['subscriptions'], schemaFilter: ['subscriptions'],
}); });

View file

@ -14,7 +14,7 @@ export function loadConfig(): Config {
port: parseInt(env('PORT', '3063'), 10), port: parseInt(env('PORT', '3063'), 10),
databaseUrl: env( databaseUrl: env(
'DATABASE_URL', 'DATABASE_URL',
'postgresql://manacore:devpassword@localhost:5432/mana_subscriptions' 'postgresql://manacore:devpassword@localhost:5432/mana_platform'
), ),
manaAuthUrl: env('MANA_CORE_AUTH_URL', 'http://localhost:3001'), manaAuthUrl: env('MANA_CORE_AUTH_URL', 'http://localhost:3001'),
serviceKey: env('MANA_CORE_SERVICE_KEY', 'dev-service-key'), serviceKey: env('MANA_CORE_SERVICE_KEY', 'dev-service-key'),

View file

@ -5,6 +5,8 @@ export default defineConfig({
out: './drizzle', out: './drizzle',
dialect: 'postgresql', dialect: 'postgresql',
dbCredentials: { dbCredentials: {
url: process.env.DATABASE_URL || 'postgresql://manacore:devpassword@localhost:5432/mana_user', url:
process.env.DATABASE_URL || 'postgresql://manacore:devpassword@localhost:5432/mana_platform',
}, },
schemaFilter: ['usr'],
}); });

View file

@ -10,7 +10,10 @@ export function loadConfig(): Config {
const env = (key: string, fallback?: string) => process.env[key] || fallback || ''; const env = (key: string, fallback?: string) => process.env[key] || fallback || '';
return { return {
port: parseInt(env('PORT', '3062'), 10), port: parseInt(env('PORT', '3062'), 10),
databaseUrl: env('DATABASE_URL', 'postgresql://manacore:devpassword@localhost:5432/mana_user'), databaseUrl: env(
'DATABASE_URL',
'postgresql://manacore:devpassword@localhost:5432/mana_platform'
),
manaAuthUrl: env('MANA_CORE_AUTH_URL', 'http://localhost:3001'), manaAuthUrl: env('MANA_CORE_AUTH_URL', 'http://localhost:3001'),
serviceKey: env('MANA_CORE_SERVICE_KEY', 'dev-service-key'), serviceKey: env('MANA_CORE_SERVICE_KEY', 'dev-service-key'),
cors: { origins: env('CORS_ORIGINS', 'http://localhost:5173').split(',') }, cors: { origins: env('CORS_ORIGINS', 'http://localhost:5173').split(',') },

View file

@ -1,3 +1,4 @@
export * from './schema';
export * from './tag-groups'; export * from './tag-groups';
export * from './tags'; export * from './tags';
export * from './tag-links'; export * from './tag-links';

View file

@ -0,0 +1,3 @@
import { pgSchema } from 'drizzle-orm/pg-core';
export const usrSchema = pgSchema('usr');

View file

@ -1,6 +1,7 @@
import { pgTable, text, jsonb, timestamp } from 'drizzle-orm/pg-core'; import { text, jsonb, timestamp } from 'drizzle-orm/pg-core';
import { usrSchema } from './schema';
export const userSettings = pgTable('user_settings', { export const userSettings = usrSchema.table('user_settings', {
userId: text('user_id').primaryKey(), userId: text('user_id').primaryKey(),
globalSettings: jsonb('global_settings') globalSettings: jsonb('global_settings')
.default({ .default({

View file

@ -1,15 +1,7 @@
import { import { varchar, text, uuid, timestamp, index, unique, integer } from 'drizzle-orm/pg-core';
pgTable, import { usrSchema } from './schema';
varchar,
text,
uuid,
timestamp,
index,
unique,
integer,
} from 'drizzle-orm/pg-core';
export const tagGroups = pgTable( export const tagGroups = usrSchema.table(
'tag_groups', 'tag_groups',
{ {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),

View file

@ -1,7 +1,8 @@
import { pgTable, varchar, text, uuid, timestamp, index, unique } from 'drizzle-orm/pg-core'; import { varchar, text, uuid, timestamp, index, unique } from 'drizzle-orm/pg-core';
import { usrSchema } from './schema';
import { tags } from './tags'; import { tags } from './tags';
export const tagLinks = pgTable( export const tagLinks = usrSchema.table(
'tag_links', 'tag_links',
{ {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),

View file

@ -1,16 +1,8 @@
import { import { varchar, text, uuid, timestamp, index, unique, integer } from 'drizzle-orm/pg-core';
pgTable, import { usrSchema } from './schema';
varchar,
text,
uuid,
timestamp,
index,
unique,
integer,
} from 'drizzle-orm/pg-core';
import { tagGroups } from './tag-groups'; import { tagGroups } from './tag-groups';
export const tags = pgTable( export const tags = usrSchema.table(
'tags', 'tags',
{ {
id: uuid('id').primaryKey().defaultRandom(), id: uuid('id').primaryKey().defaultRandom(),