@oktis-works/database 0.2.0 → 0.3.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 +215 -48
- package/package.json +3 -3
package/dist/schema/schema.sql
CHANGED
|
@@ -467,11 +467,17 @@ CREATE TABLE IF NOT EXISTS content_types (
|
|
|
467
467
|
schema JSONB NOT NULL,
|
|
468
468
|
plural_label VARCHAR(255) NOT NULL,
|
|
469
469
|
singular_label VARCHAR(255) NOT NULL,
|
|
470
|
-
|
|
470
|
+
default_fields JSONB NOT NULL DEFAULT '["title","slug","content","excerpt","featured_image","seo_title","seo_description","status","author"]'::jsonb,
|
|
471
|
+
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
472
|
+
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
|
|
471
473
|
);
|
|
472
474
|
|
|
473
475
|
CREATE INDEX IF NOT EXISTS idx_content_types_slug ON content_types(slug);
|
|
474
476
|
|
|
477
|
+
-- Add new columns to existing content_types table (idempotent)
|
|
478
|
+
ALTER TABLE content_types ADD COLUMN IF NOT EXISTS default_fields JSONB NOT NULL DEFAULT '["title","slug","content","excerpt","featured_image","seo_title","seo_description","status","author"]'::jsonb;
|
|
479
|
+
ALTER TABLE content_types ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW();
|
|
480
|
+
|
|
475
481
|
-- ============================================================
|
|
476
482
|
-- Webhooks
|
|
477
483
|
-- ============================================================
|
|
@@ -527,8 +533,15 @@ CREATE TABLE IF NOT EXISTS taxonomies (
|
|
|
527
533
|
CREATE INDEX IF NOT EXISTS idx_taxonomies_tenant ON taxonomies(tenant_id);
|
|
528
534
|
CREATE INDEX IF NOT EXISTS idx_taxonomies_slug ON taxonomies(slug);
|
|
529
535
|
ALTER TABLE taxonomies ENABLE ROW LEVEL SECURITY;
|
|
530
|
-
|
|
531
|
-
|
|
536
|
+
DO $$
|
|
537
|
+
BEGIN
|
|
538
|
+
IF NOT EXISTS (
|
|
539
|
+
SELECT 1 FROM pg_policies
|
|
540
|
+
WHERE policyname = 'tenant_isolation_taxonomies' AND tablename = 'taxonomies'
|
|
541
|
+
) THEN
|
|
542
|
+
CREATE POLICY tenant_isolation_taxonomies ON taxonomies USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid OR tenant_id IS NULL);
|
|
543
|
+
END IF;
|
|
544
|
+
END $$;
|
|
532
545
|
|
|
533
546
|
-- ============================================================
|
|
534
547
|
-- Field Groups (SDD ENTI-026)
|
|
@@ -550,8 +563,15 @@ CREATE TABLE IF NOT EXISTS field_groups (
|
|
|
550
563
|
CREATE INDEX IF NOT EXISTS idx_field_groups_tenant ON field_groups(tenant_id);
|
|
551
564
|
CREATE INDEX IF NOT EXISTS idx_field_groups_active ON field_groups(active);
|
|
552
565
|
ALTER TABLE field_groups ENABLE ROW LEVEL SECURITY;
|
|
553
|
-
|
|
554
|
-
|
|
566
|
+
DO $$
|
|
567
|
+
BEGIN
|
|
568
|
+
IF NOT EXISTS (
|
|
569
|
+
SELECT 1 FROM pg_policies
|
|
570
|
+
WHERE policyname = 'tenant_isolation_field_groups' AND tablename = 'field_groups'
|
|
571
|
+
) THEN
|
|
572
|
+
CREATE POLICY tenant_isolation_field_groups ON field_groups USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid OR tenant_id IS NULL);
|
|
573
|
+
END IF;
|
|
574
|
+
END $$;
|
|
555
575
|
|
|
556
576
|
-- ============================================================
|
|
557
577
|
-- Field Definitions (SDD ENTI-027)
|
|
@@ -569,19 +589,68 @@ CREATE TABLE IF NOT EXISTS field_definitions (
|
|
|
569
589
|
required BOOLEAN NOT NULL DEFAULT false,
|
|
570
590
|
config JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
571
591
|
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
592
|
+
is_core_field BOOLEAN NOT NULL DEFAULT false,
|
|
593
|
+
is_locked BOOLEAN NOT NULL DEFAULT false,
|
|
594
|
+
core_field_key VARCHAR(100),
|
|
572
595
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
573
596
|
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
|
|
574
597
|
);
|
|
575
598
|
|
|
599
|
+
-- Add new columns to existing field_definitions table (idempotent)
|
|
600
|
+
ALTER TABLE field_definitions ADD COLUMN IF NOT EXISTS is_core_field BOOLEAN NOT NULL DEFAULT false;
|
|
601
|
+
ALTER TABLE field_definitions ADD COLUMN IF NOT EXISTS is_locked BOOLEAN NOT NULL DEFAULT false;
|
|
602
|
+
ALTER TABLE field_definitions ADD COLUMN IF NOT EXISTS core_field_key VARCHAR(100);
|
|
603
|
+
|
|
576
604
|
CREATE INDEX IF NOT EXISTS idx_field_definitions_group ON field_definitions(group_id);
|
|
577
605
|
CREATE INDEX IF NOT EXISTS idx_field_definitions_parent ON field_definitions(parent_field_id) WHERE parent_field_id IS NOT NULL;
|
|
606
|
+
CREATE INDEX IF NOT EXISTS idx_field_definitions_core ON field_definitions(is_core_field) WHERE is_core_field = true;
|
|
607
|
+
CREATE INDEX IF NOT EXISTS idx_field_definitions_locked ON field_definitions(is_locked) WHERE is_locked = true;
|
|
608
|
+
CREATE INDEX IF NOT EXISTS idx_field_definitions_core_key ON field_definitions(core_field_key) WHERE core_field_key IS NOT NULL;
|
|
578
609
|
ALTER TABLE field_definitions ENABLE ROW LEVEL SECURITY;
|
|
579
|
-
|
|
580
|
-
|
|
610
|
+
DO $$
|
|
611
|
+
BEGIN
|
|
612
|
+
IF NOT EXISTS (
|
|
613
|
+
SELECT 1 FROM pg_policies
|
|
614
|
+
WHERE policyname = 'tenant_isolation_field_definitions' AND tablename = 'field_definitions'
|
|
615
|
+
) THEN
|
|
616
|
+
CREATE POLICY tenant_isolation_field_definitions ON field_definitions USING (EXISTS (
|
|
581
617
|
SELECT 1 FROM field_groups fg
|
|
582
618
|
WHERE fg.id = field_definitions.group_id
|
|
583
619
|
AND (fg.tenant_id = current_setting('app.current_tenant_id', true)::uuid OR fg.tenant_id IS NULL)
|
|
584
620
|
));
|
|
621
|
+
END IF;
|
|
622
|
+
END $$;
|
|
623
|
+
|
|
624
|
+
-- ============================================================
|
|
625
|
+
-- Field Values (valores isolados por entidade)
|
|
626
|
+
-- ============================================================
|
|
627
|
+
CREATE TABLE IF NOT EXISTS field_values (
|
|
628
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
629
|
+
field_definition_id UUID NOT NULL REFERENCES field_definitions(id) ON DELETE CASCADE,
|
|
630
|
+
entity_type VARCHAR(50) NOT NULL CHECK (entity_type IN ('content', 'taxonomy_term')),
|
|
631
|
+
entity_id UUID NOT NULL,
|
|
632
|
+
value JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
633
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
634
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
635
|
+
UNIQUE(field_definition_id, entity_type, entity_id)
|
|
636
|
+
);
|
|
637
|
+
|
|
638
|
+
CREATE INDEX IF NOT EXISTS idx_field_values_entity ON field_values(entity_type, entity_id);
|
|
639
|
+
CREATE INDEX IF NOT EXISTS idx_field_values_field ON field_values(field_definition_id);
|
|
640
|
+
CREATE INDEX IF NOT EXISTS idx_field_values_updated ON field_values(updated_at DESC);
|
|
641
|
+
|
|
642
|
+
CREATE OR REPLACE FUNCTION update_field_values_timestamp()
|
|
643
|
+
RETURNS TRIGGER AS $$
|
|
644
|
+
BEGIN
|
|
645
|
+
NEW.updated_at = NOW();
|
|
646
|
+
RETURN NEW;
|
|
647
|
+
END;
|
|
648
|
+
$$ LANGUAGE plpgsql;
|
|
649
|
+
|
|
650
|
+
DROP TRIGGER IF EXISTS trg_field_values_updated ON field_values;
|
|
651
|
+
CREATE TRIGGER trg_field_values_updated
|
|
652
|
+
BEFORE UPDATE ON field_values
|
|
653
|
+
FOR EACH ROW EXECUTE FUNCTION update_field_values_timestamp();
|
|
585
654
|
|
|
586
655
|
-- ============================================================
|
|
587
656
|
-- Flexible Layouts (SDD ENTI-028)
|
|
@@ -650,44 +719,142 @@ ALTER TABLE sessions ENABLE ROW LEVEL SECURITY;
|
|
|
650
719
|
ALTER TABLE webhooks ENABLE ROW LEVEL SECURITY;
|
|
651
720
|
|
|
652
721
|
-- RLS Policies using app.current_tenant_id session variable
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
CREATE POLICY
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
CREATE POLICY
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
722
|
+
DO $$
|
|
723
|
+
BEGIN
|
|
724
|
+
IF NOT EXISTS (
|
|
725
|
+
SELECT 1 FROM pg_policies
|
|
726
|
+
WHERE policyname = 'tenant_isolation_content' AND tablename = 'content'
|
|
727
|
+
) THEN
|
|
728
|
+
CREATE POLICY tenant_isolation_content ON content USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
|
|
729
|
+
END IF;
|
|
730
|
+
END $$;
|
|
731
|
+
|
|
732
|
+
DO $$
|
|
733
|
+
BEGIN
|
|
734
|
+
IF NOT EXISTS (
|
|
735
|
+
SELECT 1 FROM pg_policies
|
|
736
|
+
WHERE policyname = 'tenant_isolation_media' AND tablename = 'media'
|
|
737
|
+
) THEN
|
|
738
|
+
CREATE POLICY tenant_isolation_media ON media USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
|
|
739
|
+
END IF;
|
|
740
|
+
END $$;
|
|
741
|
+
|
|
742
|
+
DO $$
|
|
743
|
+
BEGIN
|
|
744
|
+
IF NOT EXISTS (
|
|
745
|
+
SELECT 1 FROM pg_policies
|
|
746
|
+
WHERE policyname = 'tenant_isolation_categories' AND tablename = 'categories'
|
|
747
|
+
) THEN
|
|
748
|
+
CREATE POLICY tenant_isolation_categories ON categories USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
|
|
749
|
+
END IF;
|
|
750
|
+
END $$;
|
|
751
|
+
|
|
752
|
+
DO $$
|
|
753
|
+
BEGIN
|
|
754
|
+
IF NOT EXISTS (
|
|
755
|
+
SELECT 1 FROM pg_policies
|
|
756
|
+
WHERE policyname = 'tenant_isolation_tags' AND tablename = 'tags'
|
|
757
|
+
) THEN
|
|
758
|
+
CREATE POLICY tenant_isolation_tags ON tags USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
|
|
759
|
+
END IF;
|
|
760
|
+
END $$;
|
|
761
|
+
|
|
762
|
+
DO $$
|
|
763
|
+
BEGIN
|
|
764
|
+
IF NOT EXISTS (
|
|
765
|
+
SELECT 1 FROM pg_policies
|
|
766
|
+
WHERE policyname = 'tenant_isolation_menus' AND tablename = 'menus'
|
|
767
|
+
) THEN
|
|
768
|
+
CREATE POLICY tenant_isolation_menus ON menus USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
|
|
769
|
+
END IF;
|
|
770
|
+
END $$;
|
|
771
|
+
|
|
772
|
+
DO $$
|
|
773
|
+
BEGIN
|
|
774
|
+
IF NOT EXISTS (
|
|
775
|
+
SELECT 1 FROM pg_policies
|
|
776
|
+
WHERE policyname = 'tenant_isolation_settings' AND tablename = 'settings'
|
|
777
|
+
) THEN
|
|
778
|
+
CREATE POLICY tenant_isolation_settings ON settings USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid OR tenant_id IS NULL);
|
|
779
|
+
END IF;
|
|
780
|
+
END $$;
|
|
781
|
+
|
|
782
|
+
DO $$
|
|
783
|
+
BEGIN
|
|
784
|
+
IF NOT EXISTS (
|
|
785
|
+
SELECT 1 FROM pg_policies
|
|
786
|
+
WHERE policyname = 'tenant_isolation_plugins' AND tablename = 'plugins'
|
|
787
|
+
) THEN
|
|
788
|
+
CREATE POLICY tenant_isolation_plugins ON plugins USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid OR tenant_id IS NULL);
|
|
789
|
+
END IF;
|
|
790
|
+
END $$;
|
|
791
|
+
|
|
792
|
+
DO $$
|
|
793
|
+
BEGIN
|
|
794
|
+
IF NOT EXISTS (
|
|
795
|
+
SELECT 1 FROM pg_policies
|
|
796
|
+
WHERE policyname = 'tenant_isolation_themes' AND tablename = 'themes'
|
|
797
|
+
) THEN
|
|
798
|
+
CREATE POLICY tenant_isolation_themes ON themes USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid OR tenant_id IS NULL);
|
|
799
|
+
END IF;
|
|
800
|
+
END $$;
|
|
801
|
+
|
|
802
|
+
DO $$
|
|
803
|
+
BEGIN
|
|
804
|
+
IF NOT EXISTS (
|
|
805
|
+
SELECT 1 FROM pg_policies
|
|
806
|
+
WHERE policyname = 'tenant_isolation_builds' AND tablename = 'builds'
|
|
807
|
+
) THEN
|
|
808
|
+
CREATE POLICY tenant_isolation_builds ON builds USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
|
|
809
|
+
END IF;
|
|
810
|
+
END $$;
|
|
811
|
+
|
|
812
|
+
DO $$
|
|
813
|
+
BEGIN
|
|
814
|
+
IF NOT EXISTS (
|
|
815
|
+
SELECT 1 FROM pg_policies
|
|
816
|
+
WHERE policyname = 'tenant_isolation_deployments' AND tablename = 'deployments'
|
|
817
|
+
) THEN
|
|
818
|
+
CREATE POLICY tenant_isolation_deployments ON deployments USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
|
|
819
|
+
END IF;
|
|
820
|
+
END $$;
|
|
821
|
+
|
|
822
|
+
DO $$
|
|
823
|
+
BEGIN
|
|
824
|
+
IF NOT EXISTS (
|
|
825
|
+
SELECT 1 FROM pg_policies
|
|
826
|
+
WHERE policyname = 'tenant_isolation_events' AND tablename = 'events'
|
|
827
|
+
) THEN
|
|
828
|
+
CREATE POLICY tenant_isolation_events ON events USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
|
|
829
|
+
END IF;
|
|
830
|
+
END $$;
|
|
831
|
+
|
|
832
|
+
DO $$
|
|
833
|
+
BEGIN
|
|
834
|
+
IF NOT EXISTS (
|
|
835
|
+
SELECT 1 FROM pg_policies
|
|
836
|
+
WHERE policyname = 'tenant_isolation_audit_logs' AND tablename = 'audit_logs'
|
|
837
|
+
) THEN
|
|
838
|
+
CREATE POLICY tenant_isolation_audit_logs ON audit_logs USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
|
|
839
|
+
END IF;
|
|
840
|
+
END $$;
|
|
841
|
+
|
|
842
|
+
DO $$
|
|
843
|
+
BEGIN
|
|
844
|
+
IF NOT EXISTS (
|
|
845
|
+
SELECT 1 FROM pg_policies
|
|
846
|
+
WHERE policyname = 'tenant_isolation_sessions' AND tablename = 'sessions'
|
|
847
|
+
) THEN
|
|
848
|
+
CREATE POLICY tenant_isolation_sessions ON sessions USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
|
|
849
|
+
END IF;
|
|
850
|
+
END $$;
|
|
851
|
+
|
|
852
|
+
DO $$
|
|
853
|
+
BEGIN
|
|
854
|
+
IF NOT EXISTS (
|
|
855
|
+
SELECT 1 FROM pg_policies
|
|
856
|
+
WHERE policyname = 'tenant_isolation_webhooks' AND tablename = 'webhooks'
|
|
857
|
+
) THEN
|
|
858
|
+
CREATE POLICY tenant_isolation_webhooks ON webhooks USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
|
|
859
|
+
END IF;
|
|
860
|
+
END $$;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oktis-works/database",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.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.
|
|
22
|
+
"@oktis-works/types": "^0.3.0",
|
|
23
|
+
"@oktis-works/config": "^0.3.0",
|
|
24
24
|
"postgres": "3.4.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|