Skip to content

rabbitxtech/metadata-management

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 

Repository files navigation

Metadata Management

A web app that connects to relational databases over JDBC and shows their metadata: tables, columns, primary/foreign keys, indexes, views, stored procedures, and the generated CREATE TABLE DDL. Admins register connection profiles per engine; users with appropriate roles browse, annotate, tag, glossary-link, and chart cross-database data lineage.

Supported engines for browsing: Oracle, MySQL, PostgreSQL, Netezza, IBM DB2, MariaDB, Microsoft SQL Server, Teradata, Vertica, Elasticsearch SQL, H2 — 11 engines, all driven from JDBC jars in backend/driver/.

Key features:

  • Annotation overlay — edit table/column descriptions in-app, preserve the original source comment, push back to the source DB on admin approval.
  • Tags — tag tables or individual columns; colour-coded chips throughout the UI.
  • Business glossary — shared term definitions linked to specific columns.
  • Data lineage — directed graph of source → target relationships between tables, including cross-database edges (e.g. a Postgres OLTP table feeding an Oracle warehouse).
  • Schema snapshots — fingerprint a schema's structure and detect added / removed / changed tables on the next capture.
  • API tokensAuthorization: Bearer mm_… for programmatic clients alongside the SPA's cookie auth.
  • Recycle bin — soft-delete connections; restore or purge within the bin.
  • i18n — English and Vietnamese; one-click toggle in the sidebar.
  • Admin tooling — push approvals, activity monitor, user groups, LDAP group-to-role mappings, webhooks, active sessions list.

Stack:

  • Backend: Spring Boot 3 (Java 17), Maven; Oracle for the app's own persistence; per-engine JDBC drivers for browsing user-registered databases; Spring Security with Active Directory LDAP for login (plus API-token bearer auth and a bootstrap-admin escape hatch).
  • Frontend: React 18, Vite, TypeScript, Tailwind CSS v3, Zustand, React Router 6, ApexCharts, @xyflow/react (ERD + lineage graphs), react-i18next, react-hot-toast, Boxicons.

Prerequisites

  • JDK 17+

  • Maven 3.9+

  • Node.js 18+ and npm

  • An Oracle 12c+ database for the app itself — schema with CREATE TABLE grants. The app will auto-create its tables on first run via ddl-auto=update. The full list:

    Table Purpose
    database_connection Saved connection profiles (with deleted_at for soft-delete)
    metadata_annotation + metadata_annotation_history Overlay descriptions and an audit trail
    role_assignment Per-user role assignments
    user_group + group_membership Custom groups with inheritable roles
    ldap_config + ldap_group_mapping LDAP settings + group → role mapping
    bootstrap_admin_credential Hashed break-glass-admin password
    login_event Successful sign-in history (powers the activity monitor)
    audit_event Append-only audit trail of admin actions
    push_request Editor-submitted push approvals
    webhook_config Outbound webhooks for push events
    tag + table_tag Per-table / per-column tags
    glossary_term + glossary_link Business glossary + column links
    api_token Programmatic access tokens (SHA-256 hashed)
    schema_snapshot DDL fingerprints for drift detection
    lineage_edge Directed lineage between tables (including cross-DB)
  • Network access to the source databases you want to browse (registered later from the UI).

Quick start

Open two terminals.

Terminal 1 — backend (port 8080):

cd backend
mvn spring-boot:run

Terminal 2 — frontend (port 5173):

cd frontend
npm install
npm run dev

Open http://localhost:5173. On a fresh install, the first-run setup wizard appears once to configure the app's database — see the section below. It never shows again after the data source has been saved.

