Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 97 additions & 2 deletions tool/backend/sql/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,118 @@
This directory contains the SQL scripts used to initialize and seed the RTI-Tracker database.

## Directory Structure

- **`schema.sql`**: The core database structure (tables, extensions, constraints).
- **`seed.sql`**: Mock data for development and testing.

#### DB Schema

```mermaid
erDiagram
SENDERS ||--o{ RTI_REQUESTS : initiates
RECEIVERS ||--o{ RTI_REQUESTS : targets
RTI_REQUESTS ||--|{ RTI_STATUS_HISTORIES : tracks
RECEIVERS }o--|| INSTITUTIONS : has
RECEIVERS }o--|| POSITIONS : has
RTI_STATUS_HISTORIES }o--|| RTI_STATUSES : has
RTI_REQUESTS }o--o| RTI_TEMPLATES : has

SENDERS {
uuid id PK
string name
string email
string address
string contact_no
datetime created_at
datetime updated_at
}

POSITIONS {
uuid id PK
string name
datetime created_at
datetime updated_at
}

INSTITUTIONS {
uuid id PK
string name
datetime created_at
datetime updated_at
}

RECEIVERS {
uuid id PK
uuid position_id FK
uuid institution_id FK
list[string] emails
string address
list[string] contact_nos
datetime created_at
datetime updated_at
}

RTI_TEMPLATES {
uuid id PK
string title
string description
string file
datetime created_at
datetime updated_at
}

RTI_REQUESTS {
uuid id PK
string title
string description
uuid sender_id FK
uuid receiver_id FK
uuid rti_template_id FK
datetime created_at
datetime updated_at
}

RTI_STATUS_HISTORIES {
uuid id PK
uuid rti_request_id FK
uuid status_id FK
string direction
string description
datetime entry_time
datetime exit_time
list[string] files
datetime created_at
datetime updated_at
}

RTI_STATUSES {
uuid id PK
string name
datetime created_at
datetime updated_at
}
```

## Local Development

To reset your local database and apply fresh schema/seed data, run:

#### Environment setup

**macOS / Linux**

```bash
cp .env.example .env
```

**Windows (PowerShell)**

```powershell
Copy-Item .env.example .env
```

**Windows (Command Prompt)**

