diff --git a/assets/css/custom.css b/assets/css/custom.css
new file mode 100644
index 0000000..380885b
--- /dev/null
+++ b/assets/css/custom.css
@@ -0,0 +1,34 @@
+
+body {
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
+ background-color: #F8F9FA;
+ color: #212529;
+}
+
+.navbar-brand {
+ font-weight: 700;
+}
+
+.hero {
+ background: linear-gradient(to bottom, rgba(13, 110, 253, 0.05), rgba(255, 255, 255, 0));
+ padding: 6rem 0;
+}
+
+.hero h1 {
+ font-weight: 800;
+ font-size: 3.5rem;
+}
+
+.feature-icon {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 4rem;
+ height: 4rem;
+ border-radius: 0.75rem;
+}
+
+.footer {
+ padding: 3rem 0;
+ background-color: #FFFFFF;
+}
diff --git a/assets/js/main.js b/assets/js/main.js
new file mode 100644
index 0000000..f4b9868
--- /dev/null
+++ b/assets/js/main.js
@@ -0,0 +1 @@
+// No custom JS needed for this initial step, but the file is here for future use.
diff --git a/chart_of_accounts.php b/chart_of_accounts.php
new file mode 100644
index 0000000..88215ab
--- /dev/null
+++ b/chart_of_accounts.php
@@ -0,0 +1,303 @@
+prepare("SELECT id FROM companies WHERE user_id = ?");
+$stmt->execute([$user_id]);
+$company = $stmt->fetch();
+$company_id = $company ? $company['id'] : null;
+
+// Handle POST requests
+if ($_SERVER['REQUEST_METHOD'] === 'POST' && $company_id) {
+ $action = $_POST['action'] ?? '';
+
+ // ADD ACCOUNT
+ if ($action === 'add_account') {
+ $account_code = trim($_POST['account_code'] ?? '');
+ $account_name = trim($_POST['account_name'] ?? '');
+ $account_type = trim($_POST['account_type'] ?? '');
+ $description = trim($_POST['description'] ?? '');
+
+ if (empty($account_code) || empty($account_name) || empty($account_type)) {
+ $errors[] = 'Account Code, Name, and Type are required.';
+ }
+ if (empty($errors)) {
+ $stmt = $pdo->prepare("INSERT INTO chart_of_accounts (company_id, account_code, account_name, account_type, description) VALUES (?, ?, ?, ?, ?)");
+ if ($stmt->execute([$company_id, $account_code, $account_name, $account_type, $description])) {
+ $success_message = 'Account added successfully!';
+ } else {
+ $errors[] = 'Failed to add account. The account code may already exist.';
+ }
+ }
+ }
+
+ // EDIT ACCOUNT
+ if ($action === 'edit_account') {
+ $account_id = $_POST['account_id'] ?? null;
+ $account_code = trim($_POST['account_code'] ?? '');
+ $account_name = trim($_POST['account_name'] ?? '');
+ $account_type = trim($_POST['account_type'] ?? '');
+ $description = trim($_POST['description'] ?? '');
+
+ if (empty($account_id) || empty($account_code) || empty($account_name) || empty($account_type)) {
+ $errors[] = 'All fields are required for editing.';
+ }
+ if (empty($errors)) {
+ $stmt = $pdo->prepare("UPDATE chart_of_accounts SET account_code = ?, account_name = ?, account_type = ?, description = ? WHERE id = ? AND company_id = ?");
+ if ($stmt->execute([$account_code, $account_name, $account_type, $description, $account_id, $company_id])) {
+ $success_message = 'Account updated successfully!';
+ } else {
+ $errors[] = 'Failed to update account. The account code may already exist for another account.';
+ }
+ }
+ }
+
+ // DELETE ACCOUNT
+ if ($action === 'delete_account') {
+ $account_id = $_POST['account_id'] ?? null;
+ if (empty($account_id)) {
+ $errors[] = 'Invalid account for deletion.';
+ }
+ if (empty($errors)) {
+ $stmt = $pdo->prepare("DELETE FROM chart_of_accounts WHERE id = ? AND company_id = ?");
+ if ($stmt->execute([$account_id, $company_id])) {
+ $success_message = 'Account deleted successfully!';
+ } else {
+ $errors[] = 'Failed to delete account.';
+ }
+ }
+ }
+}
+
+// Fetch all accounts for the company
+$accounts = [];
+if ($company_id) {
+ $stmt = $pdo->prepare("SELECT * FROM chart_of_accounts WHERE company_id = ? ORDER BY account_code");
+ $stmt->execute([$company_id]);
+ $accounts = $stmt->fetchAll();
+}
+
+require_once __DIR__ . '/includes/sidebar.php';
+?>
+
+
+
Chart of Accounts
+
+
+
+This is the list of all financial accounts for your company.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | Code |
+ Name |
+ Type |
+ Description |
+ Actions |
+
+
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+
+ |
+
+
+
+
+ | No accounts found. Please add one. |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Are you sure you want to delete this account? This action cannot be undone.
+
+
+
+
+
+
+
+
+
diff --git a/company_setup.php b/company_setup.php
new file mode 100644
index 0000000..c0a86e6
--- /dev/null
+++ b/company_setup.php
@@ -0,0 +1,97 @@
+prepare("SELECT * FROM companies WHERE user_id = ?");
+$stmt->execute([$user_id]);
+$company = $stmt->fetch();
+
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ $name = trim($_POST['name'] ?? '');
+ $address = trim($_POST['address'] ?? '');
+ $currency = trim($_POST['currency'] ?? 'SGD');
+ $gst_number = trim($_POST['gst_number'] ?? '');
+
+ if (empty($name)) {
+ $errors[] = 'Company name is required.';
+ }
+
+ if (empty($errors)) {
+ if ($company) {
+ // Update existing record
+ $stmt = $pdo->prepare("UPDATE companies SET name = ?, address = ?, currency = ?, gst_number = ? WHERE user_id = ?");
+ if ($stmt->execute([$name, $address, $currency, $gst_number, $user_id])) {
+ $success_message = 'Company settings updated successfully!';
+ } else {
+ $errors[] = 'Failed to update settings. Please try again.';
+ }
+ } else {
+ // Insert new record
+ $stmt = $pdo->prepare("INSERT INTO companies (user_id, name, address, currency, gst_number) VALUES (?, ?, ?, ?, ?)");
+ if ($stmt->execute([$user_id, $name, $address, $currency, $gst_number])) {
+ $success_message = 'Company settings saved successfully!';
+ } else {
+ $errors[] = 'Failed to save settings. Please try again.';
+ }
+ }
+ // Refresh company data after update/insert
+ $stmt = $pdo->prepare("SELECT * FROM companies WHERE user_id = ?");
+ $stmt->execute([$user_id]);
+ $company = $stmt->fetch();
+ }
+}
+
+require_once __DIR__ . '/includes/sidebar.php';
+?>
+
+Company Settings
+Use this form to set up or update your company's details. This information will be used on invoices and other official documents.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dashboard.php b/dashboard.php
new file mode 100644
index 0000000..1607a86
--- /dev/null
+++ b/dashboard.php
@@ -0,0 +1,19 @@
+
+
+
+Dashboard
+Welcome, ! This is your main dashboard. From here you can manage all aspects of your business.
+
+
+
+
+
+
Company Setup
+
Before you can start creating invoices or tracking inventory, you need to set up your company details.
+
Go to Company Setup
+
+
+
+
+
+
\ No newline at end of file
diff --git a/db/migrate.php b/db/migrate.php
new file mode 100644
index 0000000..01a585e
--- /dev/null
+++ b/db/migrate.php
@@ -0,0 +1,25 @@
+exec($sql);
+ } catch (PDOException $e) {
+ echo "Error running migration: " . $e->getMessage() . "\n";
+ return false;
+ }
+ }
+ echo "Migrations completed successfully.\n";
+ return true;
+}
+
+run_migrations();
+
diff --git a/db/migrations/001_create_users_table.sql b/db/migrations/001_create_users_table.sql
new file mode 100644
index 0000000..8e9556e
--- /dev/null
+++ b/db/migrations/001_create_users_table.sql
@@ -0,0 +1,10 @@
+
+CREATE TABLE IF NOT EXISTS `users` (
+ `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
+ `name` VARCHAR(255) NOT NULL,
+ `email` VARCHAR(255) NOT NULL,
+ `password` VARCHAR(255) NOT NULL,
+ `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `email` (`email`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
diff --git a/db/migrations/002_create_companies_table.sql b/db/migrations/002_create_companies_table.sql
new file mode 100644
index 0000000..2b6907c
--- /dev/null
+++ b/db/migrations/002_create_companies_table.sql
@@ -0,0 +1,11 @@
+CREATE TABLE IF NOT EXISTS `companies` (
+ `id` INT AUTO_INCREMENT PRIMARY KEY,
+ `user_id` INT UNSIGNED NOT NULL,
+ `name` VARCHAR(255) NOT NULL,
+ `address` TEXT,
+ `currency` VARCHAR(10) DEFAULT 'SGD',
+ `gst_number` VARCHAR(50),
+ `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
\ No newline at end of file
diff --git a/db/migrations/003_create_chart_of_accounts_table.sql b/db/migrations/003_create_chart_of_accounts_table.sql
new file mode 100644
index 0000000..c06f020
--- /dev/null
+++ b/db/migrations/003_create_chart_of_accounts_table.sql
@@ -0,0 +1,12 @@
+CREATE TABLE IF NOT EXISTS `chart_of_accounts` (
+ `id` INT AUTO_INCREMENT PRIMARY KEY,
+ `company_id` INT NOT NULL,
+ `account_code` VARCHAR(20) NOT NULL,
+ `account_name` VARCHAR(255) NOT NULL,
+ `account_type` ENUM('Asset', 'Liability', 'Equity', 'Revenue', 'Expense') NOT NULL,
+ `description` TEXT,
+ `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ UNIQUE KEY `company_account_code` (`company_id`, `account_code`),
+ FOREIGN KEY (`company_id`) REFERENCES `companies`(`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
\ No newline at end of file
diff --git a/db/migrations/004_create_customers_table.sql b/db/migrations/004_create_customers_table.sql
new file mode 100644
index 0000000..4eafc90
--- /dev/null
+++ b/db/migrations/004_create_customers_table.sql
@@ -0,0 +1,11 @@
+CREATE TABLE IF NOT EXISTS `customers` (
+ `id` INT AUTO_INCREMENT PRIMARY KEY,
+ `company_id` INT NOT NULL,
+ `name` VARCHAR(255) NOT NULL,
+ `email` VARCHAR(255),
+ `phone` VARCHAR(50),
+ `address` TEXT,
+ `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ FOREIGN KEY (`company_id`) REFERENCES `companies`(`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
\ No newline at end of file
diff --git a/db/setup_db.php b/db/setup_db.php
new file mode 100644
index 0000000..0ba1ba0
--- /dev/null
+++ b/db/setup_db.php
@@ -0,0 +1,17 @@
+ PDO::ERRMODE_EXCEPTION,
+ ]);
+
+ // Create the database if it doesn't exist
+ $pdo->exec("CREATE DATABASE IF NOT EXISTS `" . DB_NAME . "`");
+ echo "Database '" . DB_NAME . "' created or already exists.\n";
+
+} catch (PDOException $e) {
+ die("DB ERROR: " . $e->getMessage());
+}
+
diff --git a/includes/footer.php b/includes/footer.php
new file mode 100644
index 0000000..ebd9c06
--- /dev/null
+++ b/includes/footer.php
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+