The Vite dev server proxies /api/* to http://localhost:8080, so CORS is not exercised during development.

Frontend-only mock backend

For UI work or demos without a real backend, the repo ships an Express-based mock that mirrors every endpoint:

cd frontend
npm run dev:mock        # starts both: mock API on :8080 + Vite on :5173

Login with any credentials. Usernames containing viewer → VIEWER, editor → EDITOR, anything else → ADMIN. Seven connections come pre-seeded (one per engine family) along with sample overlay annotations and pending push requests so the Approvals + Preview flows show real content immediately.

First-run setup wizard

This wizard runs exactly once — the first time the app is started before the app's Oracle database has been configured. Once the data source is saved, the wizard never appears again.

Before any login is possible, the backend must be pointed at its own Oracle database. When the backend starts for the first time — before app-data/datasource.properties has been written — it falls back to an in-memory H2 database so it can serve the setup wizard.

The frontend detects this by calling GET /api/setup/status on load. If the response shows configured: false or reachable: false, the setup wizard replaces the whole app. The wizard lets you:

  1. Enter Oracle JDBC connection details (URL, username, password).
  2. Click Test connection to verify they work.
  3. Click Save — writes app-data/datasource.properties next to the jar and restarts the Spring datasource in-process.

After a successful save, the backend reconnects to Oracle, creates the schema tables automatically, and the login screen appears.

Login is blocked with HTTP 503 until the file exists — this prevents bypassing the wizard via curl.

Production note: the setup endpoints (/api/setup/*) are intentionally unauthenticated. Bind the backend to localhost or put it behind a VPN/reverse proxy during initial setup on public infrastructure.

Alternatively, skip the wizard entirely by supplying environment variables (see App DB configuration) before the first run — the wizard won't appear if the file already exists or the env vars point at a reachable Oracle instance.

App DB configuration

The app writes its Oracle connection details to app-data/datasource.properties via the setup wizard. You can also point the app at its Oracle DB directly via environment variables — these override the defaults in application.yml and take precedence over any wizard-saved file:

Env var Example Notes
APP_DB_URL jdbc:oracle:thin:@//db.example.com:1521/ORCLPDB1 Service-name form. Use jdbc:oracle:thin:@host:port:SID for SID-based DBs.
APP_DB_USERNAME metadata_app Schema owner; needs CREATE TABLE grants.
APP_DB_PASSWORD s3cret

If neither env vars nor the wizard file are present, the backend starts with an in-memory H2 fallback and shows the setup wizard on first load.

Bootstrap admin (super-admin)

The app ships a built-in local administrator account that authenticates without LDAP — the "bootstrap admin". Its purpose is to let you sign in and configure LDAP even when Active Directory is unreachable, and to give you a way in before any AD users have been assigned roles.

Env var Default Notes
APP_BOOTSTRAP_ADMIN_USERNAME admin Username for the break-glass account. Set to "" to disable entirely.
APP_BOOTSTRAP_ADMIN_PASSWORD admin Change this in production.

The bootstrap admin is always granted ADMIN role (it is included in APP_DEFAULT_ADMINS). It does not go through LDAP — credentials are verified against the value stored by BootstrapAdminService (initially from application.yml, then from the app's Oracle DB once a custom password has been saved).

Changing the password: the bootstrap admin has a Change password link at the bottom of the admin sidebar. Only the bootstrap admin (superAdmin: true in GET /api/auth/me) can reach that page — other ADMIN users get a 403. The current password must be supplied to set a new one.

The bootstrap admin shows as superAdmin: true in the API and UI. Regular AD admins are superAdmin: false.

Authentication (Active Directory)

The app requires sign-in before any /api/* endpoint can be called. Regular users sign in with Active Directory credentials. The bootstrap admin (see above) can also sign in without LDAP.

LDAP settings are configured at runtime via the LDAP Config page in the admin sidebar — they are stored in the ldap_config table in the app's Oracle DB and take effect immediately without a restart. Environment variables serve as a production override if the DB row is unavailable.

Env var Example Notes
APP_LDAP_URL ldap://dc01.corp.example.com:389 Use ldaps://...:636 for TLS
APP_LDAP_DOMAIN corp.example.com Username is bound as user@DOMAIN
APP_LDAP_ROOT_DN DC=corp,DC=example,DC=com Optional; blank lets the provider derive it from the domain
APP_LDAP_USER_SEARCH_FILTER (&(objectClass=user)(sAMAccountName={0})) Default — works for standard AD
APP_DEFAULT_ADMINS alice,bob Comma-separated AD usernames always granted ADMIN, even with no DB row

Sessions are stored in a cookie (JSESSIONID). There is no JWT, no local user table, and no signup flow — accounts live entirely in AD (except the bootstrap admin).

Sessions expire automatically after 20 minutes of inactivity — any mouse movement, keypress, or scroll resets the timer. The Spring backend's server.servlet.session.timeout matches so the cookie and the SPA's countdown expire together.

If /api/auth/me returns 401 mid-session, the SPA automatically falls back to the login screen.

API tokens (programmatic access)

For automation, scripts, or external services, generate an API token from the API Tokens page in the sidebar (Settings → API Tokens). Each token is granted a fixed role (VIEWER, EDITOR, or ADMIN) and an optional expiry. The raw secret (mm_…) is shown once on creation — copy it immediately; it's not retrievable later.

Pass it as a bearer header on any /api/* call instead of a session cookie:

Authorization: Bearer mm_<token>

Bearer auth and session auth coexist — programmatic clients don't need to call /api/auth/login first.

URL routes

The SPA uses React Router 6 with browser history — every page is bookmarkable, back/forward works, and refreshing keeps you on the same screen.

URL Page Required role
/ Empty state with "Manage connections" CTA any signed-in user
/connections Connections management (table, filter, edit, delete) any signed-in user (CRUD is admin-only)
/browse/:id Metadata explorer (schemas → tables → details → DDL → ERD) any signed-in user
/tags Tag catalog any signed-in user (CRUD is editor/admin)
/glossary Business glossary any signed-in user (CRUD is editor/admin)
/lineage Data lineage graph (cross-DB capable) any signed-in user (CRUD is editor/admin)
/compare Schema compare (side-by-side diff) any signed-in user
/monitoring Activity Monitor ADMIN
/approvals Push request approvals with diff + DDL preview ADMIN
/sessions Active sessions list (force sign-out) ADMIN
/recycle-bin Soft-deleted connections (restore / purge) ADMIN
/roles Users & Roles ADMIN
/groups User Groups ADMIN
/ldap-config LDAP configuration (runtime, stored in DB) ADMIN
/webhooks Outbound webhook configuration ADMIN
/api-tokens Programmatic API token management ADMIN
/change-password Change bootstrap-admin password super-admin only

Visiting an admin-only URL as a non-admin redirects to /. Visiting any URL while anonymous shows the login screen; after sign-in the user lands at the URL they originally requested.

Roles

Three roles in increasing capability:

Role What they can do
VIEWER Browse metadata (tables, columns, keys, indexes, views, procedures, generated DDL). Default for any authenticated user with no assignment.
EDITOR Everything VIEWER can do, plus edit table/column descriptions and submit push requests for admin approval. Cannot push directly.
ADMIN Everything EDITOR can do, plus create/edit/delete connection profiles, approve or reject push requests, push to source DB directly, and manage role assignments.

Assignments are managed from the Users & Roles page in the app (admins only). Usernames listed in APP_DEFAULT_ADMINS are always treated as ADMIN regardless of any DB row, so you can't lock yourself out by deleting every assignment — set at least one trusted username there.

Connections

Connections appear in two places:

  • Sidebar "Recent" — the last 6 connections you've actually browsed (per-user, persisted to localStorage). Empty until you visit one.
  • Manage Connections (/connections) — full table view of every saved profile with filter, click-to-browse, and admin-only New / Edit / Delete buttons.

Connection profiles (host, port, service name / SID / database, username, password) are persisted in the app's own Oracle database (database_connection table). Passwords are encrypted at rest with AES-GCM (256-bit) before being written.

Allowed schemas — each connection can optionally carry an allowedSchemas list. When non-empty, only the listed schema names are offered in the schema picker, regardless of what the database user can see. Leave it empty to expose all visible schemas.

The AES key is read from app.security.encryption-key in application.yml, which can be overridden with the APP_ENCRYPTION_KEY environment variable. The default key in application.yml is a placeholder — generate your own for any non-local use:

# 32 random bytes, Base64 encoded — paste into APP_ENCRYPTION_KEY
[Convert]::ToBase64String([byte[]](1..32 | ForEach-Object { Get-Random -Maximum 256 }))

If you change the key after saving connections, previously stored passwords cannot be decrypted — truncate database_connection in the app DB and re-create the connections.

User groups

Admins can divide users into custom groups from the User Groups page in the sidebar. A group has a name, an optional description, and an optional inherited role.

  • Purely organisational group (no role) — useful for tagging "Marketing Analysts" or "Data Platform Team"; no permission effect.
  • Group with a role — every member of the group inherits that role on top of any explicit per-user assignment they have. Effective role on each sign-in is max(explicit, every group role) using the ordering VIEWER < EDITOR < ADMIN.

Group membership can only raise a user's role, never lower it — there is no deny rule. Changes take effect on the affected user's next sign-in.

Activity monitor

Admins get an Activity Monitor page from the sidebar that shows:

  • Five summary stat cards — total logins all-time, distinct users all-time, annotated tables, logins in the last 30 days, and table edits in the last 30 days.
  • Users logged in (last 30 days) — daily bar chart. Primary bars are distinct users per day; lighter overlay bars are total login events per day.
  • Tables with updated metadata (last 30 days) — daily bar chart of distinct (connection, schema, table) tuples touched.
  • Logins per user — total login count and last-seen timestamp, sorted by busiest user first.
  • Recent logins — the last ~25 successful sign-in events with username and client IP.
  • Tables with changing metadata — every table that has at least one overlay annotation, ordered by most recently edited.

Daily buckets use Oracle TRUNC() in the DB session timezone (not UTC), so the chart's "day" is a day on the database server's clock.

Login events are written on every successful sign-in (AD or bootstrap admin) into the login_event table. Failed logins are not stored; this is for usage reporting, not intrusion detection.

Supported source engines

When an admin clicks + New Connection they pick the engine. The form adapts: default port auto-fills, the database field is labelled appropriately, and the Oracle-only SID/Service Name toggle only appears for Oracle.

Engine Driver jar (in backend/driver/) Default port What "database" means Comment push DDL
Oracle ojdbc17.jar 1521 Service name or SID COMMENT ON TABLE/COLUMN <schema>.<table>[.<column>] IS '…'
MySQL mysql-connector-j-9.7.0.jar 3306 Database name ALTER TABLE <schema>.<table> COMMENT = '…' / MODIFY COLUMN <name> <type> COMMENT '…'
PostgreSQL postgresql-42.7.11.jar 5432 Database name Same COMMENT ON as Oracle
Netezza nzjdbc3.jar 5480 Database name COMMENT ON TABLE <schema>.<table>; COMMENT ON COLUMN <table>.<column> (no schema prefix)
IBM DB2 jcc-11.5.9.0.jar 50000 Database name COMMENT ON TABLE/COLUMN …
MariaDB mariadb-java-client-3.3.2.jar 3306 Database name Same as MySQL (ALTER TABLE … COMMENT =)
SQL Server mssql-jdbc-12.8.0.jre11.jar 1433 Database name EXEC sp_addextendedproperty 'MS_Description', N'…', 'SCHEMA', N'…', 'TABLE', N'…'[, 'COLUMN', N'…']
Teradata terajdbc-20.00.00.06.jar 1025 Database (= schema) COMMENT ON TABLE/COLUMN … IS '…'
Vertica vertica-jdbc-23.3.0-0.jar 5433 Database name COMMENT ON TABLE/COLUMN … IS '…'
Elasticsearch x-pack-sql-jdbc-8.12.1.jar 9200 (unused — indices are flat) Read-only; cannot push comments
H2 h2-legacy.jar 9092 Database name COMMENT ON TABLE/COLUMN … IS '…'

Drivers live in backend/driver/

All JDBC drivers — including Oracle/MySQL/Postgres — are sourced from backend/driver/ as system-scoped Maven dependencies. The build is self-contained and doesn't reach out to Maven Central for any driver. See backend/driver/README.md for the rationale and the upgrade procedure.

To replace a driver:

  1. Drop the new jar into backend/driver/.
  2. Update the matching <systemPath> in backend/pom.xml (and the <version> if you care — it's cosmetic for system-scoped deps).
  3. Rebuild: mvn spring-boot:run for dev, mvn clean package for prod.

The spring-boot-maven-plugin is configured with <includeSystemScope>true</includeSystemScope>, so the jars land in BOOT-INF/lib of the fat-jar automatically.

backend/driver/*.jar is gitignored — the licensed binaries stay on your machine. The folder and its README are tracked so a fresh clone has the convention in place.

Metadata fidelity per engine

Oracle uses a native extractor (OracleMetadataExtractor) that hits ALL_* dictionary views and returns column defaults, view bodies, procedure validity, and uses DBMS_METADATA.GET_DDL for table DDL.

PostgreSQL (PostgresMetadataExtractor) and MySQL (MySqlMetadataExtractor) have native extractors that extend the generic base to return view definition bodies (from information_schema.views) and apply engine-correct schema casing (lowercase pass-through instead of Oracle-style uppercasing).

All other engines use the generic DatabaseMetaData-based extractor — fast and portable, with the table DDL constructed from the standard JDBC metadata. To add native fidelity for any engine, drop a new MetadataExtractor @Component next to the others in service/metadata/ and the dispatcher picks it up automatically.

Editing metadata: overlay → push request → admin approval

Descriptions for tables and individual columns can be edited inline in the UI. Edits are stored as an overlay in the app's own Oracle database, keyed by (connection, schema, table, column). The source database is never modified by an edit — the overlay is layered on top of live metadata when the table is viewed.

Edited fields are marked with an (overlay) badge, and the original source comment is preserved so you can see what was there before. Use Clear overlay to drop the edit and fall back to the source.

To get overlay descriptions written into the source database, the path depends on role:

  • EDITOR clicks Request push approval → creates a PENDING row in push_request. Their overlays stay editable until an admin acts. They cannot push directly (/annotations/push is ADMIN-only).
  • ADMIN can either click Push to source DB for an immediate push, or open Push Approvals to review and approve pending requests one at a time.

Approving with a preview

The Push Approvals page shows all pending requests. Clicking any cell in a row opens a preview dialog that:

  1. Fetches the merged table detail and shows a Before / After diff of every overlay annotation (table-level + per column).
  2. Calls a dry-run endpoint that builds the exact engine-correct DDL the source DB would receive — COMMENT ON … for the Oracle family, ALTER TABLE … COMMENT = for MySQL/MariaDB, sp_addextendedproperty for SQL Server, etc.
  3. Lists any targets that can't be pushed (e.g. an Elasticsearch column comment) under a separate "Will be skipped" section.

Admins Approve to execute the push and close the request, or Reject to close it without touching the source DB. Pending count surfaces as a badge on the sidebar nav. Partial push failures are stored on the request row in the push_errors column.

Identifiers are validated against an engine-portable safe-identifier regex (^[A-Za-z_][A-Za-z0-9_$#]{0,127}$) before being inlined into DDL. Description literals are escaped by doubling single quotes. The identifier check is the only injection guard — descriptions can never be parameterised in DDL, so do not relax it.

Theme

Sidebar has a sun/moon toggle (also available on the login screen, top-right). Choice is persisted to localStorage; defaults to the OS-level prefers-color-scheme on first load. Colors are driven by CSS variables (--bg-rgb, --fg-rgb, --accent-rgb, …) so charts, toasts, code blocks, and custom scrollbars all flip in sync.

Building for production

cd frontend; npm run build              # outputs to frontend/dist
cd ../backend; mvn clean package        # outputs backend/target/*.jar
java -jar backend/target/metadata-management-0.0.1-SNAPSHOT.jar

Single-jar deployment (recommended)

Copy the SPA build into Spring's static resources before packaging — the resulting fat-jar serves both the API and the SPA on port 8080:

cd frontend; npm run build
cp -r dist/* ../backend/src/main/resources/static/
cd ../backend; mvn clean package
java -jar target/metadata-management-0.0.1-SNAPSHOT.jar

SpaForwardController forwards every non-API, non-asset GET to /index.html, so a hard refresh on routes like /browse/42 or /lineage works without needing a separate reverse-proxy rewrite rule.

Split deployment

Serve frontend/dist from any static host or a reverse proxy in front of Spring Boot. Make sure your host falls back to index.html for unknown paths so React Router routes work on refresh. Set APP_CORS_ALLOWED_ORIGINS to the SPA's origin so the auth cookie flows.

REST endpoints

All /api/* endpoints require an authenticated session, except /api/auth/login and the /api/setup/* group.

Setup (no auth required)

Method Path Notes
GET /api/setup/status Returns {configured, reachable} — drives the first-run wizard
POST /api/setup/datasource/test Test-connect with the supplied credentials before saving
POST /api/setup/datasource Save credentials to app-data/datasource.properties and reload the datasource

Auth

Method Path Notes
POST /api/auth/login Body {username, password} — authenticates against AD or as bootstrap admin
POST /api/auth/logout Clears the session cookie
GET /api/auth/me Returns {username, role, superAdmin} or 401

Connections

Method Path Notes
GET /api/connections List active (non-deleted) connections
POST /api/connections Create connection (ADMIN)
PUT /api/connections/{id} Update connection (ADMIN)
DELETE /api/connections/{id} Soft-delete — sets deleted_at; row stays recoverable via the recycle bin (ADMIN)
GET /api/connections/recycle-bin List soft-deleted connections (ADMIN)
PUT /api/connections/{id}/restore Restore a soft-deleted connection (ADMIN)
DELETE /api/connections/{id}/purge Permanently delete a connection + all dependent rows (ADMIN)
POST /api/connections/test Test ad-hoc credentials (ADMIN)
POST /api/connections/{id}/test Test saved connection (ADMIN)

Metadata

Method Path Notes
GET /api/connections/{id}/metadata/schemas List schemas visible to the connection user
GET /api/connections/{id}/metadata/tables?schema= List tables in a schema
GET /api/connections/{id}/metadata/tables/{tableName}?schema= Columns, PK, FKs, indexes
GET /api/connections/{id}/metadata/tables/{tableName}/ddl?schema= Generated CREATE TABLE DDL + indexes + COMMENT ON … for every annotated row
GET /api/connections/{id}/metadata/views?schema= Views and their text
GET /api/connections/{id}/metadata/procedures?schema= Procedures, functions, packages

Annotations

Method Path Notes
GET /api/connections/{id}/annotations?schema=&tableName= List overlay annotations for a table
PUT /api/connections/{id}/annotations Upsert one annotation (EDITOR/ADMIN)
DELETE /api/connections/{id}/annotations?schema=&tableName=&columnName= Remove an overlay (EDITOR/ADMIN); columnName omitted ⇒ table-level
POST /api/connections/{id}/annotations/push?schema=&tableName= ADMIN only — push overlays to source DB directly
GET /api/connections/{id}/annotations/push/preview?schema=&tableName= Dry-run: returns the exact statements the source DB would receive (EDITOR/ADMIN)

Push requests

Method Path Notes
POST /api/push-requests Submit an approval request (EDITOR/ADMIN). Body {connectionId, schemaName, tableName, requestNote?}
GET /api/push-requests?status=pending|all List push requests (ADMIN only)
GET /api/push-requests/pending-count Sidebar badge count (ADMIN only)
POST /api/push-requests/{id}/approve Approve and execute the push (ADMIN only). Optional body {reviewerNote}
POST /api/push-requests/{id}/reject Reject without pushing (ADMIN only). Optional body {reviewerNote}

Roles

Method Path Notes
GET /api/roles List role assignments (ADMIN only)
PUT /api/roles Upsert one assignment (ADMIN only)
DELETE /api/roles/{username} Remove an assignment (ADMIN only)

Groups

Method Path Notes
GET /api/groups List custom user groups (ADMIN only)
PUT /api/groups Create or update a group (ADMIN only)
DELETE /api/groups/{id} Delete a group and its memberships (ADMIN only)
GET /api/groups/{id}/members List members of a group (ADMIN only)
POST /api/groups/{id}/members Add a user; body {"username": "…"} (ADMIN only)
DELETE /api/groups/{id}/members/{username} Remove a user from a group (ADMIN only)

Monitoring

Method Path Notes
GET /api/monitoring/login-stats Per-user login counts and last seen (ADMIN only)
GET /api/monitoring/recent-logins?limit= Most recent login events (ADMIN only)
GET /api/monitoring/annotation-activity?limit= Tables with changing metadata (ADMIN only)
GET /api/monitoring/login-trend?days= Daily login bucket for the trailing N days, zero-filled (ADMIN only)
GET /api/monitoring/annotation-trend?days= Daily count of distinct tables updated, trailing N days (ADMIN only)

Tags

Method Path Notes
GET /api/tags List tag catalog
PUT /api/tags Upsert a tag (EDITOR/ADMIN)
DELETE /api/tags/{id} Delete a tag (EDITOR/ADMIN)
GET /api/connections/{id}/tags?schema=&tableName=&columnName= Tags assigned to a table (or specific column when columnName is set)
GET /api/connections/{id}/tags/by-column?schema=&tableName= All tags on the table, grouped by columnName ("" key = table-level)
POST /api/connections/{id}/tags/{tagId}?schema=&tableName=&columnName= Assign a tag (EDITOR/ADMIN)
DELETE /api/connections/{id}/tags/{tagId}?schema=&tableName=&columnName= Unassign a tag (EDITOR/ADMIN)

Glossary

Method Path Notes
GET /api/glossary List business terms
PUT /api/glossary Upsert a term (EDITOR/ADMIN)
DELETE /api/glossary/{id} Delete a term and all its links (EDITOR/ADMIN)
GET /api/connections/{id}/glossary-links?schema=&tableName= All glossary links on a table
POST /api/connections/{id}/glossary-links?schema=&tableName=&termId=&columnName= Link a term to a column (EDITOR/ADMIN)
DELETE /api/connections/{id}/glossary-links?schema=&tableName=&termId=&columnName= Remove a link (EDITOR/ADMIN)

Data lineage

Edges are directional source → target. The target may live in a different connection and/or schema — pass targetConnectionId and targetSchemaName in the POST body to record a cross-DB edge. Omit them to default to the source's connection/schema.

Method Path Notes
GET /api/connections/{id}/lineage?schema= All edges where this (connection, schema) is source OR target
GET /api/connections/{id}/lineage/table/{table}?schema= Edges where the given table is source OR target
POST /api/connections/{id}/lineage Create an edge (EDITOR/ADMIN)
DELETE /api/connections/{id}/lineage/{edgeId} Delete an edge (EDITOR/ADMIN)

Schema snapshots

Method Path Notes
POST /api/connections/{id}/snapshots/capture?schema= Capture a new snapshot — returns drift vs. the previous one
GET /api/connections/{id}/snapshots?schema= List historical snapshots for a schema

Documentation export

Method Path Notes
GET /api/connections/{id}/metadata/schemas/{schema}/docs Markdown export of every table in the schema, including overlay annotations, tags, and glossary links
GET /api/connections/{id}/annotations/export?format=json|csv Export overlay annotations for one connection
POST /api/connections/{id}/annotations/import Multipart upload — re-imports a previously exported file (EDITOR/ADMIN)

API tokens

Method Path Notes
GET /api/tokens List tokens (raw secret never returned) (ADMIN only)
POST /api/tokens Create a token. Body {label, role, expiresAt?} — the raw mm_… secret is returned once in the response (ADMIN only)
DELETE /api/tokens/{id} Revoke a token (ADMIN only)

Webhooks

Method Path Notes
GET /api/webhooks List configured outbound webhooks (ADMIN only)
PUT /api/webhooks Create or update one. Body {name, url, secret?, events, active}events is ALL or a comma-separated list of PUSH_SUBMITTED, PUSH_APPROVED, PUSH_REJECTED (ADMIN only)
DELETE /api/webhooks/{id} Delete (ADMIN only)

Sessions

Method Path Notes
GET /api/admin/sessions All active HTTP sessions (ADMIN only)
DELETE /api/admin/sessions/{sessionId} Force-invalidate one session (ADMIN only)

Admin configuration

Method Path Notes
GET /api/admin/ldap-config Get current LDAP settings (ADMIN only)
PUT /api/admin/ldap-config Save LDAP settings and reload the auth provider in-process (ADMIN only)
GET /api/admin/ldap-group-mappings List LDAP-group → role mappings (ADMIN only)
PUT /api/admin/ldap-group-mappings Upsert a mapping (ADMIN only)
DELETE /api/admin/ldap-group-mappings/{id} Remove a mapping (ADMIN only)
GET /api/admin/bootstrap-admin/password/status Returns {hasCustomPassword} — signals the default password is still in use (super-admin only)
PUT /api/admin/bootstrap-admin/password Change the bootstrap-admin password. Body {currentPassword, newPassword} (super-admin only)

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors