feat: comprehensive project structure improvements and Cloud for Sovereignty landing zone

- Add Cloud for Sovereignty landing zone architecture and deployment
- Implement complete legal document management system
- Reorganize documentation with improved navigation
- Add infrastructure improvements (Dockerfiles, K8s, monitoring)
- Add operational improvements (graceful shutdown, rate limiting, caching)
- Create comprehensive project structure documentation
- Add Azure deployment automation scripts
- Improve repository navigation and organization
This commit is contained in:
defiQUG
2025-11-13 09:32:55 -08:00
parent 92cc41d26d
commit 6a8582e54d
202 changed files with 22699 additions and 981 deletions

View File

@@ -0,0 +1,265 @@
/**
* Document Comments and Annotations
* Handles comments, annotations, and collaborative review features
*/
import { query } from './client';
import { z } from 'zod';
export const DocumentCommentSchema = z.object({
id: z.string().uuid(),
document_id: z.string().uuid(),
version_id: z.string().uuid().optional(),
parent_comment_id: z.string().uuid().optional(),
comment_text: z.string(),
comment_type: z.enum(['comment', 'suggestion', 'question', 'resolution']),
status: z.enum(['open', 'resolved', 'dismissed']),
page_number: z.number().int().optional(),
x_position: z.number().optional(),
y_position: z.number().optional(),
highlight_text: z.string().optional(),
author_id: z.string().uuid(),
resolved_by: z.string().uuid().optional(),
resolved_at: z.date().optional(),
created_at: z.date(),
updated_at: z.date(),
});
export type DocumentComment = z.infer<typeof DocumentCommentSchema>;
export interface CreateDocumentCommentInput {
document_id: string;
version_id?: string;
parent_comment_id?: string;
comment_text: string;
comment_type?: 'comment' | 'suggestion' | 'question' | 'resolution';
status?: 'open' | 'resolved' | 'dismissed';
page_number?: number;
x_position?: number;
y_position?: number;
highlight_text?: string;
author_id: string;
}
/**
* Create a document comment
*/
export async function createDocumentComment(
input: CreateDocumentCommentInput
): Promise<DocumentComment> {
const result = await query<DocumentComment>(
`INSERT INTO document_comments
(document_id, version_id, parent_comment_id, comment_text, comment_type,
status, page_number, x_position, y_position, highlight_text, author_id)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
RETURNING *`,
[
input.document_id,
input.version_id || null,
input.parent_comment_id || null,
input.comment_text,
input.comment_type || 'comment',
input.status || 'open',
input.page_number || null,
input.x_position || null,
input.y_position || null,
input.highlight_text || null,
input.author_id,
]
);
return result.rows[0]!;
}
/**
* Get comment by ID
*/
export async function getDocumentComment(id: string): Promise<DocumentComment | null> {
const result = await query<DocumentComment>(
`SELECT * FROM document_comments WHERE id = $1`,
[id]
);
return result.rows[0] || null;
}
/**
* Get all comments for a document
*/
export async function getDocumentComments(
document_id: string,
version_id?: string,
include_resolved = false
): Promise<DocumentComment[]> {
const conditions = ['document_id = $1'];
const params: unknown[] = [document_id];
let paramIndex = 2;
if (version_id) {
conditions.push(`version_id = $${paramIndex++}`);
params.push(version_id);
}
if (!include_resolved) {
conditions.push(`status != 'resolved'`);
}
const result = await query<DocumentComment>(
`SELECT * FROM document_comments
WHERE ${conditions.join(' AND ')}
ORDER BY created_at ASC`,
params
);
return result.rows;
}
/**
* Get threaded comments (with replies)
*/
export interface ThreadedComment extends DocumentComment {
replies?: ThreadedComment[];
}
export async function getThreadedDocumentComments(
document_id: string,
version_id?: string
): Promise<ThreadedComment[]> {
const allComments = await getDocumentComments(document_id, version_id, true);
// Build tree structure
const commentMap = new Map<string, ThreadedComment>();
const rootComments: ThreadedComment[] = [];
// First pass: create map
for (const comment of allComments) {
commentMap.set(comment.id, { ...comment, replies: [] });
}
// Second pass: build tree
for (const comment of allComments) {
const threaded = commentMap.get(comment.id)!;
if (comment.parent_comment_id) {
const parent = commentMap.get(comment.parent_comment_id);
if (parent) {
parent.replies!.push(threaded);
}
} else {
rootComments.push(threaded);
}
}
return rootComments;
}
/**
* Update comment
*/
export async function updateDocumentComment(
id: string,
updates: Partial<Pick<DocumentComment, 'comment_text' | 'status'>>
): Promise<DocumentComment | null> {
const fields: string[] = [];
const values: unknown[] = [];
let paramIndex = 1;
if (updates.comment_text !== undefined) {
fields.push(`comment_text = $${paramIndex++}`);
values.push(updates.comment_text);
}
if (updates.status !== undefined) {
fields.push(`status = $${paramIndex++}`);
values.push(updates.status);
if (updates.status === 'resolved') {
// Get current user from context - for now, we'll need to pass it
// This should be handled by the service layer
}
}
if (fields.length === 0) {
return getDocumentComment(id);
}
fields.push(`updated_at = NOW()`);
values.push(id);
const result = await query<DocumentComment>(
`UPDATE document_comments
SET ${fields.join(', ')}
WHERE id = $${paramIndex}
RETURNING *`,
values
);
return result.rows[0] || null;
}
/**
* Resolve comment
*/
export async function resolveDocumentComment(
id: string,
resolved_by: string
): Promise<DocumentComment | null> {
const result = await query<DocumentComment>(
`UPDATE document_comments
SET status = 'resolved', resolved_by = $1, resolved_at = NOW(), updated_at = NOW()
WHERE id = $2
RETURNING *`,
[resolved_by, id]
);
return result.rows[0] || null;
}
/**
* Get comment statistics for a document
*/
export interface CommentStatistics {
total: number;
open: number;
resolved: number;
dismissed: number;
by_type: Record<string, number>;
}
export async function getDocumentCommentStatistics(
document_id: string
): Promise<CommentStatistics> {
const result = await query<{
total: string;
open: string;
resolved: string;
dismissed: string;
comment_type: string;
count: string;
}>(
`SELECT
COUNT(*) as total,
COUNT(*) FILTER (WHERE status = 'open') as open,
COUNT(*) FILTER (WHERE status = 'resolved') as resolved,
COUNT(*) FILTER (WHERE status = 'dismissed') as dismissed,
comment_type,
COUNT(*) as count
FROM document_comments
WHERE document_id = $1
GROUP BY comment_type`,
[document_id]
);
const stats: CommentStatistics = {
total: parseInt(result.rows[0]?.total || '0', 10),
open: parseInt(result.rows[0]?.open || '0', 10),
resolved: parseInt(result.rows[0]?.resolved || '0', 10),
dismissed: parseInt(result.rows[0]?.dismissed || '0', 10),
by_type: {},
};
for (const row of result.rows) {
stats.by_type[row.comment_type] = parseInt(row.count, 10);
}
return stats;
}