```cmd
copy .env.example .env
```
Expand All @@ -33,9 +126,11 @@ copy .env.example .env
docker compose down -v && docker compose up --build
```

*Note: The `-v` flag is required to clear the named volume and trigger re-initialization.*
_Note: The `-v` flag is required to clear the named volume and trigger re-initialization._

## Production

For production environments (like Neon):

1. Execute **`schema.sql`** to set up the tables.
2. **Do not** run `seed.sql` unless you specifically need mock data in a staging environment.
2. **Do not** run `seed.sql` unless you specifically need mock data in a staging environment.
11 changes: 6 additions & 5 deletions tool/backend/sql/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ CREATE TABLE IF NOT EXISTS receivers (
id uuid DEFAULT uuid_generate_v4() PRIMARY KEY,
position_id uuid NOT NULL REFERENCES positions(id),
institution_id uuid NOT NULL REFERENCES institutions(id),
email VARCHAR UNIQUE,
emails JSONB,
Comment thread
ChanukaUOJ marked this conversation as resolved.
address VARCHAR,
contact_no VARCHAR UNIQUE,
contact_nos JSONB,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);
Expand Down Expand Up @@ -94,10 +94,11 @@ ADD CONSTRAINT check_senders_email_or_contact_no
CHECK (email IS NOT NULL OR contact_no IS NOT NULL);

-- RECEIVERS TABLE
ALTER TABLE receivers DROP CONSTRAINT IF EXISTS check_receivers_email_or_contact_no;
ALTER TABLE receivers DROP CONSTRAINT IF EXISTS check_receivers_emails_or_contact_nos;
ALTER TABLE receivers
ADD CONSTRAINT check_receivers_email_or_contact_no
CHECK (email IS NOT NULL OR contact_no IS NOT NULL);
ADD CONSTRAINT check_receivers_emails_or_contact_nos
CHECK ((emails IS NOT NULL AND emails <> '[]'::jsonb) OR
(contact_nos IS NOT NULL AND contact_nos <> '[]'::jsonb));

-- Foreign Key Indexes
-- RECEIVERS TABLE
Expand Down
46 changes: 23 additions & 23 deletions tool/backend/sql/seed.sql
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,17 @@ INSERT INTO senders (name, email, address, contact_no) VALUES

-- 4. RECEIVERS
-- Linking using subqueries to match existing data
INSERT INTO receivers (position_id, institution_id, email, address, contact_no) VALUES
((SELECT id FROM positions WHERE name = 'Information Officer' LIMIT 1), (SELECT id FROM institutions WHERE name = 'Ministry of Health' LIMIT 1), 'io.health@gov.lk', NULL, '0112444555'),
((SELECT id FROM positions WHERE name = 'Designated Officer' LIMIT 1), (SELECT id FROM institutions WHERE name = 'Department of Education' LIMIT 1), 'do.edu@gov.lk', NULL, NULL),
((SELECT id FROM positions WHERE name = 'Secretary' LIMIT 1), (SELECT id FROM institutions WHERE name = 'Central Environmental Authority' LIMIT 1), NULL, 'Colombo', '0112888999'),
((SELECT id FROM positions WHERE name = 'Director General' LIMIT 1), (SELECT id FROM institutions WHERE name = 'Road Development Authority' LIMIT 1), 'dg.rda@gov.lk', 'Colombo', '0112000111'),
((SELECT id FROM positions WHERE name = 'Legal Officer' LIMIT 1), (SELECT id FROM institutions WHERE name = 'Sri Lanka Police' LIMIT 1), NULL, NULL, '0112222333'),
((SELECT id FROM positions WHERE name = 'Administrative Assistant' LIMIT 1), (SELECT id FROM institutions WHERE name = 'National Water Supply & Drainage Board' LIMIT 1), 'admin.nwsdb@gov.lk', 'Colombo', '0112555666'),
((SELECT id FROM positions WHERE name = 'Research Analyst' LIMIT 1), (SELECT id FROM institutions WHERE name = 'University of Colombo' LIMIT 1), 'research.uoc@ac.lk', NULL, NULL),
((SELECT id FROM positions WHERE name = 'Public Relations Officer' LIMIT 1), (SELECT id FROM institutions WHERE name = 'Sri Lanka Customs' LIMIT 1), 'pro.customs@gov.lk', 'Colombo', '0112111222'),
((SELECT id FROM positions WHERE name = 'Chief Executive Officer' LIMIT 1), (SELECT id FROM institutions WHERE name = 'Ministry of Finance' LIMIT 1), 'ceo.finance@gov.lk', 'Gampaha', '0112999000'),
((SELECT id FROM positions WHERE name = 'Department Head' LIMIT 1), (SELECT id FROM institutions WHERE name = 'Public Service Commission' LIMIT 1), 'head.psc@gov.lk', 'Gampaha', NULL);
INSERT INTO receivers (position_id, institution_id, emails, address, contact_nos) VALUES
((SELECT id FROM positions WHERE name = 'Information Officer' LIMIT 1), (SELECT id FROM institutions WHERE name = 'Ministry of Health' LIMIT 1), '["io.health@gov.lk"]', NULL, '["0112444555"]'),
((SELECT id FROM positions WHERE name = 'Designated Officer' LIMIT 1), (SELECT id FROM institutions WHERE name = 'Department of Education' LIMIT 1), '["do.edu@gov.lk"]', NULL, '[]'),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we not keep empty values for contact nos or emails as NULL? Does it have to be an empty list?

((SELECT id FROM positions WHERE name = 'Secretary' LIMIT 1), (SELECT id FROM institutions WHERE name = 'Central Environmental Authority' LIMIT 1), '[]', 'Colombo', '["0112888999"]'),
((SELECT id FROM positions WHERE name = 'Director General' LIMIT 1), (SELECT id FROM institutions WHERE name = 'Road Development Authority' LIMIT 1), '["dg.rda@gov.lk"]', 'Colombo', '["0112000111","0771212123","0789090987","0771212121","0789090988"]'),
((SELECT id FROM positions WHERE name = 'Legal Officer' LIMIT 1), (SELECT id FROM institutions WHERE name = 'Sri Lanka Police' LIMIT 1), '[]', NULL, '["0112222333"]'),
((SELECT id FROM positions WHERE name = 'Administrative Assistant' LIMIT 1), (SELECT id FROM institutions WHERE name = 'National Water Supply & Drainage Board' LIMIT 1), '["admin.nwsdb@gov.lk"]', 'Colombo', '["0112555666"]'),
((SELECT id FROM positions WHERE name = 'Research Analyst' LIMIT 1), (SELECT id FROM institutions WHERE name = 'University of Colombo' LIMIT 1), '["research.uoc@ac.lk"]', NULL, '[]'),
((SELECT id FROM positions WHERE name = 'Public Relations Officer' LIMIT 1), (SELECT id FROM institutions WHERE name = 'Sri Lanka Customs' LIMIT 1), '["pro.customs@gov.lk"]', 'Colombo', '["0112111222","0113434543"]'),
((SELECT id FROM positions WHERE name = 'Chief Executive Officer' LIMIT 1), (SELECT id FROM institutions WHERE name = 'Ministry of Finance' LIMIT 1), '["ceo.finance@gov.lk"]', 'Gampaha', '["0112999000"]'),
((SELECT id FROM positions WHERE name = 'Department Head' LIMIT 1), (SELECT id FROM institutions WHERE name = 'Public Service Commission' LIMIT 1), '["head.psc@gov.lk"]', 'Gampaha', '[]');

-- 5. RTI TEMPLATES
INSERT INTO rti_templates (title, description, file) VALUES
Expand Down Expand Up @@ -79,16 +79,16 @@ INSERT INTO rti_statuses (name) VALUES

-- 7. RTI REQUESTS
INSERT INTO rti_requests (title, description, sender_id, receiver_id, rti_template_id, created_at) VALUES
('Inquiry on Hospital Supplies', 'Requesting details of medicine availability for Colombo South Hospital.', (SELECT id FROM senders WHERE name = 'Amal Perera' LIMIT 1), (SELECT id FROM receivers WHERE email = 'io.health@gov.lk' LIMIT 1), (SELECT id FROM rti_templates WHERE title = 'Health Statistics Request' LIMIT 1), NOW() - INTERVAL '30 days'),
('School Expenditure 2024', 'Requesting budget allocation for primary schools in Jaffna.', (SELECT id FROM senders WHERE name = 'Bimali Silva' LIMIT 1), (SELECT id FROM receivers WHERE email = 'do.edu@gov.lk' LIMIT 1), (SELECT id FROM rti_templates WHERE title = 'Education Data Request' LIMIT 1), NOW() - INTERVAL '29 days'),
('Highway Project Budget', 'Details on the funding sources for the Central Expressway Phase III.', (SELECT id FROM senders WHERE name = 'Chamara Bandara' LIMIT 1), (SELECT id FROM receivers WHERE email = 'dg.rda@gov.lk' LIMIT 1), (SELECT id FROM rti_templates WHERE title = 'Infrastructure Project Details' LIMIT 1), NOW() - INTERVAL '28 days'),
('Environmental Clearance List', 'Requesting a list of projects approved in wetlands during 2023.', (SELECT id FROM senders WHERE name = 'Dilini Fernando' LIMIT 1), (SELECT id FROM receivers WHERE contact_no = '0112888999' LIMIT 1), (SELECT id FROM rti_templates WHERE title = 'Environmental Impact Inquiry' LIMIT 1), NOW() - INTERVAL '27 days'),
('Police Recruitment Ratio', 'Requesting data on gender ratio in recent constable recruitment.', (SELECT id FROM senders WHERE name = 'Eshani Jayawardena' LIMIT 1), (SELECT id FROM receivers WHERE contact_no = '0112222333' LIMIT 1), (SELECT id FROM rti_templates WHERE title = 'Public Service Vacancy Info' LIMIT 1), NOW() - INTERVAL '26 days'),
('NWSDB Water Quality Data', 'Requesting seasonal water quality reports for Kandy district.', (SELECT id FROM senders WHERE name = 'Fathima Nasreen' LIMIT 1), (SELECT id FROM receivers WHERE email = 'admin.nwsdb@gov.lk' LIMIT 1), (SELECT id FROM rti_templates WHERE title = 'Water Supply Project Status' LIMIT 1), NOW() - INTERVAL '25 days'),
('University Research Grants', 'Summary of research grants awarded to UoC faculty in 2025.', (SELECT id FROM senders WHERE name = 'Gayan Ratnayake' LIMIT 1), (SELECT id FROM receivers WHERE email = 'research.uoc@ac.lk' LIMIT 1), (SELECT id FROM rti_templates WHERE title = 'General Request Template' LIMIT 1), NOW() - INTERVAL '24 days'),
('Customs Duty Exemptions', 'List of organizations granted duty exemptions for vehicle imports.', (SELECT id FROM senders WHERE name = 'Harsha Kumara' LIMIT 1), (SELECT id FROM receivers WHERE email = 'pro.customs@gov.lk' LIMIT 1), (SELECT id FROM rti_templates WHERE title = 'Customs Import/Export Data' LIMIT 1), NOW() - INTERVAL '23 days'),
('Foreign Debt Repayment', 'Quarterly report on interest paid toward sovereign bonds.', (SELECT id FROM senders WHERE name = 'Iromi Wickramasinghe' LIMIT 1), (SELECT id FROM receivers WHERE email = 'ceo.finance@gov.lk' LIMIT 1), (SELECT id FROM rti_templates WHERE title = 'Financial Expenditure Inquiry' LIMIT 1), NOW() - INTERVAL '22 days'),
('PSC Disciplinary Actions', 'Stats on administrative inquiries concluded in the last 6 months.', (SELECT id FROM senders WHERE name = 'Janaka Abeysekera' LIMIT 1), (SELECT id FROM receivers WHERE email = 'head.psc@gov.lk' LIMIT 1), (SELECT id FROM rti_templates WHERE title = 'Legal Proceeding Inquiry' LIMIT 1), NOW() - INTERVAL '21 days');
('Inquiry on Hospital Supplies', 'Requesting details of medicine availability for Colombo South Hospital.', (SELECT id FROM senders WHERE name = 'Amal Perera' LIMIT 1), (SELECT id FROM receivers WHERE emails @> '["io.health@gov.lk"]' LIMIT 1), (SELECT id FROM rti_templates WHERE title = 'Health Statistics Request' LIMIT 1), NOW() - INTERVAL '30 days'),
('School Expenditure 2024', 'Requesting budget allocation for primary schools in Jaffna.', (SELECT id FROM senders WHERE name = 'Bimali Silva' LIMIT 1), (SELECT id FROM receivers WHERE emails @> '["do.edu@gov.lk"]' LIMIT 1), (SELECT id FROM rti_templates WHERE title = 'Education Data Request' LIMIT 1), NOW() - INTERVAL '29 days'),
('Highway Project Budget', 'Details on the funding sources for the Central Expressway Phase III.', (SELECT id FROM senders WHERE name = 'Chamara Bandara' LIMIT 1), (SELECT id FROM receivers WHERE emails @> '["dg.rda@gov.lk"]' LIMIT 1), (SELECT id FROM rti_templates WHERE title = 'Infrastructure Project Details' LIMIT 1), NOW() - INTERVAL '28 days'),
('Environmental Clearance List', 'Requesting a list of projects approved in wetlands during 2023.', (SELECT id FROM senders WHERE name = 'Dilini Fernando' LIMIT 1), (SELECT id FROM receivers WHERE contact_nos @> '["0112888999"]' LIMIT 1), (SELECT id FROM rti_templates WHERE title = 'Environmental Impact Inquiry' LIMIT 1), NOW() - INTERVAL '27 days'),
('Police Recruitment Ratio', 'Requesting data on gender ratio in recent constable recruitment.', (SELECT id FROM senders WHERE name = 'Eshani Jayawardena' LIMIT 1), (SELECT id FROM receivers WHERE contact_nos @> '["0112222333"]' LIMIT 1), (SELECT id FROM rti_templates WHERE title = 'Public Service Vacancy Info' LIMIT 1), NOW() - INTERVAL '26 days'),
('NWSDB Water Quality Data', 'Requesting seasonal water quality reports for Kandy district.', (SELECT id FROM senders WHERE name = 'Fathima Nasreen' LIMIT 1), (SELECT id FROM receivers WHERE emails @> '["admin.nwsdb@gov.lk"]' LIMIT 1), (SELECT id FROM rti_templates WHERE title = 'Water Supply Project Status' LIMIT 1), NOW() - INTERVAL '25 days'),
('University Research Grants', 'Summary of research grants awarded to UoC faculty in 2025.', (SELECT id FROM senders WHERE name = 'Gayan Ratnayake' LIMIT 1), (SELECT id FROM receivers WHERE emails @> '["research.uoc@ac.lk"]' LIMIT 1), (SELECT id FROM rti_templates WHERE title = 'General Request Template' LIMIT 1), NOW() - INTERVAL '24 days'),
('Customs Duty Exemptions', 'List of organizations granted duty exemptions for vehicle imports.', (SELECT id FROM senders WHERE name = 'Harsha Kumara' LIMIT 1), (SELECT id FROM receivers WHERE emails @> '["pro.customs@gov.lk"]' LIMIT 1), (SELECT id FROM rti_templates WHERE title = 'Customs Import/Export Data' LIMIT 1), NOW() - INTERVAL '23 days'),
('Foreign Debt Repayment', 'Quarterly report on interest paid toward sovereign bonds.', (SELECT id FROM senders WHERE name = 'Iromi Wickramasinghe' LIMIT 1), (SELECT id FROM receivers WHERE emails @> '["ceo.finance@gov.lk"]' LIMIT 1), (SELECT id FROM rti_templates WHERE title = 'Financial Expenditure Inquiry' LIMIT 1), NOW() - INTERVAL '22 days'),
('PSC Disciplinary Actions', 'Stats on administrative inquiries concluded in the last 6 months.', (SELECT id FROM senders WHERE name = 'Janaka Abeysekera' LIMIT 1), (SELECT id FROM receivers WHERE emails @> '["head.psc@gov.lk"]' LIMIT 1), (SELECT id FROM rti_templates WHERE title = 'Legal Proceeding Inquiry' LIMIT 1), NOW() - INTERVAL '21 days');

-- 8. RTI STATUS HISTORIES
-- First, add the mandatory 'CREATED' status for every request
Expand Down Expand Up @@ -145,8 +145,8 @@ WHERE title = 'Education Data Request';

-- Scenario 4: Update a receiver
UPDATE receivers
SET email = 'do.edu.updated@gov.lk', updated_at = NOW()
WHERE email = 'do.edu@gov.lk';
SET emails = '["do.edu.updated@gov.lk","do.edu2@gov.lk","do.edu@gov.lk"]'::jsonb, updated_at = NOW()
WHERE emails @> '["do.edu@gov.lk"]';

-- Scenario 5: Update an institution
UPDATE institutions
Expand Down
12 changes: 6 additions & 6 deletions tool/backend/src/models/request_models/receiver.py
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is called receiver.py but the file in response_models is receivers.py

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from pydantic import BaseModel, Field, ConfigDict, EmailStr, model_validator
from typing import Optional
from typing import Optional, List, Annotated
from uuid import UUID
from src.core.exceptions import BadRequestException

Expand All @@ -8,21 +8,21 @@ class ReceiverUpdateRequest(BaseModel):

position_id: Optional[UUID] = Field(None, alias="positionId", description="ID of the position")
institution_id: Optional[UUID] = Field(None, alias="institutionId", description="ID of the institution")
email: Optional[EmailStr] = Field(None, description="Email of the receiver")
emails: Optional[List[EmailStr]] = Field(None, description="List of receiver Emails")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
emails: Optional[List[EmailStr]] = Field(None, description="List of receiver Emails")
emails: Optional[List[EmailStr]] = Field(None, description="List of receiver emails")

address: Optional[str] = Field(None, description="Address of the receiver")
contact_no: Optional[str] = Field(None, alias="contactNo", pattern=r"^(?:\+94|0)\d{9}$", description="Contact number of the receiver")
contact_nos: Optional[List[Annotated[str, Field(pattern=r"^(?:\+94|0)\d{9}$")]]] = Field(None, alias="contactNos", description="List of receiver contact numbers")

class ReceiverRequest(BaseModel):
model_config = ConfigDict(from_attributes=True, str_strip_whitespace=True, populate_by_name=True)

position_id: UUID = Field(..., alias="positionId", description="ID of the position")
institution_id: UUID = Field(..., alias="institutionId", description="ID of the institution")
email: Optional[EmailStr] = Field(None, description="Email of the receiver")
emails: Optional[List[EmailStr]] = Field(None, description="List of receiver Emails")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
emails: Optional[List[EmailStr]] = Field(None, description="List of receiver Emails")
emails: Optional[List[EmailStr]] = Field(None, description="List of receiver emails")

address: Optional[str] = Field(None, description="Address of the receiver")
contact_no: Optional[str] = Field(None, alias="contactNo", pattern=r"^(?:\+94|0)\d{9}$", description="Contact number of the receiver")
contact_nos: Optional[List[Annotated[str, Field(pattern=r"^(?:\+94|0)\d{9}$")]]] = Field(None, alias="contactNos", description="List of receiver contact numbers")

@model_validator(mode="after")
def validate_email_or_contact(self):
if not self.email and not self.contact_no:
if not self.emails and not self.contact_nos:
raise BadRequestException("Either email or contactNo must be provided.")
return self
Loading
Loading