diff --git a/CLAUDE.md b/CLAUDE.md
index 4c0f108..994f8ea 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -58,7 +58,7 @@ node apps/hq/dist/server.cjs # first boot on an empty data/ prints a one-ti
cd apps/hq-web && npm run dev
```
-- Owner login on first boot: `admin@tecnostac.com` + the one-time password printed in the
+- Owner login on first boot: `admin@sims.com` + the one-time password printed in the
server log (change it immediately). The "Gmail disconnected" banner is expected until Gmail is connected.
- Env: `DATABASE_URL` (set → Postgres engine, absent → SQLite at `HQ_DATA_DIR`; D19),
`SIMS_PIN_PEPPER` (set once, never change), `GOOGLE_*` (Gmail), `AWS_*` (Cost Explorer),
diff --git a/README.md b/README.md
index fbd59a4..d634ff0 100644
--- a/README.md
+++ b/README.md
@@ -88,7 +88,7 @@ npm install # from the repo root (workspaces: packages/*, ap
npm run build --workspace @sims/hq
node apps/hq/dist/server.cjs # serves :5182 (API, built web UI, /share/:token)
# First boot on an empty data/ creates data/hq.db and prints a one-time owner
-# password — capture it. Log in as admin@tecnostac.com, then change it.
+# password — capture it. Log in as admin@sims.com, then change it.
# Frontend — hq-web dev server (Vite on :5183, proxies /api and /share to :5182)
cd apps/hq-web && npm run dev
diff --git a/apps/hq/scripts/demo-seed.ts b/apps/hq/scripts/demo-seed.ts
index 9998471..f2dfe24 100644
--- a/apps/hq/scripts/demo-seed.ts
+++ b/apps/hq/scripts/demo-seed.ts
@@ -1,5 +1,5 @@
/**
- * Demo seed — populates a fresh HQ_DATA_DIR with a realistic Tecnostac dataset so the
+ * Demo seed — populates a fresh HQ_DATA_DIR with a realistic SiMS dataset so the
* app can be shown with live screens. Run: HQ_DATA_DIR=
npx tsx scripts/demo-seed.ts
* Not shipped; a presentation helper.
*/
@@ -17,7 +17,7 @@ void (async () => {
const db = openDb(process.env['HQ_DATA_DIR'])
// Known owner so we can log in for screenshots (before seedIfEmpty, so it skips its own).
- await createStaff(db, { email: 'owner@tecnostac.com', displayName: 'Thomas (Owner)', role: 'owner', password: 'demo-owner-2026' })
+ await createStaff(db, { email: 'owner@sims.com', displayName: 'Thomas (Owner)', role: 'owner', password: 'demo-owner-2026' })
await seedIfEmpty(db)
const U = 'demo'
@@ -28,20 +28,20 @@ void (async () => {
// Company + template letterhead data (what the Document Template page edits).
const settings: Record = {
- 'company.name': 'Tecnostac Solutions Pvt Ltd',
+ 'company.name': 'SiMS Solutions Pvt Ltd',
'company.address': '2nd Floor, Cyber Park, Kakkanad, Kochi, Kerala 682030',
'company.gstin': '32ABCDE1234F1Z9',
'company.state_code': '32',
'company.phone': '+91 98470 12345',
- 'company.email': 'accounts@tecnostac.com',
+ 'company.email': 'accounts@sims.com',
'company.bank': 'HDFC Bank · A/c 50200012345678 · IFSC HDFC0001234 · Kakkanad',
'template.accent': '#1e3a5f',
'template.logo': LOGO,
'template.terms': '1. Prices are valid for 15 days from the date of this quotation.\n2. 50% advance on confirmation, balance before go-live.\n3. Annual subscription renews on the anniversary of activation.',
'template.declaration': 'We declare that this invoice shows the actual price of the services described and that all particulars are true and correct.',
'template.jurisdiction': 'Subject to Ernakulam jurisdiction',
- 'template.footer_note': 'Thank you for your business. For support: support@tecnostac.com · +91 98470 12345',
- 'template.signatory_label': 'For Tecnostac Solutions Pvt Ltd',
+ 'template.footer_note': 'Thank you for your business. For support: support@sims.com · +91 98470 12345',
+ 'template.signatory_label': 'For SiMS Solutions Pvt Ltd',
}
for (const [k, v] of Object.entries(settings)) await setSetting(db, U, k, v)
@@ -100,7 +100,7 @@ void (async () => {
const shareToken = ((await db.get<{ token: string }>(`SELECT token FROM document_share LIMIT 1`))!).token
console.log('DEMO_READY')
- console.log('login: owner@tecnostac.com / demo-owner-2026')
+ console.log('login: owner@sims.com / demo-owner-2026')
console.log('quotation_id:', qtIssued.id, 'doc_no:', qtIssued.docNo)
console.log('invoice_id:', inv1.id, 'doc_no:', inv1.docNo)
console.log('share_token:', shareToken)
diff --git a/apps/hq/src/seed.ts b/apps/hq/src/seed.ts
index b8d75dc..8aac5b2 100644
--- a/apps/hq/src/seed.ts
+++ b/apps/hq/src/seed.ts
@@ -15,7 +15,7 @@ import { SCHEDULE_DEFAULTS, type ScheduleRuleKind } from './repos-reminders'
const OWNER_EMAIL = process.env['HQ_OWNER_EMAIL']?.trim() || 'simssoftware13@gmail.com'
const SETTING_DEFAULTS: Record = {
- 'company.name': 'Tecnostac',
+ 'company.name': 'SiMS',
'company.address': '',
'company.gstin': '',
'company.state_code': '32', // Kerala — founder to confirm
diff --git a/apps/hq/test/auth.test.ts b/apps/hq/test/auth.test.ts
index 72a44b9..ccded21 100644
--- a/apps/hq/test/auth.test.ts
+++ b/apps/hq/test/auth.test.ts
@@ -6,9 +6,9 @@ import { createStaff, login, verifySession } from '../src/auth'
describe('hq auth', () => {
it('logs in with correct password, rejects wrong one', async () => {
const db = openDb(':memory:')
- await createStaff(db, { email: 'admin@tecnostac.com', displayName: 'Owner', role: 'owner', password: 'let-me-in-9' })
- expect(await login(db, 'admin@tecnostac.com', 'wrong')).toMatchObject({ ok: false, reason: 'invalid' })
- const ok = await login(db, 'admin@tecnostac.com', 'let-me-in-9')
+ await createStaff(db, { email: 'admin@sims.com', displayName: 'Owner', role: 'owner', password: 'let-me-in-9' })
+ expect(await login(db, 'admin@sims.com', 'wrong')).toMatchObject({ ok: false, reason: 'invalid' })
+ const ok = await login(db, 'admin@sims.com', 'let-me-in-9')
expect(ok.ok).toBe(true)
const staff = await verifySession(db, ok.ok ? ok.token : '')
expect(staff).toMatchObject({ role: 'owner' })
diff --git a/apps/hq/test/bounces.test.ts b/apps/hq/test/bounces.test.ts
index f97c8ad..b6ae53e 100644
--- a/apps/hq/test/bounces.test.ts
+++ b/apps/hq/test/bounces.test.ts
@@ -26,7 +26,7 @@ function bounceFetch(recipient: string): typeof fetch {
describe('pollBounces', () => {
it('flips the sent email_log to bounced and raises an email_bounced reminder, idempotently', async () => {
const db = openDb(':memory:'); await seedIfEmpty(db)
- await saveAccount(db, 'us@tecnostac.com', encrypt('rt', KEY))
+ await saveAccount(db, 'us@sims.com', encrypt('rt', KEY))
await logEmail(db, { to: 'ravi@acme.in', subject: 'INV/26-27-0001', status: 'sent', gmailMessageId: 'g1' })
const deps: BounceDeps = {
gmail: { f: bounceFetch('ravi@acme.in'), clientId: 'cid', clientSecret: 'sec', keyHex: KEY },
diff --git a/apps/hq/test/client-owner.test.ts b/apps/hq/test/client-owner.test.ts
index f772b59..11943a3 100644
--- a/apps/hq/test/client-owner.test.ts
+++ b/apps/hq/test/client-owner.test.ts
@@ -17,7 +17,7 @@ import { apiRouter } from '../src/api'
async function withOwner(): Promise<{ db: DB; ownerId: string }> {
const db = openDb(':memory:')
const { id } = await createStaff(db, {
- email: 'admin@tecnostac.com', displayName: 'Owner', role: 'owner', password: 'let-me-in-9',
+ email: 'admin@sims.com', displayName: 'Owner', role: 'owner', password: 'let-me-in-9',
})
return { db, ownerId: id }
}
diff --git a/apps/hq/test/convert-and-send.test.ts b/apps/hq/test/convert-and-send.test.ts
index 71cac34..939197a 100644
--- a/apps/hq/test/convert-and-send.test.ts
+++ b/apps/hq/test/convert-and-send.test.ts
@@ -89,7 +89,7 @@ async function appWith(fetchImpl: typeof fetch) {
const db = openDb(':memory:')
const { c, m } = await base(db)
await createStaff(db, { email: 'owner@test.in', displayName: 'Owner', role: 'owner', password: 'owner-password' })
- await saveAccount(db, 'us@tecnostac.com', encrypt('refresh-token', KEY))
+ await saveAccount(db, 'us@sims.com', encrypt('refresh-token', KEY))
const pi = await issueDocument(db, 'u1', (await createDraft(db, 'u1', {
docType: 'PROFORMA', clientId: c.id, lines: [{ moduleId: m.id, qty: 1, kind: 'yearly' }],
})).id)
diff --git a/apps/hq/test/dashboard.test.ts b/apps/hq/test/dashboard.test.ts
index d293ba1..a995061 100644
--- a/apps/hq/test/dashboard.test.ts
+++ b/apps/hq/test/dashboard.test.ts
@@ -14,7 +14,7 @@ import { runDailyScan, type ScanDeps } from '../src/scheduler'
const scanDeps: ScanDeps = {
gmail: { f: (async () => new Response('{}')) as typeof fetch, clientId: '', clientSecret: '', keyHex: '' },
- renderPdf: async () => Buffer.from('%PDF-'), company: () => ({ 'company.name': 'Tecnostac' }), now: () => '2026-07-10T00:00:00Z',
+ renderPdf: async () => Buffer.from('%PDF-'), company: () => ({ 'company.name': 'SiMS' }), now: () => '2026-07-10T00:00:00Z',
}
async function seeded() {
diff --git a/apps/hq/test/due-dates.test.ts b/apps/hq/test/due-dates.test.ts
index df160a6..9384f2c 100644
--- a/apps/hq/test/due-dates.test.ts
+++ b/apps/hq/test/due-dates.test.ts
@@ -13,7 +13,7 @@ import { runDailyScan, type ScanDeps } from '../src/scheduler'
const deps: ScanDeps = {
gmail: { f: (async () => new Response('{}')) as typeof fetch, clientId: '', clientSecret: '', keyHex: '' },
- renderPdf: async () => Buffer.from('%PDF-'), company: () => ({ 'company.name': 'Tecnostac' }),
+ renderPdf: async () => Buffer.from('%PDF-'), company: () => ({ 'company.name': 'SiMS' }),
now: () => '2026-07-17T00:00:00Z',
}
@@ -122,7 +122,7 @@ describe('due dates (D18)', () => {
const inv = await issueDocument(db, 'u1', (await invoiceDraft()).id)
await db.run(`UPDATE document SET due_date='2026-07-02' WHERE id=?`, inv.id)
const { id } = await upsertReminder(db, { ruleKind: 'invoice_overdue', subjectId: inv.id, duePeriod: 'd15', clientId: c.id, docId: inv.id, now: '2026-07-17T00:00:00Z' })
- const { ctx } = await reminderContext(db, (await getReminder(db, id))!, 'Tecnostac', '2026-07-17')
+ const { ctx } = await reminderContext(db, (await getReminder(db, id))!, 'SiMS', '2026-07-17')
expect(ctx.dueDate).toBe('2026-07-02')
expect(ctx.daysOverdue).toBe(15)
expect(reminderEmail('invoice_overdue', ctx).bodyText).toMatch(/was due on 2026-07-02 and is now 15 day\(s\) overdue/)
@@ -133,7 +133,7 @@ describe('due dates (D18)', () => {
const inv = await issueDocument(db, 'u1', (await invoiceDraft()).id)
await db.run(`UPDATE document SET doc_date='2026-07-07', due_date=NULL WHERE id=?`, inv.id)
const { id } = await upsertReminder(db, { ruleKind: 'invoice_overdue', subjectId: inv.id, duePeriod: 'd7', clientId: c.id, docId: inv.id, now: '2026-07-17T00:00:00Z' })
- const { ctx } = await reminderContext(db, (await getReminder(db, id))!, 'Tecnostac', '2026-07-17')
+ const { ctx } = await reminderContext(db, (await getReminder(db, id))!, 'SiMS', '2026-07-17')
expect(ctx.dueDate).toBeUndefined()
expect(reminderEmail('invoice_overdue', ctx).bodyText).toMatch(/is outstanding and is now 10 day\(s\) past due/)
})
diff --git a/apps/hq/test/employees.test.ts b/apps/hq/test/employees.test.ts
index fd20cf1..f7479f0 100644
--- a/apps/hq/test/employees.test.ts
+++ b/apps/hq/test/employees.test.ts
@@ -12,7 +12,7 @@ import { listAudit } from '../src/audit'
async function withOwner(): Promise<{ db: DB; ownerId: string }> {
const db = openDb(':memory:')
const { id } = await createStaff(db, {
- email: 'admin@tecnostac.com', displayName: 'Owner', role: 'owner', password: 'let-me-in-9',
+ email: 'admin@sims.com', displayName: 'Owner', role: 'owner', password: 'let-me-in-9',
})
return { db, ownerId: id }
}
diff --git a/apps/hq/test/module-roster.test.ts b/apps/hq/test/module-roster.test.ts
index df1cb04..3cb3109 100644
--- a/apps/hq/test/module-roster.test.ts
+++ b/apps/hq/test/module-roster.test.ts
@@ -94,7 +94,7 @@ async function appWith(fetchImpl: typeof fetch) {
const { db, m, mkClient } = await world()
await createStaff(db, { email: 'owner@test.in', displayName: 'Owner', role: 'owner', password: 'owner-password' })
await createStaff(db, { email: 'staff@test.in', displayName: 'Staff', role: 'staff', password: 'staff-password' })
- await saveAccount(db, 'us@tecnostac.com', encrypt('refresh-token', KEY))
+ await saveAccount(db, 'us@sims.com', encrypt('refresh-token', KEY))
const withMail = await mkClient('Acme Bank', 'ravi@acme.in')
const noMail = await mkClient('Beta Coop') // no contact email — must be reported, not skipped silently
await assignModule(db, 'u1', { clientId: withMail.id, moduleId: m.id, kind: 'yearly' })
diff --git a/apps/hq/test/preview-sample.test.ts b/apps/hq/test/preview-sample.test.ts
index ffbf044..8a6ef55 100644
--- a/apps/hq/test/preview-sample.test.ts
+++ b/apps/hq/test/preview-sample.test.ts
@@ -17,7 +17,7 @@ const sampleClient = { id: 'c1', code: 'X', name: 'X', stateCode: '32', address:
describe('templates: screen paper styles + documentHtmlSample', () => {
it('documentHtml carries screen-only paper styles (PDF unaffected — print media)', () => {
- expect(documentHtml(sampleDoc, sampleClient, { 'company.name': 'Tecnostac' })).toContain('@media screen')
+ expect(documentHtml(sampleDoc, sampleClient, { 'company.name': 'SiMS' })).toContain('@media screen')
})
it('documentHtmlSample renders letterhead, bank box and given bullets through the one renderer', () => {
const html = documentHtmlSample(
diff --git a/apps/hq/test/quote-followup.test.ts b/apps/hq/test/quote-followup.test.ts
index 4f273b1..64a7ad1 100644
--- a/apps/hq/test/quote-followup.test.ts
+++ b/apps/hq/test/quote-followup.test.ts
@@ -26,13 +26,13 @@ const okFetch = (async (url: string) =>
const deps: ScanDeps & SendReminderDeps = {
gmail: { f: okFetch, clientId: 'cid', clientSecret: 'sec', keyHex: KEY },
renderPdf: async () => Buffer.from('%PDF-fake'),
- company: () => ({ 'company.name': 'Tecnostac' }),
+ company: () => ({ 'company.name': 'SiMS' }),
now: () => '2026-07-10T09:00:00Z',
}
async function world() {
const db = openDb(':memory:'); await seedIfEmpty(db)
- await saveAccount(db, 'us@tecnostac.com', encrypt('refresh-token', KEY))
+ await saveAccount(db, 'us@sims.com', encrypt('refresh-token', KEY))
await setSetting(db, 'u1', 'share.base_url', 'https://hq.example.in') // sends refuse a dead relative link without it
const c = await createClient(db, 'u1', { name: 'Acme', stateCode: '32', contacts: [{ name: 'Ravi', email: 'ravi@acme.in' }] })
const m = await createModule(db, 'u1', { code: 'CBS', name: 'Core Banking' })
@@ -203,9 +203,9 @@ describe('quote_followup context, preview and send', () => {
await runDailyScan(db, deps, '2026-07-04')
const rem = (await followups(db))[0]!
const auditBefore = ((await db.get<{ n: number }>(`SELECT COUNT(*) AS n FROM audit_log`))!).n
- const { ctx } = await reminderContext(db, rem, 'Tecnostac')
+ const { ctx } = await reminderContext(db, rem, 'SiMS')
const mail = reminderEmail('quote_followup', ctx)
- expect(mail.subject).toContain('Tecnostac')
+ expect(mail.subject).toContain('SiMS')
expect(await shareCount(db)).toBe(0) // resolve-only: preview NEVER mints
expect(((await db.get<{ n: number }>(`SELECT COUNT(*) AS n FROM audit_log`))!).n).toBe(auditBefore)
})
@@ -213,7 +213,7 @@ describe('quote_followup context, preview and send', () => {
const { db, c, m } = await world()
const q = await sentQuote(db, c, m, '2026-07-01T09:00:00Z') // never issued: docNo is null (F10)
await runDailyScan(db, deps, '2026-07-04')
- const { ctx } = await reminderContext(db, (await followups(db))[0]!, 'Tecnostac')
+ const { ctx } = await reminderContext(db, (await followups(db))[0]!, 'SiMS')
const mail = reminderEmail('quote_followup', ctx)
expect(mail.subject).not.toContain('null')
expect(mail.bodyText).not.toContain('null')
@@ -225,7 +225,7 @@ describe('quote_followup context, preview and send', () => {
const q = await sentQuote(db, c, m, '2026-07-01T09:00:00Z')
const issued = await issueDocument(db, 'u1', q.id)
await runDailyScan(db, deps, '2026-07-04')
- const { ctx } = await reminderContext(db, (await followups(db))[0]!, 'Tecnostac')
+ const { ctx } = await reminderContext(db, (await followups(db))[0]!, 'SiMS')
expect(reminderEmail('quote_followup', ctx).subject).toContain(issued.docNo!)
})
it('send resolves the dated subject/body on the injected clock, not the wall clock', async () => {
@@ -238,9 +238,9 @@ describe('quote_followup context, preview and send', () => {
await sentQuote(db, c, m, '2026-07-01T09:00:00Z')
await runDailyScan(db, deps, '2026-07-04')
const rem = (await followups(db))[0]!
- const before = await reminderContext(db, rem, 'Tecnostac', '2026-07-10')
+ const before = await reminderContext(db, rem, 'SiMS', '2026-07-10')
expect(reminderEmail('quote_followup', before.ctx).subject).not.toContain('FUTURE')
- const after = await reminderContext(db, rem, 'Tecnostac', '2026-07-11')
+ const after = await reminderContext(db, rem, 'SiMS', '2026-07-11')
expect(reminderEmail('quote_followup', after.ctx).subject).toContain('FUTURE')
})
it('refuses to send when share.base_url is unset — loud error, NO share minted, row still queued', async () => {
@@ -284,7 +284,7 @@ describe('quote_followup context, preview and send', () => {
expect(out).toEqual({ ok: true })
expect(await shareCount(db)).toBe(1)
// The sent body carries a live share link.
- const { ctx } = await reminderContext(db, (await getReminder(db, first.id))!, 'Tecnostac')
+ const { ctx } = await reminderContext(db, (await getReminder(db, first.id))!, 'SiMS')
expect(reminderEmail('quote_followup', ctx).bodyText).toContain('/share/')
await runDailyScan(db, deps, '2026-07-08') // d7
const second = (await followups(db)).find((r) => r.duePeriod === 'd7')!
diff --git a/apps/hq/test/receipt.test.ts b/apps/hq/test/receipt.test.ts
index cb6e289..d4572e7 100644
--- a/apps/hq/test/receipt.test.ts
+++ b/apps/hq/test/receipt.test.ts
@@ -45,7 +45,7 @@ describe('payment receipts', () => {
it('renders a receipt acknowledgment (no SAC/GST table)', async () => {
const { db, c, inv } = await setup()
const out = await recordPayment(db, 'u1', { clientId: c.id, receivedOn: '2026-07-10', mode: 'bank', amountPaise: 11_800_00, allocations: [{ documentId: inv.id, amountPaise: 11_800_00 }], issueReceipt: true })
- const html = documentHtml(out.receipt!, c, { 'company.name': 'Tecnostac' })
+ const html = documentHtml(out.receipt!, c, { 'company.name': 'SiMS' })
expect(html).toContain('RECEIPT')
expect(html).toContain('Received with thanks')
expect(html).not.toContain('>SAC<') // the GST line table header is absent on receipts
diff --git a/apps/hq/test/reminder-preview.test.ts b/apps/hq/test/reminder-preview.test.ts
index 547f23c..7e6efc6 100644
--- a/apps/hq/test/reminder-preview.test.ts
+++ b/apps/hq/test/reminder-preview.test.ts
@@ -11,7 +11,7 @@ import { upsertReminder } from '../src/repos-reminders'
import { apiRouter } from '../src/api'
async function appWith() {
- const db = openDb(':memory:'); await seedIfEmpty(db) // company.name='Tecnostac'
+ const db = openDb(':memory:'); await seedIfEmpty(db) // company.name='SiMS'
await createStaff(db, { email: 'owner@test.in', displayName: 'Owner', role: 'owner', password: 'owner-password' })
const c = await createClient(db, 'u1', { name: 'Acme', code: 'ACME', stateCode: '32', contacts: [{ name: 'Ravi', email: 'ravi@acme.in' }] })
const m = await createModule(db, 'u1', { code: 'POS', name: 'POS' })
@@ -40,8 +40,8 @@ describe('GET /reminders/:id/preview', () => {
const token = await login()
const r = await get(token, ctx.overdueId)
expect(r.status).toBe(200)
- expect(r.json.subject).toContain(ctx.inv.docNo) // 'Payment reminder — Invoice INV/26-27-0001 (Tecnostac)'
- expect(r.json.subject).toContain('Tecnostac')
+ expect(r.json.subject).toContain(ctx.inv.docNo) // 'Payment reminder — Invoice INV/26-27-0001 (SiMS)'
+ expect(r.json.subject).toContain('SiMS')
expect(r.json.body).toContain('Acme') // clientName
})
it('404s an unknown reminder and 400s an internal follow_up', async () => {
diff --git a/apps/hq/test/reminders-page.test.ts b/apps/hq/test/reminders-page.test.ts
index bbec794..2e5e2d0 100644
--- a/apps/hq/test/reminders-page.test.ts
+++ b/apps/hq/test/reminders-page.test.ts
@@ -23,13 +23,13 @@ const okFetch = (async (url: string) =>
const deps: ScanDeps & SendReminderDeps = {
gmail: { f: okFetch, clientId: 'cid', clientSecret: 'sec', keyHex: KEY },
renderPdf: async () => Buffer.from('%PDF-fake'),
- company: () => ({ 'company.name': 'Tecnostac' }),
+ company: () => ({ 'company.name': 'SiMS' }),
now: () => '2026-07-10T09:00:00Z',
}
async function world() {
const db = openDb(':memory:'); await seedIfEmpty(db)
- await saveAccount(db, 'us@tecnostac.com', encrypt('refresh-token', KEY))
+ await saveAccount(db, 'us@sims.com', encrypt('refresh-token', KEY))
await setSetting(db, 'u1', 'share.base_url', 'https://hq.example.in')
const c = await createClient(db, 'u1', { name: 'Acme', stateCode: '32', contacts: [{ name: 'Ravi', email: 'ravi@acme.in' }] })
const m = await createModule(db, 'u1', { code: 'CBS', name: 'Core Banking' })
diff --git a/apps/hq/test/reminders.test.ts b/apps/hq/test/reminders.test.ts
index 7535bc6..bb068a0 100644
--- a/apps/hq/test/reminders.test.ts
+++ b/apps/hq/test/reminders.test.ts
@@ -9,7 +9,7 @@ import {
describe('reminder templates', () => {
it('renders an overdue dunning email with the amount and a polite tone', () => {
const mail = reminderEmail('invoice_overdue', {
- clientName: 'Malabar Stores', companyName: 'Tecnostac',
+ clientName: 'Malabar Stores', companyName: 'SiMS',
docNo: 'INV/26-27-0007', amountPaise: 11_800_00, daysOverdue: 12,
})
expect(mail.subject).toContain('INV/26-27-0007')
diff --git a/apps/hq/test/scheduler-recurring.test.ts b/apps/hq/test/scheduler-recurring.test.ts
index 59ca450..d3f0ba7 100644
--- a/apps/hq/test/scheduler-recurring.test.ts
+++ b/apps/hq/test/scheduler-recurring.test.ts
@@ -17,12 +17,12 @@ const okFetch = (async (url: string) =>
const deadFetch = (async () => new Response(JSON.stringify({ error: 'invalid_grant' }), { status: 400 })) as typeof fetch
function deps(f: typeof fetch): ScanDeps {
- return { gmail: { f, clientId: 'cid', clientSecret: 'sec', keyHex: KEY }, renderPdf: async () => Buffer.from('%PDF-'), company: () => ({ 'company.name': 'Tecnostac' }), now: () => '2026-07-10T00:00:00Z' }
+ return { gmail: { f, clientId: 'cid', clientSecret: 'sec', keyHex: KEY }, renderPdf: async () => Buffer.from('%PDF-'), company: () => ({ 'company.name': 'SiMS' }), now: () => '2026-07-10T00:00:00Z' }
}
async function world() {
const db = openDb(':memory:'); await seedIfEmpty(db)
- await saveAccount(db, 'us@tecnostac.com', encrypt('rt', KEY))
+ await saveAccount(db, 'us@sims.com', encrypt('rt', KEY))
const c = await createClient(db, 'u1', { name: 'Acme', stateCode: '32', contacts: [{ name: 'R', email: 'r@acme.in' }] })
const m = await createModule(db, 'u1', { code: 'CLOUD', name: 'Cloud', allowedKinds: ['monthly'] })
await setPrice(db, 'u1', { moduleId: m.id, kind: 'monthly', pricePaise: 2_000_00, effectiveFrom: '2026-01-01' })
diff --git a/apps/hq/test/scheduler-scan.test.ts b/apps/hq/test/scheduler-scan.test.ts
index 45b6498..9b790e4 100644
--- a/apps/hq/test/scheduler-scan.test.ts
+++ b/apps/hq/test/scheduler-scan.test.ts
@@ -14,7 +14,7 @@ import { runDailyScan, type ScanDeps } from '../src/scheduler'
const deps: ScanDeps = {
gmail: { f: (async () => new Response('{}')) as typeof fetch, clientId: '', clientSecret: '', keyHex: '' },
- renderPdf: async () => Buffer.from('%PDF-'), company: () => ({ 'company.name': 'Tecnostac' }),
+ renderPdf: async () => Buffer.from('%PDF-'), company: () => ({ 'company.name': 'SiMS' }),
now: () => '2026-07-10T00:00:00Z',
}
@@ -112,7 +112,7 @@ describe('invoice_overdue — dN milestone escalation (Phase 9, spec §8)', () =
it('the email renders "N day(s) past due" from ctx.daysOverdue', async () => {
const { db, c, inv } = await agedInvoice('2026-06-25') // 15 days before the 10th
const { id } = await upsertReminder(db, { ruleKind: 'invoice_overdue', subjectId: inv.id, duePeriod: 'd15', clientId: c.id, docId: inv.id, now: '2026-07-10T00:00:00Z' })
- const { ctx } = await reminderContext(db, (await getReminder(db, id))!, 'Tecnostac', '2026-07-10')
+ const { ctx } = await reminderContext(db, (await getReminder(db, id))!, 'SiMS', '2026-07-10')
expect(ctx.daysOverdue).toBe(15)
expect(reminderEmail('invoice_overdue', ctx).bodyText).toMatch(/15 day\(s\) past due/)
})
diff --git a/apps/hq/test/send-reminder.test.ts b/apps/hq/test/send-reminder.test.ts
index ef39a99..11f6969 100644
--- a/apps/hq/test/send-reminder.test.ts
+++ b/apps/hq/test/send-reminder.test.ts
@@ -12,7 +12,7 @@ import { sendReminder, type SendReminderDeps } from '../src/send-reminder'
const KEY = '11'.repeat(32)
const fakePdf = async () => Buffer.from('%PDF-fake')
-const company = () => ({ 'company.name': 'Tecnostac' })
+const company = () => ({ 'company.name': 'SiMS' })
function deps(f: typeof fetch): SendReminderDeps {
return { gmail: { f, clientId: 'cid', clientSecret: 'sec', keyHex: KEY }, renderPdf: fakePdf, company, now: () => '2026-07-10T09:00:00Z' }
@@ -20,7 +20,7 @@ function deps(f: typeof fetch): SendReminderDeps {
async function invoiceSetup() {
const db = openDb(':memory:'); await seedIfEmpty(db)
- await saveAccount(db, 'us@tecnostac.com', encrypt('refresh-token', KEY))
+ await saveAccount(db, 'us@sims.com', encrypt('refresh-token', KEY))
const c = await createClient(db, 'u1', { name: 'Acme', stateCode: '32', contacts: [{ name: 'Ravi', email: 'ravi@acme.in' }] })
const m = await createModule(db, 'u1', { code: 'POS', name: 'POS' })
await setPrice(db, 'u1', { moduleId: m.id, kind: 'yearly', pricePaise: 10_000_00, effectiveFrom: '2026-04-01' })
diff --git a/apps/hq/test/settings-company.test.ts b/apps/hq/test/settings-company.test.ts
index 76d3f48..c004591 100644
--- a/apps/hq/test/settings-company.test.ts
+++ b/apps/hq/test/settings-company.test.ts
@@ -30,10 +30,10 @@ describe('company profile settings', () => {
it('owner reads and updates company.* and it is audited', async () => {
const token = await login('owner@test.in', 'owner-password')
const before = await call(token, 'GET', '/settings/company')
- expect(before.json.company['company.name']).toBe('Tecnostac')
- const put = await call(token, 'PUT', '/settings/company', { name: 'Tecnostac Pvt Ltd', phone: '0484-1234567', stateCode: '32' })
+ expect(before.json.company['company.name']).toBe('SiMS')
+ const put = await call(token, 'PUT', '/settings/company', { name: 'SiMS Pvt Ltd', phone: '0484-1234567', stateCode: '32' })
expect(put.status).toBe(200)
- expect(put.json.company['company.name']).toBe('Tecnostac Pvt Ltd')
+ expect(put.json.company['company.name']).toBe('SiMS Pvt Ltd')
expect(put.json.company['company.phone']).toBe('0484-1234567')
const audits = (await ctx.db.get<{ n: number }>(`SELECT COUNT(*) AS n FROM audit_log WHERE entity='setting' AND entity_id LIKE 'company.%'`))!
expect(audits.n).toBeGreaterThanOrEqual(3)
diff --git a/apps/hq/test/settings-template.test.ts b/apps/hq/test/settings-template.test.ts
index 4e8d642..69417c9 100644
--- a/apps/hq/test/settings-template.test.ts
+++ b/apps/hq/test/settings-template.test.ts
@@ -31,7 +31,7 @@ describe('template settings', () => {
it('owner GET returns company.* + template.*; PUT writes template fields + a title, each audited', async () => {
const token = await login('owner@test.in', 'owner-password')
const before = await call(token, 'GET', '/settings/template')
- expect(before.json.settings['company.name']).toBe('Tecnostac')
+ expect(before.json.settings['company.name']).toBe('SiMS')
const put = await call(token, 'PUT', '/settings/template', {
template: { footerNote: 'Thank you!', declaration: 'We declare…', signatoryLabel: 'Proprietor' },
titles: { INVOICE: 'GST INVOICE' },
diff --git a/apps/hq/test/template-accent.test.ts b/apps/hq/test/template-accent.test.ts
index 6ad3b28..47e8800 100644
--- a/apps/hq/test/template-accent.test.ts
+++ b/apps/hq/test/template-accent.test.ts
@@ -14,7 +14,7 @@ const client = { id: 'c1', code: 'CL1', name: 'Acme', stateCode: '32', address:
describe('template.accent (validated hex, single source of truth)', () => {
it('defaults to slate-indigo #334155 when unset', () => {
- const html = documentHtml(base, client, { 'company.name': 'Tecnostac' })
+ const html = documentHtml(base, client, { 'company.name': 'SiMS' })
expect(html).toContain('--accent:#334155')
})
it('applies a valid hex accent verbatim (6- and 3-digit)', () => {
diff --git a/apps/hq/test/template-render.test.ts b/apps/hq/test/template-render.test.ts
index e237139..7de69ad 100644
--- a/apps/hq/test/template-render.test.ts
+++ b/apps/hq/test/template-render.test.ts
@@ -14,7 +14,7 @@ const client = { id: 'c1', code: 'CL1', name: 'Acme', stateCode: '32', address:
describe('template.* rendering (default-fallback)', () => {
it('renders built-in defaults when template.* is unset (nothing breaks pre-config)', () => {
- const html = documentHtml(invoice, client, { 'company.name': 'Tecnostac' })
+ const html = documentHtml(invoice, client, { 'company.name': 'SiMS' })
expect(html).toContain('TAX INVOICE') // built-in title
expect(html).toContain('Authorised Signatory') // built-in signatory label
expect(html).not.toContain('class="declaration"')
@@ -24,7 +24,7 @@ describe('template.* rendering (default-fallback)', () => {
})
it('applies each template.* override where set', () => {
const html = documentHtml(invoice, client, {
- 'company.name': 'Tecnostac',
+ 'company.name': 'SiMS',
'template.title_INVOICE': 'GST INVOICE',
'template.declaration': 'We declare the particulars are true.',
'template.jurisdiction': 'Subject to Kochi jurisdiction',
diff --git a/apps/hq/test/templates.test.ts b/apps/hq/test/templates.test.ts
index feadf4b..df539ba 100644
--- a/apps/hq/test/templates.test.ts
+++ b/apps/hq/test/templates.test.ts
@@ -12,7 +12,7 @@ const doc = {
} as never
const client = { id: 'c1', code: 'CL0001', name: 'Acme', stateCode: '32', address: 'Kochi',
contacts: [], status: 'active', notes: '' } as never
-const company = { 'company.name': 'Tecnostac', 'company.gstin': '', 'company.address': '',
+const company = { 'company.name': 'SiMS', 'company.gstin': '', 'company.address': '',
'company.phone': '', 'company.email': '', 'company.bank': 'HDFC ****1234' }
describe('document html', () => {
diff --git a/docs/DEPLOY-HQ.md b/docs/DEPLOY-HQ.md
index 5e89396..cc1d45f 100644
--- a/docs/DEPLOY-HQ.md
+++ b/docs/DEPLOY-HQ.md
@@ -59,7 +59,7 @@ npm i -g pm2
env $(grep -v '^#' apps/hq/.env | xargs) pm2 start apps/hq/dist/server.cjs --name sims-hq
pm2 save && pm2 startup
```
-Owner login on first boot is `admin@tecnostac.com` + the printed password (change it
+Owner login on first boot is `admin@sims.com` + the printed password (change it
immediately). The Gmail-disconnected banner is expected until step 6.
## 4. Put HTTPS in front (never expose Node directly)
diff --git a/docs/superpowers/plans/2026-07-10-hq1-console.md b/docs/superpowers/plans/2026-07-10-hq1-console.md
index fa5f10c..88037ca 100644
--- a/docs/superpowers/plans/2026-07-10-hq1-console.md
+++ b/docs/superpowers/plans/2026-07-10-hq1-console.md
@@ -411,9 +411,9 @@ import { createStaff, login, verifySession } from '../src/auth'
describe('hq auth', () => {
it('logs in with correct password, rejects wrong one', () => {
const db = openDb(':memory:')
- createStaff(db, { email: 'admin@tecnostac.com', displayName: 'Owner', role: 'owner', password: 'let-me-in-9' })
- expect(login(db, 'admin@tecnostac.com', 'wrong')).toBeNull()
- const ok = login(db, 'admin@tecnostac.com', 'let-me-in-9')
+ createStaff(db, { email: 'admin@sims.com', displayName: 'Owner', role: 'owner', password: 'let-me-in-9' })
+ expect(login(db, 'admin@sims.com', 'wrong')).toBeNull()
+ const ok = login(db, 'admin@sims.com', 'let-me-in-9')
expect(ok).not.toBeNull()
const staff = verifySession(db, ok!.token)
expect(staff).toMatchObject({ role: 'owner' })
@@ -912,7 +912,7 @@ const doc = {
} as never
const client = { id: 'c1', code: 'CL0001', name: 'Acme', stateCode: '32', address: 'Kochi',
contacts: [], status: 'active', notes: '' } as never
-const company = { 'company.name': 'Tecnostac', 'company.gstin': '', 'company.address': '',
+const company = { 'company.name': 'SiMS', 'company.gstin': '', 'company.address': '',
'company.phone': '', 'company.email': '', 'company.bank': 'HDFC ****1234' }
describe('document html', () => {
@@ -1031,7 +1031,7 @@ describe('gmail connect', () => {
**Interfaces:**
- Produces:
- - `seedIfEmpty(db): void` — if no `staff_user`: owner `admin@tecnostac.com` with a random 12-char password **printed to console once**; settings `company.*` placeholders + `company.state_code='32'`; `tax_class` row `('GST18', 1800, '2017-07-01')`.
+ - `seedIfEmpty(db): void` — if no `staff_user`: owner `admin@sims.com` with a random 12-char password **printed to console once**; settings `company.*` placeholders + `company.state_code='32'`; `tax_class` row `('GST18', 1800, '2017-07-01')`.
- `stageCsv(db, kind: 'clients'|'invoices', csvText: string): { staged: number }` — tiny CSV parser (header row, comma, double-quote escaping — ~20 lines, no dependency); per-row problems collected into `problems` JSON: missing name, GSTIN checksum failure, bad date, duplicate code/doc_no.
- `verificationReport(db): { clients: { staged: number; problems: number }; invoices: { staged: number; problems: number; totalPaise: number }; samples: { firstClients: string[]; lastInvoices: string[] } }`
- `commitImport(db, userId): { clients: number; invoices: number; seeded: { fy: string; lastSeq: number } | null }` — inserts clients (`source='apex'`), invoices as issued documents (`source='apex'`, status `paid` when `paid=1` else `sent`, payload lines empty — history-only), then **seeds the INVOICE series**: parse the max numeric tail of current-FY staged doc numbers → `seedSeries(db,'INVOICE', fy, lastSeq)`. Refuses to run when any staged row has problems.
diff --git a/docs/superpowers/plans/2026-07-10-hq2-reminders.md b/docs/superpowers/plans/2026-07-10-hq2-reminders.md
index 079759e..d8fc243 100644
--- a/docs/superpowers/plans/2026-07-10-hq2-reminders.md
+++ b/docs/superpowers/plans/2026-07-10-hq2-reminders.md
@@ -1001,7 +1001,7 @@ import {
describe('reminder templates', () => {
it('renders an overdue dunning email with the amount and a polite tone', () => {
const mail = reminderEmail('invoice_overdue', {
- clientName: 'Malabar Stores', companyName: 'Tecnostac',
+ clientName: 'Malabar Stores', companyName: 'SiMS',
docNo: 'INV/26-27-0007', amountPaise: 11_800_00, daysOverdue: 12,
})
expect(mail.subject).toContain('INV/26-27-0007')
@@ -1302,7 +1302,7 @@ import { sendReminder, type SendReminderDeps } from '../src/send-reminder'
const KEY = '11'.repeat(32)
const fakePdf = async () => Buffer.from('%PDF-fake')
-const company = () => ({ 'company.name': 'Tecnostac' })
+const company = () => ({ 'company.name': 'SiMS' })
function deps(f: typeof fetch): SendReminderDeps {
return { gmail: { f, clientId: 'cid', clientSecret: 'sec', keyHex: KEY }, renderPdf: fakePdf, company, now: () => '2026-07-10T09:00:00Z' }
@@ -1310,7 +1310,7 @@ function deps(f: typeof fetch): SendReminderDeps {
function invoiceSetup() {
const db = openDb(':memory:'); seedIfEmpty(db)
- saveAccount(db, 'us@tecnostac.com', encrypt('refresh-token', KEY))
+ saveAccount(db, 'us@sims.com', encrypt('refresh-token', KEY))
const c = createClient(db, 'u1', { name: 'Acme', stateCode: '32', contacts: [{ name: 'Ravi', email: 'ravi@acme.in' }] })
const m = createModule(db, 'u1', { code: 'POS', name: 'POS' })
setPrice(db, 'u1', { moduleId: m.id, kind: 'yearly', pricePaise: 10_000_00, effectiveFrom: '2026-04-01' })
@@ -1587,7 +1587,7 @@ import { runDailyScan, type ScanDeps } from '../src/scheduler'
const deps: ScanDeps = {
gmail: { f: (async () => new Response('{}')) as typeof fetch, clientId: '', clientSecret: '', keyHex: '' },
- renderPdf: async () => Buffer.from('%PDF-'), company: () => ({ 'company.name': 'Tecnostac' }),
+ renderPdf: async () => Buffer.from('%PDF-'), company: () => ({ 'company.name': 'SiMS' }),
now: () => '2026-07-10T00:00:00Z',
}
@@ -1789,12 +1789,12 @@ const okFetch = (async (url: string) =>
const deadFetch = (async () => new Response(JSON.stringify({ error: 'invalid_grant' }), { status: 400 })) as typeof fetch
function deps(f: typeof fetch): ScanDeps {
- return { gmail: { f, clientId: 'cid', clientSecret: 'sec', keyHex: KEY }, renderPdf: async () => Buffer.from('%PDF-'), company: () => ({ 'company.name': 'Tecnostac' }), now: () => '2026-07-10T00:00:00Z' }
+ return { gmail: { f, clientId: 'cid', clientSecret: 'sec', keyHex: KEY }, renderPdf: async () => Buffer.from('%PDF-'), company: () => ({ 'company.name': 'SiMS' }), now: () => '2026-07-10T00:00:00Z' }
}
function world() {
const db = openDb(':memory:'); seedIfEmpty(db)
- saveAccount(db, 'us@tecnostac.com', encrypt('rt', KEY))
+ saveAccount(db, 'us@sims.com', encrypt('rt', KEY))
const c = createClient(db, 'u1', { name: 'Acme', stateCode: '32', contacts: [{ name: 'R', email: 'r@acme.in' }] })
const m = createModule(db, 'u1', { code: 'CLOUD', name: 'Cloud', allowedKinds: ['monthly'] })
setPrice(db, 'u1', { moduleId: m.id, kind: 'monthly', pricePaise: 2_000_00, effectiveFrom: '2026-01-01' })
@@ -2010,7 +2010,7 @@ function bounceFetch(recipient: string): typeof fetch {
describe('pollBounces', () => {
it('flips the sent email_log to bounced and raises an email_bounced reminder, idempotently', async () => {
const db = openDb(':memory:'); seedIfEmpty(db)
- saveAccount(db, 'us@tecnostac.com', encrypt('rt', KEY))
+ saveAccount(db, 'us@sims.com', encrypt('rt', KEY))
logEmail(db, { to: 'ravi@acme.in', subject: 'INV/26-27-0001', status: 'sent', gmailMessageId: 'g1' })
const deps: BounceDeps = {
gmail: { f: bounceFetch('ravi@acme.in'), clientId: 'cid', clientSecret: 'sec', keyHex: KEY },
@@ -2198,7 +2198,7 @@ import { runDailyScan, type ScanDeps } from '../src/scheduler'
const scanDeps: ScanDeps = {
gmail: { f: (async () => new Response('{}')) as typeof fetch, clientId: '', clientSecret: '', keyHex: '' },
- renderPdf: async () => Buffer.from('%PDF-'), company: () => ({ 'company.name': 'Tecnostac' }), now: () => '2026-07-10T00:00:00Z',
+ renderPdf: async () => Buffer.from('%PDF-'), company: () => ({ 'company.name': 'SiMS' }), now: () => '2026-07-10T00:00:00Z',
}
function seeded() {
diff --git a/docs/superpowers/plans/2026-07-10-hq3a-reports-costs.md b/docs/superpowers/plans/2026-07-10-hq3a-reports-costs.md
index 0089fca..1ad630c 100644
--- a/docs/superpowers/plans/2026-07-10-hq3a-reports-costs.md
+++ b/docs/superpowers/plans/2026-07-10-hq3a-reports-costs.md
@@ -945,7 +945,7 @@ describe('payment receipts', () => {
it('renders a receipt acknowledgment (no SAC/GST table)', () => {
const { db, c, inv } = setup()
const out = recordPayment(db, 'u1', { clientId: c.id, receivedOn: '2026-07-10', mode: 'bank', amountPaise: 11_800_00, allocations: [{ documentId: inv.id, amountPaise: 11_800_00 }], issueReceipt: true })
- const html = documentHtml(out.receipt!, c, { 'company.name': 'Tecnostac' })
+ const html = documentHtml(out.receipt!, c, { 'company.name': 'SiMS' })
expect(html).toContain('RECEIPT')
expect(html).toContain('Received with thanks')
expect(html).not.toContain('>SAC<') // the GST line table header is absent on receipts
@@ -1225,10 +1225,10 @@ describe('company profile settings', () => {
it('owner reads and updates company.* and it is audited', async () => {
const token = await login('owner@test.in', 'owner-password')
const before = await call(token, 'GET', '/settings/company')
- expect(before.json.company['company.name']).toBe('Tecnostac')
- const put = await call(token, 'PUT', '/settings/company', { name: 'Tecnostac Pvt Ltd', phone: '0484-1234567', stateCode: '32' })
+ expect(before.json.company['company.name']).toBe('SiMS')
+ const put = await call(token, 'PUT', '/settings/company', { name: 'SiMS Pvt Ltd', phone: '0484-1234567', stateCode: '32' })
expect(put.status).toBe(200)
- expect(put.json.company['company.name']).toBe('Tecnostac Pvt Ltd')
+ expect(put.json.company['company.name']).toBe('SiMS Pvt Ltd')
expect(put.json.company['company.phone']).toBe('0484-1234567')
const audits = db.prepare(`SELECT COUNT(*) AS n FROM audit_log WHERE entity='setting' AND entity_id LIKE 'company.%'`).get() as { n: number }
expect(audits.n).toBeGreaterThanOrEqual(3)
diff --git a/docs/superpowers/plans/2026-07-13-live-preview.md b/docs/superpowers/plans/2026-07-13-live-preview.md
index 5c079d0..d954147 100644
--- a/docs/superpowers/plans/2026-07-13-live-preview.md
+++ b/docs/superpowers/plans/2026-07-13-live-preview.md
@@ -562,7 +562,7 @@ const client = { id: 'c1', code: 'CL1', name: 'Acme', stateCode: '32', address:
describe('template.* rendering (default-fallback)', () => {
it('renders built-in defaults when template.* is unset (nothing breaks pre-config)', () => {
- const html = documentHtml(invoice, client, { 'company.name': 'Tecnostac' })
+ const html = documentHtml(invoice, client, { 'company.name': 'SiMS' })
expect(html).toContain('TAX INVOICE') // built-in title
expect(html).toContain('Authorised Signatory') // built-in signatory label
expect(html).not.toContain('class="declaration"')
@@ -572,7 +572,7 @@ describe('template.* rendering (default-fallback)', () => {
})
it('applies each template.* override where set', () => {
const html = documentHtml(invoice, client, {
- 'company.name': 'Tecnostac',
+ 'company.name': 'SiMS',
'template.title_INVOICE': 'GST INVOICE',
'template.declaration': 'We declare the particulars are true.',
'template.jurisdiction': 'Subject to Kochi jurisdiction',
@@ -719,7 +719,7 @@ const sampleClient = { id: 'c1', code: 'X', name: 'X', stateCode: '32', address:
describe('templates: screen paper styles + documentHtmlSample', () => {
it('documentHtml carries screen-only paper styles (PDF unaffected — print media)', () => {
- expect(documentHtml(sampleDoc, sampleClient, { 'company.name': 'Tecnostac' })).toContain('@media screen')
+ expect(documentHtml(sampleDoc, sampleClient, { 'company.name': 'SiMS' })).toContain('@media screen')
})
it('documentHtmlSample renders letterhead, bank box and given bullets through the one renderer', () => {
const html = documentHtmlSample(
@@ -950,7 +950,7 @@ describe('template settings', () => {
it('owner GET returns company.* + template.*; PUT writes template fields + a title, each audited', async () => {
const token = await login('owner@test.in', 'owner-password')
const before = await call(token, 'GET', '/settings/template')
- expect(before.json.settings['company.name']).toBe('Tecnostac')
+ expect(before.json.settings['company.name']).toBe('SiMS')
const put = await call(token, 'PUT', '/settings/template', {
template: { footerNote: 'Thank you!', declaration: 'We declare…', signatoryLabel: 'Proprietor' },
titles: { INVOICE: 'GST INVOICE' },
@@ -1086,7 +1086,7 @@ import { upsertReminder } from '../src/repos-reminders'
import { apiRouter } from '../src/api'
function appWith() {
- const db = openDb(':memory:'); seedIfEmpty(db) // company.name='Tecnostac'
+ const db = openDb(':memory:'); seedIfEmpty(db) // company.name='SiMS'
createStaff(db, { email: 'owner@test.in', displayName: 'Owner', role: 'owner', password: 'owner-password' })
const c = createClient(db, 'u1', { name: 'Acme', code: 'ACME', stateCode: '32', contacts: [{ name: 'Ravi', email: 'ravi@acme.in' }] })
const m = createModule(db, 'u1', { code: 'POS', name: 'POS' })
@@ -1114,8 +1114,8 @@ describe('GET /reminders/:id/preview', () => {
const token = await login()
const r = await get(token, ctx.overdueId)
expect(r.status).toBe(200)
- expect(r.json.subject).toContain(ctx.inv.docNo) // 'Payment reminder — Invoice INV/26-27-0001 (Tecnostac)'
- expect(r.json.subject).toContain('Tecnostac')
+ expect(r.json.subject).toContain(ctx.inv.docNo) // 'Payment reminder — Invoice INV/26-27-0001 (SiMS)'
+ expect(r.json.subject).toContain('SiMS')
expect(r.json.body).toContain('Acme') // clientName
})
it('404s an unknown reminder and 400s an internal follow_up', async () => {
@@ -2121,7 +2121,7 @@ function QueueActions(props: { rem: Reminder & { docNo: string | null }; onDone:
```
- [ ] **Step 2: Browser-verify** (owner login → **Dashboard**, with at least one sendable reminder in the queue — an overdue invoice reminder is easiest to seed):
- - Click **Preview** on an overdue reminder → the exact subject (e.g. `Payment reminder — Invoice INV/… (Tecnostac)`) and body appear inline, matching what Send would email; **Hide** collapses it.
+ - Click **Preview** on an overdue reminder → the exact subject (e.g. `Payment reminder — Invoice INV/… (SiMS)`) and body appear inline, matching what Send would email; **Hide** collapses it.
- Internal-only rows (follow-up / bounced) show no Preview/Send button (only Dismiss), unchanged.
- [ ] **Step 3: Typecheck + build + commit** — `npm run typecheck` + `npm run build -w @sims/hq-web` clean.
diff --git a/docs/superpowers/plans/2026-07-17-hq-console-redesign.md b/docs/superpowers/plans/2026-07-17-hq-console-redesign.md
index 73b8b9b..8850ea6 100644
--- a/docs/superpowers/plans/2026-07-17-hq-console-redesign.md
+++ b/docs/superpowers/plans/2026-07-17-hq-console-redesign.md
@@ -26,7 +26,7 @@
**Verify commands** (run from repo root `C:\SiMS\hq`):
- Typecheck: `npm run typecheck` → exits 0
- Tests: `npm test` → all pass
-- Dev app: terminal A `cd apps/hq && npm start` (API :5182), terminal B `cd apps/hq-web && npm run dev` (Vite :5183). Login `admin@tecnostac.com` (owner password known to the user; ask them if a login is needed for visual checks).
+- Dev app: terminal A `cd apps/hq && npm start` (API :5182), terminal B `cd apps/hq-web && npm run dev` (Vite :5183). Login `admin@sims.com` (owner password known to the user; ask them if a login is needed for visual checks).
---
diff --git a/docs/superpowers/specs/2026-07-17-hq-console-redesign-design.md b/docs/superpowers/specs/2026-07-17-hq-console-redesign-design.md
index 0c68f23..36e5882 100644
--- a/docs/superpowers/specs/2026-07-17-hq-console-redesign-design.md
+++ b/docs/superpowers/specs/2026-07-17-hq-console-redesign-design.md
@@ -7,7 +7,7 @@
*Approved direction: "system upgrade" — Direction A v2's system discipline wearing H-04's
warm palette. Sources reviewed: `admin_design_v2.html` (a Claude Design handoff tar; the
-chosen "Direction A v2" system), `H-04 Client 360 (timeline ribbon).html`, `Tecnostac
+chosen "Direction A v2" system), `H-04 Client 360 (timeline ribbon).html`, `SiMS
Unified Workspace` promo, the small APEX card/loan-detail mockups, and the current
`@sims/ui` tokens. Companion docs: `2026-07-17-apex-82963-ux-reference.md` (UX checklist
honoured throughout), `2026-07-17-quote-to-close-funnel-design.md` (pages this shell must
diff --git a/docs/superpowers/specs/2026-07-17-quote-to-close-funnel-design.md b/docs/superpowers/specs/2026-07-17-quote-to-close-funnel-design.md
index c336ca9..e4211a2 100644
--- a/docs/superpowers/specs/2026-07-17-quote-to-close-funnel-design.md
+++ b/docs/superpowers/specs/2026-07-17-quote-to-close-funnel-design.md
@@ -108,7 +108,7 @@ rebuildTable(db, table, newDDL, guardToken):
Employees [ + Add employee ]
────────────────────────────────────────────────────────────────────────────
Name Email Role Active Actions
- Asha Rao asha@tecnostac.com owner ● Edit · Reset pw
+ Asha Rao asha@sims.com owner ● Edit · Reset pw
Vikram Shah vikram@… manager ● Edit · Reset pw · Deactivate
Priya Nair priya@… staff ○ Edit · Reset pw · Reactivate
────────────────────────────────────────────────────────────────────────────