Commit Graph
121 Commits
Author SHA1 Message Date
Thanakorn 4797830a5d Add Word rendering of the SDLC delivery package 2026-09-11 16:47:46 +07:00
Thanakorn 4462a972ad docs(sdlc): correct header CI to the reference measurements 2026-09-09 14:11:27 +07:00
Thanakorn 6255b31591 docs(sdlc): match reference PDF layout and company CI 2026-09-09 13:54:45 +07:00
Thanakorn 087e7b3958 docs(sdlc): reformat work products to audited reference layout
Replace the PHP/Markdown seeding with a data-driven generator in
scripts/sdlc-seed and regenerate all 59 work products.
2026-09-09 08:09:54 +07:00
Thanakorn 758922f5c4 docs(delivery): rebuild final SDLC package 2026-08-26 13:17:58 +07:00
Thanakorn c4d3c6ea9e docs(sdlc): close training and operational actions 2026-08-26 13:10:06 +07:00
Thanakorn 5d93e87771 docs(sdlc): finalize ISO 29110 evidence package 2026-08-26 12:35:57 +07:00
ThanakornandClaude Opus 5 c68a43449f docs(sdlc): regenerate delivery package
Rebuild all 46 delivery PDFs from the sdlc/ sources so the package
matches the V1.0 audit evidence alignment in 02e1483. Work Schedule
and Software Project Plan pick up the V1.1 -> V1.0 rename; the
remaining files differ only by render metadata.

Verification: content coverage 46/46, all A4 portrait/landscape.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 14:14:07 +07:00
Thanakorn 02e1483087 docs(sdlc): align V1.0 audit evidence 2026-08-19 14:11:00 +07:00
ThanakornandClaude Opus 5 36ab46b9d1 Fix SDLC delivery rendering and regenerate package
Nine layout defects were fixed in the generator so the delivery package is
reproducible from `scripts/build-sdlc-delivery.sh`.

CSS (scripts/sdlc-delivery/assets/sdlc-delivery.css):
- table-layout: fixed -> auto, so columns fit their content instead of each
  taking an equal share of the page width
- overflow-wrap: anywhere -> break-word, removing mid-word breaks such as
  "Representativ|es" and "communicati|on"
- break-inside: avoid on cells; text-align: left on th so headers match body
- new .a-right/.a-center/.tight column classes; ul/ol/li and code rules
- trimmed padding: @page bottom 28->20mm, h2 9->6mm, h3 6->4mm, cells
  2->1.6mm, .approval-fields; .document-control th shrinks to its label

Renderer (scripts/sdlc-delivery/render-sdlc.mjs):
- ordered lists emit <ol> instead of collapsing into a run-on paragraph
- column alignment read from the Markdown separator row (:---, ---:, :---:)
- columns whose longest cell is <= 12 chars marked "tight" to shrink to content
- underscore runs become styled signature rules
- each signatory's heading and fields wrapped so they cannot split across pages
- backslash escapes such as \* are unescaped

