Files
Thinh Lam 688fac73e9
CI/CD / backend (push) Failing after 2m8s
CI/CD / frontend (push) Failing after 1m40s
CI/CD / deploy (push) Has been skipped
sciagent code + Gitea Actions CI/CD
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 09:38:30 +07:00

172 lines
6.7 KiB
PL/PgSQL
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- =============================================================================
-- CRUD PATTERNS — Sáng kiến application system
-- =============================================================================
-- =============================================================================
-- CREATE: Submit a new application with multiple authors (atomic)
-- =============================================================================
BEGIN;
-- Set audit context
SELECT set_config('my.user_id', '42', true);
-- 1. Main record
INSERT INTO applications(code, title, registration_year, status, purpose,
is_technical_solution, primary_unit_id, created_by)
VALUES ('SK-2025-007',
'Hệ thống tự động điền hồ sơ sáng kiến',
2025, 'DRAFT',
'Tự động hoá việc điền các mẫu số 0104',
TRUE, 2, 42)
RETURNING application_id \gset
-- 2. Authors (defer contribution-sum check until COMMIT)
SET CONSTRAINTS trg_contribution_total DEFERRED;
INSERT INTO application_authors(application_id, user_id, contribution_pct, role, display_order) VALUES
(:application_id, 42, 60.00, 'PRIMARY', 1),
(:application_id, 13, 25.00, 'CO_AUTHOR', 2),
(:application_id, 27, 15.00, 'CO_AUTHOR', 3);
-- 3. Orgs that tested it
INSERT INTO application_adopters(application_id, org_name, address, field) VALUES
(:application_id, 'Phòng KHCN', '217 Hồng Bàng, Q.5', 'Cải cách hành chính');
COMMIT;
-- =============================================================================
-- READ: Dashboard — paginated list with filters
-- =============================================================================
SELECT * FROM v_application_summary
WHERE registration_year = 2025
AND status = ANY(ARRAY['UNDER_REVIEW','EVALUATED']::text[])
AND title ILIKE '%động vật%' -- uses trigram index
ORDER BY avg_score DESC NULLS LAST, submitted_at DESC
LIMIT 20 OFFSET 0;
-- Read: full application with nested data (app layer usually does this as N queries
-- or one JSON aggregate — here's the aggregate version)
SELECT jsonb_build_object(
'application', to_jsonb(a.*),
'authors', (SELECT jsonb_agg(jsonb_build_object(
'user_id', u.user_id,
'name', u.full_name,
'pct', aa.contribution_pct,
'role', aa.role
) ORDER BY aa.display_order)
FROM application_authors aa
JOIN users u USING (user_id)
WHERE aa.application_id = a.application_id),
'evaluations',(SELECT jsonb_agg(to_jsonb(e.*))
FROM evaluations e WHERE e.application_id = a.application_id),
'attachments',(SELECT jsonb_agg(to_jsonb(att.*))
FROM attachments att WHERE att.application_id = a.application_id)
) AS document
FROM applications a
WHERE a.application_id = 1 AND a.deleted_at IS NULL;
-- Full-text search (Vietnamese-friendly; combine with unaccent for better recall)
SELECT application_id, code, title
FROM applications
WHERE to_tsvector('simple', title || ' ' || coalesce(introduction,''))
@@ plainto_tsquery('simple', 'đạo đức động vật')
ORDER BY registration_year DESC
LIMIT 10;
-- =============================================================================
-- UPDATE: Progress an application through the workflow
-- =============================================================================
-- Submit (DRAFT → SUBMITTED). Triggers populate submitted_at automatically.
UPDATE applications SET status = 'SUBMITTED' WHERE application_id = 7;
-- Assign to review panel
UPDATE applications SET status = 'UNDER_REVIEW' WHERE application_id = 7;
-- Upsert an evaluation (same evaluator re-scores)
INSERT INTO evaluations (application_id, evaluator_id, novelty_score, effectiveness_score, conclusion)
VALUES (7, 99, 32, 48, 'Đề nghị công nhận')
ON CONFLICT (application_id, evaluator_id)
DO UPDATE SET
novelty_score = EXCLUDED.novelty_score,
effectiveness_score = EXCLUDED.effectiveness_score,
conclusion = EXCLUDED.conclusion,
evaluated_at = NOW();
-- Update JSONB field: patch a single effectiveness sub-field
UPDATE applications
SET effectiveness = effectiveness || jsonb_build_object(
'economic',
'Tiết kiệm ~30% thời gian xét duyệt'
)
WHERE application_id = 7;
-- Partial update (PATCH-style) — only update provided fields. The app layer
-- generates SET clauses from the non-null fields in the request body.
UPDATE applications
SET title = COALESCE($1, title),
purpose = COALESCE($2, purpose),
updated_at = NOW()
WHERE application_id = $3 AND deleted_at IS NULL
RETURNING *;
-- =============================================================================
-- DELETE: Soft delete + restore
-- =============================================================================
-- Soft delete
UPDATE applications SET deleted_at = NOW() WHERE application_id = 7;
-- Restore
UPDATE applications SET deleted_at = NULL WHERE application_id = 7;
-- Hard delete (only for drafts, cascades to authors/evaluations/etc.)
DELETE FROM applications
WHERE application_id = 7
AND status = 'DRAFT';
-- =============================================================================
-- ANALYTICS: Materialized-view refresh (run nightly via cron/pgAgent)
-- =============================================================================
REFRESH MATERIALIZED VIEW CONCURRENTLY mv_annual_stats;
-- Leaderboard: top-scoring approved innovations
SELECT code, title, avg_score
FROM v_application_summary
WHERE status = 'APPROVED'
ORDER BY avg_score DESC
LIMIT 10;
-- =============================================================================
-- REVIEW JSON: Persist / retrieve ReviewPanel bundle
-- =============================================================================
BEGIN;
SELECT set_config('my.user_id', '42', true);
-- Latest app version number for this application
WITH v AS (
SELECT COALESCE(MAX(document_version), 0) + 1 AS next_ver
FROM application_review_documents
WHERE application_id = 7
)
INSERT INTO application_review_documents(
application_id, case_id, document_version, official_bieu_mau, template_data, full_bundle, created_by
)
SELECT
7,
'CASE-2026-0007',
v.next_ver,
$${"TRANG BÌA":{"Tên sáng kiến (Tiếng Việt)":"Ví dụ"}}$$::jsonb,
$${"initiativeName":"Ví dụ"}$$::jsonb,
$${"meta":{"caseId":"CASE-2026-0007"}}$$::jsonb,
42
FROM v;
COMMIT;
-- Load latest ReviewPanel bundle by case id
SELECT *
FROM application_review_documents
WHERE case_id = 'CASE-2026-0007'
ORDER BY document_version DESC, created_at DESC
LIMIT 1;