Marketing Agent workspace guide
Useful content starts with a clear purpose. Marketing Agent is Nixim’s tenant-aware workspace for configuring that purpose, preparing publishing destinations, and tracking the future content workflow.
Release scope: the secure administration foundation. Content generation, scheduled runs, media production and external publishing are not enabled.
Environments
| Environment | Address | Purpose |
|---|---|---|
| Production | marketing.nixim.co.uk | Operational workspace configuration |
| Development | marketing-dev.nixim.co.uk | Testing and development |
| Documentation | docs.marketing.nixim.co.uk | This guide and architecture reference |
The admin displays the current environment in its header. Development and production have different APIs, functions, tables and website buckets. A shared identity pool lets you use the same email and password in both environments; membership and configuration are independent. Saving a development setting does not change production.
Sign-in and recovery
Access is by invitation. Public self-registration is disabled. On your first visit, select Forgot password? First time here?, enter your invited email address, and request a verification code. Enter the code and choose a password with at least eight characters. Then sign in. Codes expire; request a new one if necessary.
The initial Nixim owner is provisioned with a verified recovery email. Passwords are handled directly by Amazon Cognito in Ireland, never by the administration API. The application keeps authentication tokens in memory, so reloading the page requires signing in again. Tokens are not persisted in browser storage. Access tokens last one hour; an active page refreshes them using a one-day refresh token. Sign out revokes the refresh token and clears local session state. An already-issued access token can remain valid until expiration; workspace suspension is checked server-side on each request and immediately blocks tenant operations.
If sign-in succeeds but no workspace is listed, an operator must assign membership. If recovery does not arrive, check spam and ask an operator to check verified email status, Cognito delivery settings and sending limits. Never share recovery codes.
Configure your organisation
Organisation stores your name, line of work, business aims, website URL and time zone. Describe the audience’s practical questions and the expertise you can share. These values are preparation for future generation; no model is called on save.
Owners and administrators can save. Read-only roles cannot update configuration, and the API enforces that restriction. Each save increments a version and creates an audit event in a single DynamoDB transaction. If another person saves first, you receive a conflict. Copy any unsaved changes, choose Reload saved, then apply your changes to the latest version. Switching pages keeps the current in-memory form values; switching workspace, reloading saved settings, or signing out discards unsaved values. Save before switching workspaces.
Publishing stores the preferred interval in whole hours (1–720), content formats, planned social channels and a destination table name. The interval is a preference; no EventBridge schedule is active. Social channel selection does not connect an account. You can create the Nixim social accounts later.
The production Nixim destination is seeded from the existing website’s published content table output. The development destination starts blank to avoid accidentally pointing development publishing at production content. This release grants no cross-project table write permissions. A future connector must verify the table, schema, tenant allowlist and publishing policy before it can operate.
Never enter API keys or passwords into business fields. Provider credentials are not accepted by this release. Future provider connections will store each tenant’s keys separately in AWS Secrets Manager; the browser will never retrieve stored keys.
The content workflow
| Stage | Intended behaviour | Current status |
|---|---|---|
| 1. Discover | Find timely topics aligned with business aims and audience questions | Planned |
| 2. Write | Research and generate substantive insights with evidence and useful detail | Planned |
| 3. Website | Publish approved content and make it appear in the latest homepage content | Planned |
| 4. Scenarios | Adapt the article into Instagram, YouTube, Facebook, TikTok and other scenarios | Planned |
| 5. Scripts | Produce scripts, captions and calls to action | Planned |
| 6. Assets | Produce graphics, clips, narration and audio | Planned |
| 7. Assembly | Render platform-appropriate videos linking back to the article | Planned |
| 8. Distribution | Publish through connected accounts and retain provider receipts | Planned |
The initial implementation sequence after this foundation is Nixim website content first, followed by social scenarios, media generation and publishing. Each stage needs explicit run states, retries, idempotency, quotas, usage records and approval policies. A saved preference must never imply that a publication succeeded.
Nixim’s existing website source is at C:/Company/NIXIM/website-v2. It remains a
separate application and deployment. The connector must reuse its actual content
schema, publication rules and homepage content selection rather than inventing a
second incompatible record format. ISS and other clients will have their own
allowlisted table destinations even when they share that schema and AWS account.
Costs and usage
The cost page separates three concepts:
- Measured workspace usage: authenticated tenant API request count for the UTC calendar month. A request to the costs page also counts. It is a usage measure, not a currency amount. Health checks, login and membership listing are excluded.
- Tagged platform costs: actual AWS Cost Explorer unblended service charges for
Project=marketing-agentand the selected environment plusshared. Only a platform-operator membership sees these aggregate costs. Shared costs appear in both environment views; do not sum the views. The end date is exclusive and the current billing day is excluded. Values may still be AWS estimates. - Per-tenant allocation: not available in this release. Shared Lambda, API, DynamoDB and hosting charges cannot be exactly split by tenant using resource tags. Future metering should capture execution duration, database consumption, asset bytes, transfer and workflow activity, then apply a documented allocation model. Fixed overhead should be shown separately. Allocations are estimates.
AWS cost allocation tags must be activated in Billing. New tag keys and cost data can take time to appear; an empty result is shown as pending, not as a zero-cost claim. Billing data is cached for six hours to limit chargeable Cost Explorer requests. Provider charges are not connected. BYO AI keys will keep provider accounts separate; provider billing visibility depends on supported provider APIs.
All new stacks carry Project=marketing-agent, Environment=dev|prod|shared and
CostCenter=marketing-platform. The existing Nixim website remains separately
tagged. CloudFront and Route 53 are global; application services reside in Ireland.
The Cost Explorer API uses its global billing endpoint. It is read-only and does
not move application data to another deployment region.
Architecture
The Angular SPA is served over HTTPS by CloudFront from a private S3 REST origin. Origin Access Control restricts bucket reads to the corresponding distribution. S3 public access is blocked. Extensionless paths serve the SPA entry point. CloudFront applies CSP, HSTS, frame denial, content-type and referrer headers.
Browser sign-in communicates directly with Cognito. The HTTP API validates the JWT issuer and the environment-specific app-client audience. Lambda additionally requires an access token, resolves the subject’s active membership, and checks the selected tenant’s status and role. The request’s tenant header never establishes membership by itself. Dev tokens fail at the production API and vice versa.
| Resource group | Location | Isolation |
|---|---|---|
| CodeCommit, deployment artifacts | eu-west-1 | One project repository and private versioned bucket |
| Cognito | eu-west-1 | One shared pool, separate dev/prod clients |
| HTTP API, Lambda, CloudWatch | eu-west-1 | Separate per environment |
| DynamoDB | eu-west-1 | Four tables per environment, tenant-prefixed keys |
| Admin and documentation S3 | eu-west-1 | Separate private website buckets |
| CloudFront and Route 53 | Global | Separate distributions and hostnames |
| CloudFront ACM certificate | us-east-1 | Required AWS certificate location; no app compute or storage |
The infrastructure templates are shared.yaml, certificate.yaml,
environment.yaml and website.yaml. They are generated by
scripts/generate_infrastructure.py and committed as readable YAML. The shared
foundation bootstraps its artifact bucket from a local template; subsequent
templates and Lambda bundles are uploaded under content-hashed S3 keys. Change
sets are recorded and reviewed for removals or replacements before execution.
Each website publication also stores a complete archive and a manifest of object
version IDs and content hashes in the private artifact bucket. Dev and prod use
identical application files; only their public runtime configuration differs.
Data model
| Table | Keys and access patterns |
|---|---|
ma-{env}-control |
USER#{sub} / TENANT#{id} lists memberships; TENANT#{id} / META resolves active tenants; TENANT#{id} / SETTINGS reads versioned configuration; PLATFORM#COSTS caches platform billing |
ma-{env}-content |
Reserved for tenant-scoped content and workflow data in the next phase; unused now |
ma-{env}-audit |
TENANT#{id} / EVENT#{UTC timestamp}#{UUID} records configuration changes; query latest 30 |
ma-{env}-usage |
TENANT#{id} / MONTH#{YYYY-MM} counts tenant API requests atomically |
Tables use on-demand capacity, encryption, point-in-time recovery, deletion protection and retention on stack deletion. The application uses keyed lookups and queries, not scans. Configuration writes use an expected version and transact with their audit event. Counter failure fails the request, rather than silently claiming complete metering. The current usage metric measures accepted workspace requests, including validation failures after membership resolution; it does not estimate database or model charges.
API and permissions
All authenticated routes require a Cognito access token in Authorization: Bearer
and, except /v1/me, a verified workspace selection in X-Tenant-Id. JSON errors
return a stable code, safe message and request ID where available. API and browser
configuration responses are not cached. CORS allows only the matching environment.
| Route | Permission | Result |
|---|---|---|
GET /health |
Public | Synthetic service and environment health |
GET /v1/me |
Authenticated access token | Active authorised workspaces |
GET /v1/settings |
Active member | Workspace configuration, automation disabled |
PUT /v1/settings |
Owner or admin | Validated versioned save plus audit event |
GET /v1/costs |
Owner, admin, billing or analyst | Tenant usage; aggregate costs only for platform operators |
GET /v1/audit |
Active member | Latest 30 configuration events, without actor identities |
The API role has access only to this environment’s tables and logs, plus read-only Cost Explorer access. It has no permissions to existing website tables, Secrets Manager, social APIs or model providers. The current foundation does not expose tenant creation, invitations, role editing, subscriptions or self-service onboarding.
Operations and recovery
CloudWatch retains Lambda and API access logs for 30 days. Access logs record route, status and request ID, not request bodies or authorization tokens. Application unexpected-error logs record only error type and request ID. Lambda error and throttling alarms exist per environment. No email or SMS alarm destination is configured yet; an operator must monitor these alarms until notifications are added.
HTTP API throttling is 15 requests/second with a burst of 30 per environment. Lambda has a reserved concurrency ceiling of 10 per environment. There is no content worker, external publishing permission or scheduled automation in this release.
For a failed configuration save, use the request ID to inspect API and Lambda logs. For a 409 conflict, reload the latest settings. For a 403, check membership, role, tenant status and selected environment. For a 401, sign in again and ensure the token comes from the matching app client. Do not weaken authorization to debug.
To roll back application code, deploy the previous immutable Lambda artifact and restore the previous versioned S3 frontend objects with their matching public configuration. Invalidate CloudFront paths after publishing. Do not replace or delete DynamoDB tables to roll back code. Point-in-time restore creates a new table; inspect and validate it before changing configuration or IAM. A destructive database restore/cutover requires a separate explicit operational decision. This foundation does not claim a completed disaster-recovery exercise or production SLA.
To suspend a tenant, set its META.status to suspended; all tenant API operations
will fail on the next request. To revoke one user’s access, suspend or remove the
specific environment membership. Shared Cognito disablement affects both
environments. Future offboarding must handle retention, exports and deletion as an
auditable workflow rather than deleting a tenant’s keys ad hoc.
Onboarding another organisation
Provision an invited Cognito identity and a separate tenant ID. Create the tenant metadata, initial versioned configuration, and membership records in each intended environment. Never copy a Nixim membership into another tenant without changing the tenant identifier. A platform-operator flag is privileged and must remain false for customer memberships. Customers may own their workspace without seeing aggregate platform billing. The operator bootstrap script is only for the initial Nixim owner and never resets an existing user’s password.
Later provisioning must support organisation-specific aims, social connections, content formats, schedules, provider secrets and destination table allowlists. No customer should supply a raw IAM role or arbitrary table ARN that the publisher automatically trusts. Same schema does not mean shared authorisation.
Release boundaries
This release intentionally has no customer-facing website, payment processing, public registration, AI calls, external publishing, video rendering, social OAuth, automatic scheduler, exact tenant AWS cost allocation, or provider key management. The full supplied design remains the longer-term reference; current owner choices and foundation decisions define this release’s deviations.
Documentation is public and contains architecture and operating guidance only. Never publish credentials, recovery codes, customer data or security-sensitive incident details here. Deployment evidence and local test captures are kept out of the public documentation build unless deliberately summarised.