aios-core 2.2.2 → 3.0.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.
Files changed (107) hide show
  1. package/.aios-core/.session/current-session.json +14 -14
  2. package/.aios-core/cli/commands/migrate/validate.js +1 -1
  3. package/.aios-core/core/docs/session-update-pattern.md +17 -10
  4. package/.aios-core/core/elicitation/elicitation-engine.js +11 -6
  5. package/.aios-core/core/elicitation/session-manager.js +2 -1
  6. package/.aios-core/core/registry/registry-schema.json +166 -166
  7. package/.aios-core/core/registry/service-registry.json +6585 -6585
  8. package/.aios-core/core-config.yaml +66 -1
  9. package/.aios-core/data/agent-config-requirements.yaml +5 -5
  10. package/.aios-core/development/agents/devops.md +12 -0
  11. package/.aios-core/development/scripts/squad/README.md +112 -0
  12. package/.aios-core/development/scripts/squad/index.js +41 -0
  13. package/.aios-core/development/scripts/squad/squad-loader.js +359 -0
  14. package/.aios-core/development/scripts/squad/squad-validator.js +685 -0
  15. package/.aios-core/development/tasks/add-mcp.md +11 -5
  16. package/.aios-core/development/tasks/github-devops-github-pr-automation.md +240 -3
  17. package/.aios-core/development/tasks/search-mcp.md +309 -0
  18. package/.aios-core/development/tasks/setup-mcp-docker.md +11 -8
  19. package/.aios-core/development/tasks/squad-creator-validate.md +151 -0
  20. package/.aios-core/docs/standards/AGENT-PERSONALIZATION-STANDARD-V1.md +3 -3
  21. package/.aios-core/index.d.ts +7 -7
  22. package/.aios-core/index.js +1 -1
  23. package/.aios-core/infrastructure/scripts/batch-creator.js +1 -1
  24. package/.aios-core/infrastructure/scripts/component-generator.js +1 -1
  25. package/.aios-core/infrastructure/templates/coderabbit.yaml.template +279 -279
  26. package/.aios-core/infrastructure/templates/core-config/core-config-greenfield.tmpl.yaml +41 -0
  27. package/.aios-core/infrastructure/templates/github-workflows/ci.yml.template +169 -169
  28. package/.aios-core/infrastructure/templates/github-workflows/pr-automation.yml.template +330 -330
  29. package/.aios-core/infrastructure/templates/github-workflows/release.yml.template +196 -196
  30. package/.aios-core/infrastructure/templates/gitignore/gitignore-aios-base.tmpl +63 -63
  31. package/.aios-core/infrastructure/templates/gitignore/gitignore-brownfield-merge.tmpl +18 -18
  32. package/.aios-core/infrastructure/templates/gitignore/gitignore-node.tmpl +85 -85
  33. package/.aios-core/infrastructure/templates/gitignore/gitignore-python.tmpl +145 -145
  34. package/.aios-core/infrastructure/tests/utilities-audit-results.json +500 -500
  35. package/.aios-core/infrastructure/tools/README.md +1 -1
  36. package/.aios-core/install-manifest.yaml +4 -1
  37. package/.aios-core/manifests/schema/manifest-schema.json +190 -190
  38. package/.aios-core/manifests/workers.csv +203 -203
  39. package/.aios-core/package.json +102 -102
  40. package/.aios-core/product/templates/activation-instructions-template.md +7 -7
  41. package/.aios-core/product/templates/adr.hbs +125 -125
  42. package/.aios-core/product/templates/component-react-tmpl.tsx +98 -98
  43. package/.aios-core/product/templates/dbdr.hbs +241 -241
  44. package/.aios-core/product/templates/engine/schemas/adr.schema.json +102 -102
  45. package/.aios-core/product/templates/engine/schemas/dbdr.schema.json +205 -205
  46. package/.aios-core/product/templates/engine/schemas/epic.schema.json +175 -175
  47. package/.aios-core/product/templates/engine/schemas/pmdr.schema.json +175 -175
  48. package/.aios-core/product/templates/engine/schemas/prd-v2.schema.json +300 -300
  49. package/.aios-core/product/templates/engine/schemas/prd.schema.json +152 -152
  50. package/.aios-core/product/templates/engine/schemas/story.schema.json +222 -222
  51. package/.aios-core/product/templates/engine/schemas/task.schema.json +154 -154
  52. package/.aios-core/product/templates/epic.hbs +212 -212
  53. package/.aios-core/product/templates/eslintrc-security.json +32 -32
  54. package/.aios-core/product/templates/github-actions-cd.yml +212 -212
  55. package/.aios-core/product/templates/github-actions-ci.yml +172 -172
  56. package/.aios-core/product/templates/pmdr.hbs +186 -186
  57. package/.aios-core/product/templates/prd-v2.0.hbs +216 -216
  58. package/.aios-core/product/templates/prd.hbs +201 -201
  59. package/.aios-core/product/templates/shock-report-tmpl.html +502 -502
  60. package/.aios-core/product/templates/story.hbs +263 -263
  61. package/.aios-core/product/templates/task.hbs +170 -170
  62. package/.aios-core/product/templates/tmpl-comment-on-examples.sql +158 -158
  63. package/.aios-core/product/templates/tmpl-migration-script.sql +91 -91
  64. package/.aios-core/product/templates/tmpl-rls-granular-policies.sql +104 -104
  65. package/.aios-core/product/templates/tmpl-rls-kiss-policy.sql +10 -10
  66. package/.aios-core/product/templates/tmpl-rls-roles.sql +135 -135
  67. package/.aios-core/product/templates/tmpl-rls-simple.sql +77 -77
  68. package/.aios-core/product/templates/tmpl-rls-tenant.sql +152 -152
  69. package/.aios-core/product/templates/tmpl-rollback-script.sql +77 -77
  70. package/.aios-core/product/templates/tmpl-seed-data.sql +140 -140
  71. package/.aios-core/product/templates/tmpl-smoke-test.sql +16 -16
  72. package/.aios-core/product/templates/tmpl-staging-copy-merge.sql +139 -139
  73. package/.aios-core/product/templates/tmpl-stored-proc.sql +140 -140
  74. package/.aios-core/product/templates/tmpl-trigger.sql +152 -152
  75. package/.aios-core/product/templates/tmpl-view-materialized.sql +133 -133
  76. package/.aios-core/product/templates/tmpl-view.sql +177 -177
  77. package/.aios-core/product/templates/token-exports-css-tmpl.css +240 -240
  78. package/.aios-core/quality/schemas/quality-metrics.schema.json +233 -233
  79. package/.aios-core/schemas/squad-schema.json +185 -0
  80. package/.aios-core/scripts/README.md +90 -322
  81. package/.aios-core/scripts/migrate-framework-docs.sh +300 -300
  82. package/.claude/rules/mcp-usage.md +116 -100
  83. package/LICENSE +48 -48
  84. package/README.md +3 -4
  85. package/bin/aios.js +2 -1
  86. package/package.json +1 -3
  87. package/packages/installer/package.json +39 -39
  88. package/templates/squad/LICENSE +21 -21
  89. package/templates/squad/README.md +37 -37
  90. package/templates/squad/agents/example-agent.yaml +36 -36
  91. package/templates/squad/package.json +19 -19
  92. package/templates/squad/squad.yaml +25 -25
  93. package/templates/squad/tasks/example-task.yaml +46 -46
  94. package/templates/squad/templates/example-template.md +24 -24
  95. package/templates/squad/tests/example-agent.test.js +53 -53
  96. package/templates/squad/workflows/example-workflow.yaml +54 -54
  97. package/tools/diagnose-npx-issue.ps1 +96 -96
  98. package/tools/quick-diagnose.cmd +85 -85
  99. package/tools/quick-diagnose.ps1 +117 -117
  100. package/.aios-core/core/data/agent-config-requirements.yaml +0 -368
  101. package/.aios-core/core/data/aios-kb.md +0 -924
  102. package/.aios-core/core/data/workflow-patterns.yaml +0 -267
  103. package/.aios-core/product/templates/1mcp-config.yaml +0 -225
  104. package/.aios-core/scripts/context-detector.js +0 -226
  105. package/.aios-core/scripts/elicitation-engine.js +0 -385
  106. package/.aios-core/scripts/elicitation-session-manager.js +0 -300
  107. package/.claude/CLAUDE.md +0 -221
