Skip to main content

Frontend Developer Guide — Golan Sertifikasi Web

Stack: Angular
Repository: golan-web
Primary consumers: Students, instructors, admins, finance users, customer service
Backend: versioned REST/JSON public API through KrakenD Community Edition (golan-backend)
The Angular application is a client of the backend. It must not become a second source of truth for authorization, payments, finance, course completion, or certificate eligibility.

1. Frontend Scope

Angular web is the MVP client for:
MVP student capabilities include:
  • Google login/session handling and onboarding.
  • Catalog/course detail.
  • Midtrans top-up return/status, wallet balance and wallet-only cart/checkout.
  • Order/top-up/ledger history and wallet-refund request/status.
  • Permanent regular-course access, learning, progress, quiz, assignment, and regular certificate.
  • BNSP registration/fulfillment status and secure LSP access display.
  • In-app notification center and web push integration where supported by the selected provider/browser strategy.
MVP backoffice capabilities include the operational screens required for course/learning administration, manual grading, BNSP fulfillment/SLA monitoring, refund review, notification operations, audit visibility, and basic reporting subject to RBAC. The Angular application is a client of the backend. It must not become a second source of truth for authorization, payments, tax, refund eligibility, course completion, assessment results, certificate eligibility, BNSP delivery, or notification business state. Referral, wallet, instructor earnings/withdrawal and separate super-admin realized-profit reporting/payout controls belong to MVP web workflows, subject to backend authorization and the SSOT §51 production gate. Wishlist, discussions/community, advanced CMS and advanced analytics are non-blocking Phase 2 features.

1.1 Public Client Architecture

Angular is a public API client. Its network boundary is:
Angular must not:
  • call internal gRPC ports;
  • publish to or consume RabbitMQ directly;
  • connect to PostgreSQL or Dragonfly;
  • connect to ClamAV;
  • construct internal service URLs or discover services;
  • depend on private service database schemas or protobuf contracts;
  • bypass KrakenD to call a service directly in production.
The canonical public contract is OpenAPI (/openapi/openapi.yaml in the backend repository) under /api/v1/.... Internal gRPC/protobuf and RabbitMQ event schemas are backend implementation contracts, not Angular contracts. Angular may know domain ownership for diagnostics and UI semantics, but it must address public resources, not deployment units. A future backend service split/merge that preserves OpenAPI should not require a frontend architectural rewrite. Use feature-based boundaries.
Avoid one large components/ directory containing unrelated features.

3. Routing

Example:
Use route-level lazy loading for large feature areas.

4. Authentication

Google login flow should be thin on the frontend:
Do not infer authentication from local UI state alone. KrakenD may reject structurally invalid/expired access tokens at the edge, but authorization remains enforced by the owning backend service. A route guard or hidden button is never authorization. Web security preference:
  • If backend architecture supports same-site cookies, prefer secure HttpOnly session/refresh cookies.
  • Do not store long-lived sensitive tokens in localStorage unless architecture requires it and risks are explicitly accepted.

5. Auth State

Central auth state should contain only what the UI needs. Example:
UI permissions are for rendering/UX only. The backend still enforces every permission.

6. Guards

Examples:
Expected behavior:
  • Authenticated but onboarding incomplete → /onboarding.
  • Guest accessing private route → /login.
  • User lacking frontend permission → render 403/access denied.
  • Never assume route guard equals backend authorization.

7. HTTP Layer

Use one consistent public API client layer whose base URL points to KrakenD, not to individual services.
Cross-cutting responsibilities:
Canonical success envelopes:
Canonical list envelope:
Canonical error shape:
Rules:
  • UI logic may branch on stable error.code; do not branch on arbitrary message text.
  • Surface fields for form validation when supplied.
  • Preserve request_id for support/diagnostics.
  • Do not expose raw gateway/service stack traces.
  • Do not scatter raw HttpClient calls through components.
  • Do not blindly retry mutation requests. A retryable mutation requires an explicit idempotency contract/key or a backend-provided safe recovery flow.
  • 502, 503, timeout, and network errors mean canonical state may be unknown; refetch authoritative resources before claiming failure/success for critical workflows.

8. API Models

Do not manually invent slightly different models per screen. Use:
  • Shared generated API types from OpenAPI, or
  • A disciplined API model layer.
Backend enums are canonical. Public DTOs describe resources; they do not expose private service tables. Cross-domain IDs in DTOs must be treated as opaque identifiers. Never attempt client-side joins by assuming database relationships across services. Examples:

9. State Management

Do not add a heavy global store by default for every screen. Recommended approach:
  • Local component state for small isolated UI.
  • Signals/services for feature state.
  • Introduce NgRx only where state complexity justifies it.
Good global/long-lived candidates:
Avoid treating API response cache as permanent business state.

10. Public Catalog

Course cards should clearly distinguish:
This distinction must be visible before purchase. BNSP product copy must not imply:
  • Golan issues the BNSP certificate.
  • Assessment happens inside Golan.
  • Passing is guaranteed by purchase.
Recommended BNSP disclosure:

11. Course Detail

Regular course

May show:

BNSP product

Should show:
Do not show an internal “Golan BNSP certificate” badge.

12. Onboarding

Three steps:

Step 1 — Profile

Step 2 — Interests

Multi-select course categories.

Step 3 — Acquisition

Single-select source + Other text when needed. Requirements:
  • Preserve entered values between steps.
  • Load categories from API.
  • Validate client-side for UX.
  • Backend remains authoritative.
  • Completion request only after required steps are saved.

13. Cart

Cart must support both course types. Each item should show type:
Do not compute final payable totals as authoritative client values. Backend checkout response is canonical for:
Customer-facing prices are tax-inclusive. Frontend may render previews returned by the backend, but it must not add PPN itself or derive a payable total from a hardcoded tax rate. The final breakdown and amount always come from backend checkout.

14. Top-up and Wallet Checkout

Suggested flow:
Critical rule:
A successful Midtrans browser callback is not proof of a wallet credit or course purchase. Midtrans never pays a course order directly.
The UI must wait for backend canonical status. States:

15. Payment Result UX

After Midtrans top-up UI closes/returns:
  • Do not instantly create local enrollment state.
  • Refetch top-up and wallet; never create or mark a course order paid from the redirect.
  • If pending, show top-up verification state.
  • Offer manual “Check top-up status”.
  • After wallet credit, checkout via Commerce and refetch its order until it reports paid:
    • Regular course → link to My Courses.
    • BNSP → link to BNSP Registration status.

16. Student Regular Learning

Suggested layout:
Progress displayed from backend. Avoid client-only progress calculations that may diverge from server rules.

17. Quiz UX

Support:
Requirements:
  • Timer only when the backend/API returns an effective timed-attempt policy.
  • Warn before leaving an active attempt.
  • Submit through backend with double-submit protection.
  • Show score/status according to backend response.
  • Never expose correct-answer metadata before submission unless backend review policy explicitly permits it.
  • Essay submission must render pending_review or equivalent when manual grading is outstanding.
  • Do not show passed merely because the HTTP submission request succeeded.
  • Manual grading screens are available only to actors with grading permission and must show grading actor/result history where the API exposes it.
  • After grading mutation, refetch/reconcile the canonical attempt rather than locally manufacturing final course-completion state.

18. Assignment UX

Support:
Files should upload through approved backend/object-storage flow. Rules:
  • The current MVP default is three submissions, but Angular must never embed 3 as the business authority.
  • Render max_submissions, submissions_used, can_resubmit, and any deadline/reason from the backend response.
  • Every submission is shown as its own historical record where UX requires history; a resubmission must not visually overwrite the prior attempt as though it never existed.
  • Disable/enable resubmit controls from canonical backend capability fields and still handle server rejection because policy may change between render and click.
  • Grading success is not inferred from upload/submission success.

19. Regular Certificates

Student area:
Show:
Current certificate status semantics:
Regular certificates do not expire. Do not show an expiration date, countdown, or client-generated expiry state. Public verification:
Verification page should reveal only approved public data. Certificate availability/status is always taken from backend; course completion UI alone is not proof of issuance.

20. BNSP Student Experience

Dedicated area:
List states:
The API should provide operational fields such as:
Angular renders these fields; it does not calculate the SLA by adding a hardcoded 24 hours. The current product default is 1 × 24 hours on the configured business-day calendar, but backend policy remains authoritative. Detail page may show:

Credential UX

Credentials are sensitive. Requirements:
  • Password hidden by default.
  • Explicit “Show” action.
  • Copy button available.
  • No secret in browser URL.
  • No secret in analytics payload.
  • No secret in error logging.
  • Avoid persisting secret in application state longer than necessary.
  • API response containing secret should not be cached.
  • Clear secret state when navigating away if practical.