Regenerated sdlc-delivery/ with the fixed pipeline: 46 PDFs, 163 pages, both
content-coverage and A4-format verification passing. Work Schedule 14 -> 9
pages, Correction Register 11 -> 10, Acceptance Report 7 -> 6. The four
Meeting Records are included for the first time, and PDFs for renamed sources
follow their new paths.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 10:18:32 +07:00
Thanakorn 155cf783ae SDLC docs feedback and additional adjustment 2026-08-19 10:02:21 +07:00
Thanakorn 6dc8444139 SDLC delivery package 2026-08-18 13:22:26 +07:00
Thanakorn d0e727f107 SDLC docs package delivery script 2026-08-18 12:38:15 +07:00
Thanakorn d8868bd6b6 SDLC docs alignment 2026-08-18 12:37:28 +07:00
Thanakorn f4eccacbc2 Hand off 2026-08-17 17:12:34 +07:00
Thanakorn a71366ec9f SDLC docs 2026-08-17 17:09:27 +07:00
Thanakorn 6c39700d74 Add interactive script to generate root .env for docker-compose
Prompts for DB password, public host, EMIT_SECRET, and SMTP creds,
auto-generating secrets where left blank, instead of hand-editing
.env.example.
2026-08-17 13:50:03 +07:00
Thanakorn 136084f259 Add Docker Compose production stack (php-apache, mariadb, node/pm2)
Single-command deploy: docker compose up -d --build brings up the LEMP
stack plus the Node realtime/scheduler service. app/config.php and DB
secrets are generated from .env at container start, never baked into
the image or committed.
2026-08-17 13:44:14 +07:00
Thanakorn 63cea23dc4 Seed Demo Data - Rebranding 2026-08-17 13:12:07 +07:00
Thanakorn dd48a8b96d Demo Data Population 2026-08-14 14:10:31 +07:00
nok b2c437426b fix login and configurations 2026-08-03 11:17:41 +07:00
Thanakorn S a0677d6d8d Classe methods: remove reducdancy 2026-05-29 08:56:58 +07:00
Thanakorn SandClaude Sonnet 4.6 ed3dd2f215 Fix horizontal scrollbar caused by sidebar margin overflowing viewport
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 16:58:15 +07:00
Thanakorn SandClaude Sonnet 4.6 fda211b1a8 Block concurrent login: reject new session if account already active
If session_token is set and session_last_seen is within the last hour,
the incoming login is rejected with a clear message. Stale sessions
(idle > 1 h) and explicit logouts (token = NULL via back.php) still allow
re-login normally.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 16:21:55 +07:00
Thanakorn S 9a50238347 Scope stock table access by company warehouses 2026-05-28 15:36:49 +07:00
Thanakorn SandClaude Sonnet 4.6 5df67367fa Fix incomplete Rack→Bin rename: missing file renames, stale UI labels, ReportManager property bug
- Rename rack_log.php → bin_log.php and rack_occupancy.php → bin_occupancy.php
  (occupy_rack.php was already calling bin_*.php, causing 404 on every load)
- Fix occupy_rack.php: page title, stat card label (add id="stat_label_bins"),
  section headings, and <th> column headers still read "Rack/Racks"
