Establishes the deploy baseline on main so the admin agent's publish/rollback has a clean starting point. Everything built to date: sumi-e brand system, homepage, projects (DB-driven case studies), resume, about, services + website-design detail, contact form + DB, changelog, favicon + share card. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DoFYZY9gkGPNDqZ7NuEa9a
36 lines
1.5 KiB
SQL
36 lines
1.5 KiB
SQL
-- Contact form submissions.
|
|
--
|
|
-- `subject` is stored as free text (a slug from a known list), not an ENUM.
|
|
-- ENUMs need a migration every time an option is added; the list of enquiry
|
|
-- types will change more often than the schema should. The controller
|
|
-- validates against the allowed set, so bad values never reach here.
|
|
--
|
|
-- Anti-spam and audit columns live alongside the message: a honeypot outcome,
|
|
-- the origin IP, and the user agent. These make it possible to review what got
|
|
-- flagged without a separate log.
|
|
|
|
CREATE TABLE IF NOT EXISTS `cja_contact` (
|
|
`contact_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
|
|
|
`name` varchar(160) NOT NULL,
|
|
`email` varchar(255) NOT NULL,
|
|
`subject` varchar(60) NOT NULL DEFAULT 'other',
|
|
`message` text NOT NULL,
|
|
|
|
-- lifecycle so the inbox is workable, not just a dump
|
|
`status` enum('new','read','replied','spam','archived')
|
|
NOT NULL DEFAULT 'new',
|
|
|
|
-- audit / anti-spam
|
|
`ip` varchar(45) DEFAULT NULL, -- v4 or v6
|
|
`user_agent` varchar(255) DEFAULT NULL,
|
|
`referrer` varchar(255) DEFAULT NULL,
|
|
|
|
`created_at` datetime NOT NULL DEFAULT current_timestamp(),
|
|
`updated_at` datetime NOT NULL DEFAULT current_timestamp()
|
|
ON UPDATE current_timestamp(),
|
|
|
|
PRIMARY KEY (`contact_id`),
|
|
KEY `idx_cja_contact_status` (`status`, `created_at`),
|
|
KEY `idx_cja_contact_email` (`email`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|