Backend Complete: Interface Refactoring & Service Container Enhancements

Repository Interface Optimization:
- Created IBaseRepository.ts and IPaginatedRepository.ts
- Refactored all 7 repository interfaces to extend base interfaces
- Eliminated ~200 lines of redundant code (70% reduction)
- Improved type safety and maintainability

 Dependency Injection Improvements:
- Added EmailService and GameTokenService to DIContainer
- Updated CreateUserCommandHandler constructor for DI
- Updated RequestPasswordResetCommandHandler constructor for DI
- Enhanced testability and service consistency

 Environment Configuration:
- Created comprehensive .env.example with 40+ variables
- Organized into 12 logical sections (Database, Security, Email, etc.)
- Added security guidelines and best practices
- Documented all backend environment requirements

 Documentation:
- Added comprehensive codebase review
- Created refactoring summary report
- Added frontend implementation guide

Impact: Improved code quality, reduced maintenance overhead, enhanced developer experience
This commit is contained in:
2025-09-21 03:27:57 +02:00
parent 5b7c3ba4b2
commit 86211923db
306 changed files with 52956 additions and 0 deletions
@@ -0,0 +1,370 @@
-- SerpentRace Backend Database Schema and Test Data
-- Generated on: August 22, 2025
-- PostgreSQL Database Dump
-- Enable UUID extension
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- ============================================================================
-- DROP EXISTING TABLES (in reverse dependency order)
-- ============================================================================
DROP TABLE IF EXISTS "ChatArchives";
DROP TABLE IF EXISTS "Chats";
DROP TABLE IF EXISTS "Contacts";
DROP TABLE IF EXISTS "Decks";
DROP TABLE IF EXISTS "Users";
DROP TABLE IF EXISTS "Organizations";
DROP TABLE IF EXISTS "migrations";
-- ============================================================================
-- CREATE TABLES
-- ============================================================================
-- Organizations Table
CREATE TABLE "Organizations" (
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
"name" character varying(255) NOT NULL,
"contactfname" character varying(100) NOT NULL,
"contactlname" character varying(100) NOT NULL,
"contactphone" character varying(20) NOT NULL,
"contactemail" character varying(255) NOT NULL,
"state" integer NOT NULL DEFAULT 0,
"regdate" TIMESTAMP NOT NULL DEFAULT now(),
"updatedate" TIMESTAMP NOT NULL DEFAULT now(),
"url" character varying(500),
"userinorg" integer NOT NULL DEFAULT 0,
"maxOrganizationalDecks" integer,
CONSTRAINT "PK_Organizations" PRIMARY KEY ("id")
);
-- Users Table
CREATE TABLE "Users" (
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
"orgid" uuid,
"username" character varying(100) NOT NULL UNIQUE,
"password" character varying(255) NOT NULL,
"email" character varying(255) NOT NULL UNIQUE,
"fname" character varying(100) NOT NULL,
"lname" character varying(100) NOT NULL,
"token" character varying(255),
"TokenExpires" TIMESTAMP,
"type" character varying(50) NOT NULL,
"phone" character varying(20),
"state" integer NOT NULL DEFAULT 0,
"regdate" TIMESTAMP NOT NULL DEFAULT now(),
"updatedate" TIMESTAMP NOT NULL DEFAULT now(),
"Orglogindate" TIMESTAMP,
CONSTRAINT "PK_Users" PRIMARY KEY ("id"),
CONSTRAINT "FK_Users_Organizations" FOREIGN KEY ("orgid") REFERENCES "Organizations"("id")
);
-- Decks Table
CREATE TABLE "Decks" (
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
"name" character varying(255) NOT NULL,
"type" integer NOT NULL,
"user_id" uuid NOT NULL,
"creation_date" TIMESTAMP NOT NULL DEFAULT now(),
"cards" json NOT NULL,
"played_number" integer NOT NULL DEFAULT 0,
"ctype" integer NOT NULL DEFAULT 0,
"update_date" TIMESTAMP NOT NULL DEFAULT now(),
"state" integer NOT NULL DEFAULT 0,
"organization_id" uuid,
CONSTRAINT "PK_Decks" PRIMARY KEY ("id"),
CONSTRAINT "FK_Decks_Users" FOREIGN KEY ("user_id") REFERENCES "Users"("id"),
CONSTRAINT "FK_Decks_Organizations" FOREIGN KEY ("organization_id") REFERENCES "Organizations"("id")
);
-- Chats Table
CREATE TABLE "Chats" (
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
"users" uuid[] NOT NULL,
"messages" json NOT NULL DEFAULT '[]',
"updateDate" TIMESTAMP NOT NULL DEFAULT now(),
"state" integer NOT NULL DEFAULT 0,
"type" character varying(50) NOT NULL DEFAULT 'direct',
"name" character varying(255),
"gameId" uuid,
"createdBy" uuid,
"lastActivity" TIMESTAMP,
"createDate" TIMESTAMP NOT NULL DEFAULT now(),
"archiveDate" TIMESTAMP,
CONSTRAINT "PK_Chats" PRIMARY KEY ("id")
);
-- Chat Archives Table
CREATE TABLE "ChatArchives" (
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
"chatId" uuid NOT NULL,
"archivedMessages" json NOT NULL,
"archivedAt" TIMESTAMP NOT NULL,
"createDate" TIMESTAMP NOT NULL DEFAULT now(),
"chatType" character varying(50) NOT NULL,
"chatName" character varying(255),
"gameId" uuid,
"participants" uuid[] NOT NULL,
CONSTRAINT "PK_ChatArchives" PRIMARY KEY ("id")
);
-- Contacts Table
CREATE TABLE "Contacts" (
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
"name" character varying(255) NOT NULL,
"email" character varying(255) NOT NULL,
"userid" uuid,
"type" integer NOT NULL,
"txt" text NOT NULL,
"state" integer NOT NULL DEFAULT 0,
"createDate" TIMESTAMP NOT NULL DEFAULT now(),
"updateDate" TIMESTAMP NOT NULL DEFAULT now(),
"adminResponse" text,
"responseDate" TIMESTAMP,
"respondedBy" uuid,
CONSTRAINT "PK_Contacts" PRIMARY KEY ("id"),
CONSTRAINT "FK_Contacts_Users" FOREIGN KEY ("userid") REFERENCES "Users"("id"),
CONSTRAINT "FK_Contacts_Admins" FOREIGN KEY ("respondedBy") REFERENCES "Users"("id")
);
-- Migrations table (for TypeORM)
CREATE TABLE "migrations" (
"id" SERIAL NOT NULL,
"timestamp" bigint NOT NULL,
"name" character varying NOT NULL,
CONSTRAINT "PK_migrations" PRIMARY KEY ("id")
);
-- ============================================================================
-- CREATE INDEXES
-- ============================================================================
CREATE INDEX "IDX_DECK_USER_STATE_CTYPE" ON "Decks" ("user_id", "state", "ctype");
CREATE INDEX "IDX_DECK_ORG_CTYPE_STATE" ON "Decks" ("organization_id", "ctype", "state");
CREATE INDEX "IDX_USERS_EMAIL" ON "Users" ("email");
CREATE INDEX "IDX_USERS_USERNAME" ON "Users" ("username");
CREATE INDEX "IDX_USERS_ORGID" ON "Users" ("orgid");
-- ============================================================================
-- INSERT TEST DATA
-- ============================================================================
-- Organizations Test Data
INSERT INTO "Organizations" ("id", "name", "contactfname", "contactlname", "contactphone", "contactemail", "state", "regdate", "updatedate", "url", "userinorg", "maxOrganizationalDecks") VALUES
('11111111-1111-1111-1111-111111111111', 'Tech Solutions Inc', 'John', 'Smith', '+1-555-0001', 'john.smith@techsolutions.com', 1, '2024-01-15 10:00:00', '2024-01-15 10:00:00', 'https://techsolutions.com', 5, 20),
('22222222-2222-2222-2222-222222222222', 'Educational Institute', 'Sarah', 'Johnson', '+1-555-0002', 'sarah.johnson@eduinst.edu', 1, '2024-02-01 09:30:00', '2024-02-01 09:30:00', 'https://eduinstitute.edu', 15, 50),
('33333333-3333-3333-3333-333333333333', 'Healthcare Corp', 'Michael', 'Brown', '+1-555-0003', 'michael.brown@healthcorp.com', 0, '2024-03-10 14:20:00', '2024-03-10 14:20:00', NULL, 0, 10);
-- Users Test Data
INSERT INTO "Users" ("id", "orgid", "username", "password", "email", "fname", "lname", "token", "TokenExpires", "type", "phone", "state", "regdate", "updatedate", "Orglogindate") VALUES
-- Regular users
('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', NULL, 'john_doe', '$2b$10$dPXxS9Byg7AbB.fngFtNWel1llS1nHJlQrTO4zQToy7vVitS9mr96', 'john.doe@email.com', 'John', 'Doe', NULL, NULL, 'personal', '+1-555-1001', 1, '2024-01-20 11:00:00', '2024-01-20 11:00:00', NULL),
('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', '11111111-1111-1111-1111-111111111111', 'jane_premium', '$2b$10$dPXxS9Byg7AbB.fngFtNWel1llS1nHJlQrTO4zQToy7vVitS9mr96', 'jane.smith@email.com', 'Jane', 'Smith', NULL, NULL, 'premium', '+1-555-1002', 2, '2024-01-25 12:30:00', '2024-01-25 12:30:00', '2024-01-25 12:30:00'),
('cccccccc-cccc-cccc-cccc-cccccccccccc', '22222222-2222-2222-2222-222222222222', 'teacher_bob', '$2b$10$dPXxS9Byg7AbB.fngFtNWel1llS1nHJlQrTO4zQToy7vVitS9mr96', 'bob.teacher@eduinst.edu', 'Bob', 'Teacher', NULL, NULL, 'premium', '+1-555-1003', 2, '2024-02-05 09:15:00', '2024-02-05 09:15:00', '2024-02-05 09:15:00'),
-- Admin user
('dddddddd-dddd-dddd-dddd-dddddddddddd', NULL, 'admin_user', '$2b$10$dPXxS9Byg7AbB.fngFtNWel1llS1nHJlQrTO4zQToy7vVitS9mr96', 'admin@serpentrace.com', 'Admin', 'User', NULL, NULL, 'admin', '+1-555-9999', 5, '2024-01-01 08:00:00', '2024-01-01 08:00:00', NULL),
-- Unverified user
('eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee', NULL, 'new_user', '$2b$10$dPXxS9Byg7AbB.fngFtNWel1llS1nHJlQrTO4zQToy7vVitS9mr96', 'newuser@email.com', 'New', 'User', 'verification_token_12345', '2025-08-23 23:59:59', 'personal', NULL, 0, '2025-08-22 16:00:00', '2025-08-22 16:00:00', NULL);
-- Decks Test Data
INSERT INTO "Decks" ("id", "name", "type", "user_id", "creation_date", "cards", "played_number", "ctype", "update_date", "state", "organization_id") VALUES
-- Public decks
('dddd1111-1111-1111-1111-111111111111', 'General Knowledge Quiz', 2, 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', '2024-02-01 10:00:00',
'[
{"id": "c1", "type": 0, "text": "What is the capital of France?", "answer": "Paris", "options": ["London", "Paris", "Berlin", "Madrid"]},
{"id": "c2", "type": 0, "text": "Which planet is known as the Red Planet?", "answer": "Mars", "options": ["Venus", "Mars", "Jupiter", "Saturn"]},
{"id": "c3", "type": 1, "text": "The Great Wall of China", "answer": "is visible from space", "options": ["is visible from space", "was built in one century"]},
{"id": "c4", "type": 2, "text": "Describe the process of photosynthesis", "answer": null},
{"id": "c5", "type": 3, "text": "The Earth is flat", "answer": false}
]',
25, 0, '2024-02-01 10:00:00', 0, NULL),
('dddd2222-2222-2222-2222-222222222222', 'Math Fundamentals', 2, 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', '2024-02-05 14:30:00',
'[
{"id": "m1", "type": 0, "text": "What is 2 + 2?", "answer": "4", "options": ["3", "4", "5", "6"]},
{"id": "m2", "type": 0, "text": "What is the square root of 16?", "answer": "4", "options": ["2", "4", "8", "16"]},
{"id": "m3", "type": 3, "text": "Pi is approximately 3.14", "answer": true},
{"id": "m4", "type": 4, "text": "Complete the sequence: 2, 4, 6, ?", "answer": "8"}
]',
15, 0, '2024-02-05 14:30:00', 0, NULL),
-- Private decks
('dddd3333-3333-3333-3333-333333333333', 'My Personal Study Notes', 2, 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', '2024-02-10 16:45:00',
'[
{"id": "p1", "type": 2, "text": "What did I learn about React hooks today?", "answer": null},
{"id": "p2", "type": 2, "text": "Key points from the management meeting", "answer": null}
]',
3, 1, '2024-02-10 16:45:00', 0, NULL),
-- Organizational decks
('dddd4444-4444-4444-4444-444444444444', 'Company Training Module', 2, 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', '2024-02-15 11:20:00',
'[
{"id": "o1", "type": 0, "text": "What is our company policy on remote work?", "answer": "Flexible hybrid model", "options": ["No remote work", "Full remote", "Flexible hybrid model", "Weekends only"]},
{"id": "o2", "type": 3, "text": "All employees must attend the monthly all-hands meeting", "answer": true},
{"id": "o3", "type": 2, "text": "Describe the steps for requesting vacation time", "answer": null}
]',
8, 2, '2024-02-15 11:20:00', 0, '11111111-1111-1111-1111-111111111111'),
('dddd5555-5555-5555-5555-555555555555', 'Educational Content for Students', 2, 'cccccccc-cccc-cccc-cccc-cccccccccccc', '2024-03-01 08:15:00',
'[
{"id": "e1", "type": 0, "text": "When did World War II end?", "answer": "1945", "options": ["1943", "1944", "1945", "1946"]},
{"id": "e2", "type": 1, "text": "Shakespeare wrote", "answer": "Romeo and Juliet", "options": ["Romeo and Juliet", "The Great Gatsby"]},
{"id": "e3", "type": 3, "text": "The American Revolution began in 1776", "answer": false},
{"id": "e4", "type": 4, "text": "Name three primary colors", "answer": "Red, Blue, Yellow"}
]',
42, 2, '2024-03-01 08:15:00', 0, '22222222-2222-2222-2222-222222222222'),
-- Joker and Luck type decks
('dddd6666-6666-6666-6666-666666666666', 'Lucky Challenges', 0, 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', '2024-03-05 13:40:00',
'[
{"id": "l1", "type": 4, "text": "Do 10 jumping jacks", "answer": null},
{"id": "l2", "type": 4, "text": "Name your favorite childhood memory", "answer": null},
{"id": "l3", "type": 4, "text": "Sing happy birthday", "answer": null}
]',
7, 0, '2024-03-05 13:40:00', 0, NULL),
('dddd7777-7777-7777-7777-777777777777', 'Wild Cards', 1, 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', '2024-03-08 19:25:00',
'[
{"id": "j1", "type": 4, "text": "Skip your next turn", "answer": null},
{"id": "j2", "type": 4, "text": "Draw two extra cards", "answer": null},
{"id": "j3", "type": 4, "text": "Trade places with another player", "answer": null},
{"id": "j4", "type": 4, "text": "Double your next score", "answer": null}
]',
12, 0, '2024-03-08 19:25:00', 0, NULL);
-- Chats Test Data
INSERT INTO "Chats" ("id", "users", "messages", "updateDate", "state", "type", "name", "gameId", "createdBy", "lastActivity", "createDate", "archiveDate") VALUES
-- Direct message between two users
('chat1111-1111-1111-1111-111111111111',
'{"aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"}',
'[
{"id": "msg1", "date": "2024-03-20T10:30:00Z", "userid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "text": "Hey Jane! How are you doing?"},
{"id": "msg2", "date": "2024-03-20T10:32:00Z", "userid": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", "text": "Hi John! I'\''m great, thanks for asking. How about you?"},
{"id": "msg3", "date": "2024-03-20T10:35:00Z", "userid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "text": "Doing well! Want to play a quiz game later?"},
{"id": "msg4", "date": "2024-03-20T10:37:00Z", "userid": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", "text": "Absolutely! I'\''ll prepare some questions."}
]',
'2024-03-20 10:37:00', 0, 'direct', NULL, NULL, NULL, '2024-03-20 10:37:00', '2024-03-20 10:30:00', NULL),
-- Group chat for organization
('chat2222-2222-2222-2222-222222222222',
'{"bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", "cccccccc-cccc-cccc-cccc-cccccccccccc", "dddddddd-dddd-dddd-dddd-dddddddddddd"}',
'[
{"id": "msg5", "date": "2024-03-21T14:15:00Z", "userid": "dddddddd-dddd-dddd-dddd-dddddddddddd", "text": "Welcome everyone to the study group!"},
{"id": "msg6", "date": "2024-03-21T14:16:00Z", "userid": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", "text": "Thanks for organizing this!"},
{"id": "msg7", "date": "2024-03-21T14:18:00Z", "userid": "cccccccc-cccc-cccc-cccc-cccccccccccc", "text": "I'\''ve prepared some educational content to share"},
{"id": "msg8", "date": "2024-03-21T14:20:00Z", "userid": "dddddddd-dddd-dddd-dddd-dddddddddddd", "text": "Great! Let'\''s start with the basics"}
]',
'2024-03-21 14:20:00', 0, 'group', 'Study Group', NULL, 'dddddddd-dddd-dddd-dddd-dddddddddddd', '2024-03-21 14:20:00', '2024-03-21 14:15:00', NULL),
-- Game chat
('chat3333-3333-3333-3333-333333333333',
'{"aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"}',
'[
{"id": "msg9", "date": "2024-03-22T16:45:00Z", "userid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "text": "Ready to start the quiz game?"},
{"id": "msg10", "date": "2024-03-22T16:46:00Z", "userid": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", "text": "Yes! Let'\''s do this!"},
{"id": "msg11", "date": "2024-03-22T16:50:00Z", "userid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "text": "Great job on that last question!"},
{"id": "msg12", "date": "2024-03-22T16:52:00Z", "userid": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", "text": "Thanks! This is fun!"}
]',
'2024-03-22 16:52:00', 0, 'game', 'Quiz Game Session', 'game1111-1111-1111-1111-111111111111', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', '2024-03-22 16:52:00', '2024-03-22 16:45:00', NULL);
-- Chat Archives Test Data
INSERT INTO "ChatArchives" ("id", "chatId", "archivedMessages", "archivedAt", "createDate", "chatType", "chatName", "gameId", "participants") VALUES
('arch1111-1111-1111-1111-111111111111', 'chat0000-0000-0000-0000-000000000000',
'[
{"id": "oldmsg1", "date": "2024-01-15T09:00:00Z", "userid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "text": "This is an old conversation"},
{"id": "oldmsg2", "date": "2024-01-15T09:05:00Z", "userid": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", "text": "Yes, from last month"},
{"id": "oldmsg3", "date": "2024-01-15T09:10:00Z", "userid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "text": "Good times!"}
]',
'2024-02-15 00:00:00', '2024-02-15 00:00:00', 'direct', NULL, NULL, '{"aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"}');
-- Contacts Test Data
INSERT INTO "Contacts" ("id", "name", "email", "userid", "type", "txt", "state", "createDate", "updateDate", "adminResponse", "responseDate", "respondedBy") VALUES
-- Bug report from registered user
('cont1111-1111-1111-1111-111111111111', 'John Doe', 'john.doe@email.com', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 0, 'I found a bug when creating a new deck. The cards are not saving properly when I add more than 10 cards.', 1, '2024-03-18 14:30:00', '2024-03-19 09:15:00', 'Thank you for reporting this issue. We have identified the problem and deployed a fix. Please try creating your deck again.', '2024-03-19 09:15:00', 'dddddddd-dddd-dddd-dddd-dddddddddddd'),
-- General question from anonymous user
('cont2222-2222-2222-2222-222222222222', 'Sarah Wilson', 'sarah.wilson@email.com', NULL, 2, 'Hi, I'\''m interested in using SerpentRace for my classroom. Do you have any educational pricing or features specifically designed for teachers?', 0, '2024-03-19 11:20:00', '2024-03-19 11:20:00', NULL, NULL, NULL),
-- Problem report from premium user
('cont3333-3333-3333-3333-333333333333', 'Jane Smith', 'jane.smith@email.com', 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 1, 'I'\''m having trouble with the organization deck sharing feature. When I share a deck with my team, they can'\''t see the latest updates I made.', 0, '2024-03-20 16:45:00', '2024-03-20 16:45:00', NULL, NULL, NULL),
-- Sales inquiry
('cont4444-4444-4444-4444-444444444444', 'Michael Chen', 'michael.chen@company.com', NULL, 3, 'Our company is interested in purchasing premium licenses for 50 employees. Could you provide pricing information and enterprise features?', 0, '2024-03-21 10:10:00', '2024-03-21 10:10:00', NULL, NULL, NULL),
-- Other type of contact
('cont5555-5555-5555-5555-555555555555', 'Lisa Johnson', 'lisa.johnson@email.com', NULL, 4, 'I love using SerpentRace! Could you add support for audio questions in the quiz decks? This would be great for language learning.', 0, '2024-03-22 13:25:00', '2024-03-22 13:25:00', NULL, NULL, NULL);
-- Migration entries
INSERT INTO "migrations" ("timestamp", "name") VALUES
(1755691733404, 'test1755691733404'),
(1755706019351, 'AddEmailVerificationFields1755706019351'),
(1755817306222, 'AddChatMessagingSystem1755817306222'),
(1755855028839, 'CreateContactTable1755855028839'),
(1692712800000, 'AddMaxOrganizationalDecksToOrganization1692712800000');
-- ============================================================================
-- UPDATE ORGANIZATION USER COUNTS
-- ============================================================================
UPDATE "Organizations" SET "userinorg" = (
SELECT COUNT(*) FROM "Users" WHERE "Users"."orgid" = "Organizations"."id"
);
-- ============================================================================
-- HELPFUL QUERIES FOR TESTING
-- ============================================================================
-- Query to see all users with their organizations
-- SELECT u.username, u.email, u.state, o.name as organization_name
-- FROM "Users" u
-- LEFT JOIN "Organizations" o ON u.orgid = o.id;
-- Query to see deck distribution by type and visibility
-- SELECT
-- CASE ctype
-- WHEN 0 THEN 'Public'
-- WHEN 1 THEN 'Private'
-- WHEN 2 THEN 'Organization'
-- END as deck_type,
-- CASE type
-- WHEN 0 THEN 'Luck'
-- WHEN 1 THEN 'Joker'
-- WHEN 2 THEN 'Question'
-- END as card_type,
-- COUNT(*) as count
-- FROM "Decks"
-- WHERE state = 0
-- GROUP BY ctype, type
-- ORDER BY ctype, type;
-- Query to see active chats with participant count
-- SELECT
-- id,
-- type,
-- name,
-- array_length(users, 1) as participant_count,
-- json_array_length(messages) as message_count,
-- lastActivity
-- FROM "Chats"
-- WHERE state = 0
-- ORDER BY lastActivity DESC;
-- Query to see contact distribution by type and status
-- SELECT
-- CASE type
-- WHEN 0 THEN 'Bug'
-- WHEN 1 THEN 'Problem'
-- WHEN 2 THEN 'Question'
-- WHEN 3 THEN 'Sales'
-- WHEN 4 THEN 'Other'
-- END as contact_type,
-- CASE state
-- WHEN 0 THEN 'Active'
-- WHEN 1 THEN 'Resolved'
-- WHEN 2 THEN 'Deleted'
-- END as status,
-- COUNT(*) as count
-- FROM "Contacts"
-- GROUP BY type, state
-- ORDER BY type, state;
-- ============================================================================
-- END OF SQL DUMP
-- ============================================================================