Files

91 lines
3.6 KiB
TypeScript

// The notes module's manifest (spec §4.1, §16): the one place it registers anything.
//
// The example module of the template and the pattern a product's own follows. It is small on
// purpose and uses every seam a module has:
//
// - a contract, a core of pure use cases and a Kysely-bound repository (entities.ts, migrations/);
// - the kernel's files module for attachments: the browser uploads through the files procedures
// (`files.file.beginUpload`, `putPart`, `completeUpload`; the platform's Blob store; one audit
// event and one usage fact per upload, recorded by the files module) and links the file with
// `notes.attachment.add`;
// - audit events and a usage meter that hang off the module's own outbox events, exactly once;
// - a feature flag (`notes.attachments`), evaluated through a port;
// - messages in English and Lithuanian, a navigation entry and the pages (`ui/pages.tsx`), which
// the web shell mounts from `modules/index.ts` with no route file of its own.
import { defineModule, subscribe } from "@conusai-kit/core"
import { repositoryBindings } from "@conusai-kit/data"
import { fileDeleted } from "@conusai-kit/files"
import { NOTE_PROCEDURES } from "./adapters/procedures.js"
import {
ATTACHMENT_ADDED,
ATTACHMENT_REMOVED,
attachmentAdded,
attachmentRemoved,
NOTE_CREATED,
NOTE_DELETED,
NOTE_UPDATED,
NOTES_CREATED_METER,
NOTES_ENTITIES,
NOTES_EVENTS,
NOTES_FLAG_DEFAULTS,
noteCreated,
noteDeleted,
noteUpdated,
} from "./contract/index.js"
import {
onAttachmentAdded,
onAttachmentRemoved,
onFileDeleted,
onNoteCreated,
onNoteDeleted,
onNoteUpdated,
} from "./core/subscribers.js"
import { NOTES_GUIDES } from "./guides/index.js" // kit:guides
import { en, lt } from "./i18n/index.js"
const tables = repositoryBindings(...NOTES_ENTITIES)
export const notesModule = defineModule({
id: "notes",
version: "0.1.0",
kit: "^0.1.0",
requires: ["tenancy", "files"],
permissions: {
"notes.note.read": "viewer",
"notes.note.write": "editor",
"notes.note.delete": "editor",
"notes.attachment.write": "editor",
},
procedures: NOTE_PROCEDURES,
repositories: { postgres: tables, mariadb: tables, mongodb: tables, convex: tables },
// Forward-only migrations, one numbered file per change per dialect (spec §5.3: the dialect
// differences are explicit, not generated), run by the migrate job after the app's own.
migrations: {
postgres: "migrations",
mariadb: "adapters/kysely/mysql/migrations",
mongodb: "adapters/mongo/migrations",
},
events: {
publishes: NOTES_EVENTS,
subscribes: [
subscribe(noteCreated, onNoteCreated),
subscribe(noteUpdated, onNoteUpdated),
subscribe(noteDeleted, onNoteDeleted),
subscribe(attachmentAdded, onAttachmentAdded),
subscribe(attachmentRemoved, onAttachmentRemoved),
// A deleted file takes its links with it.
subscribe(fileDeleted, onFileDeleted),
],
},
audit: [NOTE_CREATED, NOTE_UPDATED, NOTE_DELETED, ATTACHMENT_ADDED, ATTACHMENT_REMOVED],
usage: { meters: [NOTES_CREATED_METER] },
flags: Object.fromEntries(Object.entries(NOTES_FLAG_DEFAULTS).map(([flag, value]) => [flag, { default: value }])),
// The project-level entry the org home lists next to each project; `notes` is the segment the
// web shell's module mount routes to `notesPages` (ui/pages.tsx).
ui: { nav: [{ scope: "project", label: "notes.title", href: "notes", permission: "notes.note.read" }] },
// Both languages, as objects: kit-i18n merges them from the registry (AT-D23).
i18n: { en, lt },
extends: [...NOTES_GUIDES], // kit:guides -- the code tour, checklist and survey of guides/
})