Recommended status copy for pending_access should communicate that payment is confirmed and admin is preparing LSP access without promising a client-computed timestamp. access_delivered means authorized staff have recorded delivery. Student opening/viewing credentials must not trigger that status transition. If a future acknowledgement feature exists, render it as a separate concept. This is not an internal BNSP assessment screen.

21. Admin BNSP Fulfillment

Admin screen:
Filters should support canonical status plus SLA operations, for example:
Detail should show:
Rules:
  • Creating/updating credentials and marking delivery are distinct mutations.
  • “Mark Delivered” is an explicit authorized action; merely viewing the admin screen or student screen does not set delivery state.
  • After mark-delivered succeeds, refetch the backend record before showing final state.
  • SLA overdue styling/badges are derived from backend fields/filter results, not from a locally embedded policy duration.
  • Credential mutation forms must avoid accidental resubmission and must not write secrets to logs, analytics, URL state, or persistent client caches.
  • Monitoring/escalation queues should be operationally sortable/filterable without inventing a new certification state.

22. Admin Course Management

Course editor should conditionally render sections. For regular:
For bnsp:
Do not expose regular certificate configuration for BNSP.

23. RBAC UX

Navigation visibility can use permissions. Examples:
However:
  • Hidden button ≠ authorization.
  • Handle backend 403 cleanly.
  • Provide a generic access denied page.

24. Reviews and Wishlist

wishlist is Phase 2 and must not block MVP delivery. If its existing UI/domain code remains, keep it isolated from core checkout/catalog paths. reviews/ratings have not been explicitly assigned to MVP or Phase 2 in the current product decision. Treat release scope for reviews as an Open Product Decision; do not silently make reviews a release blocker. For any enabled review UI, backend remains authoritative for eligibility and moderation state.

24.1 Media Upload and Scan Contract

Assignments, course media, certificate files, and other binary objects are governed by Media Service behind the public API. Angular must not construct arbitrary S3 object keys or treat a successful upload transfer as proof that a file is usable. Expected untrusted-upload lifecycle:
Rules:
  • Only clean media can be treated as trusted/usable.
  • pending_scan, scanning, and scan_failed require a waiting/error state; do not silently attach them as completed assignment content.
  • infected must be rejected and never offered for normal download.
  • Private downloads use authorized temporary URLs or another backend-controlled access mechanism.
  • Original filenames are presentation metadata, not trusted object identifiers.
  • BNSP credentials and auth tokens must never be sent through media metadata.

25. Errors

Map backend error codes to useful UI. Examples:
Prefer error-code mapping over parsing backend message strings.

26. Loading and Empty States

Every data screen needs:
High-value screens that require careful states:

27. Analytics

Track approved UI events only. Examples:
Never send:
UTM parameters should be captured on first relevant landing and sent through the supported backend attribution flow.

28. Accessibility

Minimum:
  • Keyboard navigable controls.
  • Form labels.
  • Semantic headings.
  • Error messages associated with fields.
  • Accessible dialogs.
  • Color is not the only status indicator.
  • Video content should support accessibility improvements when content production allows.

29. Responsive Design

Primary breakpoints should support:
Even with a Flutter mobile app, public web and authenticated web should remain responsive.

30. Performance

Use:
  • Lazy routes.
  • Image optimization.
  • Pagination/infinite load where appropriate.
  • Avoid loading complete course content in catalog payload.
  • Avoid repeated /me calls.
  • Cache only non-sensitive data appropriately.
  • Use trackBy/equivalent stable identity for lists.
Never cache BNSP secret responses in persistent browser storage.

31. Environment and Runtime Configuration

Typical environments:
Frontend runtime/build config may include deployment values such as:
Do not configure Angular with internal addresses or credentials such as:
The browser talks to KrakenD/public endpoints only. Never put backend secrets in Angular builds.

Business-policy rule

Do not add frontend environment variables such as:
as authoritative product policy. Angular should consume derived API fields such as:
Client-side use of these fields is for presentation and validation hints only; every mutation remains backend-validated.

31.1 Distributed Backend Workflow Semantics

The backend uses service-owned transactions plus asynchronous RabbitMQ processing for many cross-domain effects. Angular must not assume that one HTTP response means every downstream service has converged. Examples:
These effects may converge asynchronously. UX rules:
  • After Midtrans top-up return, fetch canonical top-up and wallet status; never infer wallet credit or paid order from redirect parameters.
  • If Commerce confirms wallet capture and the order is paid but enrollment/BNSP registration is not yet visible, show a neutral processing state and refetch with bounded backoff.
  • A timeout on a mutation is an unknown outcome until the resource is refetched or the idempotent command result is resolved.
  • Duplicate notifications/events must not trigger duplicate UI mutations.
  • Do not build UI logic around RabbitMQ event names or queue timing.
  • Use backend-exposed business statuses, timestamps, capabilities, and reason codes.

