feat(infra): add mana-sync and mana-notify-go to docker-compose

- mana-sync on port 3051 (Go sync server for local-first apps)
- mana-notify-go on port 3040 (Go notification service)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-03-27 22:35:05 +01:00
parent 313779f439
commit ef19018e71
60 changed files with 908 additions and 2876 deletions

View file

@ -0,0 +1,15 @@
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
import * as schema from './schema/index';
let db: ReturnType<typeof drizzle<typeof schema>> | null = null;
export function getDb(databaseUrl: string) {
if (!db) {
const client = postgres(databaseUrl, { max: 10 });
db = drizzle(client, { schema });
}
return db;
}
export type Database = ReturnType<typeof getDb>;

View file

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

View file

@ -0,0 +1,18 @@
import { pgTable, text, jsonb, timestamp } from 'drizzle-orm/pg-core';
export const userSettings = pgTable('user_settings', {
userId: text('user_id').primaryKey(),
globalSettings: jsonb('global_settings')
.default({
nav: { desktopPosition: 'top', sidebarCollapsed: false },
theme: { mode: 'system', colorScheme: 'ocean' },
locale: 'de',
})
.notNull(),
appOverrides: jsonb('app_overrides').default({}).notNull(),
deviceSettings: jsonb('device_settings').default({}).notNull(),
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
});
export type UserSettings = typeof userSettings.$inferSelect;

View file

@ -0,0 +1,31 @@
import {
pgTable,
varchar,
text,
uuid,
timestamp,
index,
unique,
integer,
} from 'drizzle-orm/pg-core';
export const tagGroups = pgTable(
'tag_groups',
{
id: uuid('id').primaryKey().defaultRandom(),
userId: text('user_id').notNull(),
name: varchar('name', { length: 100 }).notNull(),
color: varchar('color', { length: 7 }).default('#3B82F6'),
icon: varchar('icon', { length: 50 }),
sortOrder: integer('sort_order').default(0).notNull(),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at').defaultNow().notNull(),
},
(table) => [
index('tag_groups_user_idx').on(table.userId),
unique('tag_groups_user_name_unique').on(table.userId, table.name),
]
);
export type TagGroup = typeof tagGroups.$inferSelect;
export type NewTagGroup = typeof tagGroups.$inferInsert;

View file

@ -0,0 +1,26 @@
import { pgTable, varchar, text, uuid, timestamp, index, unique } from 'drizzle-orm/pg-core';
import { tags } from './tags';
export const tagLinks = pgTable(
'tag_links',
{
id: uuid('id').primaryKey().defaultRandom(),
tagId: uuid('tag_id')
.notNull()
.references(() => tags.id, { onDelete: 'cascade' }),
appId: varchar('app_id', { length: 50 }).notNull(),
entityId: varchar('entity_id', { length: 255 }).notNull(),
entityType: varchar('entity_type', { length: 100 }).notNull(),
userId: text('user_id').notNull(),
createdAt: timestamp('created_at').defaultNow().notNull(),
},
(table) => [
index('tag_links_tag_idx').on(table.tagId),
index('tag_links_entity_idx').on(table.appId, table.entityId),
index('tag_links_user_app_idx').on(table.userId, table.appId),
unique('tag_links_unique').on(table.tagId, table.appId, table.entityId),
]
);
export type TagLink = typeof tagLinks.$inferSelect;
export type NewTagLink = typeof tagLinks.$inferInsert;

View file

@ -0,0 +1,34 @@
import {
pgTable,
varchar,
text,
uuid,
timestamp,
index,
unique,
integer,
} from 'drizzle-orm/pg-core';
import { tagGroups } from './tag-groups';
export const tags = pgTable(
'tags',
{
id: uuid('id').primaryKey().defaultRandom(),
userId: text('user_id').notNull(),
name: varchar('name', { length: 100 }).notNull(),
color: varchar('color', { length: 7 }).default('#3B82F6'),
icon: varchar('icon', { length: 50 }),
groupId: uuid('group_id').references(() => tagGroups.id, { onDelete: 'set null' }),
sortOrder: integer('sort_order').default(0).notNull(),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at').defaultNow().notNull(),
},
(table) => [
index('tags_user_idx').on(table.userId),
index('tags_group_idx').on(table.groupId),
unique('tags_user_name_unique').on(table.userId, table.name),
]
);
export type Tag = typeof tags.$inferSelect;
export type NewTag = typeof tags.$inferInsert;