@oktis-works/database 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/schema/schema.sql +125 -0
- package/package.json +3 -3
package/dist/schema/schema.sql
CHANGED
|
@@ -536,6 +536,34 @@ CREATE TABLE IF NOT EXISTS webhooks (
|
|
|
536
536
|
-- mantidos para que instalações existentes migrem sem perder seus segredos.
|
|
537
537
|
ALTER TABLE webhooks ADD COLUMN IF NOT EXISTS auth_type VARCHAR(30) NOT NULL DEFAULT 'hmac_sha256';
|
|
538
538
|
ALTER TABLE webhooks ADD COLUMN IF NOT EXISTS auth_config JSONB NOT NULL DEFAULT '{}'::jsonb;
|
|
539
|
+
|
|
540
|
+
-- ============================================================
|
|
541
|
+
-- Webhook hardening (Item 19 — rotação de segredos + dead-letter)
|
|
542
|
+
-- ============================================================
|
|
543
|
+
CREATE TABLE IF NOT EXISTS webhook_secrets (
|
|
544
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
545
|
+
webhook_id UUID NOT NULL REFERENCES webhooks(id) ON DELETE CASCADE,
|
|
546
|
+
secret VARCHAR(255) NOT NULL,
|
|
547
|
+
version INT NOT NULL DEFAULT 1,
|
|
548
|
+
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
549
|
+
rotated_at TIMESTAMPTZ,
|
|
550
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
551
|
+
UNIQUE(webhook_id, version)
|
|
552
|
+
);
|
|
553
|
+
|
|
554
|
+
CREATE INDEX IF NOT EXISTS idx_webhook_secrets_webhook ON webhook_secrets(webhook_id, is_active);
|
|
555
|
+
|
|
556
|
+
CREATE TABLE IF NOT EXISTS webhook_dead_letters (
|
|
557
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
558
|
+
webhook_id UUID NOT NULL REFERENCES webhooks(id) ON DELETE CASCADE,
|
|
559
|
+
event VARCHAR(191) NOT NULL,
|
|
560
|
+
payload JSONB NOT NULL,
|
|
561
|
+
error TEXT,
|
|
562
|
+
attempts INT NOT NULL DEFAULT 1,
|
|
563
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
564
|
+
);
|
|
565
|
+
|
|
566
|
+
CREATE INDEX IF NOT EXISTS idx_webhook_dead_letters_webhook ON webhook_dead_letters(webhook_id, created_at);
|
|
539
567
|
UPDATE webhooks
|
|
540
568
|
SET auth_config = jsonb_build_object('secret', secret)
|
|
541
569
|
WHERE auth_type = 'hmac_sha256' AND auth_config = '{}'::jsonb AND secret <> '';
|
|
@@ -779,6 +807,103 @@ CREATE TABLE IF NOT EXISTS content_taxonomy_terms (
|
|
|
779
807
|
CREATE INDEX IF NOT EXISTS idx_content_terms_content ON content_taxonomy_terms(content_id);
|
|
780
808
|
CREATE INDEX IF NOT EXISTS idx_content_terms_term ON content_taxonomy_terms(term_id);
|
|
781
809
|
|
|
810
|
+
-- ============================================================
|
|
811
|
+
-- Comments (Item 11 — paridade WordPress: comentários moderados, thread)
|
|
812
|
+
-- ============================================================
|
|
813
|
+
CREATE TABLE IF NOT EXISTS comments (
|
|
814
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
815
|
+
tenant_id UUID REFERENCES tenants(id) ON DELETE CASCADE,
|
|
816
|
+
content_id UUID NOT NULL REFERENCES content(id) ON DELETE CASCADE,
|
|
817
|
+
parent_id UUID REFERENCES comments(id) ON DELETE CASCADE,
|
|
818
|
+
author_name VARCHAR(255) NOT NULL,
|
|
819
|
+
author_email VARCHAR(255),
|
|
820
|
+
author_url VARCHAR(500),
|
|
821
|
+
author_id UUID REFERENCES users(id) ON DELETE SET NULL,
|
|
822
|
+
body TEXT NOT NULL,
|
|
823
|
+
status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
|
|
824
|
+
ip_address VARCHAR(64),
|
|
825
|
+
user_agent VARCHAR(500),
|
|
826
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
827
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
828
|
+
);
|
|
829
|
+
|
|
830
|
+
CREATE INDEX IF NOT EXISTS idx_comments_content_status ON comments(content_id, status);
|
|
831
|
+
CREATE INDEX IF NOT EXISTS idx_comments_tenant_status ON comments(tenant_id, status);
|
|
832
|
+
CREATE INDEX IF NOT EXISTS idx_comments_parent ON comments(parent_id);
|
|
833
|
+
|
|
834
|
+
CREATE TABLE IF NOT EXISTS comment_meta (
|
|
835
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
836
|
+
comment_id UUID NOT NULL REFERENCES comments(id) ON DELETE CASCADE,
|
|
837
|
+
key VARCHAR(191) NOT NULL,
|
|
838
|
+
value JSONB,
|
|
839
|
+
UNIQUE(comment_id, key)
|
|
840
|
+
);
|
|
841
|
+
|
|
842
|
+
ALTER TABLE comments ENABLE ROW LEVEL SECURITY;
|
|
843
|
+
ALTER TABLE comments FORCE ROW LEVEL SECURITY;
|
|
844
|
+
DO $$
|
|
845
|
+
BEGIN
|
|
846
|
+
IF NOT EXISTS (
|
|
847
|
+
SELECT 1 FROM pg_policies
|
|
848
|
+
WHERE policyname = 'tenant_isolation_comments' AND tablename = 'comments'
|
|
849
|
+
) THEN
|
|
850
|
+
CREATE POLICY tenant_isolation_comments ON comments
|
|
851
|
+
USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid OR tenant_id IS NULL);
|
|
852
|
+
END IF;
|
|
853
|
+
END $$;
|
|
854
|
+
|
|
855
|
+
ALTER TABLE comment_meta ENABLE ROW LEVEL SECURITY;
|
|
856
|
+
ALTER TABLE comment_meta FORCE ROW LEVEL SECURITY;
|
|
857
|
+
DO $$
|
|
858
|
+
BEGIN
|
|
859
|
+
IF NOT EXISTS (
|
|
860
|
+
SELECT 1 FROM pg_policies
|
|
861
|
+
WHERE policyname = 'tenant_isolation_comment_meta' AND tablename = 'comment_meta'
|
|
862
|
+
) THEN
|
|
863
|
+
CREATE POLICY tenant_isolation_comment_meta ON comment_meta
|
|
864
|
+
USING (EXISTS (
|
|
865
|
+
SELECT 1 FROM comments c
|
|
866
|
+
WHERE c.id = comment_meta.comment_id
|
|
867
|
+
AND (c.tenant_id = current_setting('app.current_tenant_id', true)::uuid OR c.tenant_id IS NULL)
|
|
868
|
+
));
|
|
869
|
+
END IF;
|
|
870
|
+
END $$;
|
|
871
|
+
|
|
872
|
+
-- ============================================================
|
|
873
|
+
-- Mails (Item 12 — paridade WordPress: outbox durável para api.mail.send)
|
|
874
|
+
-- ============================================================
|
|
875
|
+
CREATE TABLE IF NOT EXISTS mails (
|
|
876
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
877
|
+
tenant_id UUID REFERENCES tenants(id) ON DELETE CASCADE,
|
|
878
|
+
plugin_name VARCHAR(255) NOT NULL,
|
|
879
|
+
to_email VARCHAR(320) NOT NULL,
|
|
880
|
+
subject VARCHAR(998) NOT NULL,
|
|
881
|
+
html TEXT,
|
|
882
|
+
text TEXT,
|
|
883
|
+
template VARCHAR(191),
|
|
884
|
+
params JSONB,
|
|
885
|
+
status VARCHAR(20) NOT NULL DEFAULT 'QUEUED',
|
|
886
|
+
attempts INT NOT NULL DEFAULT 0,
|
|
887
|
+
error TEXT,
|
|
888
|
+
sent_at TIMESTAMPTZ,
|
|
889
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
890
|
+
);
|
|
891
|
+
|
|
892
|
+
CREATE INDEX IF NOT EXISTS idx_mails_tenant_status ON mails(tenant_id, status);
|
|
893
|
+
|
|
894
|
+
ALTER TABLE mails ENABLE ROW LEVEL SECURITY;
|
|
895
|
+
ALTER TABLE mails FORCE ROW LEVEL SECURITY;
|
|
896
|
+
DO $$
|
|
897
|
+
BEGIN
|
|
898
|
+
IF NOT EXISTS (
|
|
899
|
+
SELECT 1 FROM pg_policies
|
|
900
|
+
WHERE policyname = 'tenant_isolation_mails' AND tablename = 'mails'
|
|
901
|
+
) THEN
|
|
902
|
+
CREATE POLICY tenant_isolation_mails ON mails
|
|
903
|
+
USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid OR tenant_id IS NULL);
|
|
904
|
+
END IF;
|
|
905
|
+
END $$;
|
|
906
|
+
|
|
782
907
|
ALTER TABLE taxonomy_terms ENABLE ROW LEVEL SECURITY;
|
|
783
908
|
ALTER TABLE taxonomy_terms FORCE ROW LEVEL SECURITY;
|
|
784
909
|
ALTER TABLE content_taxonomy_terms ENABLE ROW LEVEL SECURITY;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oktis-works/database",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"db:rollback": "node --loader ts-node/esm src/migrations/runner.ts rollback"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@oktis-works/types": "^0.
|
|
23
|
-
"@oktis-works/config": "^0.6.
|
|
22
|
+
"@oktis-works/types": "^0.9.0",
|
|
23
|
+
"@oktis-works/config": "^0.6.4",
|
|
24
24
|
"postgres": "3.4.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|