- Fix ReportManager: constructor wrote to $this->companyId (dynamic property)
  instead of the declared $this->company_id, causing all queries to filter on
  company_id = 0 under strict PHP 8.2+ property semantics

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 09:53:19 +07:00
Thanakorn S 8f57ab5570 Change 'Rack' to 'Bin' 2026-05-27 17:14:53 +07:00
Thanakorn SandClaude Sonnet 4.6 b8798bc02d Wire targeted toast notifications to document status transitions
Adds emit_notification_user() to 7 endpoints so the acting user and
all admins/owners receive a real-time toast on key document actions:
confirm/cancel order, issue/void invoice, confirm return, confirm PO,
receive PO goods. Other staff and viewers are not notified.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 13:44:55 +07:00
Thanakorn S bbe89b0380 notify node: userIDguard 2026-05-27 13:12:18 +07:00
Thanakorn S 714b70d552 NODEJS cron fix 2026-05-27 12:05:29 +07:00
Thanakorn S f3c0e3c876 fix NodeJS cron 2026-05-27 11:56:40 +07:00
Thanakorn S a6651c41b9 cron low stock - overdue invoice 2026-05-27 11:45:48 +07:00
Thanakorn S 458a883810 CORS whitelist for NodeJS 2026-05-27 11:26:40 +07:00
Thanakorn S 5221b3a1a1 nodejs status check 2026-05-27 11:18:09 +07:00
Thanakorn S 418dbf9ba6 autostart node process 2026-05-27 11:07:30 +07:00
Thanakorn S 99ae35dc98 all .md reviewed - fix remaining gaps 2026-05-27 10:42:44 +07:00
Thanakorn S 1f371c6f94 add missing roleGuards 2026-05-27 09:19:52 +07:00
Thanakorn SandClaude Sonnet 4.6 d7f104ff25 Stop tracking docs/ — already in .gitignore
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 08:15:29 +07:00
Thanakorn SandClaude Sonnet 4.6 dfeb57533a Master data review: spec updates and C1/C2/M3-M6 fixes
Spec (docs/reviewing/master-data.md):
- M1: Remove margin from stored product fields (it's a derived frontend value)
- M2: Clarify posting window only restricts transaction dates, not master data
- M5: Document AccountFormulaManager::delete() as archive, not physical delete

Code:
- C1: Fix CompanySettingManager property typo (company_id → companyId) —
  prevented PHP 8.4 dynamic property fatal on all posting window operations
- C2: Fix WarehouseManager::deleteWarehouse() guard — was comparing
  warehouse_name (string) against warehouse id column (no-op); now correctly
  blocks on storage rows and active stock rows
- M3: Remove hard-delete of td_rack_log in deleteStorage() — retain rack
  history consistent with soft-delete philosophy elsewhere
- M4: Add reference guards to ChartOfAccounts::delete() (blocks on GL items,
  formula items, product account mappings) and DepartmentManager::delete()
  (blocks on GL items)
- M6: Fix CompanySettingManager::handle() partial update — only upsert keys
  present in the request, not all allowed keys defaulted

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 17:33:58 +07:00
Thanakorn SandClaude Sonnet 4.6 cb36d3b8fd Document lifecycle review: spec updates and C2/M9 code fixes
Spec (docs/reviewed/document-lifecycle.md):
- C1: Correct GlManager::delete() description — reversal entry, not hard delete
- C3: Clarify PO status 2/3 are derived (receipt_status), never stored
- C4: Add invoice status=2 (Paid/Settled) to status table
- C5: Add full Receipt/Payment Billing Note lifecycle section
- C6: Add Quotation status table and transition rules
- C7: Document soft-delete tombstone mechanism (company_id negation)

Code (InvoiceManager.php):
- C2: voidInvoice() now blocks on active credit notes, posted receipt
  billing notes, and posted payment billing notes in addition to the
  existing receipt/payment checks
- M9: softDelete() skips assertPostingWindow for draft invoices (status=0)
  since drafts have no GL entry and no accounting impact

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 16:23:46 +07:00
Thanakorn S 5687b562fb system notification 2026-05-26 13:26:57 +07:00
Thanakorn S d93abb0b81 Seal transaction limit coverage gaps 2026-05-26 13:10:54 +07:00
Thanakorn SandClaude Sonnet 4.6 b4b1f5cbec Security hardening: invited user onboarding flow (C1–N7)
- C1: verify.php now filters license='owner' — invite tokens no longer accepted
- C1: onboarding API rejects non-owner sessions
- C2: Existing-user invite requires explicit acceptance via accept_invite.php
- C2: New accept_invite.php page and API engine added
- C2: inviteUser() generates token + expiry for existing users; resendInvite() handles active users
- C3: session_regenerate_id(true) before writing invite session keys on both invite pages
- C4: invited_onboarding API wraps activation in transaction with SELECT FOR UPDATE; rowCount check added; SQLSTATE 23000 caught cleanly
- C5: inviteUser() and resendInvite() two-table writes wrapped in transactions
- M2: removeUser() wrapped in transaction with FOR UPDATE; clears default_company on active user removal
- M4: Logged-in user guard added to invited_onboarding.php and accept_invite.php
- M5: manage_users.php uses $server_url instead of HTTP_HOST for invite URLs
- M6: Username regex enforces 3-32 chars; reserved name blocklist added
- N5: searchUsers() changed from LIKE fuzzy search to exact email match only
- N7: resendInvite() rate-limited to once per 60s via invite_resent_at column
- Schema: company_map_user gains invite_expires_at and invite_resent_at columns

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 10:18:40 +07:00
Thanakorn S 1904fea84c document number sequence 2026-05-26 08:19:40 +07:00
Thanakorn S 4f884177a5 Seal live dashboard event gaps 2026-05-25 17:02:52 +07:00
Thanakorn S 4733c78ac6 Close login gap 2026-05-25 15:34:12 +07:00
Thanakorn S 9b41c0a73a PHP event trigger by NodeJS [stock dashboard] 2026-05-25 14:33:36 +07:00
Thanakorn S ba96de50a1 stock aggregate table 2026-05-25 13:30:10 +07:00
Thanakorn S 293097363b login/ block concurrent login, allow single factor authen for staff and viewer 2026-05-25 09:43:30 +07:00
Thanakorn SandClaude Sonnet 4.6 b07882e3f4 code audit fixes: require_once, issue flow, role guards
- Upgraded all plain `require` to `require_once` across 172 api/engine
  and api/engine_report files to prevent class-redeclaration errors
- Added issue button, issue_invoice() with GL toastr, and delete_invoice()
  to expense/manage_purchase_invoice.php, bringing it in line with
  po/manage_purchase_invoice.php
- Added can_delete role guard (admin/owner only) to trash icons on
  revenue/invoice.php and expense/purchase_invoice.php, matching the
  existing pattern in finance/receipt.php and finance/payment.php

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 17:06:08 +07:00