32. Testing

Unit

Focus on:

Component

Focus on:

E2E

Critical web flows:
Use test accounts and synthetic credentials only.

33. Frontend Definition of Done

A feature is complete when:
  1. Success/loading/empty/error states exist.
  2. Backend validation errors are rendered correctly.
  3. Permissions affect UX without pretending to provide backend security.
  4. Sensitive data is not persisted unnecessarily.
  5. BNSP and regular product semantics are clearly separated.
  6. Payment success waits for backend canonical status.
  7. Mobile-responsive behavior is acceptable.
  8. Tests cover critical interactions.
  9. API contract matches current OpenAPI/SSOT.
  10. All production API traffic uses the configured KrakenD/public API origin; no feature calls internal service hosts/gRPC.
  11. Distributed-workflow screens tolerate eventual convergence and unknown mutation outcomes.
  12. Upload-dependent flows respect Media Service scan state before considering a file usable.

34. Frontend Engineering Baseline

The web repository should define a small set of non-negotiable conventions so feature teams do not create incompatible patterns. Recommended baseline:
Avoid introducing a global state framework merely because the project has many screens. Add one only when actual cross-feature state complexity requires it. Each feature should expose a narrow public surface. A feature should not import another feature’s internal components/services directly unless that dependency is intentional and stable. Suggested dependency direction:

35. Route and Access Contract

Routes should encode presentation/navigation, while the backend remains authoritative for access. Recommended route metadata concept:
Expected route behavior:
Do not authorize solely by checking role strings such as admin. Route access should use backend-supplied permissions where practical. When a protected API returns 403 despite the UI believing access exists, the UI must accept the backend result, show access denied, and refresh permissions if appropriate.

36. Session and Authentication Lifecycle

The web app must handle more than the initial Google button. Canonical client states:
Bootstrap sequence:
Requirements:
  • Prevent multiple simultaneous refresh attempts from producing a refresh storm.
  • Queue or fail requests consistently while a refresh is in progress.
  • A failed refresh that definitively means session expiry must clear authenticated state.
  • A temporary network error must not be confused with explicit logout/session invalidation.
  • Logout must clear client auth state and sensitive feature state.
  • Never log OAuth credentials, access tokens, refresh tokens, or raw auth responses.
If cookies are used:
If bearer tokens are used, storage and refresh behavior must be documented as part of the backend contract.

37. DTO, View Model, and Enum Discipline

API DTOs and UI view models solve different problems and should not be conflated. Recommended pattern:
Use a mapper when the UI needs derived presentation data such as:
Do not rewrite canonical enums inside components. Bad:
when backend canonical state is paid. Prefer exhaustive handling of known states so a new backend enum causes a visible development/test failure rather than silent incorrect UI.

38. Form Architecture and Validation

Use reactive forms for onboarding, checkout-adjacent forms, admin forms, refund/withdrawal forms, and other multi-field workflows. Validation layers:
Field errors returned by backend should map to the relevant form control where possible. Example normalized error handling:
Rules:
  • Preserve form values after server validation failure.
  • Disable duplicate submit while the same mutation is in flight.
  • Do not permanently disable the button after recoverable network failures.
  • Dirty-form navigation warnings should be used for high-loss forms such as course editing and admin BNSP credential entry.

39. Query, Pagination, Filter, and URL State

Catalog and admin lists should have predictable URL-addressable state. Recommended URL parameters:
For admin list pages, include status/filter parameters where relevant. Requirements:
  • Refreshing the page should preserve meaningful list/filter state.
  • Back/forward navigation should behave correctly.
  • Do not fetch on every keystroke without debounce for search.
  • Cancel or ignore stale requests when new query state supersedes them.
  • Pagination metadata comes from backend.
  • Do not infer total pages from current page length.

40. Mutation and Idempotency UX

Client mutation state should distinguish:
unknown_result matters for operations where the request may have reached the server but the response was lost. For checkout/payment/financial mutations:
  • Prefer backend-supported idempotency keys where defined.
  • Do not automatically replay a request merely because a timeout occurred.
  • Provide a safe reconciliation action such as refetching order status.
For harmless idempotent actions such as wishlist state, optimistic UI may be used with rollback.

41. Detailed BNSP Credential Retrieval Contract

