02794e565e
A tool for authoring, sharing, and curating social protocols. Features: - Protocol library with search, tag filtering, and sort by date/relevance - Protocol authoring with structured fields (title, description, steps, outcome, practice, source, tags) - Protocol forking with provenance tracking - Collection creation with searchable protocol picker and ordering - User accounts with roles (admin, member, viewer) - YAML import/export for portability - Self-hostable on LAMP/Cloudron, works in subdirectories - Responsive design with hamburger menu on mobile - About page Security: - CSRF protection via Origin/Referer validation - Session regeneration on login/register - Secure session cookie params (HttpOnly, SameSite, Secure) - Visibility enforcement on private/unlisted items - YAML object injection hardening - Login rate limiting - Path traversal protection - Input validation and length clamping - Vote value constraining Stack: PHP 8.x + MySQL/MariaDB, vanilla JS frontend, no external dependencies. Hippocratic License (HL3-CORE).
81 lines
3.4 KiB
SQL
Executable File
81 lines
3.4 KiB
SQL
Executable File
-- Protocol Droid — MySQL Schema
|
|
-- Works with MySQL 5.7+ / MariaDB 10.3+
|
|
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
username VARCHAR(32) UNIQUE NOT NULL,
|
|
display_name VARCHAR(128),
|
|
bio TEXT,
|
|
password_hash VARCHAR(255), -- bcrypt; NULL if SSO-only
|
|
sso_provider VARCHAR(64), -- 'oidc', 'github', 'google', etc.
|
|
sso_id VARCHAR(255), -- external identity id
|
|
role ENUM('admin','member','viewer') DEFAULT 'member',
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
CREATE TABLE IF NOT EXISTS protocols (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
slug VARCHAR(128) UNIQUE NOT NULL,
|
|
title VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
source VARCHAR(255), -- free text or @username
|
|
source_url VARCHAR(500),
|
|
tags VARCHAR(500), -- JSON array string
|
|
forked_from VARCHAR(128), -- slug of parent protocol
|
|
image VARCHAR(500),
|
|
steps TEXT, -- JSON array of {headline, description}
|
|
outcome TEXT,
|
|
practice TEXT,
|
|
author_id INT REFERENCES users(id),
|
|
visibility ENUM('public','private','unlisted') DEFAULT 'public',
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
INDEX idx_visibility (visibility),
|
|
INDEX idx_author (author_id),
|
|
INDEX idx_forked (forked_from)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
CREATE TABLE IF NOT EXISTS collections (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
slug VARCHAR(128) UNIQUE NOT NULL,
|
|
title VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
source VARCHAR(255),
|
|
image VARCHAR(500),
|
|
author_id INT REFERENCES users(id),
|
|
visibility ENUM('public','private','unlisted') DEFAULT 'public',
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
INDEX idx_visibility (visibility),
|
|
INDEX idx_author (author_id)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
CREATE TABLE IF NOT EXISTS collection_items (
|
|
collection_id INT NOT NULL REFERENCES collections(id) ON DELETE CASCADE,
|
|
item_type ENUM('protocol','collection') NOT NULL,
|
|
item_slug VARCHAR(128) NOT NULL,
|
|
position INT DEFAULT 0,
|
|
PRIMARY KEY (collection_id, item_type, item_slug)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
CREATE TABLE IF NOT EXISTS votes (
|
|
user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
protocol_slug VARCHAR(128) NOT NULL,
|
|
value INT DEFAULT 1, -- +1 upvote, -1 downvote
|
|
comment TEXT, -- optional evaluation text
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
PRIMARY KEY (user_id, protocol_slug)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
CREATE TABLE IF NOT EXISTS config (
|
|
`key` VARCHAR(64) PRIMARY KEY,
|
|
`value` TEXT
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
-- Default config entries
|
|
INSERT INTO config (`key`, `value`) VALUES
|
|
('site_name', 'Protocol Droid'),
|
|
('site_tagline', 'A commons of social protocols'),
|
|
('registration_enabled', 'true'),
|
|
('require_approval', 'false')
|
|
ON DUPLICATE KEY UPDATE `value` = VALUES(`value`); |