@@ -1,133 +1,133 @@
1
- -- Materialized View Template
2
- -- View: :view_name
3
- -- Created: :created_date
4
- -- Author: :author
5
- -- Description: :description
6
- --
7
- -- Materialized views cache query results for performance
8
- -- IMPORTANT: Data is not live - must be refreshed periodically
9
-
10
- -- =============================================================================
11
- -- BASIC MATERIALIZED VIEW
12
- -- =============================================================================
13
-
14
- -- Drop existing view if exists
15
- DROP MATERIALIZED VIEW IF EXISTS :view_name CASCADE;
16
-
17
- -- Create materialized view
18
- CREATE MATERIALIZED VIEW :view_name AS
19
- SELECT
20
- t.id,
21
- t.name,
22
- t.category,
23
- t.created_at,
24
- -- Aggregations
25
- COUNT(r.id) AS related_count,
26
- SUM(r.amount) AS total_amount,
27
- AVG(r.rating) AS avg_rating,
28
- -- Computed columns
29
- CASE
30
- WHEN t.status = 'active' THEN true
31
- ELSE false
32
- END AS is_active
33
- FROM :base_table t
34
- LEFT JOIN :related_table r ON r.parent_id = t.id
35
- WHERE t.deleted_at IS NULL
36
- GROUP BY t.id, t.name, t.category, t.created_at, t.status
37
- -- Store data sorted for efficient access
38
- WITH DATA;
39
-
40
- -- =============================================================================
41
- -- INDEXES ON MATERIALIZED VIEW
42
- -- =============================================================================
43
-
44
- -- Unique index (required for CONCURRENT refresh)
45
- CREATE UNIQUE INDEX IF NOT EXISTS idx_:view_name_id
46
- ON :view_name (id);
47
-
48
- -- Additional indexes for common queries
49
- CREATE INDEX IF NOT EXISTS idx_:view_name_category
50
- ON :view_name (category);
51
-
52
- CREATE INDEX IF NOT EXISTS idx_:view_name_created_at
53
- ON :view_name (created_at DESC);
54
-
55
- -- =============================================================================
56
- -- REFRESH FUNCTION
57
- -- =============================================================================
58
-
59
- -- Function to refresh the materialized view
60
- CREATE OR REPLACE FUNCTION refresh_:view_name()
61
- RETURNS void
62
- LANGUAGE plpgsql
63
- SECURITY DEFINER
64
- AS $$
65
- BEGIN
66
- -- CONCURRENTLY allows queries during refresh (requires unique index)
67
- REFRESH MATERIALIZED VIEW CONCURRENTLY :view_name;
68
-
69
- -- Log refresh
70
- RAISE NOTICE 'Materialized view :view_name refreshed at %', NOW();
71
- END;
72
- $$;
73
-
74
- -- Grant execute to service role (for scheduled refresh)
75
- GRANT EXECUTE ON FUNCTION refresh_:view_name() TO service_role;
76
-
77
- -- =============================================================================
78
- -- SCHEDULED REFRESH (pg_cron)
79
- -- =============================================================================
80
- --
81
- -- If using pg_cron extension (available in Supabase):
82
- --
83
- -- Enable extension (one-time, requires superuser)
84
- -- CREATE EXTENSION IF NOT EXISTS pg_cron;
85
- --
86
- -- Schedule refresh every hour
87
- -- SELECT cron.schedule(
88
- -- 'refresh-:view_name',
89
- -- '0 * * * *', -- Every hour at minute 0
90
- -- $$SELECT refresh_:view_name()$$
91
- -- );
92
- --
93
- -- To remove schedule:
94
- -- SELECT cron.unschedule('refresh-:view_name');
95
-
96
- -- =============================================================================
97
- -- TRIGGER-BASED REFRESH (Alternative)
98
- -- =============================================================================
99
-
100
- -- Refresh when base table changes (use with caution - can be slow)
101
- -- CREATE OR REPLACE FUNCTION refresh_:view_name_trigger()
102
- -- RETURNS TRIGGER AS $$
103
- -- BEGIN
104
- -- REFRESH MATERIALIZED VIEW CONCURRENTLY :view_name;
105
- -- RETURN NULL;
106
- -- END;
107
- -- $$ LANGUAGE plpgsql;
108
- --
109
- -- CREATE TRIGGER trigger_refresh_:view_name
110
- -- AFTER INSERT OR UPDATE OR DELETE ON :base_table
111
- -- FOR EACH STATEMENT
112
- -- EXECUTE FUNCTION refresh_:view_name_trigger();
113
-
114
- -- =============================================================================
115
- -- VIEW METADATA
116
- -- =============================================================================
117
-
118
- COMMENT ON MATERIALIZED VIEW :view_name IS ':description. Refresh: hourly or on-demand.';
119
-
120
- -- =============================================================================
121
- -- USAGE
122
- -- =============================================================================
123
- --
124
- -- Query the view (cached data, very fast):
125
- -- SELECT * FROM :view_name WHERE category = 'example';
126
- --
127
- -- Manual refresh (use during low-traffic periods):
128
- -- REFRESH MATERIALIZED VIEW CONCURRENTLY :view_name;
129
- -- OR
130
- -- SELECT refresh_:view_name();
131
- --
132
- -- Check last refresh time (approximate):
133
- -- SELECT pg_stat_get_last_analyze_time(':view_name'::regclass);
1
+ -- Materialized View Template
2
+ -- View: :view_name
3
+ -- Created: :created_date
4
+ -- Author: :author
5
+ -- Description: :description
6
+ --
7
+ -- Materialized views cache query results for performance
8
+ -- IMPORTANT: Data is not live - must be refreshed periodically
9
+
10
+ -- =============================================================================
11
+ -- BASIC MATERIALIZED VIEW
12
+ -- =============================================================================
13
+
14
+ -- Drop existing view if exists
15
+ DROP MATERIALIZED VIEW IF EXISTS :view_name CASCADE;
16
+
17
+ -- Create materialized view
18
+ CREATE MATERIALIZED VIEW :view_name AS
19
+ SELECT
20
+ t.id,
21
+ t.name,
22
+ t.category,
23
+ t.created_at,
24
+ -- Aggregations
25
+ COUNT(r.id) AS related_count,
26
+ SUM(r.amount) AS total_amount,
27
+ AVG(r.rating) AS avg_rating,
28
+ -- Computed columns
29
+ CASE
30
+ WHEN t.status = 'active' THEN true
31
+ ELSE false
32
+ END AS is_active
33
+ FROM :base_table t
34
+ LEFT JOIN :related_table r ON r.parent_id = t.id
35
+ WHERE t.deleted_at IS NULL
36
+ GROUP BY t.id, t.name, t.category, t.created_at, t.status
37
+ -- Store data sorted for efficient access
38
+ WITH DATA;
39
+
40
+ -- =============================================================================
41
+ -- INDEXES ON MATERIALIZED VIEW
42
+ -- =============================================================================
43
+
44
+ -- Unique index (required for CONCURRENT refresh)
45
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_:view_name_id
46
+ ON :view_name (id);
47
+
48
+ -- Additional indexes for common queries
49
+ CREATE INDEX IF NOT EXISTS idx_:view_name_category
50
+ ON :view_name (category);
51
+
52
+ CREATE INDEX IF NOT EXISTS idx_:view_name_created_at
53
+ ON :view_name (created_at DESC);
54
+
55
+ -- =============================================================================
56
+ -- REFRESH FUNCTION
57
+ -- =============================================================================
58
+
59
+ -- Function to refresh the materialized view
60
+ CREATE OR REPLACE FUNCTION refresh_:view_name()
61
+ RETURNS void
62
+ LANGUAGE plpgsql
63
+ SECURITY DEFINER
64
+ AS $$
65
+ BEGIN
66
+ -- CONCURRENTLY allows queries during refresh (requires unique index)
67
+ REFRESH MATERIALIZED VIEW CONCURRENTLY :view_name;
68
+
69
+ -- Log refresh
70
+ RAISE NOTICE 'Materialized view :view_name refreshed at %', NOW();
71
+ END;
72
+ $$;
73
+
74
+ -- Grant execute to service role (for scheduled refresh)
75
+ GRANT EXECUTE ON FUNCTION refresh_:view_name() TO service_role;
76
+
77
+ -- =============================================================================
78
+ -- SCHEDULED REFRESH (pg_cron)
79
+ -- =============================================================================
80
+ --
81
+ -- If using pg_cron extension (available in Supabase):
82
+ --
83
+ -- Enable extension (one-time, requires superuser)
84
+ -- CREATE EXTENSION IF NOT EXISTS pg_cron;
85
+ --
86
+ -- Schedule refresh every hour
87
+ -- SELECT cron.schedule(
88
+ -- 'refresh-:view_name',
89
+ -- '0 * * * *', -- Every hour at minute 0
90
+ -- $$SELECT refresh_:view_name()$$
91
+ -- );
92
+ --
93
+ -- To remove schedule:
94
+ -- SELECT cron.unschedule('refresh-:view_name');
95
+
96
+ -- =============================================================================
97
+ -- TRIGGER-BASED REFRESH (Alternative)
98
+ -- =============================================================================
99
+
100
+ -- Refresh when base table changes (use with caution - can be slow)
101
+ -- CREATE OR REPLACE FUNCTION refresh_:view_name_trigger()
102
+ -- RETURNS TRIGGER AS $$
103
+ -- BEGIN
104
+ -- REFRESH MATERIALIZED VIEW CONCURRENTLY :view_name;
105
+ -- RETURN NULL;
106
+ -- END;
107
+ -- $$ LANGUAGE plpgsql;
108
+ --
109
+ -- CREATE TRIGGER trigger_refresh_:view_name
110
+ -- AFTER INSERT OR UPDATE OR DELETE ON :base_table
111
+ -- FOR EACH STATEMENT
112
+ -- EXECUTE FUNCTION refresh_:view_name_trigger();
113
+
114
+ -- =============================================================================
115
+ -- VIEW METADATA
116
+ -- =============================================================================
117
+
118
+ COMMENT ON MATERIALIZED VIEW :view_name IS ':description. Refresh: hourly or on-demand.';
119
+
120
+ -- =============================================================================
121
+ -- USAGE
122
+ -- =============================================================================
123
+ --
124
+ -- Query the view (cached data, very fast):
125
+ -- SELECT * FROM :view_name WHERE category = 'example';
126
+ --
127
+ -- Manual refresh (use during low-traffic periods):
128
+ -- REFRESH MATERIALIZED VIEW CONCURRENTLY :view_name;
129
+ -- OR
130
+ -- SELECT refresh_:view_name();
131
+ --
132
+ -- Check last refresh time (approximate):
133
+ -- SELECT pg_stat_get_last_analyze_time(':view_name'::regclass);
@@ -1,177 +1,177 @@
1
- -- View Template
2
- -- View: :view_name
3
- -- Created: :created_date
4
- -- Author: :author
5
- -- Description: :description
6
- --
7
- -- Views are virtual tables that provide a simplified interface
8
- -- Data is always live (not cached like materialized views)
9
-
10
- -- =============================================================================
11
- -- BASIC VIEW
12
- -- =============================================================================
13
-
14
- -- Drop existing view if exists
15
- DROP VIEW IF EXISTS :view_name CASCADE;
16
-
17
- -- Create view
18
- CREATE OR REPLACE VIEW :view_name AS
19
- SELECT
20
- t.id,
21
- t.name,
22
- t.description,
23
- t.status,
24
- t.created_at,
25
- t.updated_at,
26
- -- Related data
27
- u.email AS owner_email,
28
- u.raw_user_meta_data->>'full_name' AS owner_name,
29
- -- Computed columns
30
- CASE
31
- WHEN t.status = 'active' THEN 'Active'
32
- WHEN t.status = 'pending' THEN 'Pending'
33
- WHEN t.status = 'archived' THEN 'Archived'
34
- ELSE 'Unknown'
35
- END AS status_label,
36
- -- Age calculation
37
- EXTRACT(DAY FROM NOW() - t.created_at) AS days_old
38
- FROM :base_table t
39
- LEFT JOIN auth.users u ON u.id = t.user_id
40
- WHERE t.deleted_at IS NULL;
41
-
42
- -- =============================================================================
43
- -- VIEW WITH AGGREGATIONS
44
- -- =============================================================================
45
-
46
- CREATE OR REPLACE VIEW :view_name_summary AS
47
- SELECT
48
- t.category,
49
- COUNT(*) AS total_count,
50
- COUNT(*) FILTER (WHERE t.status = 'active') AS active_count,
51
- COUNT(*) FILTER (WHERE t.status = 'pending') AS pending_count,
52
- MIN(t.created_at) AS earliest,
53
- MAX(t.created_at) AS latest,
54
- AVG(t.value)::NUMERIC(10,2) AS avg_value
55
- FROM :base_table t
56
- WHERE t.deleted_at IS NULL
57
- GROUP BY t.category;
58
-
59
- -- =============================================================================
60
- -- VIEW WITH RLS CONSIDERATION
61
- -- =============================================================================
62
-
63
- -- Views inherit RLS from underlying tables
64
- -- If base table has RLS, view will respect it
65
- --
66
- -- For views that need custom RLS-like behavior,
67
- -- wrap in a SECURITY DEFINER function:
68
-
69
- CREATE OR REPLACE FUNCTION get_:view_name_for_user()
70
- RETURNS TABLE (
71
- id UUID,
72
- name TEXT,
73
- status TEXT,
74
- created_at TIMESTAMPTZ
75
- )
76
- LANGUAGE plpgsql
77
- SECURITY INVOKER
78
- STABLE
79
- AS $$
80
- BEGIN
81
- RETURN QUERY
82
- SELECT
83
- v.id,
84
- v.name,
85
- v.status,
86
- v.created_at
87
- FROM :view_name v
88
- WHERE v.user_id = auth.uid()
89
- ORDER BY v.created_at DESC;
90
- END;
91
- $$;
92
-
93
- -- =============================================================================
94
- -- VIEW WITH JOINED DATA
95
- -- =============================================================================
96
-
97
- CREATE OR REPLACE VIEW :view_name_detailed AS
98
- SELECT
99
- t.id,
100
- t.name,
101
- t.status,
102
- -- One-to-one relationship
103
- d.detail_field,
104
- -- One-to-many aggregation
105
- (
106
- SELECT json_agg(json_build_object(
107
- 'id', c.id,
108
- 'name', c.name,
109
- 'created_at', c.created_at
110
- ))
111
- FROM :child_table c
112
- WHERE c.parent_id = t.id
113
- ) AS children,
114
- -- Count
115
- (
116
- SELECT COUNT(*)
117
- FROM :child_table c
118
- WHERE c.parent_id = t.id
119
- ) AS children_count,
120
- t.created_at,
121
- t.updated_at
122
- FROM :base_table t
123
- LEFT JOIN :detail_table d ON d.id = t.detail_id
124
- WHERE t.deleted_at IS NULL;
125
-
126
- -- =============================================================================
127
- -- UPDATEABLE VIEW (with INSTEAD OF triggers)
128
- -- =============================================================================
129
-
130
- -- Simple updateable view (for basic cases)
131
- CREATE OR REPLACE VIEW :view_name_editable AS
132
- SELECT
133
- id,
134
- name,
135
- description,
136
- status,
137
- updated_at
138
- FROM :base_table
139
- WHERE deleted_at IS NULL;
140
-
141
- -- Make it updateable via trigger
142
- CREATE OR REPLACE FUNCTION :view_name_editable_update()
143
- RETURNS TRIGGER AS $$
144
- BEGIN
145
- UPDATE :base_table
146
- SET
147
- name = NEW.name,
148
- description = NEW.description,
149
- status = NEW.status,
150
- updated_at = NOW()
151
- WHERE id = NEW.id
152
- AND user_id = auth.uid(); -- RLS check
153
-
154
- RETURN NEW;
155
- END;
156
- $$ LANGUAGE plpgsql SECURITY DEFINER;
157
-
158
- CREATE TRIGGER trigger_:view_name_editable_update
159
- INSTEAD OF UPDATE ON :view_name_editable
160
- FOR EACH ROW
161
- EXECUTE FUNCTION :view_name_editable_update();
162
-
163
- -- =============================================================================
164
- -- VIEW METADATA
165
- -- =============================================================================
166
-
167
- COMMENT ON VIEW :view_name IS ':description';
168
-
169
- -- =============================================================================
170
- -- PERMISSIONS
171
- -- =============================================================================
172
-
173
- -- Grant SELECT on view (inherits base table RLS)
174
- GRANT SELECT ON :view_name TO authenticated;
175
-
176
- -- For updateable views, also grant UPDATE
177
- -- GRANT UPDATE ON :view_name_editable TO authenticated;
1
+ -- View Template
2
+ -- View: :view_name
3
+ -- Created: :created_date
4
+ -- Author: :author
5
+ -- Description: :description
6
+ --
7
+ -- Views are virtual tables that provide a simplified interface
8
+ -- Data is always live (not cached like materialized views)
9
+
10
+ -- =============================================================================
11
+ -- BASIC VIEW
12
+ -- =============================================================================
13
+
14
+ -- Drop existing view if exists
15
+ DROP VIEW IF EXISTS :view_name CASCADE;
16
+
17
+ -- Create view
18
+ CREATE OR REPLACE VIEW :view_name AS
19
+ SELECT
20
+ t.id,
21
+ t.name,
22
+ t.description,
23
+ t.status,
24
+ t.created_at,
25
+ t.updated_at,
26
+ -- Related data
27
+ u.email AS owner_email,
28
+ u.raw_user_meta_data->>'full_name' AS owner_name,
29
+ -- Computed columns
30
+ CASE
31
+ WHEN t.status = 'active' THEN 'Active'
32
+ WHEN t.status = 'pending' THEN 'Pending'
33
+ WHEN t.status = 'archived' THEN 'Archived'
34
+ ELSE 'Unknown'
35
+ END AS status_label,
36
+ -- Age calculation
37
+ EXTRACT(DAY FROM NOW() - t.created_at) AS days_old
38
+ FROM :base_table t
39
+ LEFT JOIN auth.users u ON u.id = t.user_id
40
+ WHERE t.deleted_at IS NULL;
41
+
42
+ -- =============================================================================
43
+ -- VIEW WITH AGGREGATIONS
44
+ -- =============================================================================
45
+
46
+ CREATE OR REPLACE VIEW :view_name_summary AS
47
+ SELECT
48
+ t.category,
49
+ COUNT(*) AS total_count,
50
+ COUNT(*) FILTER (WHERE t.status = 'active') AS active_count,
51
+ COUNT(*) FILTER (WHERE t.status = 'pending') AS pending_count,
52
+ MIN(t.created_at) AS earliest,
53
+ MAX(t.created_at) AS latest,
54
+ AVG(t.value)::NUMERIC(10,2) AS avg_value
55
+ FROM :base_table t
56
+ WHERE t.deleted_at IS NULL
57
+ GROUP BY t.category;
58
+
59
+ -- =============================================================================
60
+ -- VIEW WITH RLS CONSIDERATION
61
+ -- =============================================================================
62
+
63
+ -- Views inherit RLS from underlying tables
64
+ -- If base table has RLS, view will respect it
65
+ --
66
+ -- For views that need custom RLS-like behavior,
67
+ -- wrap in a SECURITY DEFINER function:
68
+
69
+ CREATE OR REPLACE FUNCTION get_:view_name_for_user()
70
+ RETURNS TABLE (
71
+ id UUID,
72
+ name TEXT,
73
+ status TEXT,
74
+ created_at TIMESTAMPTZ
75
+ )
76
+ LANGUAGE plpgsql
77
+ SECURITY INVOKER
78
+ STABLE
79
+ AS $$
80
+ BEGIN
81
+ RETURN QUERY
82
+ SELECT
83
+ v.id,
84
+ v.name,
85
+ v.status,
86
+ v.created_at
87
+ FROM :view_name v
88
+ WHERE v.user_id = auth.uid()
89
+ ORDER BY v.created_at DESC;
90
+ END;
91
+ $$;
92
+
93
+ -- =============================================================================
94
+ -- VIEW WITH JOINED DATA
95
+ -- =============================================================================
96
+
97
+ CREATE OR REPLACE VIEW :view_name_detailed AS
98
+ SELECT
99
+ t.id,
100
+ t.name,
101
+ t.status,
102
+ -- One-to-one relationship
103
+ d.detail_field,
104
+ -- One-to-many aggregation
105
+ (
106
+ SELECT json_agg(json_build_object(
107
+ 'id', c.id,
108
+ 'name', c.name,
109
+ 'created_at', c.created_at
110
+ ))
111
+ FROM :child_table c
112
+ WHERE c.parent_id = t.id
113
+ ) AS children,
114
+ -- Count
115
+ (
116
+ SELECT COUNT(*)
117
+ FROM :child_table c
118
+ WHERE c.parent_id = t.id
119
+ ) AS children_count,
120
+ t.created_at,
121
+ t.updated_at
122
+ FROM :base_table t
123
+ LEFT JOIN :detail_table d ON d.id = t.detail_id
124
+ WHERE t.deleted_at IS NULL;
125
+
126
+ -- =============================================================================
127
+ -- UPDATEABLE VIEW (with INSTEAD OF triggers)
128
+ -- =============================================================================
129
+
130
+ -- Simple updateable view (for basic cases)
131
+ CREATE OR REPLACE VIEW :view_name_editable AS
132
+ SELECT
133
+ id,
134
+ name,
135
+ description,
136
+ status,
137
+ updated_at
138
+ FROM :base_table
139
+ WHERE deleted_at IS NULL;
140
+
141
+ -- Make it updateable via trigger
142
+ CREATE OR REPLACE FUNCTION :view_name_editable_update()
143
+ RETURNS TRIGGER AS $$
144
+ BEGIN
145
+ UPDATE :base_table
146
+ SET
147
+ name = NEW.name,
148
+ description = NEW.description,
149
+ status = NEW.status,
150
+ updated_at = NOW()
151
+ WHERE id = NEW.id
152
+ AND user_id = auth.uid(); -- RLS check
153
+
154
+ RETURN NEW;
155
+ END;
156
+ $$ LANGUAGE plpgsql SECURITY DEFINER;
157
+
158
+ CREATE TRIGGER trigger_:view_name_editable_update
159
+ INSTEAD OF UPDATE ON :view_name_editable
160
+ FOR EACH ROW
161
+ EXECUTE FUNCTION :view_name_editable_update();
162
+
163
+ -- =============================================================================
164
+ -- VIEW METADATA
165
+ -- =============================================================================
166
+
167
+ COMMENT ON VIEW :view_name IS ':description';
168
+
169
+ -- =============================================================================
170
+ -- PERMISSIONS
171
+ -- =============================================================================
172
+
173
+ -- Grant SELECT on view (inherits base table RLS)
174
+ GRANT SELECT ON :view_name TO authenticated;
175
+
176
+ -- For updateable views, also grant UPDATE
177
+ -- GRANT UPDATE ON :view_name_editable TO authenticated;