The student credential screen should be deliberately isolated from ordinary cached feature state. Suggested UI flow:
Do not preload secrets in:
When the credential endpoint returns 403/404/not-ready, display a state-specific message instead of exposing raw backend text. Admin credential form rules:
  • Password/secret is never shown in list rows.
  • Edit behavior must not accidentally blank an existing encrypted secret when the secret field is left untouched.
  • If the backend uses explicit replace semantics, the form must distinguish unchanged, replace, and clear where clearing is permitted.
  • After saving, scrub the plaintext secret from the form model as soon as practical.

42. Admin and Backoffice Interaction Standards

Backoffice screens are operational tools and should prioritize correctness over decorative UI. Every table/list that can trigger consequential actions should expose enough context to avoid acting on the wrong entity. Examples:
High-impact actions should use explicit confirmation:
Confirmation dialogs must describe the actual effect. Avoid generic Are you sure? for financial or irreversible actions.

43. Design System and UI State Contract

Create shared primitives for repeated behavior rather than one-off implementations. Minimum reusable components/patterns:
Status colors/icons are presentation only. Always include text labels so state is not communicated by color alone. Canonical client state labels should map from backend enums through one centralized mapping layer. Example:

44. Frontend Observability and Privacy

Production frontend telemetry should help diagnose failures without collecting secrets. Useful context:
Never include:
Global error handling must distinguish application bugs from expected domain errors. Expected 4xx outcomes should not create noisy fatal alerts when they are already handled by the feature.

45. Expanded Frontend Test Matrix

Testing should be organized by risk and locked business semantics, not just component count.

Contract tests

Verify that generated/central API models compile against the current OpenAPI contract and that enum/field changes are surfaced, including derived policy fields.

Auth tests

Commerce + refund tests

Learning tests

BNSP tests

Notification tests

Backoffice tests

Accessibility tests

Critical flows should be usable by keyboard and expose labels/roles for automated accessibility checks.

46. Build, Delivery, and Runtime Configuration

The built Angular artifact must not contain backend-only secrets. CI stages should include at minimum:
Deployment should make the application version discoverable for support/observability without exposing sensitive build metadata. When runtime configuration is used, validate required variables during startup and fail clearly if configuration is invalid rather than silently targeting the wrong backend/environment.

47. Frontend Feature Acceptance Template

Every substantial feature should be reviewed against this template before merge/release.
For payment, refund, BNSP, manual grading, certificate, and notification features, reconciliation/security semantics are release blockers rather than polish items.

48. Refund Workflow UX

Refund is MVP and is manual/admin reviewed. Student flow:
Rules:
  • Current default request window is seven days after payment, but the UI must never calculate eligibility from payment_date + 7 days as authority.
  • Prefer rendering refund_request_deadline_at, can_request_refund, and reason codes supplied by backend.
  • Request success does not mean refund approval or completed financial reversal.
  • Do not revoke/hide course/BNSP access client-side merely because a request was submitted.
  • BNSP with access_delivered is non-refundable by default; render backend decision/reason rather than reproducing this logic locally.
Admin/backoffice flow:
Approval/rejection controls require explicit permissions. UI should display audit metadata returned by backend and prevent accidental double action.

49. Push + In-App Notification Contract

The locked product SSOT and backend guide require push in MVP alongside in-app and email. Angular must not compensate for notification delivery delays or failures by inventing notification business state. Rules:
  • Backend notification/event state is canonical.
  • A browser push payload is a navigation/refetch hint, not the final business state.
  • Opening a notification should route using a safe reference and fetch the current resource through KrakenD.
  • Duplicate push events must not cause duplicate mutations.
  • Handle permission denied, unsupported browser, subscription rotation, logout, and revoked-session cleanup without breaking the in-app notification center.
  • Never put LSP credentials, auth tokens, payment secrets, private document URLs, or sensitive financial values in push payloads.
  • Do not require WebSocket for MVP notification correctness. Persistent in-app notification state plus refetch/push is sufficient; if one-way live UI updates are later required, evaluate an explicit backend-supported mechanism rather than opening arbitrary service sockets.

50. MVP Scope and Open Product Decisions

Web MVP includes student web plus admin/instructor/finance/customer-service operational workflows. Phase 2 features listed in the SSOT are non-blocking. If a product behavior is not specified by the SSOT/API, Angular must not invent a durable rule. Important unresolved examples currently include:
Treat these as Open Product Decision until the SSOT is revised. UI can show generic backend-provided capability/reason fields without defining the missing policy itself.